DefaultInternalKernelServices.java
0001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
0002  *
0003  * Copyright 2000-2014,  Michael Meyling <mime@qedeq.org>.
0004  *
0005  * "Hilbert II" is free software; you can redistribute
0006  * it and/or modify it under the terms of the GNU General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 of the License, or (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0013  * GNU General Public License for more details.
0014  */
0015 
0016 package org.qedeq.kernel.bo.service.internal;
0017 
0018 import java.io.File;
0019 import java.io.FileFilter;
0020 import java.io.IOException;
0021 import java.io.Reader;
0022 import java.io.UnsupportedEncodingException;
0023 import java.net.MalformedURLException;
0024 import java.net.URL;
0025 import java.net.URLEncoder;
0026 import java.util.ArrayList;
0027 import java.util.Iterator;
0028 import java.util.List;
0029 
0030 import org.qedeq.base.io.IoUtility;
0031 import org.qedeq.base.io.LoadingListener;
0032 import org.qedeq.base.io.Parameters;
0033 import org.qedeq.base.io.SourceArea;
0034 import org.qedeq.base.io.TextInput;
0035 import org.qedeq.base.io.UrlUtility;
0036 import org.qedeq.base.trace.Trace;
0037 import org.qedeq.base.utility.StringUtility;
0038 import org.qedeq.kernel.bo.common.Element2Utf8;
0039 import org.qedeq.kernel.bo.common.Kernel;
0040 import org.qedeq.kernel.bo.common.KernelProperties;
0041 import org.qedeq.kernel.bo.common.QedeqBo;
0042 import org.qedeq.kernel.bo.common.ServiceJob;
0043 import org.qedeq.kernel.bo.log.QedeqLog;
0044 import org.qedeq.kernel.bo.module.InternalKernelServices;
0045 import org.qedeq.kernel.bo.module.InternalModuleServiceCall;
0046 import org.qedeq.kernel.bo.module.InternalServiceJob;
0047 import org.qedeq.kernel.bo.module.KernelQedeqBo;
0048 import org.qedeq.kernel.bo.module.ModuleArbiter;
0049 import org.qedeq.kernel.bo.module.ModuleLabels;
0050 import org.qedeq.kernel.bo.module.QedeqFileDao;
0051 import org.qedeq.kernel.bo.service.basis.ModuleFileNotFoundException;
0052 import org.qedeq.kernel.bo.service.basis.ModuleLabelsCreator;
0053 import org.qedeq.kernel.bo.service.basis.ModuleServiceExecutor;
0054 import org.qedeq.kernel.bo.service.basis.QedeqVoBuilder;
0055 import org.qedeq.kernel.bo.service.basis.ServiceErrors;
0056 import org.qedeq.kernel.bo.service.dependency.LoadDirectlyRequiredModulesPlugin;
0057 import org.qedeq.kernel.bo.service.dependency.LoadRequiredModulesPlugin;
0058 import org.qedeq.kernel.bo.service.logic.FormalProofCheckerPlugin;
0059 import org.qedeq.kernel.bo.service.logic.SimpleProofFinderPlugin;
0060 import org.qedeq.kernel.bo.service.logic.WellFormedCheckerPlugin;
0061 import org.qedeq.kernel.se.base.module.Qedeq;
0062 import org.qedeq.kernel.se.base.module.Specification;
0063 import org.qedeq.kernel.se.common.DefaultModuleAddress;
0064 import org.qedeq.kernel.se.common.ModuleAddress;
0065 import org.qedeq.kernel.se.common.ModuleDataException;
0066 import org.qedeq.kernel.se.common.ModuleService;
0067 import org.qedeq.kernel.se.common.Service;
0068 import org.qedeq.kernel.se.common.SourceFileException;
0069 import org.qedeq.kernel.se.common.SourceFileExceptionList;
0070 import org.qedeq.kernel.se.config.QedeqConfig;
0071 import org.qedeq.kernel.se.dto.module.QedeqVo;
0072 import org.qedeq.kernel.se.state.LoadingState;
0073 import org.qedeq.kernel.se.visitor.ContextChecker;
0074 import org.qedeq.kernel.se.visitor.DefaultContextChecker;
0075 import org.qedeq.kernel.se.visitor.InterruptException;
0076 
0077 
0078 /**
0079  * This class provides a default implementation for the QEDEQ module services.
0080  *
0081  @author  Michael Meyling
0082  */
0083 public class DefaultInternalKernelServices implements Kernel, InternalKernelServices,
0084         Service {
0085 
0086     /** This class. */
0087     private static final Class CLASS = DefaultInternalKernelServices.class;
0088 
0089     /** Collection of already known QEDEQ modules. */
0090     private KernelQedeqBoStorage modules;
0091 
0092     /** Config access. */
0093     private final QedeqConfig config;
0094 
0095     /** Basic kernel properties. */
0096     private final KernelProperties kernel;
0097 
0098     /** This instance nows how to load a module from the file system. */
0099     private final QedeqFileDao qedeqFileDao;
0100 
0101     /** Synchronize module access. */
0102     private ModuleArbiter arbiter;
0103 
0104     /** This instance manages plugins. */
0105     private final PluginManager pluginManager;
0106 
0107     /** This instance manages service processes. */
0108     private ServiceProcessManager processManager;
0109 
0110     /** Validate module dependencies and status. */
0111     private boolean validate = true;
0112 
0113     /** We check the context with this checker. */
0114     private ContextChecker contextChecker;
0115 
0116 
0117     /**
0118      * Constructor.
0119      *
0120      @param   config  For config access.
0121      @param   kernel  For kernel properties.
0122      @param   loader  For loading QEDEQ modules.
0123      */
0124     public DefaultInternalKernelServices(final QedeqConfig config, final KernelProperties kernel,
0125             final QedeqFileDao loader) {
0126         this.config = config;
0127         this.kernel = kernel;
0128         this.qedeqFileDao = loader;
0129         pluginManager = new PluginManager(this);
0130         loader.setServices(this);
0131 
0132 ////      pluginManager.addPlugin(MultiProofFinderPlugin.class.getName());
0133         pluginManager.addPlugin("org.qedeq.kernel.bo.service.unicode.Qedeq2UnicodeTextPlugin");
0134         pluginManager.addPlugin("org.qedeq.kernel.bo.service.latex.Qedeq2LatexPlugin");
0135         pluginManager.addPlugin("org.qedeq.kernel.bo.service.unicode.Qedeq2Utf8Plugin");
0136 ////        pluginManager.addPlugin("org.qedeq.kernel.bo.service.heuristic.HeuristicCheckerPlugin");
0137         pluginManager.addPlugin("org.qedeq.kernel.bo.service.heuristic.DynamicHeuristicCheckerPlugin");
0138         pluginManager.addPlugin(SimpleProofFinderPlugin.class.getName());
0139 
0140         // add internal plugins
0141         pluginManager.addPlugin(LoadDirectlyRequiredModulesPlugin.class.getName());
0142         pluginManager.addPlugin(LoadRequiredModulesPlugin.class.getName());
0143         pluginManager.addPlugin(WellFormedCheckerPlugin.class.getName());
0144         pluginManager.addPlugin(FormalProofCheckerPlugin.class.getName());
0145     }
0146 
0147     public synchronized void startupServices() {
0148         modules = new KernelQedeqBoStorage();
0149         arbiter = new ModuleArbiterImpl();
0150         processManager = new ServiceProcessManager(pluginManager, arbiter);
0151         contextChecker = new DefaultContextChecker();
0152         if (config.isAutoReloadLastSessionChecked()) {
0153             autoReloadLastSessionChecked();
0154         }
0155     }
0156 
0157     public synchronized void shutdownServices() {
0158         processManager.terminateAndRemoveAllServiceProcesses();
0159         processManager = null;
0160         modules.removeAllModules();
0161         modules = null;
0162         arbiter = null;
0163         // clear thread interrupt flag because we might have interrupted ourself
0164         Thread.interrupted();
0165     }
0166 
0167     /**
0168      * If configured load all QEDEQ modules that where successfully loaded the last time.
0169      */
0170     private void autoReloadLastSessionChecked() {
0171         if (config.isAutoReloadLastSessionChecked()) {
0172             final Thread thread = new Thread() {
0173                 public void run() {
0174                     final String method = "autoReloadLastSessionChecked.thread.run()";
0175                     try {
0176                         Trace.begin(CLASS, this, method);
0177                         QedeqLog.getInstance().logMessage(
0178                             "Trying to load previously successfully loaded modules.");
0179                         final int number = config.getPreviouslyLoadedModules().length;
0180                         if (loadPreviouslySuccessfullyLoadedModules()) {
0181                             QedeqLog.getInstance().logMessage(
0182                                 "Loading of " + number + " previously successfully loaded module"
0183                                     (number != "s" """ successfully done.");
0184                         else {
0185                             QedeqLog.getInstance().logMessage(
0186                                 "Loading of all previously successfully checked modules failed. "
0187                                     + number + " module" (number != "s" "")
0188                                     " were tried.");
0189                         }
0190                     catch (Exception e) {
0191                         Trace.trace(CLASS, this, method, e);
0192                     finally {
0193                         Trace.end(CLASS, this, method);
0194                     }
0195                 }
0196             };
0197             thread.setDaemon(true);
0198             thread.start();
0199         }
0200     }
0201 
0202     public boolean removeAllModules() {
0203         final String method = "removeAllModules()";
0204         Trace.begin(CLASS, this, method);
0205 //        getModules().removeAllModules();
0206         InternalServiceJob proc = null;
0207         proc = processManager.createServiceProcess("remove all modules");
0208         final List calls = new ArrayList();
0209         final List m = getModules().getAllModules();
0210         boolean ok = false;
0211         try {
0212             // lock all modules
0213             for (final Iterator iterator = m.iterator(); iterator.hasNext()) {
0214                 final DefaultKernelQedeqBo prop = (DefaultKernelQedeqBoiterator.next();
0215                 final InternalModuleServiceCall call  = processManager.createServiceCall(this, prop, Parameters.EMPTY,
0216                     Parameters.EMPTY, proc);
0217                 calls.add(call);
0218             }
0219 
0220             // delete all modules
0221             for (final Iterator iterator = m.iterator(); iterator.hasNext()) {
0222                 final DefaultKernelQedeqBo prop = (DefaultKernelQedeqBoiterator.next();
0223                 removeModule(prop);
0224             }
0225             ok = true;
0226         catch (final InterruptException e) {
0227             for (final Iterator iterator = calls.iterator(); iterator.hasNext()) {
0228                 final InternalModuleServiceCall call = (InternalModuleServiceCalliterator.next();
0229                 call.finishError("couldn't lock all modules");
0230                 processManager.endServiceCall(call);
0231             }
0232             QedeqLog.getInstance().logMessage("Remove all modules failed: " + e.getMessage());
0233             proc.setInterruptedState();
0234         finally {
0235             for (final Iterator iterator = calls.iterator(); iterator.hasNext()) {
0236                 final InternalModuleServiceCall call = (InternalModuleServiceCalliterator.next();
0237                 call.finishOk();
0238                 processManager.endServiceCall(call);
0239             }
0240             if (ok) {
0241                 proc.setSuccessState();
0242             else {
0243                 proc.setFailureState();
0244             }
0245         }
0246         if (validate) {
0247             modules.validateDependencies();
0248         }
0249         Trace.end(CLASS, this, method);
0250         return ok;
0251     }
0252 
0253     public void removeModule(final ModuleAddress address) {
0254         final KernelQedeqBo prop = getKernelQedeqBo(address);
0255         if (prop != null) {
0256             QedeqLog.getInstance().logRequest("Removing module", address.getUrl());
0257             InternalServiceJob proc = processManager.createServiceProcess("remove module");
0258             InternalModuleServiceCall call = null;
0259             try {
0260                 call = processManager.createServiceCall(this, prop, Parameters.EMPTY,
0261                     Parameters.EMPTY, proc);
0262                 removeModule((DefaultKernelQedeqBoprop);
0263                 call.finishOk();
0264                 proc.setSuccessState();
0265             catch (final InterruptException e) {
0266                 QedeqLog.getInstance().logFailureReply(
0267                     "Remove failed", address.getUrl(), e.getMessage());
0268                 proc.setInterruptedState();
0269             finally {
0270                 processManager.endServiceCall(call);
0271             }
0272             if (validate) {
0273                 modules.validateDependencies();
0274             }
0275         }
0276     }
0277 
0278     /**
0279      * Remove a QEDEQ module from memory. This method must block all other methods and if this
0280      * method runs no other is allowed to run
0281      *
0282      @param prop Remove module identified by this property.
0283      */
0284     private void removeModule(final DefaultKernelQedeqBo prop) {
0285         synchronized (prop) {
0286             // FIXME mime 20080319: one could call prop.setLoadingProgressState(
0287             // LoadingState.STATE_DELETED) alone but that would
0288             // miss to inform the KernelQedeqBoPool. How do we inform the pool?
0289             // must the StateManager have a reference to it?
0290             prop.delete();
0291             getModules().removeModule(prop);
0292             return;
0293         }
0294     }
0295 
0296     /**
0297      * Clear local file buffer and all loaded QEDEQ modules.
0298      *
0299      @return  Successful?
0300      */
0301     public boolean clearLocalBuffer() {
0302         final String method = "clearLocalBuffer";
0303         try {
0304             QedeqLog.getInstance().logMessage(
0305                 "Clear local buffer from all QEDEQ files.");
0306             if (removeAllModules()) {
0307                 final File bufferDir = getBufferDirectory().getCanonicalFile();
0308                 if (bufferDir.exists() && !IoUtility.deleteDir(bufferDir, new FileFilter() {
0309                             public boolean accept(final File pathname) {
0310                                 return pathname.getName().endsWith(".xml");
0311                             }
0312                         })) {
0313                     throw new IOException("buffer could not be deleted: " + bufferDir);
0314                 }
0315                 QedeqLog.getInstance().logMessage("Local buffer was cleared.");
0316                 return true;
0317             }
0318             QedeqLog.getInstance().logMessage("Local buffer was not cleared.");
0319             return false;
0320         catch (IOException e) {
0321             Trace.fatal(CLASS, this, method, "IO access problem", e);
0322             QedeqLog.getInstance().logMessage(
0323                 "Local buffer not cleared. IO access problem. " + e.getMessage());
0324             return false;
0325         catch (final RuntimeException e) {
0326             Trace.fatal(CLASS, this, method, "unexpected problem", e);
0327             QedeqLog.getInstance().logMessage(
0328                 "Local buffer not cleared. " + e.getMessage());
0329             return false;
0330         }
0331     }
0332 
0333     public KernelQedeqBo loadKernelModule(final InternalServiceJob process, final ModuleAddress address)
0334             throws InterruptException {
0335         final String method = "loadModule(InternalServiceProcess, ModuleAddress)";
0336         final DefaultKernelQedeqBo prop = getModules().getKernelQedeqBo(this, address);
0337         if (prop.isLoaded()) {
0338             return prop;
0339         }
0340         final ModuleServiceExecutor executor = new ModuleServiceExecutor() {
0341             public void executeService(final InternalModuleServiceCall callthrows InterruptException {
0342                 try {
0343                     synchronized (prop) {
0344                         if (prop.isLoaded()) {
0345                             call.finishOk();
0346                             return;
0347                         }
0348                         QedeqLog.getInstance().logRequest("Load module", address.getUrl());
0349                         if (prop.getModuleAddress().isFileAddress()) {
0350                             call.setAction("file loading");
0351                             loadLocalModule(call.getInternalServiceProcess(), prop);
0352                         else {
0353                             // search in local file buffer
0354                             try {
0355                                 getCanonicalReadableFile(prop);
0356                             catch (ModuleFileNotFoundException e) { // file not found
0357                                 // we will continue by creating a local copy
0358                                 call.setAction("web loading");
0359                                 saveQedeqFromWebToBuffer(call, prop);
0360                                 call.setExecutionPercentage(50);
0361                             }
0362                             call.setAction("buffer loading");
0363                             loadBufferedModule(call.getInternalServiceProcess(), prop);
0364                         }
0365                         QedeqLog.getInstance().logSuccessfulReply(
0366                             "Successfully loaded", address.getUrl());
0367                         call.finishOk();
0368                     }
0369                 catch (SourceFileExceptionList e) {
0370                     Trace.trace(CLASS, this, method, e);
0371                     QedeqLog.getInstance().logFailureState("Loading of module failed.", address.getUrl(),
0372                         e.toString());
0373                     call.finishError("Loading of module failed.");
0374                 catch (final RuntimeException e) {
0375                     Trace.fatal(CLASS, this, method, "unexpected problem", e);
0376                     QedeqLog.getInstance().logFailureReply("Loading failed", address.getUrl(), e.getMessage());
0377                     call.finishError("Loading of module failed: " + e.getMessage());
0378                 }
0379             }
0380 
0381         };
0382         this.processManager.executeService(new ModuleService() {
0383             public String getServiceAction() {
0384                 return "load QEDEQ module";
0385             }
0386 
0387             public String getServiceDescription() {
0388                 return "take QEDEQ module address and try to load and parse the content";
0389             }
0390 
0391             public String getServiceId() {
0392                 return "" + hashCode();
0393             }
0394         }, executor, prop, process);
0395         return prop;
0396 //        try {
0397 //            synchronized (prop) {
0398 //                if (prop.isLoaded()) {
0399 //                    return prop;
0400 //                }
0401 //                QedeqLog.getInstance().logRequest("Load module", address.getUrl());
0402 //                if (prop.getModuleAddress().isFileAddress()) {
0403 //                    loadLocalModule(proc, prop);
0404 //                } else {
0405 //                    // search in local file buffer
0406 //                    try {
0407 //                        getCanonicalReadableFile(prop);
0408 //                    } catch (ModuleFileNotFoundException e) { // file not found
0409 //                        // we will continue by creating a local copy
0410 //                        saveQedeqFromWebToBuffer(prop);
0411 //                    }
0412 //                    loadBufferedModule(proc, prop);
0413 //                }
0414 //                QedeqLog.getInstance().logSuccessfulReply(
0415 //                    "Successfully loaded", address.getUrl());
0416 //            }
0417 //        } catch (SourceFileExceptionList e) {
0418 //            Trace.trace(CLASS, this, method, e);
0419 //            QedeqLog.getInstance().logFailureState("Loading of module failed!", address.getUrl(),
0420 //                e.toString());
0421 //        } catch (final RuntimeException e) {
0422 //            Trace.fatal(CLASS, this, method, "unexpected problem", e);
0423 //            QedeqLog.getInstance().logFailureReply("Loading failed", address.getUrl(), e.getMessage());
0424 //        } finally {
0425 //            call.setSuccessState();
0426 //        }
0427 //        return prop;
0428     }
0429 
0430     public QedeqBo loadModule(final ModuleAddress address) {
0431         final InternalServiceJob process = processManager.createServiceProcess("LoadModule");
0432         final QedeqBo result = getQedeqBo(address);
0433         try {
0434             loadKernelModule(process, address);
0435             process.setSuccessState();
0436         catch (InterruptException e) {
0437             process.setInterruptedState();
0438         }
0439         return result;
0440     }
0441 
0442     /**
0443      * Load buffered QEDEQ module file.
0444      *
0445      @param   process Service process we run within.
0446      @param   prop    Load this.
0447      @throws  SourceFileExceptionList Loading or QEDEQ module failed.
0448      */
0449     private void loadBufferedModule(final InternalServiceJob process,
0450             final DefaultKernelQedeqBo propthrows SourceFileExceptionList {
0451         prop.setLoadingProgressState(LoadingState.STATE_LOADING_FROM_BUFFER);
0452         final File localFile;
0453         try {
0454             localFile = getCanonicalReadableFile(prop);
0455         catch (ModuleFileNotFoundException e) {
0456             final SourceFileExceptionList sfl = createSourceFileExceptionList(
0457                 ServiceErrors.LOADING_FROM_FILE_BUFFER_FAILED_CODE,
0458                 ServiceErrors.LOADING_FROM_FILE_BUFFER_FAILED_TEXT,
0459                 prop.getUrl(), e);
0460             prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_BUFFER_FAILED, sfl);
0461             throw sfl;
0462         }
0463 
0464         prop.setQedeqFileDao(getQedeqFileDao())// remember loader for this module
0465         final Qedeq qedeq;
0466         try {
0467             qedeq = getQedeqFileDao().loadQedeq(process, prop, localFile);
0468         catch (SourceFileExceptionList sfl) {
0469             prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_BUFFER_FAILED, sfl);
0470             throw sfl;
0471         }
0472         setCopiedQedeq(process, prop, qedeq);
0473     }
0474 
0475     /**
0476      * Load QEDEQ module file with file loader.
0477      *
0478      @param   process Service process we run within.
0479      @param   prop    Load this.
0480      @throws  SourceFileExceptionList Loading or copying QEDEQ module failed.
0481      */
0482     private void loadLocalModule(final InternalServiceJob process,
0483             final DefaultKernelQedeqBo propthrows SourceFileExceptionList {
0484         prop.setLoadingProgressState(LoadingState.STATE_LOADING_FROM_LOCAL_FILE);
0485         final File localFile;
0486         try {
0487             localFile = getCanonicalReadableFile(prop);
0488         catch (ModuleFileNotFoundException e) {
0489             final SourceFileExceptionList sfl = createSourceFileExceptionList(
0490                 ServiceErrors.LOADING_FROM_LOCAL_FILE_FAILED_CODE,
0491                 ServiceErrors.LOADING_FROM_LOCAL_FILE_FAILED_TEXT,
0492                 prop.getUrl(), e);
0493             prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_LOCAL_FILE_FAILED, sfl);
0494             throw sfl;
0495         }
0496         prop.setQedeqFileDao(getQedeqFileDao())// remember loader for this module
0497 
0498         final Qedeq qedeq;
0499         try {
0500             qedeq = getQedeqFileDao().loadQedeq(process, prop, localFile);
0501         catch (SourceFileExceptionList sfl) {
0502             prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_LOCAL_FILE_FAILED, sfl);
0503             throw sfl;
0504         }
0505         setCopiedQedeq(process, prop, qedeq);
0506     }
0507 
0508     private void setCopiedQedeq(final InternalServiceJob process, final DefaultKernelQedeqBo prop,
0509             final Qedeq qedeqthrows SourceFileExceptionList {
0510         final String method = "setCopiedQedeq(DefaultKernelQedeqBo, Qedeq)";
0511         prop.setLoadingProgressState(LoadingState.STATE_LOADING_INTO_MEMORY);
0512         QedeqVo vo = null;
0513         try {
0514             vo = QedeqVoBuilder.createQedeq(prop.getModuleAddress(), qedeq);
0515         catch (RuntimeException e) {
0516             Trace.fatal(CLASS, this, method, "looks like a programming error", e);
0517             final SourceFileExceptionList xl = createSourceFileExceptionList(
0518                 ServiceErrors.RUNTIME_ERROR_CODE,
0519                 ServiceErrors.RUNTIME_ERROR_TEXT,
0520                 prop.getModuleAddress().getUrl(), e);
0521             prop.setLoadingFailureState(LoadingState.STATE_LOADING_INTO_MEMORY_FAILED, xl);
0522             throw xl;
0523         catch (ModuleDataException e) {
0524             if (e.getCause() != null) {
0525                 Trace.fatal(CLASS, this, method, "looks like a programming error", e.getCause());
0526             else {
0527                 Trace.fatal(CLASS, this, method, "looks like a programming error", e);
0528             }
0529             final SourceFileExceptionList xl = prop.createSourceFileExceptionList(this, e, qedeq);
0530             prop.setLoadingFailureState(LoadingState.STATE_LOADING_INTO_MEMORY_FAILED, xl);
0531             throw xl;
0532         }
0533         prop.setQedeqVo(vo);
0534         // TODO 20110213 m31: perhaps we need a new state, pre loaded? So when we put more
0535         // label testing into the moduleLabelCreator, we still can launch some plugins
0536         // On the other side: Label checking is only possible, if all referenced modules can
0537         // be loaded.
0538         //
0539         // Correct labels are necessary for many plugins (e.g. LaTeX and UTF-8 generation).
0540         // So a label checker must be run before that.
0541         // It might be a good idea to put it into the formal logic checker.
0542         // We could make a FormalChecker plugin. This starts loading required modules, checks
0543         // the labels and checks if the formulas are correctly written.
0544         // So we get some sub status (for every check) and an overall status (all checks
0545         // green). Later on the formal proof checker can be integrated too.
0546         // This should be the extended load status.
0547         final ModuleLabelsCreator moduleNodesCreator = new ModuleLabelsCreator(this, prop);
0548         try {
0549             final ModuleLabels labels = new ModuleLabels();
0550             final Element2LatexImpl converter = new Element2LatexImpl(labels);
0551             final Element2Utf8 textConverter = new Element2Utf8Impl(converter);
0552             moduleNodesCreator.createLabels(process, labels);
0553             prop.setLoaded(vo, labels, converter, textConverter);
0554         catch (SourceFileExceptionList sfl) {
0555             prop.setLoadingFailureState(LoadingState.STATE_LOADING_INTO_MEMORY_FAILED, sfl);
0556             throw sfl;
0557         }
0558     }
0559 
0560     /**
0561      * Check if file exists and is readable. Checks the local buffer file for a buffered module or
0562      * the module file address directly. Returns canonical file path.
0563      *
0564      @param prop Check for this file.
0565      @return Canonical file path.
0566      @throws ModuleFileNotFoundException File doesn't exist or is not readable.
0567      */
0568     private File getCanonicalReadableFile(final QedeqBo propthrows ModuleFileNotFoundException {
0569         final String method = "getCanonicalReadableFile(File)";
0570         final File localFile = getLocalFilePath(prop.getModuleAddress());
0571         final File file;
0572         try {
0573             file = localFile.getCanonicalFile();
0574         catch (IOException e) {
0575             Trace.trace(CLASS, this, method, e);
0576             throw new ModuleFileNotFoundException("file path not correct: " + localFile);
0577         }
0578         if (!file.canRead()) {
0579             Trace.trace(CLASS, this, method, "file not readable=" + file);
0580             throw new ModuleFileNotFoundException("file not readable: " + file);
0581         }
0582         return file;
0583     }
0584 
0585     /**
0586      * Load specified QEDEQ module from QEDEQ parent module.
0587      *
0588      @param   process    Our service process we run within.
0589      @param   parent  Parent module address.
0590      @param   spec    Specification for another QEDEQ module.
0591      @return  Loaded module.
0592      @throws  SourceFileExceptionList Loading failed.
0593      @throws  InterruptException User canceled request.
0594      */
0595     public KernelQedeqBo loadKernelModule(final InternalServiceJob process, final ModuleAddress parent,
0596             final Specification specthrows SourceFileExceptionList, InterruptException {
0597 
0598         final String method = "loadModule(Module, Specification)";
0599         Trace.begin(CLASS, this, method);
0600         Trace.trace(CLASS, this, method, spec);
0601         DefaultKernelQedeqBo prop = null// currently tried module
0602         try {
0603             final ModuleAddress[] modulePaths;
0604             try {
0605                 modulePaths = parent.getModulePaths(spec);
0606             catch (IOException e) {
0607                 Trace.fatal(CLASS, this, method, "getting module path failed", e);  // TODO 20110308 m31: make constant
0608                 throw createSourceFileExceptionList(
0609                     ServiceErrors.LOADING_FROM_FILE_BUFFER_FAILED_CODE,
0610                     ServiceErrors.LOADING_FROM_FILE_BUFFER_FAILED_TEXT,
0611                     parent.getUrl(), e);
0612             }
0613 
0614             // now we iterate over the possible module addresses
0615             for (int i = 0; i < modulePaths.length; i++) {
0616                 prop = getModules().getKernelQedeqBo(this, modulePaths[i]);
0617                 Trace.trace(CLASS, this, method, "synchronizing at prop=" + prop);
0618                 if (prop.isLoaded()) {
0619                     return (prop);
0620                 }
0621                 synchronized (prop) {
0622                     if (prop.isLoaded()) {
0623                         return (prop);
0624                     }
0625                     try {
0626                         if (prop.getModuleAddress().isFileAddress()) {
0627                             loadLocalModule(process, prop);
0628                         else {
0629                             // search in local file buffer
0630                             try {
0631                                 getCanonicalReadableFile(prop);
0632                             catch (ModuleFileNotFoundException e) { // file not found
0633                                 // we will continue by creating a local copy
0634                                 saveQedeqFromWebToBuffer((InternalModuleServiceCallprocess.getModuleServiceCall(),
0635                                     prop);
0636                             }
0637                             loadBufferedModule(process, prop);
0638                         }
0639                         // success!
0640                         return prop;
0641                     catch (SourceFileExceptionList e) {
0642                         Trace.trace(CLASS, this, method, e);
0643                         if (i + < modulePaths.length) {
0644                             QedeqLog.getInstance().logMessage("trying alternate path");
0645                             // we continue with the next path
0646                         else {
0647                             // we surrender
0648                             throw e;
0649                         }
0650                     }
0651                 }
0652             }
0653             return prop; // never called, only here to soothe the compiler
0654         catch (final RuntimeException e) {
0655             Trace.fatal(CLASS, this, method, "unexpected problem", e);
0656             QedeqLog.getInstance().logFailureReply("Loading failed",
0657                 (prop != null ? prop.getUrl() "unknownURL"), e.getMessage());
0658             throw e;
0659         finally {
0660             Trace.end(CLASS, this, method);
0661         }
0662     }
0663 
0664     public ModuleAddress[] getAllLoadedModules() {
0665         return getModules().getAllLoadedModules();
0666     }
0667 
0668     /**
0669      * Load all previously checked QEDEQ modules.
0670      *
0671      @return Successfully reloaded all modules.
0672      */
0673     public boolean loadPreviouslySuccessfullyLoadedModules() {
0674         final String[] list = config.getPreviouslyLoadedModules();
0675         boolean errors = false;
0676         for (int i = 0; i < list.length; i++) {
0677             try {
0678                 final ModuleAddress address = getModuleAddress(list[i]);
0679                 final QedeqBo prop = loadModule(address);
0680                 if (prop.hasErrors()) {
0681                     errors = true;
0682                 }
0683             catch (IOException e) {
0684                 Trace.fatal(CLASS, this, "loadPreviouslySuccessfullyLoadedModules",
0685                     "internal error: " "saved URLs are malformed", e);
0686                 errors = true;
0687             }
0688         }
0689         return !errors;
0690     }
0691 
0692     // LATER mime 20070326: dynamic loading from web page directory
0693     public boolean loadAllModulesFromQedeq() {
0694         final String prefix = "http://www.qedeq.org/" + kernel.getKernelVersionDirectory() "/";
0695         final String[] list = new String[] {
0696             prefix + "doc/math/qedeq_logic_v1.xml",
0697             prefix + "doc/math/qedeq_formal_logic_v1.xml",
0698             prefix + "doc/math/qedeq_set_theory_v1.xml",
0699             prefix + "doc/project/qedeq_basic_concept.xml",
0700             prefix + "doc/project/qedeq_logic_language.xml",
0701             prefix + "sample/qedeq_sample1.xml",
0702             prefix + "sample/qedeq_sample2.xml",
0703             prefix + "sample/qedeq_sample3.xml",
0704             prefix + "sample/qedeq_sample4.xml",
0705             prefix + "sample/qedeq_error_sample_00.xml",
0706             prefix + "sample/qedeq_error_sample_01.xml",
0707             prefix + "sample/qedeq_error_sample_02.xml",
0708             prefix + "sample/qedeq_error_sample_03.xml",
0709             prefix + "sample/qedeq_error_sample_04.xml",
0710             prefix + "sample/qedeq_error_sample_05.xml",
0711             prefix + "sample/qedeq_error_sample_12.xml",
0712             prefix + "sample/qedeq_error_sample_13.xml",
0713             prefix + "sample/qedeq_error_sample_14.xml",
0714             prefix + "sample/qedeq_error_sample_15.xml",
0715             prefix + "sample/qedeq_error_sample_16.xml",
0716             prefix + "sample/qedeq_error_sample_17.xml",
0717             prefix + "sample/qedeq_error_sample_18.xml"};
0718         boolean errors = false;
0719         for (int i = 0; i < list.length; i++) {
0720             try {
0721                 final ModuleAddress address = getModuleAddress(list[i]);
0722                 final QedeqBo prop = loadModule(address);
0723                 if (prop.hasErrors()) {
0724                     errors = true;
0725                 }
0726             catch (final IOException e) {
0727                 Trace.fatal(CLASS, this, "loadPreviouslySuccessfullyLoadedModules",
0728                     "internal error: " "saved URLs are malformed", e);
0729                 errors = true;
0730             }
0731         }
0732         return !errors;
0733     }
0734 
0735     /**
0736      * Make local copy of a module if it is no file address.
0737      *
0738      @param   call    Service call we run within.
0739      @param   prop    Module properties.
0740      @throws  SourceFileExceptionList Address was malformed or the file can not be found.
0741      @throws  InterruptException User canceled request.
0742      */
0743     private void saveQedeqFromWebToBuffer(final InternalModuleServiceCall call, final DefaultKernelQedeqBo prop)
0744             throws SourceFileExceptionList,  InterruptException {
0745         final String method = "saveQedeqFromWebToBuffer(DefaultKernelQedeqBo)";
0746         Trace.begin(CLASS, this, method);
0747 
0748         if (prop.getModuleAddress().isFileAddress()) { // this is already a local file
0749             Trace.fatal(CLASS, this, method, "tried to make a local copy for a local module"null);
0750             Trace.end(CLASS, this, method);
0751             return;
0752         }
0753 
0754         final ModuleServiceExecutor executor = new ModuleServiceExecutor() {
0755 
0756             public void executeService(final InternalModuleServiceCall call) {
0757                 final File f = getLocalFilePath(prop.getModuleAddress());
0758                 prop.setLoadingProgressState(LoadingState.STATE_LOADING_FROM_WEB);
0759                 try {
0760                     UrlUtility.saveUrlToFile(prop.getUrl(), f,
0761                         config.getHttpProxyHost(), config.getHttpProxyPort(), config.getHttpNonProxyHosts(),
0762                         config.getConnectionTimeout(), config.getReadTimeout()new LoadingListener() {
0763                         public void loadingCompletenessChanged(final double completeness) {
0764                             final double percentage = completeness * 100;
0765                             call.setExecutionPercentage(percentage);
0766                             prop.setLoadingCompleteness((intpercentage);
0767                         }
0768                     });
0769                     call.finishOk();
0770                 catch (IOException e) {
0771                     Trace.trace(CLASS, this, method, e);
0772                     try {
0773                         f.delete();
0774                     catch (Exception ex) {
0775                         Trace.trace(CLASS, this, method, ex);
0776                     }
0777                     final SourceFileExceptionList sfl = createSourceFileExceptionList(
0778                         ServiceErrors.LOADING_FROM_WEB_FAILED_CODE,
0779                         ServiceErrors.LOADING_FROM_WEB_FAILED_TEXT,
0780                         prop.getUrl(), e);
0781                     prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_WEB_FAILED, sfl);
0782                     Trace.trace(CLASS, this, method, "Couldn't access " + prop.getUrl());
0783                     call.finishError("Couldn't save URL " + prop.getUrl() " to file: " + e.getMessage());
0784                 }
0785             }
0786         };
0787 
0788         this.processManager.executeService(new ModuleService() {
0789             public String getServiceAction() {
0790                 return "saving from web to file buffer";
0791             }
0792 
0793             public String getServiceDescription() {
0794                 return "download QEDEQ module from web URL and save it to a local file";
0795             }
0796 
0797             public String getServiceId() {
0798                 return "" + hashCode();
0799             }
0800         }, executor, prop, call.getInternalServiceProcess());
0801         Trace.end(CLASS, this, method);
0802 
0803     }
0804 
0805     public final File getLocalFilePath(final ModuleAddress address) {
0806         final String method = "getLocalFilePath(ModuleAddress)";
0807         URL url;
0808         try {
0809             url = new URL(address.getUrl());
0810         catch (MalformedURLException e) {
0811             Trace.fatal(CLASS, this, method, "Could not get local file path.", e);
0812             return null;
0813         }
0814         Trace.param(CLASS, this, method, "protocol", url.getProtocol());
0815         Trace.param(CLASS, this, method, "host", url.getHost());
0816         Trace.param(CLASS, this, method, "port", url.getPort());
0817         Trace.param(CLASS, this, method, "path", url.getPath());
0818         Trace.param(CLASS, this, method, "file", url.getFile());
0819         if (address.isFileAddress()) {
0820             try {
0821                 return UrlUtility.transformURLPathToFilePath(url);
0822             catch (IllegalArgumentException e) {
0823                 // should not occur because check for validy must be done in constructor of address
0824                 Trace.fatal(CLASS, this, method, "Loading failed of local file with URL=" + url, e);
0825                 throw new RuntimeException(e);
0826             }
0827         }
0828         StringBuffer file = new StringBuffer(url.getFile());
0829         StringUtility.replace(file, "_""_1")// remember all '_'
0830         StringUtility.replace(file, "/""_2")// preserve all '/'
0831         String encoded = file.toString()// fallback file name
0832         try {
0833             encoded = URLEncoder.encode(file.toString()"UTF-8");
0834         catch (UnsupportedEncodingException e) {
0835             // should not occur
0836             Trace.trace(CLASS, method, e);
0837         }
0838         file.setLength(0);
0839         file.append(encoded);
0840         StringUtility.replace(file, "#""##")// escape all '#'
0841         StringUtility.replace(file, "_2""#")// from '/' into '#'
0842         StringUtility.replace(file, "_1""_")// from '_' into '_'
0843         // mime 2010-06-25: use if we throw no RuntimException
0844         // StringBuffer adr = new StringBuffer(url.toExternalForm());
0845         final StringBuffer adr;
0846         try {
0847             adr = new StringBuffer(new URL(url.getProtocol(), url.getHost(), url.getPort(), file
0848                 .toString()).toExternalForm());
0849         catch (MalformedURLException e) {
0850             Trace.fatal(CLASS, this, method, "unexpected", e);
0851             throw new RuntimeException(e);
0852         }
0853         // escape characters:
0854         StringUtility.replace(adr, "://""_")// before host
0855         StringUtility.replace(adr, ":""_")// before protocol
0856         return new File(getBufferDirectory(), adr.toString());
0857     }
0858 
0859     public File getBufferDirectory() {
0860         return config.getBufferDirectory();
0861     }
0862 
0863     public File getGenerationDirectory() {
0864         return config.getGenerationDirectory();
0865     }
0866 
0867     public KernelQedeqBo getKernelQedeqBo(final ModuleAddress address) {
0868         return getModules().getKernelQedeqBo(this, address);
0869     }
0870 
0871     public QedeqBo getQedeqBo(final ModuleAddress address) {
0872         return getKernelQedeqBo(address);
0873     }
0874 
0875     public ModuleAddress getModuleAddress(final URL urlthrows IOException {
0876         return new DefaultModuleAddress(url);
0877     }
0878 
0879     public ModuleAddress getModuleAddress(final String urlthrows IOException {
0880         return new DefaultModuleAddress(url);
0881     }
0882 
0883     public ModuleAddress getModuleAddress(final File filethrows IOException {
0884         return new DefaultModuleAddress(file);
0885     }
0886 
0887     public String getSource(final ModuleAddress addressthrows IOException {
0888         final KernelQedeqBo bo = getKernelQedeqBo(address);
0889         if (bo.getLoadingState().equals(LoadingState.STATE_UNDEFINED)
0890             || bo.getLoadingState().equals(LoadingState.STATE_LOADING_FROM_WEB)
0891             || bo.getLoadingState().equals(LoadingState.STATE_LOADING_FROM_WEB_FAILED)) {
0892             return null;
0893         }
0894         final StringBuffer buffer = new StringBuffer();
0895         final Reader reader = getQedeqFileDao().getModuleReader(bo);
0896         try {
0897             IoUtility.loadReader(reader, buffer);
0898         finally {
0899             IoUtility.close(reader);
0900         }
0901         return buffer.toString();
0902     }
0903 
0904     public boolean loadRequiredModules(final ModuleAddress address) {
0905         final KernelQedeqBo prop = getKernelQedeqBo(address);
0906         // did we check this already?
0907         if (prop.hasLoadedRequiredModules()) {
0908             return true// everything is OK
0909         }
0910         executePlugin(LoadRequiredModulesPlugin.class.getName(), prop.getModuleAddress()null);
0911         return prop.hasLoadedRequiredModules();
0912     }
0913 
0914     public boolean loadRequiredModules(final InternalServiceJob process, final KernelQedeqBo qedeq)
0915             throws InterruptException {
0916         // did we check this already?
0917         if (qedeq.hasLoadedRequiredModules()) {
0918             return true// everything is OK
0919         }
0920         executePlugin(process, LoadRequiredModulesPlugin.class.getName(), qedeq, null);
0921         return qedeq.hasLoadedRequiredModules();
0922     }
0923 
0924     public boolean checkWellFormedness(final ModuleAddress address) {
0925         final DefaultKernelQedeqBo prop = modules.getKernelQedeqBo(this, address);
0926         // did we check this already?
0927         if (prop.isWellFormed()) {
0928             return true// everything is OK
0929         }
0930         executePlugin(WellFormedCheckerPlugin.class.getName(), prop.getModuleAddress()null);
0931         return prop.isWellFormed();
0932     }
0933 
0934     public boolean checkWellFormedness(final InternalServiceJob process, final KernelQedeqBo qedeq)
0935             throws InterruptException {
0936         // did we check this already?
0937         if (qedeq.isWellFormed()) {
0938             return true// everything is OK
0939         }
0940         executePlugin(process, WellFormedCheckerPlugin.class.getName(), qedeq, null);
0941         return qedeq.isWellFormed();
0942     }
0943 
0944     public boolean checkFormallyProved(final ModuleAddress address) {
0945         final DefaultKernelQedeqBo prop = modules.getKernelQedeqBo(this, address);
0946         // did we check this already?
0947         if (prop.isFullyFormallyProved()) {
0948             return true// everything is OK
0949         }
0950         executePlugin(FormalProofCheckerPlugin.class.getName(), prop.getModuleAddress()null);
0951         return prop.isFullyFormallyProved();
0952     }
0953 
0954     public boolean checkFormallyProved(final InternalServiceJob process, final KernelQedeqBo qedeq)
0955             throws InterruptException {
0956         // did we check this already?
0957         if (qedeq.isFullyFormallyProved()) {
0958             return true// everything is OK
0959         }
0960         executePlugin(process, FormalProofCheckerPlugin.class.getName(), qedeq, null);
0961         return qedeq.isFullyFormallyProved();
0962     }
0963 
0964     /**
0965      * Add plugin to services.
0966      *
0967      @param   pluginClass Plugin class to instantiate.
0968      @throws  RuntimeException    Addition failed.
0969      */
0970     public void addPlugin(final String pluginClass) {
0971         pluginManager.addPlugin(pluginClass);
0972     }
0973 
0974     public ModuleService[] getPlugins() {
0975         return pluginManager.getNonInternalPlugins();
0976     }
0977 
0978 
0979     public Object executePlugin(final String id, final ModuleAddress address, final Object data) {
0980         final InternalServiceJob process = processManager.createServiceJob(id);
0981         try {
0982             final KernelQedeqBo qedeq = loadKernelModule(process, address);
0983             if (qedeq.isLoaded()) {
0984                 return processManager.executePlugin(id, qedeq, data, process);
0985             else {
0986                 process.setFailureState();
0987             }
0988         catch (InterruptException e) {
0989             process.setInterruptedState();
0990         finally {
0991             process.setSuccessState();
0992             if (validate) {
0993                 modules.validateDependencies();
0994             }
0995         }
0996         return null;
0997     }
0998 
0999     public Object executePlugin(final InternalServiceJob process, final String id, final KernelQedeqBo qedeq,
1000             final Object datathrows InterruptException {
1001         if (process == null) {
1002             throw new NullPointerException("process parameter must not be null");
1003         }
1004         loadKernelModule(process, qedeq.getModuleAddress());
1005         return processManager.executePlugin(id, qedeq, data, process);
1006     }
1007 
1008     public void clearAllPluginResults(final ModuleAddress address) {
1009         pluginManager.clearAllPluginResults(getKernelQedeqBo(address));
1010     }
1011 
1012     public ServiceJob[] getServiceProcesses() {
1013         return processManager.getServiceProcesses();
1014     }
1015 
1016     public ServiceJob[] getRunningServiceProcesses() {
1017         return processManager.getRunningServiceProcesses();
1018     }
1019 
1020     public void terminateAllServiceProcesses() {
1021         processManager.terminateAllServiceProcesses();
1022     }
1023 
1024 
1025     /**
1026      * Get all loaded QEDEQ modules.
1027      *
1028      @return All QEDEQ modules.
1029      */
1030     private KernelQedeqBoStorage getModules() {
1031         return modules;
1032     }
1033 
1034     public SourceFileExceptionList createSourceFileExceptionList(final int code,
1035             final String message, final String address, final IOException e) {
1036         return new SourceFileExceptionList(new SourceFileException(this,
1037             code, message, e, new SourceArea(address)null));
1038     }
1039 
1040     public SourceFileExceptionList createSourceFileExceptionList(final int code,
1041             final String message, final String address, final RuntimeException e) {
1042         return new SourceFileExceptionList(new SourceFileException(this,
1043             code, message, e, new SourceArea(address)null));
1044     }
1045 
1046     public SourceFileExceptionList createSourceFileExceptionList(final int code,
1047             final String message, final String address, final Exception e) {
1048         return new SourceFileExceptionList(new SourceFileException(this,
1049             code, message, e, new SourceArea(address)null));
1050     }
1051 
1052     /**
1053      * Get description of source file exception list.
1054      *
1055      @param address Get description for this module exceptions.
1056      @return Error description and location.
1057      */
1058     public String[] getSourceFileExceptionList(final ModuleAddress address) {
1059         final List list = new ArrayList();
1060         final KernelQedeqBo bo = getKernelQedeqBo(address);
1061         final SourceFileExceptionList sfl = bo.getErrors();
1062         if (sfl.size() 0) {
1063             final StringBuffer buffer = new StringBuffer();
1064             do {
1065                 Reader reader = null;
1066                 try {
1067                     reader = getQedeqFileDao().getModuleReader(bo);
1068                     IoUtility.loadReader(reader, buffer);
1069                 catch (IOException e) {
1070                     IoUtility.close(reader);
1071                     for (int i = 0; i < sfl.size(); i++) {
1072                         list.add(sfl.get(i).getDescription());
1073                     }
1074                     break// out of do while
1075                 }
1076                 final TextInput input = new TextInput(buffer);
1077                 try {
1078                     input.setPosition(0);
1079                     final StringBuffer buf = new StringBuffer();
1080                     for (int i = 0; i < sfl.size(); i++) {
1081                         buf.setLength(0);
1082                         final SourceFileException sf = sfl.get(i);
1083                         buf.append(sf.getDescription());
1084                         try {
1085                             if (sf.getSourceArea() != null
1086                                 && sf.getSourceArea().getStartPosition() != null) {
1087                                 buf.append("\n");
1088                                 input.setRow(sf.getSourceArea().getStartPosition().getRow());
1089                                 buf.append(StringUtility.replace(input.getLine()"\t"" "));
1090                                 buf.append("\n");
1091                                 final StringBuffer whitespace = StringUtility.getSpaces(sf
1092                                     .getSourceArea().getStartPosition().getColumn() 1);
1093                                 buffer.append(whitespace);
1094                                 buffer.append("^");
1095                             }
1096                         catch (Exception e) {
1097                             Trace.trace(CLASS, this, "getSourceFileExceptionList(ModuleAddress)", e);
1098                         }
1099                         list.add(buf.toString());
1100                     }
1101                 finally {
1102                     IoUtility.close(input);
1103                 }
1104                 break// out of do while
1105             while (true);
1106         }
1107         return (String[]) list.toArray(new String[list.size()]);
1108     }
1109 
1110     public String getServiceId() {
1111         return CLASS.getName();
1112     }
1113 
1114     public String getServiceAction() {
1115         return "Basis";
1116     }
1117     public QedeqFileDao getQedeqFileDao() {
1118         return qedeqFileDao;
1119     }
1120 
1121     public String getServiceDescription() {
1122         return "provides basic services for loading QEDEQ modules";
1123     }
1124 
1125     public QedeqConfig getConfig() {
1126         return config;
1127     }
1128 
1129     public String getKernelVersionDirectory() {
1130         return kernel.getKernelVersionDirectory();
1131     }
1132 
1133     public String getBuildId() {
1134         return kernel.getBuildId();
1135     }
1136 
1137     public String getDedication() {
1138         return kernel.getDedication();
1139     }
1140 
1141     public String getDescriptiveKernelVersion() {
1142         return kernel.getDescriptiveKernelVersion();
1143     }
1144 
1145     public String getKernelCodeName() {
1146         return kernel.getKernelCodeName();
1147     }
1148 
1149     public String getKernelVersion() {
1150         return kernel.getKernelVersion();
1151     }
1152 
1153     public String getMaximalRuleVersion() {
1154         return kernel.getMaximalRuleVersion();
1155     }
1156 
1157     public boolean isRuleVersionSupported(final String ruleVersion) {
1158         return kernel.isRuleVersionSupported(ruleVersion);
1159     }
1160 
1161     public boolean isSetConnectionTimeOutSupported() {
1162         return kernel.isSetConnectionTimeOutSupported();
1163     }
1164 
1165     public boolean isSetReadTimeoutSupported() {
1166         return kernel.isSetReadTimeoutSupported();
1167     }
1168 
1169     public ContextChecker getContextChecker() {
1170         return contextChecker;
1171     }
1172 
1173     /**
1174      * Set the context checker. This is useful especially for test classes.
1175      *
1176      @param   contextChecker  We check the context with this checker now.
1177      */
1178     public void setContextChecker(final ContextChecker contextChecker) {
1179         this.contextChecker = contextChecker;
1180     }
1181 
1182 }