001    /**
002     * Copyright (C) 2007-2011, 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     */
019    
020    package org.dllearner.reasoning;
021    
022    import java.io.File;
023    import java.io.IOException;
024    import java.net.MalformedURLException;
025    import java.net.URI;
026    import java.net.URL;
027    import java.util.Collection;
028    import java.util.HashMap;
029    import java.util.HashSet;
030    import java.util.LinkedList;
031    import java.util.Map;
032    import java.util.Set;
033    import java.util.SortedSet;
034    import java.util.TreeMap;
035    import java.util.TreeSet;
036    
037    import javax.xml.namespace.QName;
038    
039    import org.apache.xmlbeans.XmlCursor;
040    import org.dllearner.core.ComponentInitException;
041    import org.dllearner.core.AbstractKnowledgeSource;
042    import org.dllearner.core.OntologyFormat;
043    import org.dllearner.core.AbstractReasonerComponent;
044    import org.dllearner.core.configurators.DIGReasonerConfigurator;
045    import org.dllearner.core.options.BooleanConfigOption;
046    import org.dllearner.core.options.ConfigEntry;
047    import org.dllearner.core.options.ConfigOption;
048    import org.dllearner.core.options.InvalidConfigOptionValueException;
049    import org.dllearner.core.options.StringConfigOption;
050    import org.dllearner.core.owl.ClassHierarchy;
051    import org.dllearner.core.owl.Description;
052    import org.dllearner.core.owl.Individual;
053    import org.dllearner.core.owl.NamedClass;
054    import org.dllearner.core.owl.Nothing;
055    import org.dllearner.core.owl.ObjectProperty;
056    import org.dllearner.core.owl.ObjectPropertyHierarchy;
057    import org.dllearner.core.owl.Thing;
058    import org.dllearner.utilities.Files;
059    import org.dllearner.utilities.Helper;
060    import org.dllearner.utilities.owl.ConceptComparator;
061    import org.dllearner.utilities.owl.RoleComparator;
062    import org.kr.dl.dig.v1_1.Concepts;
063    import org.kr.dl.dig.v1_1.Csynonyms;
064    import org.kr.dl.dig.v1_1.IdType;
065    import org.kr.dl.dig.v1_1.Named;
066    import org.kr.dl.dig.v1_1.ResponseDocument;
067    import org.kr.dl.dig.v1_1.ResponsesDocument;
068    import org.kr.dl.dig.v1_1.Roles;
069    import org.kr.dl.dig.v1_1.Rsynonyms;
070    import org.kr.dl.dig.v1_1.IndividualSetDocument.IndividualSet;
071    
072    /**
073     * DIG 1.1 implementation of the reasoner interface.
074     * 
075     * @author Jens Lehmann
076     * 
077     */
078    public class DIGReasoner extends AbstractReasonerComponent {
079            
080            private DIGReasonerConfigurator configurator;
081            @Override
082            public DIGReasonerConfigurator getConfigurator(){
083                    return configurator;
084            }
085            
086    
087            URL reasonerURL;
088    
089            // Variablen für Reasoner
090            DIGHTTPConnector connector;
091            String identifier;
092            URI kbURI;
093            private String asksPrefix;
094            // Cache für Konzepte, Rollen und Individuen
095            Set<NamedClass> atomicConcepts;
096            Set<ObjectProperty> atomicRoles;
097            SortedSet<Individual> individuals;
098    
099            // Cache für Subsumptionhierarchie
100            // Comparator ist notwendig, da sonst z.B. verschiedene Instanzen des
101            // atomaren Konzepts male
102            // unterschiedlich sind;
103            // alternativ wäre auch eine Indizierung über Strings möglich
104            ConceptComparator conceptComparator = new ConceptComparator();
105            RoleComparator roleComparator = new RoleComparator();
106            ClassHierarchy subsumptionHierarchy;
107            ObjectPropertyHierarchy roleHierarchy;
108            // enthält atomare Konzepte, sowie Top und Bottom
109            Set<Description> allowedConceptsInSubsumptionHierarchy;
110    
111            private boolean writeDIGProtocol;
112            private File digProtocolFile;
113            private static String defaultDIGProtocolFile = "log/digProtocol.txt";
114            
115            
116            
117            public DIGReasoner(Set<AbstractKnowledgeSource> sources) {
118                    super(sources);
119                    this.configurator =  new DIGReasonerConfigurator(this);
120                    try {
121                            reasonerURL = new URL("http://localhost:8081");
122                    } catch (MalformedURLException e) {
123                    }
124            }
125    
126            @Override
127            public void init() throws ComponentInitException {
128                    // if a DIG protocol is written clear the file first
129                    if(writeDIGProtocol) {
130                            if(digProtocolFile == null)
131                                    digProtocolFile = new File(defaultDIGProtocolFile);
132                            Files.clearFile(digProtocolFile);
133                            connector = new DIGHTTPConnector(reasonerURL, digProtocolFile);
134                    } else {
135                            connector = new DIGHTTPConnector(reasonerURL);
136                    }
137                    
138                    try {
139                            identifier = connector.getIdentifier();
140                    } catch (IOException e1) {
141                            throw new ComponentInitException("Communication problem with DIG Reasoner. Please make sure there is a DIG reasoner running at " + reasonerURL + " and try again.", e1);
142                    }
143                    kbURI = connector.newKB();
144    
145                    // asks-Prefix entsprechend der KB-URI initialisieren
146                    asksPrefix = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
147                    asksPrefix += "<asks xmlns=\"http://dl.kr.org/dig/2003/02/lang\" "
148                                    + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
149                                    + "xsi:schemaLocation=\"http://dl.kr.org/dig/2003/02/lang\n"
150                                    + "http://dl-web.man.ac.uk/dig/2003/02/dig.xsd\" uri=\"" + kbURI + "\">";
151    
152                    // momementan wird davon ausgegangen, dass toDIG(kbURI) den gesamten
153                    // tells-Request liefert
154                    StringBuilder sb = new StringBuilder();
155                    // sb.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
156                    // sb.append("<tells xmlns=\"http://dl.kr.org/dig/2003/02/lang\" " +
157                    // "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
158                    // "xsi:schemaLocation=\"http://dl.kr.org/dig/2003/02/lang\n" +
159                    // "http://dl-web.man.ac.uk/dig/2003/02/dig.xsd\" uri=\""+kbURI+"\">");
160                    for (AbstractKnowledgeSource source : sources) {
161                            sb.append(source.toDIG(kbURI));
162    
163                            ResponseDocument rd = null;
164                            try {
165                                    rd = connector.tells(sb.toString());
166                            } catch (IOException e) {
167                                    throw new ComponentInitException("Could not read knowledge source " + source + ".", e);
168                            }
169                            if (!rd.getResponse().isSetOk()) {
170                                    System.err.println("DIG-Reasoner cannot read knowledgebase.");
171                                    System.exit(0);
172                            }
173                    }
174                    // sb.append("</tells>");
175    
176                    // DIG-Abfragen nach Konzepten, Rollen, Individuals
177                    atomicConcepts = getAtomicConceptsDIG();
178                    atomicRoles = getAtomicRolesDIG();
179                    individuals = getIndividualsDIG();
180                    
181            }
182    
183            public static String getName() {
184                    return "DIG reasoner";
185            }
186            
187    
188            public static Collection<ConfigOption<?>> createConfigOptions() {
189                    Collection<ConfigOption<?>> options = new LinkedList<ConfigOption<?>>();
190                    options.add(new StringConfigOption("reasonerUrl", "URL of the DIG reasoner"));
191                    options.add(new BooleanConfigOption("writeDIGProtocol",
192                                    "specifies whether or not to write a protocoll of send and received DIG requests",
193                                    false));
194                    options.add(new StringConfigOption("digProtocolFile", "the file to store the DIG protocol",
195                                    defaultDIGProtocolFile));
196                    return options;
197            }
198    
199            /*
200             * (non-Javadoc)
201             * 
202             * @see org.dllearner.core.Component#applyConfigEntry(org.dllearner.core.ConfigEntry)
203             */
204            @Override
205            public <T> void applyConfigEntry(ConfigEntry<T> entry) throws InvalidConfigOptionValueException {
206                    String name = entry.getOptionName();
207                    if (name.equals("reasonerUrl")) {
208                            String s = (String) entry.getValue();
209                            try {
210                                    reasonerURL = new URL(s);
211                            } catch (MalformedURLException e) {
212                                    // e.printStackTrace();
213                                    throw new InvalidConfigOptionValueException(entry.getOption(), entry.getValue());
214                            }
215                    } else if(name.equals("writeDIGProtocol")) {
216                            writeDIGProtocol = (Boolean) entry.getValue();
217                    } else if(name.equals("digProtocolFile")) {
218                            digProtocolFile = new File((String) entry.getValue());
219                    }
220            }
221    
222            /**
223             * Construct a subsumption hierarchy using DIG queries. After calling this
224             * method one can ask for children or parents in the subsumption hierarchy.
225             */
226    //      public void prepareSubsumptionHierarchy(Set<NamedClass> allowedConcepts) {
227    //              allowedConceptsInSubsumptionHierarchy = new TreeSet<Description>(conceptComparator);
228    //              allowedConceptsInSubsumptionHierarchy.addAll(allowedConcepts);
229    //              allowedConceptsInSubsumptionHierarchy.add(new Thing());
230    //              allowedConceptsInSubsumptionHierarchy.add(new Nothing());
231    //
232    //              TreeMap<Description, TreeSet<Description>> subsumptionHierarchyUp = new TreeMap<Description, TreeSet<Description>>(
233    //                              conceptComparator);
234    //              TreeMap<Description, TreeSet<Description>> subsumptionHierarchyDown = new TreeMap<Description, TreeSet<Description>>(
235    //                              conceptComparator);
236    //
237    //              // Subsumptionhierarchy berechnen
238    //              // TODO: kann man effizienter auch in einer Abfrage machen
239    //
240    //              // Refinements von Top
241    //              TreeSet<Description> tmp = getMoreSpecialConceptsDIG(new Thing());
242    //              tmp.retainAll(allowedConceptsInSubsumptionHierarchy);
243    //              subsumptionHierarchyDown.put(new Thing(), tmp);
244    //
245    //              // Refinements von Bottom
246    //              tmp = getMoreGeneralConceptsDIG(new Nothing());
247    //              tmp.retainAll(allowedConceptsInSubsumptionHierarchy);
248    //              subsumptionHierarchyUp.put(new Nothing(), tmp);
249    //
250    //              // Refinement atomarer Konzepte
251    //              for (NamedClass atom : atomicConcepts) {
252    //                      tmp = getMoreSpecialConceptsDIG(atom);
253    //                      tmp.retainAll(allowedConceptsInSubsumptionHierarchy);
254    //                      subsumptionHierarchyDown.put(atom, tmp);
255    //
256    //                      tmp = getMoreGeneralConceptsDIG(atom);
257    //                      tmp.retainAll(allowedConceptsInSubsumptionHierarchy);
258    //                      subsumptionHierarchyUp.put(atom, tmp);
259    //              }
260    //
261    //              subsumptionHierarchy = new ClassHierarchy(
262    //                              subsumptionHierarchyUp, subsumptionHierarchyDown);
263    //      }
264    
265            /**
266             * Constructs a role hierarchy using DIG queries. After calling this method,
267             * one can query parents or children of roles.
268             * 
269             * TODO Does not yet take ignored roles into account.
270             */
271    //      public void prepareRoleHierarchy(Set<ObjectProperty> allowedRoles) {
272    //              TreeMap<ObjectProperty, TreeSet<ObjectProperty>> roleHierarchyUp = new TreeMap<ObjectProperty, TreeSet<ObjectProperty>>(
273    //                              roleComparator);
274    //              TreeMap<ObjectProperty, TreeSet<ObjectProperty>> roleHierarchyDown = new TreeMap<ObjectProperty, TreeSet<ObjectProperty>>(
275    //                              roleComparator);
276    // 
277    //              // Refinement atomarer Konzepte
278    //              for (ObjectProperty role : atomicRoles) {
279    //                      roleHierarchyDown.put(role, getMoreSpecialRolesDIG(role));
280    //                      roleHierarchyUp.put(role, getMoreGeneralRolesDIG(role));
281    //              }
282    //
283    //              roleHierarchy = new ObjectPropertyHierarchy(allowedRoles, roleHierarchyUp,
284    //                              roleHierarchyDown);
285    //      }
286    
287            // eigentlich müsste man klonen um sicherzustellen, dass der parent-Link
288            // bei null bleibt; bei der aktuellen Implementierung ist der parent-Link
289            // nicht immer null, was bei GP negative Auswirkungen haben könnte
290            // Update: wird durch klonen innerhalb der GP-Operationen erledigt
291            public Set<NamedClass> getNamedClasses() {
292                    /*
293                     * if(Config.algorithm == Config.Algorithm.GP || Config.algorithm ==
294                     * Config.Algorithm.HYBRID_GP) { Set<AtomicConcept> returnSet = new
295                     * HashSet<AtomicConcept>(); for(AtomicConcept ac : atomicConcepts)
296                     * returnSet.add((AtomicConcept)ac.clone()); return returnSet; }
297                     */
298                    return atomicConcepts;
299            }
300    
301            private Set<NamedClass> getAtomicConceptsDIG() {
302                    String atomicConceptsDIG = asksPrefix;
303                    atomicConceptsDIG += "<allConceptNames id=\"ask_names\"/></asks>";
304    
305                    ResponsesDocument rd = connector.asks(atomicConceptsDIG);
306                    // Struktur: einzelnes conceptSet außen, dann mehrere synonyms, die dann
307                    // die Konzept inkl. Top und Bottom enthalten
308                    Csynonyms[] synonymsArray = rd.getResponses().getConceptSetArray();
309                    Concepts[] conceptsArray = synonymsArray[0].getSynonymsArray();
310    
311                    Set<NamedClass> atomicConcepts = new TreeSet<NamedClass>(conceptComparator);
312                    for (Concepts concepts : conceptsArray) {
313                            boolean topOrBottomFound = false;
314                            if (concepts.getBottomArray().length != 0 || concepts.getTopArray().length != 0)
315                                    topOrBottomFound = true;
316    
317                            // nur weitersuchen falls das Konzept nicht äquivalent zu Top
318                            // oder Bottom ist
319                            if (!topOrBottomFound) {
320                                    boolean nonAnonymousConceptFound = false;
321                                    NamedClass foundConcept = null;
322                                    Named[] catoms = concepts.getCatomArray();
323                                    for (Named catom : catoms) {
324                                            String name = catom.getName();
325                                            if (!name.startsWith("anon")) {
326                                                    if (!nonAnonymousConceptFound) {
327                                                            nonAnonymousConceptFound = true;
328                                                            foundConcept = new NamedClass(catom.getName());
329                                                            atomicConcepts.add(foundConcept);
330                                                    } else {
331                                                            System.out
332                                                                            .println("Warning: Background knowledge contains synonym concepts. "
333                                                                                            + "We decide to pick "
334                                                                                            + foundConcept
335                                                                                            + ". \nDIG-XML:\n" + concepts);
336                                                    }
337                                            }
338                                    }
339                            }
340                    }
341    
342                    return atomicConcepts;
343            }
344    
345            public Set<ObjectProperty> getObjectProperties() {
346                    return atomicRoles;
347            }
348    
349            private Set<ObjectProperty> getAtomicRolesDIG() {
350                    String atomicRolesDIG = asksPrefix;
351                    atomicRolesDIG += "<allRoleNames id=\"ask_roles\"/></asks>";
352    
353                    ResponsesDocument rd = connector.asks(atomicRolesDIG);
354                    // Struktur: einzelnes roleSet außen, dann synonyms mit ratoms
355                    // innen
356                    Rsynonyms[] synonymsArray = rd.getResponses().getRoleSetArray();
357                    Roles[] rolesArray = synonymsArray[0].getSynonymsArray();
358    
359                    Set<ObjectProperty> digAtomicRoles = new HashSet<ObjectProperty>();
360                    for (Roles roles : rolesArray) {
361                            // hier koennen wiederum mehrere ratoms enthalten sein,
362                            // aber wir wollen nur eins auslesen
363                            Named[] ratoms = roles.getRatomArray();
364                            Named role = ratoms[0];
365                            digAtomicRoles.add(new ObjectProperty(role.getName()));
366    
367                            if (ratoms.length > 1)
368                                    System.out.println("Warning: Background knowledge contains synonym roles. "
369                                                    + "Will ignore all but the first. \nDIG-XML:\n" + roles);
370                    }
371    
372                    return digAtomicRoles;
373            }
374    
375            public SortedSet<Individual> getIndividuals() {
376                    return individuals;
377            }
378    
379            private SortedSet<Individual> getIndividualsDIG() {
380                    String individualsDIG = asksPrefix;
381                    individualsDIG += "<allIndividuals id=\"ask_individuals\"/></asks>";
382    
383                    ResponsesDocument rd = connector.asks(individualsDIG);
384                    // Struktur: einzelnes individualSet außen, dann Liste von
385                    // individual-Elementen
386                    IndividualSet[] individualsArray = rd.getResponses().getIndividualSetArray();
387                    Named[] namedIndividuals = individualsArray[0].getIndividualArray();
388    
389                    SortedSet<Individual> digIndividuals = new TreeSet<Individual>();
390                    for (Named named : namedIndividuals)
391                            digIndividuals.add(new Individual(named.getName()));
392    
393                    return digIndividuals;
394            }
395    
396            @Override
397            public ReasonerType getReasonerType() {
398                    return ReasonerType.DIG;
399            }
400    
401            @Override
402            public boolean isSuperClassOfImpl(Description superConcept, Description subConcept) {
403                    // System.out.println("subsumes(" + superConcept + "," + subConcept +
404                    // ")");
405                    String subsumesDIG = asksPrefix;
406                    subsumesDIG += "<subsumes id=\"query_subsume\">";
407                    subsumesDIG += DIGConverter.getDIGString(superConcept);
408                    subsumesDIG += DIGConverter.getDIGString(subConcept);
409                    subsumesDIG += "</subsumes></asks>";
410    
411                    return parseBooleanAnswer(subsumesDIG);
412            }
413    
414    //      @Override
415    //      public Set<Description> subsumesImpl(Description superConcept, Set<Description> subConcepts) {
416    //              String subsumesDIG = asksPrefix;
417    //              int id = 0;
418    //              // ID-Konzept-Zuordnung speichern, da bei der Antwort nur die IDs
419    //              // ausgegeben werden
420    //              Map<String, Description> queryMap = new HashMap<String, Description>();
421    //              for (Description subConcept : subConcepts) {
422    //                      queryMap.put("query" + id, subConcept);
423    //                      subsumesDIG += "<subsumes id=\"query" + id + "\">";
424    //                      subsumesDIG += DIGConverter.getDIGString(superConcept);
425    //                      subsumesDIG += DIGConverter.getDIGString(subConcept);
426    //                      subsumesDIG += "</subsumes>";
427    //                      id++;
428    //              }
429    //              subsumesDIG += "</asks>";
430    //
431    //              ResponsesDocument rd = connector.asks(subsumesDIG);
432    //              IdType[] subsumedConceptsIds = rd.getResponses().getTrueArray();
433    //
434    //              Set<Description> returnSet = new HashSet<Description>();
435    //              for (IdType idType : subsumedConceptsIds) {
436    //                      returnSet.add(queryMap.get(idType.getId()));
437    //              }
438    //              return returnSet;
439    //      }
440    
441            @Override
442            public Set<Description> isSuperClassOfImpl(Set<Description> superConcepts, Description subConcept) {
443                    String subsumesDIG = asksPrefix;
444                    int id = 0;
445                    Map<String, Description> queryMap = new HashMap<String, Description>();
446                    for (Description superConcept : superConcepts) {
447                            queryMap.put("query" + id, superConcept);
448                            subsumesDIG += "<subsumes id=\"query" + id + "\">";
449                            subsumesDIG += DIGConverter.getDIGString(superConcept);
450                            subsumesDIG += DIGConverter.getDIGString(subConcept);
451                            subsumesDIG += "</subsumes>";
452                            id++;
453                    }
454                    subsumesDIG += "</asks>";
455    
456                    ResponsesDocument rd = connector.asks(subsumesDIG);
457                    IdType[] subsumedConceptsIds = rd.getResponses().getTrueArray();
458    
459                    Set<Description> returnSet = new HashSet<Description>();
460                    for (IdType idType : subsumedConceptsIds) {
461                            returnSet.add(queryMap.get(idType.getId()));
462                    }
463                    return returnSet;
464            }
465    
466            /*
467             * // es wird geklont, damit Subsumptionhierarchie nicht von außen verändert
468             * werden // kann @SuppressWarnings("unchecked") @Override public SortedSet<Concept>
469             * getMoreGeneralConcepts(Concept concept) { return (TreeSet<Concept>)
470             * subsumptionHierarchyUp.get(concept).clone(); // return
471             * subsumptionHierarchyUp.get(concept); // ohne klonen geht es nicht }
472             * 
473             * @SuppressWarnings("unchecked") @Override public SortedSet<Concept>
474             * getMoreSpecialConcepts(Concept concept) { return (TreeSet<Concept>)
475             * subsumptionHierarchyDown.get(concept).clone(); // return
476             * subsumptionHierarchyDown.get(concept); // ohne klonen geht es nicht }
477             */
478    
479    //      @Override
480    //      public ObjectPropertyHierarchy getRoleHierarchy() {
481    //              return roleHierarchy;
482    //      }
483    
484            @Override
485            protected TreeSet<Description> getSuperClassesImpl(Description concept) {
486                    String moreGeneralDIG = asksPrefix;
487                    moreGeneralDIG += "<parents id=\"query_parents\">";
488                    moreGeneralDIG += DIGConverter.getDIGString(concept);
489                    moreGeneralDIG += "</parents></asks>";
490    
491                    ResponsesDocument rd = connector.asks(moreGeneralDIG);
492                    TreeSet<Description> resultsSet = new TreeSet<Description>(conceptComparator);
493                    // ein Array, der Synomyms-Elemente enthält, die dann Mengen von
494                    // äquivalenten Konzepten enthalten;
495                    // (es wird hier nur das erste Element des ConceptSetArrays gelesen,
496                    // da nur ein solches Element bei dieser Abfrage erwartet wird)
497                    Concepts[] conceptsArray = rd.getResponses().getConceptSetArray()[0].getSynonymsArray();
498    
499                    for (int i = 0; i < conceptsArray.length; i++) {
500                            // es werden nur atomare Konzepte erwartet
501                            Named[] atoms = conceptsArray[i].getCatomArray();
502    
503                            for (Named atom : atoms) {
504                                    NamedClass ac = new NamedClass(atom.getName());
505                                    if (allowedConceptsInSubsumptionHierarchy.contains(ac))
506                                            resultsSet.add(ac);
507                            }
508    
509                            // hinzufügen von Top, falls notwendig
510                            if (conceptsArray[i].getTopArray().length > 0)
511                                    resultsSet.add(new Thing());
512    
513                            // falls bisher kein erlaubtes Konzept gefunden wurden, dann gibt es
514                            // entweder keine allgemeineren Konzepte oder es handelt sich um
515                            // nicht erlaubte (von Jena erzeugte) Konzepte, die nicht äquivalent
516                            // zu einem erlaubten Konzept sind; in dem Fall muss die Methode
517                            // rekursiv
518                            // noch einmal aufgerufen werden
519                            if (resultsSet.size() == 0 && atoms.length > 0) {
520                                    // wir wählen das erste Konzept aus, welches ein ignoriertes
521                                    // Konzept ist
522                                    // (sonst wäre es weiter oben gefunden wurden)
523                                    NamedClass ignoredAtomicConcept = new NamedClass(atoms[0].getName());
524                                    resultsSet.addAll(getSuperClassesImpl(ignoredAtomicConcept));
525                            }
526    
527                    }
528    
529                    return resultsSet;
530            }
531    
532            @Override
533            protected TreeSet<Description> getSubClassesImpl(Description concept) {
534                    String moreSpecialDIG = asksPrefix;
535                    moreSpecialDIG += "<children id=\"query_children\">";
536                    moreSpecialDIG += DIGConverter.getDIGString(concept);
537                    moreSpecialDIG += "</children></asks>";
538    
539                    // Kommentare siehe getMoreGeneralConcepts(Concept)
540                    ResponsesDocument rd = connector.asks(moreSpecialDIG);
541                    TreeSet<Description> resultsSet = new TreeSet<Description>(conceptComparator);
542                    Concepts[] conceptsArray = rd.getResponses().getConceptSetArray()[0].getSynonymsArray();
543    
544                    for (int i = 0; i < conceptsArray.length; i++) {
545                            Named[] atoms = conceptsArray[i].getCatomArray();
546                            for (Named atom : atoms) {
547                                    NamedClass ac = new NamedClass(atom.getName());
548                                    if (allowedConceptsInSubsumptionHierarchy.contains(ac))
549                                            resultsSet.add(ac);
550                            }
551    
552                            // hinzufügen von Bottom, falls notwendig
553                            if (conceptsArray[i].getBottomArray().length > 0)
554                                    resultsSet.add(new Nothing());
555    
556                            if (resultsSet.size() == 0 && atoms.length > 0) {
557                                    NamedClass ignoredAtomicConcept = new NamedClass(atoms[0].getName());
558                                    resultsSet.addAll(getSubClassesImpl(ignoredAtomicConcept));
559                            }
560                    }
561    
562                    return resultsSet;
563            }
564    
565            @Override
566            protected TreeSet<ObjectProperty> getSuperPropertiesImpl(ObjectProperty role) {
567                    String moreGeneralRolesDIG = asksPrefix;
568                    moreGeneralRolesDIG += "<rparents id=\"query_parents\">";
569                    moreGeneralRolesDIG += "<ratom name=\"" + role.getName() + "\" />";
570                    moreGeneralRolesDIG += "</rparents></asks>";
571    
572                    ResponsesDocument rd = connector.asks(moreGeneralRolesDIG);
573                    TreeSet<ObjectProperty> resultsSet = new TreeSet<ObjectProperty>(roleComparator);
574                    Roles[] rolesArray = rd.getResponses().getRoleSetArray()[0].getSynonymsArray();
575    
576                    for (int i = 0; i < rolesArray.length; i++) {
577                            Named[] atoms = rolesArray[i].getRatomArray();
578    
579                            for (Named atom : atoms) {
580                                    ObjectProperty ar = new ObjectProperty(atom.getName());
581                                    // if(Config.Refinement.allowedRoles.contains(ar))
582                                    resultsSet.add(ar);
583                            }
584                    }
585    
586                    // System.out.println(rd);
587    
588                    return resultsSet;
589            }
590    
591            @Override
592            protected TreeSet<ObjectProperty> getSubPropertiesImpl(ObjectProperty role) {
593                    String moreSpecialRolesDIG = asksPrefix;
594                    moreSpecialRolesDIG += "<rchildren id=\"query_children\">";
595                    moreSpecialRolesDIG += "<ratom name=\"" + role.getName() + "\" />";
596                    moreSpecialRolesDIG += "</rchildren></asks>";
597    
598                    ResponsesDocument rd = connector.asks(moreSpecialRolesDIG);
599                    TreeSet<ObjectProperty> resultsSet = new TreeSet<ObjectProperty>(roleComparator);
600                    Roles[] rolesArray = rd.getResponses().getRoleSetArray()[0].getSynonymsArray();
601    
602                    for (int i = 0; i < rolesArray.length; i++) {
603                            Named[] atoms = rolesArray[i].getRatomArray();
604    
605                            for (Named atom : atoms) {
606                                    ObjectProperty ar = new ObjectProperty(atom.getName());
607                                    // if(Config.Refinement.allowedRoles.contains(ar))
608                                    resultsSet.add(ar);
609                            }
610                    }
611    
612                    return resultsSet;
613            }
614    
615            @Override
616            public boolean hasTypeImpl(Description concept, Individual individual) {
617                    String instanceCheckDIG = asksPrefix;
618                    instanceCheckDIG += "<instance id= \"query_instance\">";
619                    instanceCheckDIG += "<individual name=\"" + individual.getName() + "\"/>";
620                    instanceCheckDIG += DIGConverter.getDIGString(concept);
621                    instanceCheckDIG += "</instance></asks>";
622    
623                    return parseBooleanAnswer(instanceCheckDIG);
624            }
625    
626            @Override
627            public SortedSet<Individual> hasTypeImpl(Description concept, Set<Individual> individuals) {
628                    String instanceCheckDIG = asksPrefix;
629                    int id = 0;
630                    // ID-Konzept-Zuordnung speichern, da bei der Antwort nur die IDs
631                    // ausgegeben werden
632                    Map<String, String> queryMap = new HashMap<String, String>();
633                    for (Individual individual : individuals) {
634                            queryMap.put("query" + id, individual.getName());
635                            instanceCheckDIG += "<instance id= \"query" + id + "\">";
636                            instanceCheckDIG += "<individual name=\"" + individual.getName() + "\"/>";
637                            instanceCheckDIG += DIGConverter.getDIGString(concept);
638                            instanceCheckDIG += "</instance>";
639                            id++;
640                    }
641                    instanceCheckDIG += "</asks>";
642    
643                    ResponsesDocument rd = connector.asks(instanceCheckDIG);
644                    IdType[] ids = rd.getResponses().getTrueArray();
645    
646                    SortedSet<Individual> returnSet = new TreeSet<Individual>();
647                    for (IdType idType : ids) {
648                            returnSet.add(new Individual(queryMap.get(idType.getId())));
649                    }
650                    return returnSet;
651            }
652    
653            @Override
654            public SortedSet<Individual> getIndividualsImpl(Description concept) {
655    
656                    String retrievalDIG = asksPrefix;
657                    retrievalDIG += "<instances id= \"query_instance\">";
658                    retrievalDIG += DIGConverter.getDIGString(concept);
659                    retrievalDIG += "</instances></asks>";
660    
661                    ResponsesDocument rd = connector.asks(retrievalDIG);
662                    // System.out.println(rd);
663                    Named[] individuals = rd.getResponses().getIndividualSetArray()[0].getIndividualArray();
664    
665                    SortedSet<Individual> results = new TreeSet<Individual>();
666                    for (Named individual : individuals)
667                            results.add(new Individual(individual.getName()));
668                    return results;
669            }
670    
671            // ToDo: gibt momentan nur einen Wert bei äquivalenten Klassen aus
672            @Override
673            public Set<NamedClass> getTypesImpl(Individual individual) {
674                    String typesDIG = asksPrefix;
675                    typesDIG += "<types id=\"query_types\">";
676                    typesDIG += "<individual name=\"" + individual.getName() + "\" />";
677                    typesDIG += "</types></asks>";
678    
679                    ResponsesDocument rd = connector.asks(typesDIG);
680                    TreeSet<NamedClass> resultsSet = new TreeSet<NamedClass>(conceptComparator);
681                    Concepts[] conceptsArray = rd.getResponses().getConceptSetArray()[0].getSynonymsArray();
682    
683                    for (int i = 0; i < conceptsArray.length; i++) {
684                            Named[] atoms = conceptsArray[i].getCatomArray();
685                            for (Named atom : atoms) {
686                                    NamedClass ac = new NamedClass(atom.getName());
687                                    if (allowedConceptsInSubsumptionHierarchy.contains(ac))
688                                            // if(Config.Refinement.allowedConcepts.contains(ac))
689                                            resultsSet.add(ac);
690                            }
691                    }
692    
693                    // System.out.println("document:");
694                    // System.out.println(rd);
695                    // System.out.println("parsed:");
696                    // System.out.println(resultsSet);
697    
698                    return resultsSet;
699            }
700    
701            // es sieht so aus, als ob die XSD-Datei kaputt ist - es gibt zumindest
702            // keine getter um ein IndividualPairSet zu finden; in der XSD-Datei ist
703            // das in Responsegroup auch nicht definiert
704            // => deswegen wird hier die XML-Cursor-API verwendet
705            @Override
706            public Map<Individual, SortedSet<Individual>> getPropertyMembersImpl(ObjectProperty atomicRole) {
707                    String relatedIndividualsDIG = asksPrefix;
708                    relatedIndividualsDIG += "<relatedIndividuals id=\"related_individuals\">";
709                    relatedIndividualsDIG += "<ratom name=\"" + atomicRole.getName() + "\" />";
710                    relatedIndividualsDIG += "</relatedIndividuals></asks>";
711    
712                    ResponsesDocument rd = connector.asks(relatedIndividualsDIG);
713                    Map<Individual, SortedSet<Individual>> resultMap = new TreeMap<Individual, SortedSet<Individual>>();
714    
715                    QName name = new QName("name");
716                    XmlCursor cursor = rd.newCursor();
717                    cursor.toFirstChild(); // Responses
718                    cursor.toFirstChild(); // IndividualPairSet
719    
720                    int childNumber = 0;
721                    Individual ind1;
722                    Individual ind2;
723    
724                    // so lange noch Kinder existieren
725                    while (cursor.toChild(childNumber)) {
726                            // Cursor steht jetzt bei einem IndividualPair
727                            cursor.toFirstChild();
728                            // jetzt steht er bei einem Individual, dessen Namen wir auslesen
729                            // können
730                            ind1 = new Individual(cursor.getAttributeText(name).toString());
731                            cursor.toNextSibling();
732                            ind2 = new Individual(cursor.getAttributeText(name).toString());
733    
734                            Helper.addMapEntry(resultMap, ind1, ind2);
735    
736                            // Cursor wieder hoch auf IndividualPairSet bewegen
737                            cursor.toParent();
738                            cursor.toParent();
739                            childNumber++;
740                    }
741    
742                    /*
743                     * System.out.println("document:"); System.out.println(rd);
744                     * System.out.println("parsed:"); System.out.println(resultMap);
745                     */
746    
747                    return resultMap;
748            }
749    
750            @Override
751            public boolean isSatisfiableImpl() {
752                    String satisfiableDIG = asksPrefix;
753                    // wenn Top erfüllbar ist, dann gibt es auch ein Modell für die KB
754                    // (satisfiability für KB ist nicht Teil von DIG 1.1)
755                    satisfiableDIG += "<satisfiable id=\"query_satisfiable\"><top/></satisfiable>";
756                    satisfiableDIG += "</asks>";
757    
758                    return parseBooleanAnswer(satisfiableDIG);
759            }
760    
761            private boolean parseBooleanAnswer(String asks) {
762                    ResponsesDocument rd = connector.asks(asks);
763                    if (rd.getResponses().getTrueArray().length == 1)
764                            return true;
765                    else
766                            return false;
767            }
768    
769            public String getIdentifier() {
770                    return identifier;
771            }
772    
773            @Override
774            public void releaseKB() {
775                    connector.releaseKB(kbURI);
776            }
777    
778            // TODO: not working yet - it is probably better to include a method
779            // in knowledge source to save the corresponding source to a file
780            public void saveOntology(File file, OntologyFormat format) {
781                    // KAON2-Reasoner erzeugen und den die Ontologie speichern lassen
782                    // (später könnte man das über Jena erledigen, allerdings funktioniert
783                    // das mit KAON2 auch gut)
784                    // KAON2Reasoner kaon2Reasoner = new KAON2Reasoner(kb,imports);
785                    // kaon2Reasoner.saveOntology(file, format);
786                    throw new UnsupportedOperationException("Saving ontologies not yet implemented.");
787            }
788    
789            public URL getReasonerURL() {
790                    return reasonerURL;
791            }
792    
793            /* (non-Javadoc)
794             * @see org.dllearner.core.Reasoner#getBaseURI()
795             */
796            public String getBaseURI() {
797                    return null;
798            }
799    
800            /* (non-Javadoc)
801             * @see org.dllearner.core.Reasoner#getPrefixes()
802             */
803            public Map<String, String> getPrefixes() {
804                    return null;
805            }
806    
807    //      @Override
808    //      public boolean hasDatatypeSupport() {
809    //              return false;
810    //      }
811    
812    }