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