001    /**
002     * Copyright (C) 2007-2009, 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.server;
021    
022    import java.net.MalformedURLException;
023    import java.net.URL;
024    import java.util.Arrays;
025    import java.util.HashMap;
026    import java.util.Iterator;
027    import java.util.LinkedList;
028    import java.util.List;
029    import java.util.Map;
030    import java.util.Random;
031    import java.util.Set;
032    import java.util.SortedSet;
033    import java.util.TreeMap;
034    import java.util.TreeSet;
035    
036    import javax.jws.WebMethod;
037    import javax.jws.WebService;
038    import javax.jws.soap.SOAPBinding;
039    
040    import org.apache.log4j.Logger;
041    import org.dllearner.Info;
042    import org.dllearner.cli.ConfMapper;
043    import org.dllearner.core.Component;
044    import org.dllearner.core.ComponentInitException;
045    import org.dllearner.core.ComponentManager;
046    import org.dllearner.core.EvaluatedDescription;
047    import org.dllearner.core.KnowledgeSource;
048    import org.dllearner.core.LearningAlgorithm;
049    import org.dllearner.core.LearningProblem;
050    import org.dllearner.core.LearningProblemUnsupportedException;
051    import org.dllearner.core.ReasonerComponent;
052    import org.dllearner.core.options.ConfigOption;
053    import org.dllearner.core.owl.Description;
054    import org.dllearner.core.owl.Individual;
055    import org.dllearner.core.owl.NamedClass;
056    import org.dllearner.core.owl.ObjectProperty;
057    import org.dllearner.kb.sparql.Cache;
058    import org.dllearner.kb.sparql.NaturalLanguageDescriptionConvertVisitor;
059    import org.dllearner.kb.sparql.SPARQLTasks;
060    import org.dllearner.kb.sparql.SparqlEndpoint;
061    import org.dllearner.kb.sparql.SparqlKnowledgeSource;
062    import org.dllearner.kb.sparql.SparqlQueryDescriptionConvertVisitor;
063    import org.dllearner.kb.sparql.SparqlQueryException;
064    import org.dllearner.parser.KBParser;
065    import org.dllearner.parser.ParseException;
066    import org.dllearner.utilities.datastructures.Datastructures;
067    import org.dllearner.utilities.examples.AutomaticNegativeExampleFinderSPARQL;
068    
069    /**
070     * DL-Learner web service interface. The web service makes use of the component
071     * architecture of DL-Learner (see 
072     * <a href="http://dl-learner.org/wiki/Architecture">architecture wiki page</a>),
073     * i.e. it allows to create, configure and run components. In addition, it provides 
074     * access to some reasoning and querying methods.
075     * 
076     * @author Jens Lehmann
077     *
078     */
079    @WebService(name = "DLLearnerWebService")
080    @SOAPBinding(style = SOAPBinding.Style.RPC)
081    public class DLLearnerWS {
082    
083            private static Logger logger = Logger.getLogger(DLLearnerWS.class);
084            
085            private Map<Integer, ClientState> clients = new TreeMap<Integer,ClientState>();
086            private Random rand=new Random();
087            private static ComponentManager cm = ComponentManager.getInstance();
088            private static ConfMapper confMapper = new ConfMapper();
089            
090            /**
091             * Returns the DL-Learner version this web service is based on.
092             * @return DL-Learner-Build.
093             */
094            @WebMethod
095            public String getBuild() {
096                    return Info.build;
097            }
098            
099            /**
100             * Method to check whether web service is online and how fast it responses.
101             * This method simply returns true.
102             * @return Always returns true.
103             */
104            @WebMethod
105            public boolean ping() {
106                    return true;
107            }       
108            
109            /**
110             * Generates a unique ID for the client and initialises a session. 
111             * Using the ID the client can call the other web service methods. 
112             * Two calls to this method are guaranteed to return different results. 
113             * 
114             * @return A session ID.
115             */
116            @WebMethod
117            public int generateID() {
118                    int id;
119                    do {
120                            id = Math.abs(rand.nextInt());
121                    } while(clients.containsKey(id));
122                    clients.put(id, new ClientState());
123                    logger.info("New client " + id + " at DL-Learner web service.");
124                    return id;
125            }
126            
127            ///////////////////////////////////////
128            // methods for basic component setup //
129            ///////////////////////////////////////
130            
131            /**
132             * Gets a list of all DL-Learner components accessible via this web service. 
133             * @return All components accessible via this web service.
134             */
135            @WebMethod
136            public String[] getComponents() {
137                    Set<String> components = confMapper.getComponents();
138                    return components.toArray(new String[components.size()]);
139            }
140            
141            /**
142             * Gets a list of all DL-Learner knowledge source components accessible via this web service. 
143             * @return All knowledge source components accessible via this web service.
144             */
145            @WebMethod
146            public String[] getKnowledgeSources() {
147                    Set<String> knowledgeSources = confMapper.getKnowledgeSources();
148                    return knowledgeSources.toArray(new String[knowledgeSources.size()]);
149            }
150            
151            /**
152             * Gets a list of all DL-Learner reasoner components accessible via this web service. 
153             * @return All reasoner components accessible via this web service.
154             */     
155            @WebMethod
156            public String[] getReasoners() {
157                    Set<String> reasoners = confMapper.getReasoners();
158                    return reasoners.toArray(new String[reasoners.size()]);         
159            }
160            
161            /**
162             * Gets a list of all DL-Learner learning problem components accessible via this web service. 
163             * @return All learning problem components accessible via this web service.
164             */     
165            @WebMethod
166            public String[] getLearningProblems() {
167                    Set<String> learningProblems = confMapper.getLearningProblems();
168                    return learningProblems.toArray(new String[learningProblems.size()]);           
169            }
170            
171            /**
172             * Gets a list of all DL-Learner learning algorithm components accessible via this web service. 
173             * @return All learning algorithm components accessible via this web service.
174             */     
175            @WebMethod
176            public String[] getLearningAlgorithms() {
177                    Set<String> learningAlgorithms = confMapper.getLearningAlgorithms();
178                    return learningAlgorithms.toArray(new String[learningAlgorithms.size()]);               
179            }       
180            
181            /**
182             * Gets the configuration options supported by the component. This allows e.g. to
183             * automatically build user interfaces for configuring components.
184             * @param component Name of the component.
185             * @param allInfo Whether or not complete information is desired (including option description, allowed values, default value).
186             * @return A list of configuration options supported by the component.
187             * @throws UnknownComponentException Thrown if component is not known (see {@link #getComponents()}).
188             */
189            @WebMethod
190            public String[] getConfigOptions(String component, boolean allInfo) throws UnknownComponentException {
191                    Class<? extends Component> componentClass = confMapper.getComponentClass(component);
192                    List<ConfigOption<?>> options = ComponentManager.getConfigOptions(componentClass);
193                    String[] optionsString = new String[options.size()];
194                    for(int i=0; i<options.size(); i++) {
195                            ConfigOption<?> option = options.get(i);
196                            optionsString[i] = option.getName();
197                            if(allInfo) {
198                                    optionsString[i] += "#" + option.getDescription();
199                                    optionsString[i] += "#" + option.getAllowedValuesDescription();
200                                    optionsString[i] += "#" + option.getDefaultValue();                             
201                            }       
202                    }
203                    return optionsString;
204            }
205            
206            /**
207             * Adds a knowledge source.
208             * 
209             * @param id The session ID.
210             * @param component The name of the component.
211             * @param url The URL of the knowledge source.
212             * @return An identifier for the component.
213             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
214             * @throws UnknownComponentException Thrown if component is not known (see {@link #getComponents()}).
215             * @throws MalformedURLException Thrown if passed URL is malformed.
216             */
217            @WebMethod
218            public int addKnowledgeSource(int id, String component, String url) throws ClientNotKnownException, UnknownComponentException, MalformedURLException {
219                    ClientState state = getState(id);
220                    Class<? extends KnowledgeSource> ksClass = confMapper.getKnowledgeSourceClass(component);
221                    if(ksClass == null)
222                            throw new UnknownComponentException(component);
223                    KnowledgeSource ks = cm.knowledgeSource(ksClass);
224                    cm.applyConfigEntry(ks, "url", new URL(url));
225                    return state.addKnowledgeSource(ks);
226            }
227            
228            /**
229             * Removes a knowledge source.
230             * 
231             * @param id The session ID.
232             * @param componentID ID of knowledge source to remove.
233             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
234             */
235            @WebMethod
236            public void removeKnowledgeSource(int id, int componentID) throws ClientNotKnownException {
237                    getState(id).removeKnowledgeSource(componentID);
238            }
239            
240            /**
241             * Sets the reasoner to use.
242             * 
243             * @param id The session ID.
244             * @param component The name of the component.
245             * @return An identifier for the component.
246             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
247             * @throws UnknownComponentException  Thrown if component is not known (see {@link #getComponents()}).
248             */
249            @WebMethod
250            public int setReasoner(int id, String component) throws ClientNotKnownException, UnknownComponentException {
251                    ClientState state = getState(id);
252                    Class<? extends ReasonerComponent> rcClass = confMapper.getReasonerComponentClass(component);
253                    if(rcClass == null)
254                            throw new UnknownComponentException(component);
255                    
256                    ReasonerComponent rc = cm.reasoner(rcClass, state.getKnowledgeSources());
257                    return state.setReasonerComponent(rc);
258            }
259            
260            /**
261             * Sets the learning problem to use.
262             * 
263             * @param id The session ID.
264             * @param component The name of the component.
265             * @return An identifier for the component.
266             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
267             * @throws UnknownComponentException  Thrown if component is not known (see {@link #getComponents()}).
268             */
269            @WebMethod
270            public int setLearningProblem(int id, String component) throws ClientNotKnownException, UnknownComponentException {
271                    ClientState state = getState(id);
272                    Class<? extends LearningProblem> lpClass = confMapper.getLearningProblemClass(component);
273                    if(lpClass == null)
274                            throw new UnknownComponentException(component);
275                    
276                    LearningProblem lp = cm.learningProblem(lpClass, state.getReasonerComponent());
277                    return state.setLearningProblem(lp);
278            }
279            
280            /**
281             * Sets the learning algorithm to use.
282             * 
283             * @param id The session ID.
284             * @param component The name of the component.
285             * @return An identifier for the component.
286             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
287             * @throws UnknownComponentException  Thrown if component is not known (see {@link #getComponents()}).
288             * @throws LearningProblemUnsupportedException Thrown if the learning problem is not supported by the specified learning algorithm.
289             */
290            @WebMethod
291            public int setLearningAlgorithm(int id, String component) throws ClientNotKnownException, UnknownComponentException, LearningProblemUnsupportedException {
292                    ClientState state = getState(id);
293                    Class<? extends LearningAlgorithm> laClass = confMapper.getLearningAlgorithmClass(component);
294                    if(laClass == null)
295                            throw new UnknownComponentException(component);
296                    
297                    LearningAlgorithm la = cm.learningAlgorithm(laClass, state.getLearningProblem(), state.getReasonerComponent());
298                    return state.setLearningAlgorithm(la);
299            }
300            
301            /**
302             * Initialise all components.
303             * @param id Session ID.
304             * @throws ComponentInitException Thrown if an error occurs during component initialisation.
305             */
306            @WebMethod
307            public void initAll(int id) throws ClientNotKnownException, ComponentInitException {
308                    ClientState state = getState(id);
309                    for(KnowledgeSource ks : state.getKnowledgeSources())
310                            ks.init();
311                    state.getReasonerComponent().init();
312                    state.getLearningProblem().init();
313                    state.getLearningAlgorithm().init();
314            }
315            
316            /**
317             * Initialise the specified component.
318             * @param id Session-ID.
319             * @param componentID Component-ID.
320             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
321             * @throws UnknownComponentException Thrown if the component is unknown.
322             * @throws ComponentInitException 
323             */
324            @WebMethod
325            public void init(int id, int componentID) throws ClientNotKnownException, UnknownComponentException, ComponentInitException {
326                    ClientState state = getState(id);
327                    Component component = state.getComponent(componentID);
328                    component.init();
329            }
330            
331            /**
332             * Starts the learning algorithm and returns the best concept found. This
333             * method will block until learning is completed.
334             * 
335             * @param id Session ID.
336             * @param format The format of the result string: "manchester", "kb", "dl".
337             * @return The best solution found.
338             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
339             */     
340            @WebMethod
341            public String learn(int id, String format) throws ClientNotKnownException {
342                    ClientState state = getState(id);
343                    state.getLearningAlgorithm().start();
344                    Description solution = state.getLearningAlgorithm().getCurrentlyBestDescription();
345                    if(format.equals("manchester"))
346                            return solution.toManchesterSyntaxString(state.getReasonerComponent().getBaseURI(), new HashMap<String,String>());
347                    else if(format.equals("kb"))
348                            return solution.toKBSyntaxString();
349                    else
350                            return solution.toString();
351            }
352            
353            /**
354             * Returns a list of JSON encoded description including extra information
355             * (which partially depends on the learning problem) such as the accuracy
356             * of the learned description.
357             * 
358             * @param id The session ID.
359             * @param limit Maximum number of results desired.
360             * @return A JSON string encoding learned descriptions.
361             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
362             */
363            @WebMethod
364            public String learnDescriptionsEvaluated(int id, int limit) throws ClientNotKnownException {
365                    ClientState state = getState(id);
366                    state.getLearningAlgorithm().start();
367                    List<? extends EvaluatedDescription> descriptions = state.getLearningAlgorithm().getCurrentlyBestEvaluatedDescriptions(limit);
368                    String json = "{";
369                    int count = 1;
370                    for(EvaluatedDescription description : descriptions) {
371                            if (count>1) json += ",\"solution" + count + "\" : " + description.asJSON();
372                            else json += "\"solution" + count + "\" : " + description.asJSON();
373                            count++;
374                    }
375                    json+="}";
376                    return json;
377            }
378            
379            /**
380             * Starts the learning algorithm and returns immediately. The learning
381             * algorithm is executed in its own thread and can be queried and 
382             * controlled using other Web Service methods.
383             * 
384             * @param id Session ID.
385             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
386             */
387            @WebMethod 
388            public void learnThreaded(int id) throws ClientNotKnownException {
389                    final ClientState state = getState(id);
390                    Thread learningThread = new Thread() {
391                            @Override
392                            public void run() {
393    //                              state.setAlgorithmRunning(true);
394                                    state.getLearningAlgorithm().start();
395    //                              state.setAlgorithmRunning(false);
396                            }
397                    };
398                    learningThread.start();
399            }
400            
401            /**
402             * 
403             * @param id The session ID.
404             * @return
405             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
406             */
407            @WebMethod
408            public String getCurrentlyBestConcept(int id) throws ClientNotKnownException {
409                    ClientState state = getState(id);
410                    return state.getLearningAlgorithm().getCurrentlyBestEvaluatedDescription().toString();
411            }
412            
413            /**
414             * 
415             * @param id The session ID.
416             * @param nrOfConcepts
417             * @param format
418             * @return
419             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
420             */
421            @WebMethod
422            public String[] getCurrentlyBestConcepts(int id, int nrOfConcepts, String format) throws ClientNotKnownException {
423                    ClientState state = getState(id);
424                    List<Description> bestConcepts = state.getLearningAlgorithm().getCurrentlyBestDescriptions(nrOfConcepts);
425                    List<String> conc=new LinkedList<String>();
426                    Iterator<Description> iter=bestConcepts.iterator();
427                    while (iter.hasNext())
428                            if (format.equals("manchester"))
429                                    conc.add(iter.next().toManchesterSyntaxString(state.getReasonerComponent().getBaseURI(), new HashMap<String,String>()));
430                            else if(format.equals("kb"))
431                                    conc.add(iter.next().toKBSyntaxString());
432                            else
433                                conc.add(iter.next().toString());
434                    return conc.toArray(new String[conc.size()]);
435            }
436            
437            /**
438             * 
439             * @param id The session ID.
440             * @param limit
441             * @return
442             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
443             */
444            @WebMethod
445            public String getCurrentlyBestEvaluatedDescriptions(int id, int limit) throws ClientNotKnownException{
446                    return currentlyBestEvaluatedDescriptions(id,limit,-1,false);
447            }
448            
449            /**
450             * 
451             * @param id The session ID.
452             * @param nrOfDescriptions
453             * @param accuracyThreshold
454             * @param filterNonMinimalDescriptions
455             * @return
456             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
457             */
458            @WebMethod
459            public String getCurrentlyBestEvaluatedDescriptionsFiltered(int id,int nrOfDescriptions, double accuracyThreshold, boolean filterNonMinimalDescriptions) throws ClientNotKnownException
460            {
461                    return currentlyBestEvaluatedDescriptions(id,nrOfDescriptions,accuracyThreshold,filterNonMinimalDescriptions);
462            }
463            
464            /**
465             * 
466             * @param id The session ID.
467             * @param nrOfDescriptions
468             * @param accuracyThreshold
469             * @param filterNonMinimalDescriptions
470             * @return
471             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
472             */
473            private String currentlyBestEvaluatedDescriptions(int id,int nrOfDescriptions, double accuracyThreshold, boolean filterNonMinimalDescriptions) throws ClientNotKnownException
474            {
475                    ClientState state = getState(id);
476                    List<? extends EvaluatedDescription> descriptions;
477                    if (accuracyThreshold!=-1) descriptions = state.getLearningAlgorithm().getCurrentlyBestEvaluatedDescriptions(nrOfDescriptions, accuracyThreshold, filterNonMinimalDescriptions);
478                    else descriptions = state.getLearningAlgorithm().getCurrentlyBestEvaluatedDescriptions(nrOfDescriptions);
479                    String json = "{";
480                    int count = 1;
481                    for(EvaluatedDescription description : descriptions) {
482                            if (count>1) json += ",\"solution" + count + "\" : " + description.asJSON();
483                            else json += "\"solution" + count + "\" : " + description.asJSON();
484                            count++;
485                    }
486                    json+="}";
487                    return json;
488            }
489            
490            /**
491             * 
492             * @param id The session ID.
493             * @return
494             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
495             */
496            @WebMethod
497            public boolean isAlgorithmRunning(int id) throws ClientNotKnownException {
498                    return getState(id).getLearningAlgorithm().isRunning();
499            }
500            
501            /**
502             * Stops the learning algorithm smoothly.
503             * @param id The session ID.
504             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
505             */
506            @WebMethod
507            public void stop(int id) throws ClientNotKnownException {
508                    getState(id).getLearningAlgorithm().stop();
509            }
510            
511            /////////////////////////////////////////
512            // methods for component configuration //
513            /////////////////////////////////////////
514            
515            /**
516             * 
517             * @param id The session ID.
518             * @param positiveExamples
519             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
520             */ 
521            @WebMethod
522            public void setPositiveExamples(int id, String[] positiveExamples) throws ClientNotKnownException {
523                    ClientState state = getState(id);
524                    Set<String> posExamples = new TreeSet<String>(Arrays.asList(positiveExamples));
525                    cm.applyConfigEntry(state.getLearningProblem(), "positiveExamples", posExamples);
526            }
527            
528    
529            /**
530             * 
531             * @param id The session ID.
532             * @param negativeExamples
533             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
534             */
535            @WebMethod
536            public void setNegativeExamples(int id, String[] negativeExamples) throws ClientNotKnownException {
537                    ClientState state = getState(id);
538                    Set<String> negExamples = new TreeSet<String>(Arrays.asList(negativeExamples));
539                    cm.applyConfigEntry(state.getLearningProblem(), "negativeExamples", negExamples);
540            }
541            
542            /**
543             * 
544             * @param sessionID The session ID.
545             * @param componentID The componentID.
546             * @param optionName The name of the configuration option.
547             * @param value
548             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
549             * @throws UnknownComponentException
550             */
551            @WebMethod
552            public void applyConfigEntryInt(int sessionID, int componentID, String optionName, Integer value) throws ClientNotKnownException, UnknownComponentException     {
553                    applyConfigEntry(sessionID, componentID,optionName,value);
554            }
555            
556            /**
557             * 
558             * @param sessionID The session ID.
559             * @param componentID The componentID.
560             * @param optionName The name of the configuration option.
561             * @param value
562             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
563             * @throws UnknownComponentException
564             */
565            @WebMethod
566            public void applyConfigEntryString(int sessionID, int componentID, String optionName, String value) throws ClientNotKnownException, UnknownComponentException {
567                    applyConfigEntry(sessionID, componentID,optionName,value);
568            }
569            
570            /**
571             * 
572             * @param sessionID The session ID.
573             * @param componentID The componentID.
574             * @param optionName The name of the configuration option.
575             * @param value
576             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
577             * @throws UnknownComponentException
578             * @throws MalformedURLException
579             */
580            @WebMethod
581            public void applyConfigEntryURL(int sessionID, int componentID, String optionName, String value) throws ClientNotKnownException, UnknownComponentException, MalformedURLException {
582                    // URLs are passed as String and then converted
583                    URL url = new URL(value);
584                    applyConfigEntry(sessionID, componentID,optionName,url);
585            }       
586            
587            /**
588             * 
589             * @param sessionID The session ID.
590             * @param componentID The componentID.
591             * @param optionName The name of the configuration option.
592             * @param value
593             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
594             * @throws UnknownComponentException
595             */
596            @WebMethod
597            public void applyConfigEntryStringArray(int sessionID, int componentID, String optionName, String[] value) throws ClientNotKnownException, UnknownComponentException {
598                    Set<String> stringSet = new TreeSet<String>(Arrays.asList(value));
599                    applyConfigEntry(sessionID, componentID,optionName,stringSet);
600            }
601            
602            /**
603             * 
604             * @param sessionID The session ID.
605             * @param componentID The componentID.
606             * @param optionName The name of the configuration option.
607             * @param value
608             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
609             * @throws UnknownComponentException
610             */
611            @WebMethod
612            public void applyConfigEntryBoolean(int sessionID, int componentID, String optionName, Boolean value) throws ClientNotKnownException, UnknownComponentException {
613                    applyConfigEntry(sessionID, componentID,optionName,value);
614            }
615            
616            /**
617             * 
618             * @param sessionID The session ID.
619             * @param componentID The componentID.
620             * @param optionName The name of the configuration option.
621             * @param value
622             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
623             * @throws UnknownComponentException
624             */
625            private void applyConfigEntry(int sessionID, int componentID, String optionName, Object value) throws ClientNotKnownException, UnknownComponentException {
626                    ClientState state = getState(sessionID);
627                    Component component = state.getComponent(componentID);
628                    cm.applyConfigEntry(component, optionName, value);
629            }
630            
631            /**
632             * 
633             * @param sessionID The session ID.
634             * @param componentID The componentID.
635             * @param optionName The name of the configuration option.
636             * @return
637             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
638             * @throws UnknownComponentException
639             * @throws ConfigOptionTypeException
640             */
641            @WebMethod
642            public String[] getConfigOptionValueStringArray(int sessionID, int componentID, String optionName) throws ClientNotKnownException, UnknownComponentException, ConfigOptionTypeException {
643                    return getConfigOptionValue(sessionID, componentID, optionName, String[].class);
644            }
645            
646            /**
647             * 
648             * @param sessionID The session ID.
649             * @param componentID The componentID.
650             * @param optionName The name of the configuration option.
651             * @return
652             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
653             * @throws UnknownComponentException
654             * @throws ConfigOptionTypeException
655             */
656            @WebMethod
657            public String getConfigOptionValueString(int sessionID, int componentID, String optionName) throws ClientNotKnownException, UnknownComponentException, ConfigOptionTypeException {
658                    return getConfigOptionValue(sessionID, componentID, optionName, String.class);
659            }
660            
661            /**
662             * 
663             * @param sessionID The session ID.
664             * @param componentID The componentID.
665             * @param optionName The name of the configuration option.
666             * @return
667             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
668             * @throws UnknownComponentException
669             * @throws ConfigOptionTypeException
670             */
671            @WebMethod
672            public String getConfigOptionValueURL(int sessionID, int componentID, String optionName) throws ClientNotKnownException, UnknownComponentException, ConfigOptionTypeException {
673                    URL url = getConfigOptionValue(sessionID, componentID, optionName, URL.class);
674                    return url.toString();
675            }       
676            
677            /**
678             * 
679             * @param sessionID The session ID.
680             * @param componentID The componentID.
681             * @param optionName The name of the configuration option.
682             * @return
683             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
684             * @throws UnknownComponentException
685             * @throws ConfigOptionTypeException
686             */
687            @WebMethod
688            public Double getConfigOptionValueDouble(int sessionID, int componentID, String optionName) throws ClientNotKnownException, UnknownComponentException, ConfigOptionTypeException {
689                    return getConfigOptionValue(sessionID, componentID, optionName, Double.class);
690            }
691            
692            /**
693             * 
694             * @param sessionID The session ID.
695             * @param componentID The componentID.
696             * @param optionName The name of the configuration option.
697             * @return
698             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
699             * @throws UnknownComponentException
700             * @throws ConfigOptionTypeException
701             */
702            @WebMethod
703            public Boolean getConfigOptionValueBoolean(int sessionID, int componentID, String optionName) throws ClientNotKnownException, UnknownComponentException, ConfigOptionTypeException {
704                    return getConfigOptionValue(sessionID, componentID, optionName, Boolean.class);
705            }
706            
707            /**
708             * 
709             * @param sessionID The session ID.
710             * @param componentID The componentID.
711             * @param optionName The name of the configuration option.
712             * @return
713             * @throws ClientNotKnownException Thrown if client (session ID) is not known.
714             * @throws UnknownComponentException
715             * @throws ConfigOptionTypeException
716             */
717            @WebMethod
718            public Integer getConfigOptionValueInt(int sessionID, int componentID, String optionName) throws ClientNotKnownException, UnknownComponentException, ConfigOptionTypeException {
719                    return getConfigOptionValue(sessionID, componentID, optionName, Integer.class);
720            }
721            
722            ////////////////////////////////////
723            // reasoning and querying methods //
724            ////////////////////////////////////
725            
726            @WebMethod
727            public String[] getAtomicConcepts(int id) throws ClientNotKnownException {
728                    Set<NamedClass> atomicConcepts = getState(id).getReasonerComponent().getNamedClasses();
729                    return Datastructures.sortedSet2StringListConcepts(atomicConcepts);
730            }
731            
732            @WebMethod
733            public String getSubsumptionHierarchy(int id) throws ClientNotKnownException {
734                    return getState(id).getReasonerComponent().toString();
735            }
736            
737            @WebMethod
738            public String[] retrieval(int id, String conceptString) throws ClientNotKnownException, ParseException {
739                    ClientState state = getState(id);
740                    // call parser to parse concept
741                    Description concept = null;
742                    concept = KBParser.parseConcept(conceptString);
743                    Set<Individual> individuals = state.getReasonerComponent().getIndividuals(concept);
744                    return Datastructures.sortedSet2StringListIndividuals(individuals);
745            }
746            
747            @WebMethod
748            public int getConceptLength(String conceptString) throws ParseException {
749                    // call parser to parse concept
750                    return KBParser.parseConcept(conceptString).getLength();
751            }
752            
753            @WebMethod
754            public String[] getAtomicRoles(int id) throws ClientNotKnownException {
755                    ClientState state = getState(id);
756                    Set<ObjectProperty> roles = state.getReasonerComponent().getObjectProperties();
757                    return Datastructures.sortedSet2StringListRoles(roles);
758            }
759            
760            @WebMethod
761            public String[] getInstances(int id) throws ClientNotKnownException {
762                    ClientState state = getState(id);
763                    Set<Individual> individuals = state.getReasonerComponent().getIndividuals();
764                    return Datastructures.sortedSet2StringListIndividuals(individuals);
765            }
766            
767            @WebMethod
768            public String[] getIndividualsForARole(int id, String role) throws ClientNotKnownException {
769                    ClientState state = getState(id);
770                    Map<Individual,SortedSet<Individual>> m = state.getReasonerComponent().getPropertyMembers(new ObjectProperty(role));
771                    Set<Individual> individuals = m.keySet();
772                    return Datastructures.sortedSet2StringListIndividuals(individuals);
773            }
774            
775            ////////////////////////////////////////
776            //     SPARQL component methods       //
777            ////////////////////////////////////////
778            
779                    
780            @WebMethod
781            public String getAsJSON(int sessionID, int queryID) throws ClientNotKnownException, SparqlQueryException
782            {
783                    ClientState state = getState(sessionID);
784                    //ResultSet resultSet=null;
785                    String json = null;
786                    try {
787                        json = state.getQuery(queryID).getJson();
788                    }catch (Exception e) {
789                        e.printStackTrace();
790                        throw new SparqlQueryException("SparqlQuery failed"+e.toString());
791                    }
792                    
793                    if(json == null) { throw new SparqlQueryException("Sparql Query failed. Please try again later.");}
794                    return json;
795                    //if ((json=state.getQuery(queryID).getJson())!=null) return json;
796                    //else if ((resultSet=state.getQuery(queryID).getResultSet())!=null) return SparqlQuery.getAsJSON(resultSet); 
797                    //else return SparqlQuery.getAsJSON(state.getQuery(queryID).send());
798            }
799            
800            @WebMethod
801            public String getAsXMLString(int sessionID, int queryID) throws ClientNotKnownException, SparqlQueryException
802            {
803                    ClientState state = getState(sessionID);
804                    
805                    String xml = null;
806                    try{    
807                        xml = state.getQuery(queryID).getXMLString();
808                    }catch (Exception e) {
809                        e.printStackTrace();
810                        throw new SparqlQueryException("SparqlQuery failed"+e.toString());
811                    }
812                    
813                    if(xml == null) throw new SparqlQueryException("SparqlQuery failed xml was null");
814                    return xml;
815                    //if ((resultSet=state.getQuery(queryID).getResultSet())!=null) return SparqlQuery.getAsXMLString(resultSet);
816                    //if ((json=state.getQuery(queryID).getJson())!=null) return SparqlQuery.getAsXMLString(SparqlQuery.JSONtoResultSet(json));
817                    //else return SparqlQuery.getAsXMLString(state.getQuery(queryID).send());
818            }
819            
820            @WebMethod
821            public int sparqlQueryThreaded(int sessionID, int componentID, String query) throws ClientNotKnownException
822            {
823                    final ClientState state = getState(sessionID);
824                    Component component = state.getComponent(componentID);
825                    final SparqlKnowledgeSource ks=(SparqlKnowledgeSource)component;
826                    final int id=state.addQuery(ks.sparqlQuery(query));
827                    Thread sparqlThread = new Thread() {
828                            @Override
829                            public void run() {
830                                    if (ks.isUseCache()){
831                                            state.getQuery(id).setRunning(true);
832                                            Cache cache=new Cache(ks.getCacheDir());
833                                            cache.executeSparqlQuery(state.getQuery(id));
834                                            state.getQuery(id).setRunning(false);
835                                    }
836                                    else{
837                                            state.getQuery(id).setRunning(true);
838                                            state.getQuery(id).send();
839                                            state.getQuery(id).setRunning(false);
840                                    }
841                            }
842                    };
843                    sparqlThread.start();
844                    return id;
845            }
846            
847            @WebMethod
848            public String sparqlQuery(int sessionID, int componentID, String query) throws ClientNotKnownException
849            {
850                    ClientState state = getState(sessionID);
851                    Component component = state.getComponent(componentID);
852                    SparqlKnowledgeSource ks=(SparqlKnowledgeSource)component;
853                    return ks.getSPARQLTasks().query(query);
854                    /*SparqlQuery sparql=ks.sparqlQuery(query);
855                    if (ks.isUseCache()){
856                            Cache cache=new Cache(ks.getCacheDir());
857                            return cache.executeSparqlQuery(sparql);
858                    }
859                    else return sparql.getJson();*/
860            }
861            
862            /**
863             * Queries one of the standard endpoints defined in DL-Learner.
864             * @param predefinedEndpoint A string describing the endpoint e.g. DBpedia.
865             * @param query The SPARQL query.
866             * @param useCache Specify whether to use a cache for queries.
867             * @return The result of the SPARQL query in JSON format or null if the endpoint does not exist.
868             * @see SPARQLEndpoint#getEndpointByName;
869             */
870            @WebMethod
871            public String sparqlQueryPredefinedEndpoint(String predefinedEndpoint, String query, boolean useCache) {
872                    SparqlEndpoint endpoint = SparqlEndpoint.getEndpointByName(predefinedEndpoint);
873                    SPARQLTasks st;
874                    if(useCache) {
875                            st = new SPARQLTasks(endpoint);
876                    } else {
877                            st = new SPARQLTasks(Cache.getDefaultCache(), endpoint);
878                    }
879                    return st.query(query);
880            }
881            
882            @WebMethod
883            public boolean isSparqlQueryRunning(int sessionID, int queryID) throws ClientNotKnownException
884            {
885                    ClientState state = getState(sessionID);
886                    return state.getQuery(queryID).isRunning();
887            }
888            
889            @WebMethod
890            public void stopSparqlThread(int sessionID, int queryID) throws ClientNotKnownException
891            {
892                    ClientState state = getState(sessionID);
893                    state.getQuery(queryID).stop();
894            }
895            
896            @WebMethod
897            public int[] getConceptDepth(int id, int nrOfConcepts) throws ClientNotKnownException {
898                    ClientState state = getState(id);
899                    List<Description> bestConcepts = state.getLearningAlgorithm().getCurrentlyBestDescriptions(nrOfConcepts);
900                    Iterator<Description> iter=bestConcepts.iterator();
901                    int[] length=new int[bestConcepts.size()];
902                    int i=0;
903                    while (iter.hasNext()){
904                            length[i]=iter.next().getDepth();
905                            i++;
906                    }
907                    return length;
908            }
909            
910            @WebMethod
911            public int[] getConceptArity(int id, int nrOfConcepts) throws ClientNotKnownException {
912                    ClientState state = getState(id);
913                    List<Description> bestConcepts = state.getLearningAlgorithm().getCurrentlyBestDescriptions(nrOfConcepts);
914                    Iterator<Description> iter=bestConcepts.iterator();
915                    int[] arity=new int[bestConcepts.size()];
916                    int i=0;
917                    while (iter.hasNext()){
918                            arity[i]=iter.next().getArity();
919                            i++;
920                    }
921                    return arity;
922            }
923            
924            @WebMethod
925            public String SparqlRetrieval(String conceptString,int limit) throws ParseException {
926                    // call parser to parse concept
927                    return SparqlQueryDescriptionConvertVisitor.getSparqlQuery(conceptString,limit);
928            }
929            
930            @WebMethod
931            public String getNaturalDescription(int id, String conceptString, String endpoint) throws ParseException, ClientNotKnownException {
932                    // call parser to parse concept
933                    ClientState state = getState(id);
934                    ReasonerComponent service = state.getReasonerComponent();
935                    return NaturalLanguageDescriptionConvertVisitor.getNaturalLanguageDescription(conceptString, service);
936            }
937            
938            @WebMethod
939            public String[] getNegativeExamples(int sessionID, int componentID,String[] positives, int results, String namespace, String[] filterClasses) throws ClientNotKnownException
940            {
941                    int sparqlResultSetLimit = 500;
942                    SortedSet<String> positiveSet = new TreeSet<String>(Arrays.asList(positives));
943                    SortedSet<String> filterSet = new TreeSet<String>(Arrays.asList(filterClasses));
944                    ClientState state = getState(sessionID);
945                    Component component = state.getComponent(componentID);
946                    SparqlKnowledgeSource ks=(SparqlKnowledgeSource)component;
947                    SPARQLTasks task=ks.getSPARQLTasks();
948                    AutomaticNegativeExampleFinderSPARQL finder=new AutomaticNegativeExampleFinderSPARQL(positiveSet,task,filterSet);
949                    
950                    /*finder.makeNegativeExamplesFromNearbyClasses(positiveSet, sparqlResultSetLimit);
951                    SortedSet<String> negExamples=finder.getNegativeExamples(results);
952                    if (negExamples.isEmpty()){*/
953                            finder.makeNegativeExamplesFromParallelClasses(positiveSet, sparqlResultSetLimit);
954                            SortedSet<String> negExamples=finder.getNegativeExamples(results);
955                            if(negExamples.isEmpty()){
956                                     finder.makeNegativeExamplesFromRelatedInstances(positiveSet, namespace);
957                                     negExamples = finder.getNegativeExamples(results);
958                                     if(negExamples.isEmpty()){
959                                             finder.makeNegativeExamplesFromSuperClassesOfInstances(positiveSet, sparqlResultSetLimit);
960                                             negExamples = finder.getNegativeExamples(results);
961                                             if(negExamples.isEmpty()) {
962                                                     finder.makeNegativeExamplesFromRandomInstances();
963                                                     negExamples = finder.getNegativeExamples(results);
964                                             }
965                                     }
966                            }
967                    //}
968                    
969                    return negExamples.toArray(new String[negExamples.size()]);
970            }
971            
972            /////////////////////////////
973            // private utility methods //
974            /////////////////////////////
975            
976            // returns session state or throws client not known exception
977            private ClientState getState(int id) throws ClientNotKnownException {
978                    ClientState state = clients.get(id);
979                    if(state==null)
980                            throw new ClientNotKnownException(id);
981                    return state;
982            }
983            
984            @SuppressWarnings({"unchecked"})
985            private <T> T getConfigOptionValue(int sessionID, int componentID, String optionName, Class<T> clazz) throws ClientNotKnownException, UnknownComponentException, ConfigOptionTypeException {
986                    Object value = getConfigOptionValue(sessionID, componentID, optionName);
987                    if(clazz.isInstance(value))
988                            return (T) value;
989                    else
990                            throw new ConfigOptionTypeException(optionName, clazz, value.getClass());
991            }
992            
993            private Object getConfigOptionValue(int sessionID, int componentID, String optionName) throws ClientNotKnownException, UnknownComponentException {
994                    ClientState state = getState(sessionID);
995                    Component component = state.getComponent(componentID);
996                    return cm.getConfigOptionValue(component, optionName);
997            }       
998            
999    }