1 | /* This file is part of the project "Hilbert II" - http://www.qedeq.org |
2 | * |
3 | * Copyright 2000-2014, Michael Meyling <mime@qedeq.org>. |
4 | * |
5 | * "Hilbert II" is free software; you can redistribute |
6 | * it and/or modify it under the terms of the GNU General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | */ |
15 | |
16 | package org.qedeq.kernel.bo.service.internal; |
17 | |
18 | import java.io.File; |
19 | import java.io.FileFilter; |
20 | import java.io.IOException; |
21 | import java.io.Reader; |
22 | import java.io.UnsupportedEncodingException; |
23 | import java.net.MalformedURLException; |
24 | import java.net.URL; |
25 | import java.net.URLEncoder; |
26 | import java.util.ArrayList; |
27 | import java.util.Iterator; |
28 | import java.util.List; |
29 | |
30 | import org.qedeq.base.io.IoUtility; |
31 | import org.qedeq.base.io.LoadingListener; |
32 | import org.qedeq.base.io.Parameters; |
33 | import org.qedeq.base.io.SourceArea; |
34 | import org.qedeq.base.io.TextInput; |
35 | import org.qedeq.base.io.UrlUtility; |
36 | import org.qedeq.base.trace.Trace; |
37 | import org.qedeq.base.utility.StringUtility; |
38 | import org.qedeq.kernel.bo.common.Element2Utf8; |
39 | import org.qedeq.kernel.bo.common.Kernel; |
40 | import org.qedeq.kernel.bo.common.KernelProperties; |
41 | import org.qedeq.kernel.bo.common.QedeqBo; |
42 | import org.qedeq.kernel.bo.common.ServiceJob; |
43 | import org.qedeq.kernel.bo.log.QedeqLog; |
44 | import org.qedeq.kernel.bo.module.InternalKernelServices; |
45 | import org.qedeq.kernel.bo.module.InternalModuleServiceCall; |
46 | import org.qedeq.kernel.bo.module.InternalServiceJob; |
47 | import org.qedeq.kernel.bo.module.KernelQedeqBo; |
48 | import org.qedeq.kernel.bo.module.ModuleArbiter; |
49 | import org.qedeq.kernel.bo.module.ModuleLabels; |
50 | import org.qedeq.kernel.bo.module.QedeqFileDao; |
51 | import org.qedeq.kernel.bo.service.basis.ModuleFileNotFoundException; |
52 | import org.qedeq.kernel.bo.service.basis.ModuleLabelsCreator; |
53 | import org.qedeq.kernel.bo.service.basis.ModuleServiceExecutor; |
54 | import org.qedeq.kernel.bo.service.basis.QedeqVoBuilder; |
55 | import org.qedeq.kernel.bo.service.basis.ServiceErrors; |
56 | import org.qedeq.kernel.bo.service.dependency.LoadDirectlyRequiredModulesPlugin; |
57 | import org.qedeq.kernel.bo.service.dependency.LoadRequiredModulesPlugin; |
58 | import org.qedeq.kernel.bo.service.logic.FormalProofCheckerPlugin; |
59 | import org.qedeq.kernel.bo.service.logic.SimpleProofFinderPlugin; |
60 | import org.qedeq.kernel.bo.service.logic.WellFormedCheckerPlugin; |
61 | import org.qedeq.kernel.se.base.module.Qedeq; |
62 | import org.qedeq.kernel.se.base.module.Specification; |
63 | import org.qedeq.kernel.se.common.DefaultModuleAddress; |
64 | import org.qedeq.kernel.se.common.ModuleAddress; |
65 | import org.qedeq.kernel.se.common.ModuleDataException; |
66 | import org.qedeq.kernel.se.common.ModuleService; |
67 | import org.qedeq.kernel.se.common.Service; |
68 | import org.qedeq.kernel.se.common.SourceFileException; |
69 | import org.qedeq.kernel.se.common.SourceFileExceptionList; |
70 | import org.qedeq.kernel.se.config.QedeqConfig; |
71 | import org.qedeq.kernel.se.dto.module.QedeqVo; |
72 | import org.qedeq.kernel.se.state.LoadingState; |
73 | import org.qedeq.kernel.se.visitor.ContextChecker; |
74 | import org.qedeq.kernel.se.visitor.DefaultContextChecker; |
75 | import org.qedeq.kernel.se.visitor.InterruptException; |
76 | |
77 | |
78 | /** |
79 | * This class provides a default implementation for the QEDEQ module services. |
80 | * |
81 | * @author Michael Meyling |
82 | */ |
83 | public class DefaultInternalKernelServices implements Kernel, InternalKernelServices, |
84 | Service { |
85 | |
86 | /** This class. */ |
87 | private static final Class CLASS = DefaultInternalKernelServices.class; |
88 | |
89 | /** Collection of already known QEDEQ modules. */ |
90 | private KernelQedeqBoStorage modules; |
91 | |
92 | /** Config access. */ |
93 | private final QedeqConfig config; |
94 | |
95 | /** Basic kernel properties. */ |
96 | private final KernelProperties kernel; |
97 | |
98 | /** This instance nows how to load a module from the file system. */ |
99 | private final QedeqFileDao qedeqFileDao; |
100 | |
101 | /** Synchronize module access. */ |
102 | private ModuleArbiter arbiter; |
103 | |
104 | /** This instance manages plugins. */ |
105 | private final PluginManager pluginManager; |
106 | |
107 | /** This instance manages service processes. */ |
108 | private ServiceProcessManager processManager; |
109 | |
110 | /** Validate module dependencies and status. */ |
111 | private boolean validate = true; |
112 | |
113 | /** We check the context with this checker. */ |
114 | private ContextChecker contextChecker; |
115 | |
116 | |
117 | /** |
118 | * Constructor. |
119 | * |
120 | * @param config For config access. |
121 | * @param kernel For kernel properties. |
122 | * @param loader For loading QEDEQ modules. |
123 | */ |
124 | public DefaultInternalKernelServices(final QedeqConfig config, final KernelProperties kernel, |
125 | final QedeqFileDao loader) { |
126 | this.config = config; |
127 | this.kernel = kernel; |
128 | this.qedeqFileDao = loader; |
129 | pluginManager = new PluginManager(this); |
130 | loader.setServices(this); |
131 | |
132 | //// pluginManager.addPlugin(MultiProofFinderPlugin.class.getName()); |
133 | pluginManager.addPlugin("org.qedeq.kernel.bo.service.unicode.Qedeq2UnicodeTextPlugin"); |
134 | pluginManager.addPlugin("org.qedeq.kernel.bo.service.latex.Qedeq2LatexPlugin"); |
135 | pluginManager.addPlugin("org.qedeq.kernel.bo.service.unicode.Qedeq2Utf8Plugin"); |
136 | //// pluginManager.addPlugin("org.qedeq.kernel.bo.service.heuristic.HeuristicCheckerPlugin"); |
137 | pluginManager.addPlugin("org.qedeq.kernel.bo.service.heuristic.DynamicHeuristicCheckerPlugin"); |
138 | pluginManager.addPlugin(SimpleProofFinderPlugin.class.getName()); |
139 | |
140 | // add internal plugins |
141 | pluginManager.addPlugin(LoadDirectlyRequiredModulesPlugin.class.getName()); |
142 | pluginManager.addPlugin(LoadRequiredModulesPlugin.class.getName()); |
143 | pluginManager.addPlugin(WellFormedCheckerPlugin.class.getName()); |
144 | pluginManager.addPlugin(FormalProofCheckerPlugin.class.getName()); |
145 | } |
146 | |
147 | public synchronized void startupServices() { |
148 | modules = new KernelQedeqBoStorage(); |
149 | arbiter = new ModuleArbiterImpl(); |
150 | processManager = new ServiceProcessManager(pluginManager, arbiter); |
151 | contextChecker = new DefaultContextChecker(); |
152 | if (config.isAutoReloadLastSessionChecked()) { |
153 | autoReloadLastSessionChecked(); |
154 | } |
155 | } |
156 | |
157 | public synchronized void shutdownServices() { |
158 | processManager.terminateAndRemoveAllServiceProcesses(); |
159 | processManager = null; |
160 | modules.removeAllModules(); |
161 | modules = null; |
162 | arbiter = null; |
163 | // clear thread interrupt flag because we might have interrupted ourself |
164 | Thread.interrupted(); |
165 | } |
166 | |
167 | /** |
168 | * If configured load all QEDEQ modules that where successfully loaded the last time. |
169 | */ |
170 | private void autoReloadLastSessionChecked() { |
171 | if (config.isAutoReloadLastSessionChecked()) { |
172 | final Thread thread = new Thread() { |
173 | public void run() { |
174 | final String method = "autoReloadLastSessionChecked.thread.run()"; |
175 | try { |
176 | Trace.begin(CLASS, this, method); |
177 | QedeqLog.getInstance().logMessage( |
178 | "Trying to load previously successfully loaded modules."); |
179 | final int number = config.getPreviouslyLoadedModules().length; |
180 | if (loadPreviouslySuccessfullyLoadedModules()) { |
181 | QedeqLog.getInstance().logMessage( |
182 | "Loading of " + number + " previously successfully loaded module" |
183 | + (number != 1 ? "s" : "") + " successfully done."); |
184 | } else { |
185 | QedeqLog.getInstance().logMessage( |
186 | "Loading of all previously successfully checked modules failed. " |
187 | + number + " module" + (number != 1 ? "s" : "") |
188 | + " were tried."); |
189 | } |
190 | } catch (Exception e) { |
191 | Trace.trace(CLASS, this, method, e); |
192 | } finally { |
193 | Trace.end(CLASS, this, method); |
194 | } |
195 | } |
196 | }; |
197 | thread.setDaemon(true); |
198 | thread.start(); |
199 | } |
200 | } |
201 | |
202 | public boolean removeAllModules() { |
203 | final String method = "removeAllModules()"; |
204 | Trace.begin(CLASS, this, method); |
205 | // getModules().removeAllModules(); |
206 | InternalServiceJob proc = null; |
207 | proc = processManager.createServiceProcess("remove all modules"); |
208 | final List calls = new ArrayList(); |
209 | final List m = getModules().getAllModules(); |
210 | boolean ok = false; |
211 | try { |
212 | // lock all modules |
213 | for (final Iterator iterator = m.iterator(); iterator.hasNext(); ) { |
214 | final DefaultKernelQedeqBo prop = (DefaultKernelQedeqBo) iterator.next(); |
215 | final InternalModuleServiceCall call = processManager.createServiceCall(this, prop, Parameters.EMPTY, |
216 | Parameters.EMPTY, proc); |
217 | calls.add(call); |
218 | } |
219 | |
220 | // delete all modules |
221 | for (final Iterator iterator = m.iterator(); iterator.hasNext(); ) { |
222 | final DefaultKernelQedeqBo prop = (DefaultKernelQedeqBo) iterator.next(); |
223 | removeModule(prop); |
224 | } |
225 | ok = true; |
226 | } catch (final InterruptException e) { |
227 | for (final Iterator iterator = calls.iterator(); iterator.hasNext(); ) { |
228 | final InternalModuleServiceCall call = (InternalModuleServiceCall) iterator.next(); |
229 | call.finishError("couldn't lock all modules"); |
230 | processManager.endServiceCall(call); |
231 | } |
232 | QedeqLog.getInstance().logMessage("Remove all modules failed: " + e.getMessage()); |
233 | proc.setInterruptedState(); |
234 | } finally { |
235 | for (final Iterator iterator = calls.iterator(); iterator.hasNext(); ) { |
236 | final InternalModuleServiceCall call = (InternalModuleServiceCall) iterator.next(); |
237 | call.finishOk(); |
238 | processManager.endServiceCall(call); |
239 | } |
240 | if (ok) { |
241 | proc.setSuccessState(); |
242 | } else { |
243 | proc.setFailureState(); |
244 | } |
245 | } |
246 | if (validate) { |
247 | modules.validateDependencies(); |
248 | } |
249 | Trace.end(CLASS, this, method); |
250 | return ok; |
251 | } |
252 | |
253 | public void removeModule(final ModuleAddress address) { |
254 | final KernelQedeqBo prop = getKernelQedeqBo(address); |
255 | if (prop != null) { |
256 | QedeqLog.getInstance().logRequest("Removing module", address.getUrl()); |
257 | InternalServiceJob proc = processManager.createServiceProcess("remove module"); |
258 | InternalModuleServiceCall call = null; |
259 | try { |
260 | call = processManager.createServiceCall(this, prop, Parameters.EMPTY, |
261 | Parameters.EMPTY, proc); |
262 | removeModule((DefaultKernelQedeqBo) prop); |
263 | call.finishOk(); |
264 | proc.setSuccessState(); |
265 | } catch (final InterruptException e) { |
266 | QedeqLog.getInstance().logFailureReply( |
267 | "Remove failed", address.getUrl(), e.getMessage()); |
268 | proc.setInterruptedState(); |
269 | } finally { |
270 | processManager.endServiceCall(call); |
271 | } |
272 | if (validate) { |
273 | modules.validateDependencies(); |
274 | } |
275 | } |
276 | } |
277 | |
278 | /** |
279 | * Remove a QEDEQ module from memory. This method must block all other methods and if this |
280 | * method runs no other is allowed to run |
281 | * |
282 | * @param prop Remove module identified by this property. |
283 | */ |
284 | private void removeModule(final DefaultKernelQedeqBo prop) { |
285 | synchronized (prop) { |
286 | // FIXME mime 20080319: one could call prop.setLoadingProgressState( |
287 | // LoadingState.STATE_DELETED) alone but that would |
288 | // miss to inform the KernelQedeqBoPool. How do we inform the pool? |
289 | // must the StateManager have a reference to it? |
290 | prop.delete(); |
291 | getModules().removeModule(prop); |
292 | return; |
293 | } |
294 | } |
295 | |
296 | /** |
297 | * Clear local file buffer and all loaded QEDEQ modules. |
298 | * |
299 | * @return Successful? |
300 | */ |
301 | public boolean clearLocalBuffer() { |
302 | final String method = "clearLocalBuffer"; |
303 | try { |
304 | QedeqLog.getInstance().logMessage( |
305 | "Clear local buffer from all QEDEQ files."); |
306 | if (removeAllModules()) { |
307 | final File bufferDir = getBufferDirectory().getCanonicalFile(); |
308 | if (bufferDir.exists() && !IoUtility.deleteDir(bufferDir, new FileFilter() { |
309 | public boolean accept(final File pathname) { |
310 | return pathname.getName().endsWith(".xml"); |
311 | } |
312 | })) { |
313 | throw new IOException("buffer could not be deleted: " + bufferDir); |
314 | } |
315 | QedeqLog.getInstance().logMessage("Local buffer was cleared."); |
316 | return true; |
317 | } |
318 | QedeqLog.getInstance().logMessage("Local buffer was not cleared."); |
319 | return false; |
320 | } catch (IOException e) { |
321 | Trace.fatal(CLASS, this, method, "IO access problem", e); |
322 | QedeqLog.getInstance().logMessage( |
323 | "Local buffer not cleared. IO access problem. " + e.getMessage()); |
324 | return false; |
325 | } catch (final RuntimeException e) { |
326 | Trace.fatal(CLASS, this, method, "unexpected problem", e); |
327 | QedeqLog.getInstance().logMessage( |
328 | "Local buffer not cleared. " + e.getMessage()); |
329 | return false; |
330 | } |
331 | } |
332 | |
333 | public KernelQedeqBo loadKernelModule(final InternalServiceJob process, final ModuleAddress address) |
334 | throws InterruptException { |
335 | final String method = "loadModule(InternalServiceProcess, ModuleAddress)"; |
336 | final DefaultKernelQedeqBo prop = getModules().getKernelQedeqBo(this, address); |
337 | if (prop.isLoaded()) { |
338 | return prop; |
339 | } |
340 | final ModuleServiceExecutor executor = new ModuleServiceExecutor() { |
341 | public void executeService(final InternalModuleServiceCall call) throws InterruptException { |
342 | try { |
343 | synchronized (prop) { |
344 | if (prop.isLoaded()) { |
345 | call.finishOk(); |
346 | return; |
347 | } |
348 | QedeqLog.getInstance().logRequest("Load module", address.getUrl()); |
349 | if (prop.getModuleAddress().isFileAddress()) { |
350 | call.setAction("file loading"); |
351 | loadLocalModule(call.getInternalServiceProcess(), prop); |
352 | } else { |
353 | // search in local file buffer |
354 | try { |
355 | getCanonicalReadableFile(prop); |
356 | } catch (ModuleFileNotFoundException e) { // file not found |
357 | // we will continue by creating a local copy |
358 | call.setAction("web loading"); |
359 | saveQedeqFromWebToBuffer(call, prop); |
360 | call.setExecutionPercentage(50); |
361 | } |
362 | call.setAction("buffer loading"); |
363 | loadBufferedModule(call.getInternalServiceProcess(), prop); |
364 | } |
365 | QedeqLog.getInstance().logSuccessfulReply( |
366 | "Successfully loaded", address.getUrl()); |
367 | call.finishOk(); |
368 | } |
369 | } catch (SourceFileExceptionList e) { |
370 | Trace.trace(CLASS, this, method, e); |
371 | QedeqLog.getInstance().logFailureState("Loading of module failed.", address.getUrl(), |
372 | e.toString()); |
373 | call.finishError("Loading of module failed."); |
374 | } catch (final RuntimeException e) { |
375 | Trace.fatal(CLASS, this, method, "unexpected problem", e); |
376 | QedeqLog.getInstance().logFailureReply("Loading failed", address.getUrl(), e.getMessage()); |
377 | call.finishError("Loading of module failed: " + e.getMessage()); |
378 | } |
379 | } |
380 | |
381 | }; |
382 | this.processManager.executeService(new ModuleService() { |
383 | public String getServiceAction() { |
384 | return "load QEDEQ module"; |
385 | } |
386 | |
387 | public String getServiceDescription() { |
388 | return "take QEDEQ module address and try to load and parse the content"; |
389 | } |
390 | |
391 | public String getServiceId() { |
392 | return "" + hashCode(); |
393 | } |
394 | }, executor, prop, process); |
395 | return prop; |
396 | // try { |
397 | // synchronized (prop) { |
398 | // if (prop.isLoaded()) { |
399 | // return prop; |
400 | // } |
401 | // QedeqLog.getInstance().logRequest("Load module", address.getUrl()); |
402 | // if (prop.getModuleAddress().isFileAddress()) { |
403 | // loadLocalModule(proc, prop); |
404 | // } else { |
405 | // // search in local file buffer |
406 | // try { |
407 | // getCanonicalReadableFile(prop); |
408 | // } catch (ModuleFileNotFoundException e) { // file not found |
409 | // // we will continue by creating a local copy |
410 | // saveQedeqFromWebToBuffer(prop); |
411 | // } |
412 | // loadBufferedModule(proc, prop); |
413 | // } |
414 | // QedeqLog.getInstance().logSuccessfulReply( |
415 | // "Successfully loaded", address.getUrl()); |
416 | // } |
417 | // } catch (SourceFileExceptionList e) { |
418 | // Trace.trace(CLASS, this, method, e); |
419 | // QedeqLog.getInstance().logFailureState("Loading of module failed!", address.getUrl(), |
420 | // e.toString()); |
421 | // } catch (final RuntimeException e) { |
422 | // Trace.fatal(CLASS, this, method, "unexpected problem", e); |
423 | // QedeqLog.getInstance().logFailureReply("Loading failed", address.getUrl(), e.getMessage()); |
424 | // } finally { |
425 | // call.setSuccessState(); |
426 | // } |
427 | // return prop; |
428 | } |
429 | |
430 | public QedeqBo loadModule(final ModuleAddress address) { |
431 | final InternalServiceJob process = processManager.createServiceProcess("LoadModule"); |
432 | final QedeqBo result = getQedeqBo(address); |
433 | try { |
434 | loadKernelModule(process, address); |
435 | process.setSuccessState(); |
436 | } catch (InterruptException e) { |
437 | process.setInterruptedState(); |
438 | } |
439 | return result; |
440 | } |
441 | |
442 | /** |
443 | * Load buffered QEDEQ module file. |
444 | * |
445 | * @param process Service process we run within. |
446 | * @param prop Load this. |
447 | * @throws SourceFileExceptionList Loading or QEDEQ module failed. |
448 | */ |
449 | private void loadBufferedModule(final InternalServiceJob process, |
450 | final DefaultKernelQedeqBo prop) throws SourceFileExceptionList { |
451 | prop.setLoadingProgressState(LoadingState.STATE_LOADING_FROM_BUFFER); |
452 | final File localFile; |
453 | try { |
454 | localFile = getCanonicalReadableFile(prop); |
455 | } catch (ModuleFileNotFoundException e) { |
456 | final SourceFileExceptionList sfl = createSourceFileExceptionList( |
457 | ServiceErrors.LOADING_FROM_FILE_BUFFER_FAILED_CODE, |
458 | ServiceErrors.LOADING_FROM_FILE_BUFFER_FAILED_TEXT, |
459 | prop.getUrl(), e); |
460 | prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_BUFFER_FAILED, sfl); |
461 | throw sfl; |
462 | } |
463 | |
464 | prop.setQedeqFileDao(getQedeqFileDao()); // remember loader for this module |
465 | final Qedeq qedeq; |
466 | try { |
467 | qedeq = getQedeqFileDao().loadQedeq(process, prop, localFile); |
468 | } catch (SourceFileExceptionList sfl) { |
469 | prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_BUFFER_FAILED, sfl); |
470 | throw sfl; |
471 | } |
472 | setCopiedQedeq(process, prop, qedeq); |
473 | } |
474 | |
475 | /** |
476 | * Load QEDEQ module file with file loader. |
477 | * |
478 | * @param process Service process we run within. |
479 | * @param prop Load this. |
480 | * @throws SourceFileExceptionList Loading or copying QEDEQ module failed. |
481 | */ |
482 | private void loadLocalModule(final InternalServiceJob process, |
483 | final DefaultKernelQedeqBo prop) throws SourceFileExceptionList { |
484 | prop.setLoadingProgressState(LoadingState.STATE_LOADING_FROM_LOCAL_FILE); |
485 | final File localFile; |
486 | try { |
487 | localFile = getCanonicalReadableFile(prop); |
488 | } catch (ModuleFileNotFoundException e) { |
489 | final SourceFileExceptionList sfl = createSourceFileExceptionList( |
490 | ServiceErrors.LOADING_FROM_LOCAL_FILE_FAILED_CODE, |
491 | ServiceErrors.LOADING_FROM_LOCAL_FILE_FAILED_TEXT, |
492 | prop.getUrl(), e); |
493 | prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_LOCAL_FILE_FAILED, sfl); |
494 | throw sfl; |
495 | } |
496 | prop.setQedeqFileDao(getQedeqFileDao()); // remember loader for this module |
497 | |
498 | final Qedeq qedeq; |
499 | try { |
500 | qedeq = getQedeqFileDao().loadQedeq(process, prop, localFile); |
501 | } catch (SourceFileExceptionList sfl) { |
502 | prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_LOCAL_FILE_FAILED, sfl); |
503 | throw sfl; |
504 | } |
505 | setCopiedQedeq(process, prop, qedeq); |
506 | } |
507 | |
508 | private void setCopiedQedeq(final InternalServiceJob process, final DefaultKernelQedeqBo prop, |
509 | final Qedeq qedeq) throws SourceFileExceptionList { |
510 | final String method = "setCopiedQedeq(DefaultKernelQedeqBo, Qedeq)"; |
511 | prop.setLoadingProgressState(LoadingState.STATE_LOADING_INTO_MEMORY); |
512 | QedeqVo vo = null; |
513 | try { |
514 | vo = QedeqVoBuilder.createQedeq(prop.getModuleAddress(), qedeq); |
515 | } catch (RuntimeException e) { |
516 | Trace.fatal(CLASS, this, method, "looks like a programming error", e); |
517 | final SourceFileExceptionList xl = createSourceFileExceptionList( |
518 | ServiceErrors.RUNTIME_ERROR_CODE, |
519 | ServiceErrors.RUNTIME_ERROR_TEXT, |
520 | prop.getModuleAddress().getUrl(), e); |
521 | prop.setLoadingFailureState(LoadingState.STATE_LOADING_INTO_MEMORY_FAILED, xl); |
522 | throw xl; |
523 | } catch (ModuleDataException e) { |
524 | if (e.getCause() != null) { |
525 | Trace.fatal(CLASS, this, method, "looks like a programming error", e.getCause()); |
526 | } else { |
527 | Trace.fatal(CLASS, this, method, "looks like a programming error", e); |
528 | } |
529 | final SourceFileExceptionList xl = prop.createSourceFileExceptionList(this, e, qedeq); |
530 | prop.setLoadingFailureState(LoadingState.STATE_LOADING_INTO_MEMORY_FAILED, xl); |
531 | throw xl; |
532 | } |
533 | prop.setQedeqVo(vo); |
534 | // TODO 20110213 m31: perhaps we need a new state, pre loaded? So when we put more |
535 | // label testing into the moduleLabelCreator, we still can launch some plugins |
536 | // On the other side: Label checking is only possible, if all referenced modules can |
537 | // be loaded. |
538 | // |
539 | // Correct labels are necessary for many plugins (e.g. LaTeX and UTF-8 generation). |
540 | // So a label checker must be run before that. |
541 | // It might be a good idea to put it into the formal logic checker. |
542 | // We could make a FormalChecker plugin. This starts loading required modules, checks |
543 | // the labels and checks if the formulas are correctly written. |
544 | // So we get some sub status (for every check) and an overall status (all checks |
545 | // green). Later on the formal proof checker can be integrated too. |
546 | // This should be the extended load status. |
547 | final ModuleLabelsCreator moduleNodesCreator = new ModuleLabelsCreator(this, prop); |
548 | try { |
549 | final ModuleLabels labels = new ModuleLabels(); |
550 | final Element2LatexImpl converter = new Element2LatexImpl(labels); |
551 | final Element2Utf8 textConverter = new Element2Utf8Impl(converter); |
552 | moduleNodesCreator.createLabels(process, labels); |
553 | prop.setLoaded(vo, labels, converter, textConverter); |
554 | } catch (SourceFileExceptionList sfl) { |
555 | prop.setLoadingFailureState(LoadingState.STATE_LOADING_INTO_MEMORY_FAILED, sfl); |
556 | throw sfl; |
557 | } |
558 | } |
559 | |
560 | /** |
561 | * Check if file exists and is readable. Checks the local buffer file for a buffered module or |
562 | * the module file address directly. Returns canonical file path. |
563 | * |
564 | * @param prop Check for this file. |
565 | * @return Canonical file path. |
566 | * @throws ModuleFileNotFoundException File doesn't exist or is not readable. |
567 | */ |
568 | private File getCanonicalReadableFile(final QedeqBo prop) throws ModuleFileNotFoundException { |
569 | final String method = "getCanonicalReadableFile(File)"; |
570 | final File localFile = getLocalFilePath(prop.getModuleAddress()); |
571 | final File file; |
572 | try { |
573 | file = localFile.getCanonicalFile(); |
574 | } catch (IOException e) { |
575 | Trace.trace(CLASS, this, method, e); |
576 | throw new ModuleFileNotFoundException("file path not correct: " + localFile); |
577 | } |
578 | if (!file.canRead()) { |
579 | Trace.trace(CLASS, this, method, "file not readable=" + file); |
580 | throw new ModuleFileNotFoundException("file not readable: " + file); |
581 | } |
582 | return file; |
583 | } |
584 | |
585 | /** |
586 | * Load specified QEDEQ module from QEDEQ parent module. |
587 | * |
588 | * @param process Our service process we run within. |
589 | * @param parent Parent module address. |
590 | * @param spec Specification for another QEDEQ module. |
591 | * @return Loaded module. |
592 | * @throws SourceFileExceptionList Loading failed. |
593 | * @throws InterruptException User canceled request. |
594 | */ |
595 | public KernelQedeqBo loadKernelModule(final InternalServiceJob process, final ModuleAddress parent, |
596 | final Specification spec) throws SourceFileExceptionList, InterruptException { |
597 | |
598 | final String method = "loadModule(Module, Specification)"; |
599 | Trace.begin(CLASS, this, method); |
600 | Trace.trace(CLASS, this, method, spec); |
601 | DefaultKernelQedeqBo prop = null; // currently tried module |
602 | try { |
603 | final ModuleAddress[] modulePaths; |
604 | try { |
605 | modulePaths = parent.getModulePaths(spec); |
606 | } catch (IOException e) { |
607 | Trace.fatal(CLASS, this, method, "getting module path failed", e); // TODO 20110308 m31: make constant |
608 | throw createSourceFileExceptionList( |
609 | ServiceErrors.LOADING_FROM_FILE_BUFFER_FAILED_CODE, |
610 | ServiceErrors.LOADING_FROM_FILE_BUFFER_FAILED_TEXT, |
611 | parent.getUrl(), e); |
612 | } |
613 | |
614 | // now we iterate over the possible module addresses |
615 | for (int i = 0; i < modulePaths.length; i++) { |
616 | prop = getModules().getKernelQedeqBo(this, modulePaths[i]); |
617 | Trace.trace(CLASS, this, method, "synchronizing at prop=" + prop); |
618 | if (prop.isLoaded()) { |
619 | return (prop); |
620 | } |
621 | synchronized (prop) { |
622 | if (prop.isLoaded()) { |
623 | return (prop); |
624 | } |
625 | try { |
626 | if (prop.getModuleAddress().isFileAddress()) { |
627 | loadLocalModule(process, prop); |
628 | } else { |
629 | // search in local file buffer |
630 | try { |
631 | getCanonicalReadableFile(prop); |
632 | } catch (ModuleFileNotFoundException e) { // file not found |
633 | // we will continue by creating a local copy |
634 | saveQedeqFromWebToBuffer((InternalModuleServiceCall) process.getModuleServiceCall(), |
635 | prop); |
636 | } |
637 | loadBufferedModule(process, prop); |
638 | } |
639 | // success! |
640 | return prop; |
641 | } catch (SourceFileExceptionList e) { |
642 | Trace.trace(CLASS, this, method, e); |
643 | if (i + 1 < modulePaths.length) { |
644 | QedeqLog.getInstance().logMessage("trying alternate path"); |
645 | // we continue with the next path |
646 | } else { |
647 | // we surrender |
648 | throw e; |
649 | } |
650 | } |
651 | } |
652 | } |
653 | return prop; // never called, only here to soothe the compiler |
654 | } catch (final RuntimeException e) { |
655 | Trace.fatal(CLASS, this, method, "unexpected problem", e); |
656 | QedeqLog.getInstance().logFailureReply("Loading failed", |
657 | (prop != null ? prop.getUrl() : "unknownURL"), e.getMessage()); |
658 | throw e; |
659 | } finally { |
660 | Trace.end(CLASS, this, method); |
661 | } |
662 | } |
663 | |
664 | public ModuleAddress[] getAllLoadedModules() { |
665 | return getModules().getAllLoadedModules(); |
666 | } |
667 | |
668 | /** |
669 | * Load all previously checked QEDEQ modules. |
670 | * |
671 | * @return Successfully reloaded all modules. |
672 | */ |
673 | public boolean loadPreviouslySuccessfullyLoadedModules() { |
674 | final String[] list = config.getPreviouslyLoadedModules(); |
675 | boolean errors = false; |
676 | for (int i = 0; i < list.length; i++) { |
677 | try { |
678 | final ModuleAddress address = getModuleAddress(list[i]); |
679 | final QedeqBo prop = loadModule(address); |
680 | if (prop.hasErrors()) { |
681 | errors = true; |
682 | } |
683 | } catch (IOException e) { |
684 | Trace.fatal(CLASS, this, "loadPreviouslySuccessfullyLoadedModules", |
685 | "internal error: " + "saved URLs are malformed", e); |
686 | errors = true; |
687 | } |
688 | } |
689 | return !errors; |
690 | } |
691 | |
692 | // LATER mime 20070326: dynamic loading from web page directory |
693 | public boolean loadAllModulesFromQedeq() { |
694 | final String prefix = "http://www.qedeq.org/" + kernel.getKernelVersionDirectory() + "/"; |
695 | final String[] list = new String[] { |
696 | prefix + "doc/math/qedeq_logic_v1.xml", |
697 | prefix + "doc/math/qedeq_formal_logic_v1.xml", |
698 | prefix + "doc/math/qedeq_set_theory_v1.xml", |
699 | prefix + "doc/project/qedeq_basic_concept.xml", |
700 | prefix + "doc/project/qedeq_logic_language.xml", |
701 | prefix + "sample/qedeq_sample1.xml", |
702 | prefix + "sample/qedeq_sample2.xml", |
703 | prefix + "sample/qedeq_sample3.xml", |
704 | prefix + "sample/qedeq_sample4.xml", |
705 | prefix + "sample/qedeq_error_sample_00.xml", |
706 | prefix + "sample/qedeq_error_sample_01.xml", |
707 | prefix + "sample/qedeq_error_sample_02.xml", |
708 | prefix + "sample/qedeq_error_sample_03.xml", |
709 | prefix + "sample/qedeq_error_sample_04.xml", |
710 | prefix + "sample/qedeq_error_sample_05.xml", |
711 | prefix + "sample/qedeq_error_sample_12.xml", |
712 | prefix + "sample/qedeq_error_sample_13.xml", |
713 | prefix + "sample/qedeq_error_sample_14.xml", |
714 | prefix + "sample/qedeq_error_sample_15.xml", |
715 | prefix + "sample/qedeq_error_sample_16.xml", |
716 | prefix + "sample/qedeq_error_sample_17.xml", |
717 | prefix + "sample/qedeq_error_sample_18.xml"}; |
718 | boolean errors = false; |
719 | for (int i = 0; i < list.length; i++) { |
720 | try { |
721 | final ModuleAddress address = getModuleAddress(list[i]); |
722 | final QedeqBo prop = loadModule(address); |
723 | if (prop.hasErrors()) { |
724 | errors = true; |
725 | } |
726 | } catch (final IOException e) { |
727 | Trace.fatal(CLASS, this, "loadPreviouslySuccessfullyLoadedModules", |
728 | "internal error: " + "saved URLs are malformed", e); |
729 | errors = true; |
730 | } |
731 | } |
732 | return !errors; |
733 | } |
734 | |
735 | /** |
736 | * Make local copy of a module if it is no file address. |
737 | * |
738 | * @param call Service call we run within. |
739 | * @param prop Module properties. |
740 | * @throws SourceFileExceptionList Address was malformed or the file can not be found. |
741 | * @throws InterruptException User canceled request. |
742 | */ |
743 | private void saveQedeqFromWebToBuffer(final InternalModuleServiceCall call, final DefaultKernelQedeqBo prop) |
744 | throws SourceFileExceptionList, InterruptException { |
745 | final String method = "saveQedeqFromWebToBuffer(DefaultKernelQedeqBo)"; |
746 | Trace.begin(CLASS, this, method); |
747 | |
748 | if (prop.getModuleAddress().isFileAddress()) { // this is already a local file |
749 | Trace.fatal(CLASS, this, method, "tried to make a local copy for a local module", null); |
750 | Trace.end(CLASS, this, method); |
751 | return; |
752 | } |
753 | |
754 | final ModuleServiceExecutor executor = new ModuleServiceExecutor() { |
755 | |
756 | public void executeService(final InternalModuleServiceCall call) { |
757 | final File f = getLocalFilePath(prop.getModuleAddress()); |
758 | prop.setLoadingProgressState(LoadingState.STATE_LOADING_FROM_WEB); |
759 | try { |
760 | UrlUtility.saveUrlToFile(prop.getUrl(), f, |
761 | config.getHttpProxyHost(), config.getHttpProxyPort(), config.getHttpNonProxyHosts(), |
762 | config.getConnectionTimeout(), config.getReadTimeout(), new LoadingListener() { |
763 | public void loadingCompletenessChanged(final double completeness) { |
764 | final double percentage = completeness * 100; |
765 | call.setExecutionPercentage(percentage); |
766 | prop.setLoadingCompleteness((int) percentage); |
767 | } |
768 | }); |
769 | call.finishOk(); |
770 | } catch (IOException e) { |
771 | Trace.trace(CLASS, this, method, e); |
772 | try { |
773 | f.delete(); |
774 | } catch (Exception ex) { |
775 | Trace.trace(CLASS, this, method, ex); |
776 | } |
777 | final SourceFileExceptionList sfl = createSourceFileExceptionList( |
778 | ServiceErrors.LOADING_FROM_WEB_FAILED_CODE, |
779 | ServiceErrors.LOADING_FROM_WEB_FAILED_TEXT, |
780 | prop.getUrl(), e); |
781 | prop.setLoadingFailureState(LoadingState.STATE_LOADING_FROM_WEB_FAILED, sfl); |
782 | Trace.trace(CLASS, this, method, "Couldn't access " + prop.getUrl()); |
783 | call.finishError("Couldn't save URL " + prop.getUrl() + " to file: " + e.getMessage()); |
784 | } |
785 | } |
786 | }; |
787 | |
788 | this.processManager.executeService(new ModuleService() { |
789 | public String getServiceAction() { |
790 | return "saving from web to file buffer"; |
791 | } |
792 | |
793 | public String getServiceDescription() { |
794 | return "download QEDEQ module from web URL and save it to a local file"; |
795 | } |
796 | |
797 | public String getServiceId() { |
798 | return "" + hashCode(); |
799 | } |
800 | }, executor, prop, call.getInternalServiceProcess()); |
801 | Trace.end(CLASS, this, method); |
802 | |
803 | } |
804 | |
805 | public final File getLocalFilePath(final ModuleAddress address) { |
806 | final String method = "getLocalFilePath(ModuleAddress)"; |
807 | URL url; |
808 | try { |
809 | url = new URL(address.getUrl()); |
810 | } catch (MalformedURLException e) { |
811 | Trace.fatal(CLASS, this, method, "Could not get local file path.", e); |
812 | return null; |
813 | } |
814 | Trace.param(CLASS, this, method, "protocol", url.getProtocol()); |
815 | Trace.param(CLASS, this, method, "host", url.getHost()); |
816 | Trace.param(CLASS, this, method, "port", url.getPort()); |
817 | Trace.param(CLASS, this, method, "path", url.getPath()); |
818 | Trace.param(CLASS, this, method, "file", url.getFile()); |
819 | if (address.isFileAddress()) { |
820 | try { |
821 | return UrlUtility.transformURLPathToFilePath(url); |
822 | } catch (IllegalArgumentException e) { |
823 | // should not occur because check for validy must be done in constructor of address |
824 | Trace.fatal(CLASS, this, method, "Loading failed of local file with URL=" + url, e); |
825 | throw new RuntimeException(e); |
826 | } |
827 | } |
828 | StringBuffer file = new StringBuffer(url.getFile()); |
829 | StringUtility.replace(file, "_", "_1"); // remember all '_' |
830 | StringUtility.replace(file, "/", "_2"); // preserve all '/' |
831 | String encoded = file.toString(); // fallback file name |
832 | try { |
833 | encoded = URLEncoder.encode(file.toString(), "UTF-8"); |
834 | } catch (UnsupportedEncodingException e) { |
835 | // should not occur |
836 | Trace.trace(CLASS, method, e); |
837 | } |
838 | file.setLength(0); |
839 | file.append(encoded); |
840 | StringUtility.replace(file, "#", "##"); // escape all '#' |
841 | StringUtility.replace(file, "_2", "#"); // from '/' into '#' |
842 | StringUtility.replace(file, "_1", "_"); // from '_' into '_' |
843 | // mime 2010-06-25: use if we throw no RuntimException |
844 | // StringBuffer adr = new StringBuffer(url.toExternalForm()); |
845 | final StringBuffer adr; |
846 | try { |
847 | adr = new StringBuffer(new URL(url.getProtocol(), url.getHost(), url.getPort(), file |
848 | .toString()).toExternalForm()); |
849 | } catch (MalformedURLException e) { |
850 | Trace.fatal(CLASS, this, method, "unexpected", e); |
851 | throw new RuntimeException(e); |
852 | } |
853 | // escape characters: |
854 | StringUtility.replace(adr, "://", "_"); // before host |
855 | StringUtility.replace(adr, ":", "_"); // before protocol |
856 | return new File(getBufferDirectory(), adr.toString()); |
857 | } |
858 | |
859 | public File getBufferDirectory() { |
860 | return config.getBufferDirectory(); |
861 | } |
862 | |
863 | public File getGenerationDirectory() { |
864 | return config.getGenerationDirectory(); |
865 | } |
866 | |
867 | public KernelQedeqBo getKernelQedeqBo(final ModuleAddress address) { |
868 | return getModules().getKernelQedeqBo(this, address); |
869 | } |
870 | |
871 | public QedeqBo getQedeqBo(final ModuleAddress address) { |
872 | return getKernelQedeqBo(address); |
873 | } |
874 | |
875 | public ModuleAddress getModuleAddress(final URL url) throws IOException { |
876 | return new DefaultModuleAddress(url); |
877 | } |
878 | |
879 | public ModuleAddress getModuleAddress(final String url) throws IOException { |
880 | return new DefaultModuleAddress(url); |
881 | } |
882 | |
883 | public ModuleAddress getModuleAddress(final File file) throws IOException { |
884 | return new DefaultModuleAddress(file); |
885 | } |
886 | |
887 | public String getSource(final ModuleAddress address) throws IOException { |
888 | final KernelQedeqBo bo = getKernelQedeqBo(address); |
889 | if (bo.getLoadingState().equals(LoadingState.STATE_UNDEFINED) |
890 | || bo.getLoadingState().equals(LoadingState.STATE_LOADING_FROM_WEB) |
891 | || bo.getLoadingState().equals(LoadingState.STATE_LOADING_FROM_WEB_FAILED)) { |
892 | return null; |
893 | } |
894 | final StringBuffer buffer = new StringBuffer(); |
895 | final Reader reader = getQedeqFileDao().getModuleReader(bo); |
896 | try { |
897 | IoUtility.loadReader(reader, buffer); |
898 | } finally { |
899 | IoUtility.close(reader); |
900 | } |
901 | return buffer.toString(); |
902 | } |
903 | |
904 | public boolean loadRequiredModules(final ModuleAddress address) { |
905 | final KernelQedeqBo prop = getKernelQedeqBo(address); |
906 | // did we check this already? |
907 | if (prop.hasLoadedRequiredModules()) { |
908 | return true; // everything is OK |
909 | } |
910 | executePlugin(LoadRequiredModulesPlugin.class.getName(), prop.getModuleAddress(), null); |
911 | return prop.hasLoadedRequiredModules(); |
912 | } |
913 | |
914 | public boolean loadRequiredModules(final InternalServiceJob process, final KernelQedeqBo qedeq) |
915 | throws InterruptException { |
916 | // did we check this already? |
917 | if (qedeq.hasLoadedRequiredModules()) { |
918 | return true; // everything is OK |
919 | } |
920 | executePlugin(process, LoadRequiredModulesPlugin.class.getName(), qedeq, null); |
921 | return qedeq.hasLoadedRequiredModules(); |
922 | } |
923 | |
924 | public boolean checkWellFormedness(final ModuleAddress address) { |
925 | final DefaultKernelQedeqBo prop = modules.getKernelQedeqBo(this, address); |
926 | // did we check this already? |
927 | if (prop.isWellFormed()) { |
928 | return true; // everything is OK |
929 | } |
930 | executePlugin(WellFormedCheckerPlugin.class.getName(), prop.getModuleAddress(), null); |
931 | return prop.isWellFormed(); |
932 | } |
933 | |
934 | public boolean checkWellFormedness(final InternalServiceJob process, final KernelQedeqBo qedeq) |
935 | throws InterruptException { |
936 | // did we check this already? |
937 | if (qedeq.isWellFormed()) { |
938 | return true; // everything is OK |
939 | } |
940 | executePlugin(process, WellFormedCheckerPlugin.class.getName(), qedeq, null); |
941 | return qedeq.isWellFormed(); |
942 | } |
943 | |
944 | public boolean checkFormallyProved(final ModuleAddress address) { |
945 | final DefaultKernelQedeqBo prop = modules.getKernelQedeqBo(this, address); |
946 | // did we check this already? |
947 | if (prop.isFullyFormallyProved()) { |
948 | return true; // everything is OK |
949 | } |
950 | executePlugin(FormalProofCheckerPlugin.class.getName(), prop.getModuleAddress(), null); |
951 | return prop.isFullyFormallyProved(); |
952 | } |
953 | |
954 | public boolean checkFormallyProved(final InternalServiceJob process, final KernelQedeqBo qedeq) |
955 | throws InterruptException { |
956 | // did we check this already? |
957 | if (qedeq.isFullyFormallyProved()) { |
958 | return true; // everything is OK |
959 | } |
960 | executePlugin(process, FormalProofCheckerPlugin.class.getName(), qedeq, null); |
961 | return qedeq.isFullyFormallyProved(); |
962 | } |
963 | |
964 | /** |
965 | * Add plugin to services. |
966 | * |
967 | * @param pluginClass Plugin class to instantiate. |
968 | * @throws RuntimeException Addition failed. |
969 | */ |
970 | public void addPlugin(final String pluginClass) { |
971 | pluginManager.addPlugin(pluginClass); |
972 | } |
973 | |
974 | public ModuleService[] getPlugins() { |
975 | return pluginManager.getNonInternalPlugins(); |
976 | } |
977 | |
978 | |
979 | public Object executePlugin(final String id, final ModuleAddress address, final Object data) { |
980 | final InternalServiceJob process = processManager.createServiceJob(id); |
981 | try { |
982 | final KernelQedeqBo qedeq = loadKernelModule(process, address); |
983 | if (qedeq.isLoaded()) { |
984 | return processManager.executePlugin(id, qedeq, data, process); |
985 | } else { |
986 | process.setFailureState(); |
987 | } |
988 | } catch (InterruptException e) { |
989 | process.setInterruptedState(); |
990 | } finally { |
991 | process.setSuccessState(); |
992 | if (validate) { |
993 | modules.validateDependencies(); |
994 | } |
995 | } |
996 | return null; |
997 | } |
998 | |
999 | 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 | } |