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 != 1 ? "s" : "") + " successfully done.");
0184 } else {
0185 QedeqLog.getInstance().logMessage(
0186 "Loading of all previously successfully checked modules failed. "
0187 + number + " module" + (number != 1 ? "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 = (DefaultKernelQedeqBo) iterator.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 = (DefaultKernelQedeqBo) iterator.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 = (InternalModuleServiceCall) iterator.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 = (InternalModuleServiceCall) iterator.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((DefaultKernelQedeqBo) prop);
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 call) throws 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 prop) throws 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 prop) throws 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 qedeq) throws 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 prop) throws 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 spec) throws 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((InternalModuleServiceCall) process.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 + 1 < 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((int) percentage);
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 url) throws IOException {
0876 return new DefaultModuleAddress(url);
0877 }
0878
0879 public ModuleAddress getModuleAddress(final String url) throws IOException {
0880 return new DefaultModuleAddress(url);
0881 }
0882
0883 public ModuleAddress getModuleAddress(final File file) throws IOException {
0884 return new DefaultModuleAddress(file);
0885 }
0886
0887 public String getSource(final ModuleAddress address) throws 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 data) throws 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 }
|