001    /**
002     * Copyright (C) 2007-2011, Jens Lehmann
003     *
004     * This file is part of DL-Learner.
005     *
006     * DL-Learner is free software; you can redistribute it and/or modify
007     * it under the terms of the GNU General Public License as published by
008     * the Free Software Foundation; either version 3 of the License, or
009     * (at your option) any later version.
010     *
011     * DL-Learner is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014     * GNU General Public License for more details.
015     *
016     * You should have received a copy of the GNU General Public License
017     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018     */
019    
020    package org.dllearner.core;
021    
022    import java.io.BufferedReader;
023    import java.io.DataInputStream;
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.io.InputStreamReader;
027    import java.lang.annotation.Annotation;
028    import java.lang.reflect.Constructor;
029    import java.lang.reflect.InvocationTargetException;
030    import java.lang.reflect.Method;
031    import java.util.ArrayList;
032    import java.util.Arrays;
033    import java.util.Collection;
034    import java.util.Comparator;
035    import java.util.HashMap;
036    import java.util.HashSet;
037    import java.util.LinkedList;
038    import java.util.List;
039    import java.util.Map;
040    import java.util.Set;
041    import java.util.TreeMap;
042    import java.util.TreeSet;
043    import java.util.Map.Entry;
044    
045    import org.apache.log4j.Logger;
046    import org.dllearner.algorithms.DisjointClassesLearner;
047    import org.dllearner.algorithms.SimpleSubclassLearner;
048    import org.dllearner.algorithms.celoe.CELOE;
049    import org.dllearner.algorithms.properties.DataPropertyDomainAxiomLearner;
050    import org.dllearner.algorithms.properties.DataPropertyRangeAxiomLearner;
051    import org.dllearner.algorithms.properties.DisjointDataPropertyAxiomLearner;
052    import org.dllearner.algorithms.properties.DisjointObjectPropertyAxiomLearner;
053    import org.dllearner.algorithms.properties.EquivalentDataPropertyAxiomLearner;
054    import org.dllearner.algorithms.properties.EquivalentObjectPropertyAxiomLearner;
055    import org.dllearner.algorithms.properties.FunctionalDataPropertyAxiomLearner;
056    import org.dllearner.algorithms.properties.FunctionalObjectPropertyAxiomLearner;
057    import org.dllearner.algorithms.properties.InverseFunctionalObjectPropertyAxiomLearner;
058    import org.dllearner.algorithms.properties.ObjectPropertyDomainAxiomLearner;
059    import org.dllearner.algorithms.properties.ObjectPropertyRangeAxiomLearner;
060    import org.dllearner.algorithms.properties.SubDataPropertyOfAxiomLearner;
061    import org.dllearner.algorithms.properties.SubObjectPropertyOfAxiomLearner;
062    import org.dllearner.algorithms.properties.SymmetricObjectPropertyAxiomLearner;
063    import org.dllearner.algorithms.properties.TransitiveObjectPropertyAxiomLearner;
064    import org.dllearner.core.options.ConfigEntry;
065    import org.dllearner.core.options.ConfigOption;
066    import org.dllearner.core.options.InvalidConfigOptionValueException;
067    import org.dllearner.utilities.datastructures.Maps;
068    
069    /**
070     * Central manager class for DL-Learner. There are currently four types of
071     * components in DL-Learner: knowledge sources, reasoners, learning problems,
072     * and learning algorithms. For accessing these components you should create
073     * instances and configure them using this class. The component manager is
074     * implemented as a Singleton and will read the components file (containing a
075     * list of all components) at startup. This allows interfaces (command line,
076     * graphical, web service) to easily query the available components, set and get
077     * their configuration options, and run the algorithm.
078     * 
079     * @author Jens Lehmann
080     * 
081     */
082    public final class ComponentManager {
083    
084            private static Logger logger = Logger
085                    .getLogger(ComponentManager.class);
086            
087            private ComponentPool pool = new ComponentPool();
088            
089            // these variables are valid for the complete lifetime of a DL-Learner session
090            private static Collection<Class<? extends AbstractComponent>> components;
091            private static Collection<Class<? extends AbstractKnowledgeSource>> knowledgeSources;
092            private static Collection<Class<? extends AbstractReasonerComponent>> reasonerComponents;
093            private static Collection<Class<? extends AbstractLearningProblem>> learningProblems;
094            private static Collection<Class<? extends AbstractCELA>> learningAlgorithms;
095            // you can either use the components.ini file or directly specify the classes to use
096            @Deprecated
097        private static String componentsFile = "org/dllearner/components.ini";
098        private static List<String> componentClasses = new ArrayList<String>  ( Arrays.asList(new String[]{
099                "org.dllearner.kb.OWLFile",
100                "org.dllearner.kb.KBFile",
101                "org.dllearner.kb.sparql.SparqlKnowledgeSource",
102                "org.dllearner.kb.OWLAPIOntology",
103    //            "org.dllearner.kb.SparqlEndpointKS",
104    //reasoners
105                "org.dllearner.reasoning.OWLAPIReasoner",
106                "org.dllearner.reasoning.fuzzydll.FuzzyOWLAPIReasoner",  // added by Josue
107                "org.dllearner.reasoning.DIGReasoner",
108                "org.dllearner.reasoning.FastRetrievalReasoner",
109                "org.dllearner.reasoning.FastInstanceChecker",
110                "org.dllearner.reasoning.ProtegeReasoner",
111                "org.dllearner.reasoning.PelletReasoner",
112    //learning problems
113                "org.dllearner.learningproblems.PosNegLPStandard",
114                "org.dllearner.learningproblems.fuzzydll.FuzzyPosNegLPStandard", // added by Josue
115                "org.dllearner.learningproblems.PosNegLPStrict",
116                "org.dllearner.learningproblems.PosOnlyLP",
117                "org.dllearner.learningproblems.ClassLearningProblem",
118    //learning algorithms
119                "org.dllearner.algorithms.RandomGuesser",
120                "org.dllearner.algorithms.BruteForceLearner",
121                "org.dllearner.algorithms.refinement.ROLearner",
122                "org.dllearner.algorithms.ocel.OCEL",
123                "org.dllearner.algorithms.gp.GP",
124                "org.dllearner.algorithms.el.ELLearningAlgorithm",
125                "org.dllearner.algorithms.el.ELLearningAlgorithmDisjunctive",
126                "org.dllearner.algorithms.celoe.CELOE",
127                "org.dllearner.algorithms.fuzzydll.FuzzyCELOE", //added by Josue
128                "org.dllearner.algorithms.isle.ISLE"
129         } ));
130    
131            private static ComponentManager cm = null;      
132    
133            // list of all configuration options of all components
134            private static Map<Class<? extends AbstractComponent>, String> componentNames;
135            private static Map<Class<? extends AbstractComponent>, List<ConfigOption<?>>> componentOptions;
136            private static Map<Class<? extends AbstractComponent>, Map<String, ConfigOption<?>>> componentOptionsByName;
137            private static Map<Class<? extends AbstractCELA>, Collection<Class<? extends AbstractLearningProblem>>> algorithmProblemsMapping;
138            private static Map<Class<? extends AbstractLearningProblem>, Collection<Class<? extends AbstractCELA>>> problemAlgorithmsMapping;
139            
140            // list of default values of config options
141    //      private static Map<ConfigOption<?>,Object> configOptionDefaults;
142            
143            private Comparator<Class<?>> classComparator = new Comparator<Class<?>>() {
144    
145                    public int compare(Class<?> c1, Class<?> c2) {
146                            return c1.getName().compareTo(c2.getName());
147                    }
148    
149            };
150    
151            @SuppressWarnings("unchecked")
152            private ComponentManager() {
153            
154                    // read in components file
155            /*REMOVED THE BLOCK*/
156                    /*List<String> componentsString;
157                    if(componentClasses.length > 0) {
158                            componentsString = Arrays.asList(componentClasses);
159                    } else {
160                            componentsString = readComponentsFile();
161                    }*/
162           //List<String> componentsString2 = Arrays.asList(componentClasses);
163    
164                    // component list
165                    components = new TreeSet<Class<? extends AbstractComponent>>(classComparator);
166                    knowledgeSources = new TreeSet<Class<? extends AbstractKnowledgeSource>>(classComparator);
167                    reasonerComponents = new TreeSet<Class<? extends AbstractReasonerComponent>>(classComparator);
168                    learningProblems = new TreeSet<Class<? extends AbstractLearningProblem>>(classComparator);
169                    learningAlgorithms = new TreeSet<Class<? extends AbstractCELA>>(classComparator);
170                    algorithmProblemsMapping = new TreeMap<Class<? extends AbstractCELA>, Collection<Class<? extends AbstractLearningProblem>>>(
171                                    classComparator);               
172    
173                    // create classes from strings
174                    for (String componentString : componentClasses) {
175                            try {
176                                    Class<? extends AbstractComponent> component = Class.forName(componentString).asSubclass(
177                                                    AbstractComponent.class);
178                                    components.add(component);
179    
180                                    if (AbstractKnowledgeSource.class.isAssignableFrom(component)) {
181                                            knowledgeSources.add((Class<? extends AbstractKnowledgeSource>) component);
182                                    } else if (AbstractReasonerComponent.class.isAssignableFrom(component)) {
183                                            reasonerComponents.add((Class<? extends AbstractReasonerComponent>) component);
184                                    } else if (AbstractLearningProblem.class.isAssignableFrom(component)) {
185                                            learningProblems.add((Class<? extends AbstractLearningProblem>) component);
186                                    } else if (AbstractCELA.class.isAssignableFrom(component)) {
187                                            Class<? extends AbstractCELA> learningAlgorithmClass = (Class<? extends AbstractCELA>) component;
188                                            learningAlgorithms.add(learningAlgorithmClass);
189                                            Collection<Class<? extends AbstractLearningProblem>> problems = (Collection<Class<? extends AbstractLearningProblem>>) invokeStaticMethod(
190                                                            learningAlgorithmClass, "supportedLearningProblems");
191                                            algorithmProblemsMapping.put(learningAlgorithmClass, problems);
192                                    }
193    
194                            } catch (ClassNotFoundException e) {
195                                    e.printStackTrace();
196                            }
197                    }
198                    problemAlgorithmsMapping = Maps.revertCollectionMap(algorithmProblemsMapping);
199    
200                    componentNames = new HashMap<Class<? extends AbstractComponent>, String>();
201                    // read in all configuration options
202                    componentOptions = new HashMap<Class<? extends AbstractComponent>, List<ConfigOption<?>>>();
203                    componentOptionsByName = new HashMap<Class<? extends AbstractComponent>, Map<String, ConfigOption<?>>>();
204    //              configOptionDefaults = new HashMap<ConfigOption<?>,Object>();
205                                    
206                    for (Class<? extends AbstractComponent> component : components) {
207    
208                            String name = (String) invokeStaticMethod(component, "getName");
209                            componentNames.put(component, name);
210                            
211                            // assign options to components
212                            List<ConfigOption<?>> options = (List<ConfigOption<?>>) invokeStaticMethod(component,
213                                            "createConfigOptions");
214                            componentOptions.put(component, options);
215    
216                            // make config options accessible by name
217                            Map<String, ConfigOption<?>> byName = new HashMap<String, ConfigOption<?>>();
218                            for (ConfigOption<?> option : options) {
219                                    byName.put(option.getName(), option);
220                            }
221                            componentOptionsByName.put(component, byName);
222                            
223                    }
224    
225            }
226    
227            /**
228             * Gets the singleton instance of <code>ComponentManager</code>.
229             * @return The singleton <code>ComponentManager</code> instance.
230             */
231            public static ComponentManager getInstance() {
232                    if(cm == null) {
233                            cm = new ComponentManager();
234                    }
235                    return cm;
236            }
237    
238            /**
239             * Set the classes, which can be used as components. By default,
240             * this is read from components.ini, but this method can be used
241             * to set the components programmatically. This method must be
242             * used before the first call to {@link #getInstance()}, otherwise
243             * it has no effect.
244             * 
245             * @param componentClasses A list of class names, e.g. 
246             * org.dllearner.refinement.ROLearner.
247             */
248            public static void setComponentClasses(String[] componentClasses) {
249                    ComponentManager.componentClasses = new ArrayList<String> (Arrays.asList(componentClasses));
250            }
251    
252        @Deprecated
253            private static List<String> readComponentsFile() {
254                    List<String> componentStrings = new LinkedList<String>();
255    
256                    try {
257                             
258                            InputStream is = ComponentManager.class.getClassLoader().getResourceAsStream(componentsFile);
259                            DataInputStream in = new DataInputStream(is);
260                            BufferedReader br = new BufferedReader(new InputStreamReader(in));
261                            String line;
262    
263                            while ((line = br.readLine()) != null) {
264                                    if (!(line.startsWith("#") || line.startsWith("//") || line.startsWith("%") || line
265                                                    .length() <= 1)) {
266                                            componentStrings.add(line);
267                                    }
268                            }
269    
270                            in.close();
271                    } catch (IOException e) {
272                            e.printStackTrace();
273                    }
274    
275                    return componentStrings;
276            }
277    
278            /**
279             * Convenience method for testing purposes. If you know that the type of the
280             * value is correct, it is preferable to create a ConfigEntry object and
281             * apply it to the component (no type checking necessary).
282             * 
283             * @param <T> Type of the config option (Integer, String etc.).
284             * @param component A component.
285             * @param optionName The name of the config option.
286             * @param value The value of the config option.
287             */
288            @SuppressWarnings("unchecked")
289            public <T> void applyConfigEntry(AbstractComponent component, String optionName, T value) {
290                    logger.trace(component);
291                    logger.trace(optionName);
292                    logger.trace(value);
293                    logger.trace(value.getClass());
294                    // first we look whether the component is registered
295                    if (components.contains(component.getClass())) {
296    
297                            // look for a config option with the specified name
298                            ConfigOption<?> option = (ConfigOption<?>) componentOptionsByName.get(
299                                            component.getClass()).get(optionName);
300                            if (option != null) {
301                                    // check whether the given object has the correct type
302                                    if (!option.checkType(value)) {
303                                            System.out.println("Warning: value " + value + " is not valid for option "
304                                                            + optionName + " in component " + component
305                                                            + ". It does not have the correct type.");
306                                            return;
307                                    }
308    
309                                    // we have checked the type, hence it should now be safe to
310                                    // typecast and
311                                    // create a ConfigEntry object
312                                    ConfigEntry<T> entry = null;
313                                    try {   
314                                            entry = new ConfigEntry<T>((ConfigOption<T>) option, value);
315                                            component.applyConfigEntry(entry);
316                                            pool.addConfigEntry(component, entry, true);
317                                    } catch (InvalidConfigOptionValueException e) {
318                                            pool.addConfigEntry(component, entry, false);
319                                            System.out.println("Warning: value " + value + " is not valid for option "
320                                                            + optionName + " in component " + component);
321                                    }
322                            } else {
323                                    logger.warn("Warning: undefined option " + optionName + " in component "
324                                                    + component);
325                            }
326                    } else {
327                            logger.warn("Warning: unregistered component " + component);
328                    }
329            }
330            
331            public ComponentPool getPool() {
332                    return pool;
333            }
334    
335            /**
336             * Applies a config entry to a component. If the entry is not valid, the method
337             * prints an exception and returns false.
338             * @param <T> Type of the config option.
339             * @param component A component object.
340             * @param entry The configuration entry to set.
341             * @return True of the config entry could be applied succesfully, otherwise false.
342             */
343            public <T> boolean applyConfigEntry(AbstractComponent component, ConfigEntry<T> entry) {
344                    try {
345                            component.applyConfigEntry(entry);
346                            pool.addConfigEntry(component, entry, true);
347                            return true;
348                    } catch (InvalidConfigOptionValueException e) {
349                            pool.addConfigEntry(component, entry, false);
350                            e.printStackTrace();
351                            return false;
352                    }
353            }
354            
355            /**
356             * Factory method for creating a knowledge source.
357             * 
358             * @param <T> The type of this method is a subclass of knowledge source.
359             * @param source A registered knowledge source component.
360             * @return An instance of the given knowledge source class.
361             */
362            public <T extends AbstractKnowledgeSource> T knowledgeSource(Class<T> source) {
363                    if (!knowledgeSources.contains(source)) {
364                            logger.warn("Warning: knowledge source " + source
365                                            + " is not a registered knowledge source component.");
366                    }
367    
368                    T ks = invokeConstructor(source, new Class[] {}, new Object[] {});
369                    pool.registerComponent(ks);
370                    return ks;
371            }
372    
373            /**
374             * Factory method for creating a reasoner component from a single
375             * knowledge source. Example
376             * call: reasoner(OWLAPIReasoner.class, ks) where ks is a 
377             * knowledge source object.
378             * @see #reasoner(Class, Set)
379             * @param <T> The type of this method is a subclass of reasoner component.
380             * @param reasoner A class object, where the class is subclass of ReasonerComponent.
381             * @param source A knowledge source.
382             * @return A reasoner component.
383             */
384            public <T extends AbstractReasonerComponent> T reasoner(Class<T> reasoner,
385                            AbstractKnowledgeSource source) {
386                    Set<AbstractKnowledgeSource> sources = new HashSet<AbstractKnowledgeSource>();
387                    sources.add(source);
388                    return reasoner(reasoner, sources);
389            }
390    
391            /**
392             * Factory method for creating a reasoner component from a set of
393             * knowledge sources.
394             * @see #reasoner(Class, AbstractKnowledgeSource)
395             * @param <T> The type of this method is a subclass of reasoner component.
396             * @param reasoner A class object, where the class is subclass of ReasonerComponent.
397             * @param sources A set of knowledge sources.
398             * @return A reasoner component.
399             */
400            public <T extends AbstractReasonerComponent> T reasoner(Class<T> reasoner,
401                            Set<AbstractKnowledgeSource> sources) {
402                    if (!reasonerComponents.contains(reasoner)) {
403                            System.err.println("Warning: reasoner component " + reasoner
404                                            + " is not a registered reasoner component.");
405                    }
406    
407                    T rc = invokeConstructor(reasoner, new Class[] { Set.class },
408                                    new Object[] { sources });
409                    pool.registerComponent(rc);
410                    return rc;
411            }
412    
413            /**
414             * Factory method for creating a reasoner component from a set of
415             * knowledge sources.
416             * @see #reasoner(Class, AbstractKnowledgeSource)
417             * @param <T> The type of this method is a subclass of reasoner component.
418             * @param reasoner A class object, where the class is subclass of ReasonerComponent.
419             * @param sources A set of knowledge sources.
420             * @return A reasoner component.
421             */
422            public <T extends AbstractReasonerComponent> T reasoner(Class<T> reasoner,
423                            AbstractKnowledgeSource ... sources) {
424                    Set<AbstractKnowledgeSource> s = new HashSet<AbstractKnowledgeSource>();
425                    for(AbstractKnowledgeSource source : sources) {
426                            s.add(source);
427                    }
428                    return reasoner(reasoner, s);
429            }       
430            
431            /**
432             * This method returns an instance of <code>ReasonerComponent</code>. The
433             * difference between <code>ReasonerComponent</code> and <code>ReasonerComponent</code>
434             * is that the former delegates all calls to the latter and collects statistics
435             * while doing this. This means that the reasoning service enables the
436             * collection of query information, while the <code>ReasonerComponent</code>
437             * implements the actual reasoning methods defined by the <code>Reasoner</code>
438             * interface.
439             * 
440             * @param reasoner A reasoner component.
441             * @return The reasoning service encapsulating the reasoner.
442             */
443    //      public ReasonerComponent reasoningService(ReasonerComponent reasoner) {
444    //              return new ReasonerComponent(reasoner);
445    //      }
446            
447            /**
448             * Factory method for creating a learning problem component.
449             * @param <T> The type of this method is a subclass of learning problem.
450             * @param lpClass A class object, where the class is a subclass of learning problem.
451             * @param reasoner A reasoning service object.
452             * @return A learning problem component.
453             */
454            public <T extends AbstractLearningProblem> T learningProblem(Class<T> lpClass, AbstractReasonerComponent reasoner) {
455                    if (!learningProblems.contains(lpClass)) {
456                            System.err.println("Warning: learning problem " + lpClass
457                                            + " is not a registered learning problem component.");
458                    }
459    
460                    T lp = invokeConstructor(lpClass, new Class[] { AbstractReasonerComponent.class },
461                                    new Object[] { reasoner });
462                    pool.registerComponent(lp);
463                    return lp;
464            }
465    
466            /**
467             * Factory method for creating a learning algorithm, which 
468             * automagically calls the right constructor for the given problem.
469             * @param <T> The type of this method is a subclass of learning algorithm.
470             * @param laClass A class object, where the class is subclass of learning algorithm.
471             * @param lp A learning problem, which the algorithm should try to solve.
472             * @param rs A reasoning service for querying the background knowledge of this learning problem.
473             * @return A learning algorithm component.
474             * @throws LearningProblemUnsupportedException Thrown when the learning problem and
475             * the learning algorithm are not compatible.
476             */
477            public <T extends AbstractCELA> T learningAlgorithm(Class<T> laClass, AbstractLearningProblem lp, AbstractReasonerComponent rs) throws LearningProblemUnsupportedException {
478                    if (!learningAlgorithms.contains(laClass)) {
479                            System.err.println("Warning: learning algorithm " + laClass
480                                            + " is not a registered learning algorithm component.");
481                    }
482    
483                    // find the right constructor: use the one that is registered and
484                    // has the class of the learning problem as a subclass
485                    Class<? extends AbstractLearningProblem> constructorArgument = null;
486                    for (Class<? extends AbstractLearningProblem> problemClass : algorithmProblemsMapping.get(laClass)) {
487                            if (problemClass.isAssignableFrom(lp.getClass())) {
488                                    constructorArgument = problemClass;
489                            }
490                    }
491                    
492                    if (constructorArgument == null) {
493                            throw new LearningProblemUnsupportedException(lp.getClass(), laClass, algorithmProblemsMapping.get(laClass));
494    //                      System.err.println("Warning: No suitable constructor registered for algorithm "
495    //                                      + laClass.getName() + " and problem " + lp.getClass().getName()
496    //                                      + ". Registered constructors for " + laClass.getName() + ": "
497    //                                      + algorithmProblemsMapping.get(laClass) + ".");
498    //                      return null;
499                    }
500    
501                    T la = invokeConstructor(laClass, new Class[] { constructorArgument, AbstractReasonerComponent.class }, new Object[] { lp, rs });
502                    pool.registerComponent(la);
503                    return la;
504            }
505    //
506    //      public <T extends LearningAlgorithm> T learningAlgorithm(Class<T> laClass, KnowledgeSource ks) {
507    //              T la = invokeConstructor(laClass, new Class[] { KnowledgeSource.class }, new Object[] { ks });
508    //              return la;
509    //      }       
510            
511            /**
512             * The <code>ComponentManager</code> factory methods produce component
513             * instances, which can be freed using this method. Calling the factory
514             * methods without freeing components when they are not used anymore 
515             * can (in theory) cause memory problems.
516             * 
517             * @param component The component to free. 
518             */
519            public void freeComponent(AbstractComponent component) {
520                    pool.unregisterComponent(component);
521            }
522            
523            /**
524             * Frees all references to components created by <code>ComponentManager</code>.
525             * @see #freeComponent(AbstractComponent)
526             */
527            public synchronized void  freeAllComponents() {
528                    pool.clearComponents();
529            }
530            
531            /**
532             * Gets the value of a config option of the specified component.
533             * This is done by first checking, which value the given option
534             * was set to using {@link #applyConfigEntry(AbstractComponent, ConfigEntry)}.
535             * If the value has not been changed, the default value for this
536             * option is returned. Note, that this method will not work properly
537             * if the component options are changed internally surpassing the
538             * component manager (which is discouraged). 
539             * 
540             * @param <T> The type of the config option, e.g. String, boolean, integer.
541             * @param component The component, which has the specified option.
542             * @param option The option for which we want to know its value.
543             * @return The value of the specified option in the specified component.
544             */
545            public <T> T getConfigOptionValue(AbstractComponent component, ConfigOption<T> option) {
546                    T object = pool.getLastValidConfigValue(component, option);
547                    if(object==null) {
548                            return option.getDefaultValue();
549                    } else {
550                            return object;
551                    }
552            }
553            
554            /**
555             * Works as {@link #getConfigOptionValue(AbstractComponent, ConfigOption)},
556             * but using the name of the option instead of a <code>ConfigOption</code>
557             * object.
558             * @see #getConfigOptionValue(AbstractComponent, ConfigOption)
559             * @param component A component.
560             * @param optionName A valid option name for this component.
561             * @return The value of the specified option in the specified component.
562             */
563            public Object getConfigOptionValue(AbstractComponent component, String optionName) {
564                    ConfigOption<?> option = (ConfigOption<?>) componentOptionsByName.get(
565                                    component.getClass()).get(optionName);
566                    return getConfigOptionValue(component, option);
567            }
568            
569            // convenience method for invoking a static method;
570            // used as a central point for exception handling for Java reflection
571            // static method calls  
572            private static Object invokeStaticMethod(Class<?> clazz, String methodName, Object... args) {
573                    // unfortunately Java does not seem to offer a way to call
574                    // a static method given a class object directly, so we have
575                    // to use reflection
576                    try {
577                            Method method = clazz.getMethod(methodName);
578                            return method.invoke(null, args);
579                    } catch (SecurityException e) {
580                            e.printStackTrace();
581                    } catch (NoSuchMethodException e) {
582                            e.printStackTrace();
583                    } catch (IllegalArgumentException e) {
584                            e.printStackTrace();
585                    } catch (IllegalAccessException e) {
586                            e.printStackTrace();
587                    } catch (InvocationTargetException e) {
588                            e.printStackTrace();
589                    }
590    
591                    return null;
592            }
593    
594            // convenience method for invoking a constructor;
595            // used as a central point for exception handling for Java reflection
596            // constructor calls
597            private <T> T invokeConstructor(Class<T> clazz, Class<?>[] argumentClasses,
598                            Object[] argumentObjects) {
599                    try {
600                            Constructor<T> constructor = clazz.getConstructor(argumentClasses);
601                            return constructor.newInstance(argumentObjects);
602                    } catch (IllegalArgumentException e) {
603                            e.printStackTrace();
604                    } catch (InstantiationException e) {
605                            e.printStackTrace();
606                    } catch (IllegalAccessException e) {
607                            e.printStackTrace();
608                    } catch (InvocationTargetException e) {
609                            e.printStackTrace();
610                    } catch (SecurityException e) {
611                            e.printStackTrace();
612                    } catch (NoSuchMethodException e) {
613                            e.printStackTrace();
614                    }
615                    return null;
616            }
617            
618            /**
619             * Returns the available options of the specified component.
620             * @param componentClass The class object of a component.
621             * @return A list of available configuration options of the specified component.
622             */
623            public static List<ConfigOption<?>> getConfigOptions(Class<? extends AbstractComponent> componentClass) {
624                    if (!components.contains(componentClass)) {
625                            System.err.println("Warning: component " + componentClass
626                                            + " is not a registered component. [ComponentManager.getConfigOptions]");
627                    }
628                    return componentOptions.get(componentClass);
629            }
630            
631            /**
632             * Returns a <code>ConfigOption</code> object given a component and
633             * the option name.
634             * @param component A component class object.
635             * @param name A valid configuration option name for the component.
636             * @return A <code>ConfigOption</code> object for the specified component class and option name.
637             */
638            public ConfigOption<?> getConfigOption(Class<? extends AbstractComponent> component, String name) {
639                    return componentOptionsByName.get(component).get(name);
640            }
641            
642            /**
643             * Returns the name of a component.
644             * @param component A component class object.
645             * @return The name of the component.
646             */
647            public String getComponentName(Class<? extends AbstractComponent> component) {
648                    return componentNames.get(component);
649            }
650    
651            /**
652             * Returns a list of all available components in this instance
653             * of <code>ComponentManager</code>.
654             * @return the components A list of component classes available in this
655             * instance of <code>ComponentManager</code>.
656             */
657            public List<Class<? extends AbstractComponent>> getComponents() {
658                    return new LinkedList<Class<? extends AbstractComponent>>(components);
659            }
660    
661            /**
662             * Returns a list of all available knowledge sources in this instance
663             * of <code>ComponentManager</code>.
664             * @return the components A list of knowledge source component classes available in this
665             * instance of <code>ComponentManager</code>.
666             */
667            public List<Class<? extends AbstractKnowledgeSource>> getKnowledgeSources() {
668                    return new LinkedList<Class<? extends AbstractKnowledgeSource>>(knowledgeSources);
669            }
670    
671            /**
672             * Returns a list of all available reasoners in this instance
673             * of <code>ComponentManager</code>.
674             * @return the components A list of reasoner component classes available in this
675             * instance of <code>ComponentManager</code>.
676             */     
677            public List<Class<? extends AbstractReasonerComponent>> getReasonerComponents() {
678                    return new LinkedList<Class<? extends AbstractReasonerComponent>>(reasonerComponents);
679            }
680    
681            /**
682             * Returns a list of all available learning problems in this instance
683             * of <code>ComponentManager</code>.
684             * @return the components A list of learning problem classes available in this
685             * instance of <code>ComponentManager</code>.
686             */             
687            public List<Class<? extends AbstractLearningProblem>> getLearningProblems() {
688                    return new LinkedList<Class<? extends AbstractLearningProblem>>(learningProblems);
689            }
690    
691            /**
692             * Returns the set of learning algorithms, which support the given learning problem type.
693             * @param learningProblem A learning problem type.
694             * @return The set of learning algorithms applicable for this learning problem.
695             */
696            public List<Class<? extends AbstractCELA>> getApplicableLearningAlgorithms(Class<? extends AbstractLearningProblem> learningProblem) {
697                    List<Class<? extends AbstractCELA>> algorithms = new LinkedList<Class<? extends AbstractCELA>>();
698                    for(Entry<Class<? extends AbstractLearningProblem>,Collection<Class<? extends AbstractCELA>>> entry : problemAlgorithmsMapping.entrySet()) {
699                            Class<? extends AbstractLearningProblem> prob = entry.getKey();
700                            if(prob.isAssignableFrom(learningProblem)) {
701                                    algorithms.addAll(entry.getValue());
702                            }
703                    }
704    //              System.out.println(learningProblem + ": " + algorithms);
705                    return algorithms;
706            }
707            
708            /**
709             * Returns a list of all available learning algorithms in this instance
710             * of <code>ComponentManager</code>.
711             * @return the components A list of learning algorithm classes available in this
712             * instance of <code>ComponentManager</code>.
713             */
714            public List<Class<? extends AbstractCELA>> getLearningAlgorithms() {
715                    return new LinkedList<Class<? extends AbstractCELA>>(learningAlgorithms);
716            }
717            
718            
719            /**
720             * Retuns a list of all instanciated and registered Components 
721             * @return Currently active components.
722             */
723            public List<AbstractComponent> getLiveComponents(){
724                    return pool.getComponents();
725            }
726            
727            /**
728             *  Retuns a list of all instanciated and registered LearningAlgorithm 
729             * @return Currently active learning algorithms.
730             */
731            public List<AbstractCELA> getLiveLearningAlgorithms(){
732                    List<AbstractCELA> list = new ArrayList<AbstractCELA>();
733                    for (AbstractComponent component : cm.getLiveComponents()) {
734                            if(component instanceof AbstractCELA){
735                                    list.add((AbstractCELA) component);
736                            }
737                            
738                    }
739                    return list;
740            }
741            
742            /**
743             *  Retuns a list of all instanciated and registered KnowledgeSource 
744             * @return Currently active knowledge sources.
745             */
746            public List<AbstractKnowledgeSource> getLiveKnowledgeSources(){
747                    List<AbstractKnowledgeSource> list = new ArrayList<AbstractKnowledgeSource>();
748                    for (AbstractComponent component : cm.getLiveComponents()) {
749                            if(component instanceof AbstractKnowledgeSource){
750                                    list.add((AbstractKnowledgeSource) component);
751                            }
752                            
753                    }
754                    return list;
755            }
756    
757    }