KernelContext.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2013,  Michael Meyling <mime@qedeq.org>.
004  *
005  * "Hilbert II" is free software; you can redistribute
006  * it and/or modify it under the terms of the GNU General Public
007  * License as published by the Free Software Foundation; either
008  * version 2 of the License, or (at your option) any later version.
009  *
010  * This program is distributed in the hope that it will be useful,
011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013  * GNU General Public License for more details.
014  */
015 
016 package org.qedeq.kernel.bo;
017 
018 import java.io.File;
019 import java.io.FileOutputStream;
020 import java.io.IOException;
021 import java.net.URL;
022 import java.nio.channels.FileLock;
023 
024 import org.qedeq.base.io.IoUtility;
025 import org.qedeq.base.trace.Trace;
026 import org.qedeq.base.utility.StringUtility;
027 import org.qedeq.kernel.bo.common.BasicKernel;
028 import org.qedeq.kernel.bo.common.KernelProperties;
029 import org.qedeq.kernel.bo.common.KernelServices;
030 import org.qedeq.kernel.bo.common.KernelState;
031 import org.qedeq.kernel.bo.common.QedeqBo;
032 import org.qedeq.kernel.bo.common.ServiceModule;
033 import org.qedeq.kernel.bo.common.ServiceProcess;
034 import org.qedeq.kernel.bo.log.QedeqLog;
035 import org.qedeq.kernel.se.common.ModuleAddress;
036 import org.qedeq.kernel.se.common.Plugin;
037 import org.qedeq.kernel.se.config.QedeqConfig;
038 
039 
040 /**
041  * This class provides static access methods for the kernel.
042  *
043  @author  Michael Meyling
044  */
045 public final class KernelContext implements KernelProperties, KernelServices {
046 
047     /** Message for non started kernel. */
048     private static final String KERNEL_NOT_STARTED = "Kernel not started";
049 
050     /** Message for non initialized kernel. */
051     private static final String KERNEL_NOT_INITIALIZED = "Kernel not initialized";
052 
053     /** This class. */
054     private static final Class CLASS = KernelContext.class;
055 
056     /** One and only instance of this class. */
057     private static final KernelContext INSTANCE = new KernelContext();
058 
059     /** Lock file. */
060     private File lockFile;
061 
062     /** Lock file stream. */
063     private FileOutputStream lockStream;
064 
065     /** Initial kernel state. */
066     private final KernelState initialState = new KernelState() {
067 
068         public void init(final QedeqConfig config, final ServiceModule moduleServices, final KernelProperties basic)
069                 throws IOException {
070             KernelContext.this.config = config;
071             KernelContext.this.basic = basic;
072             Trace.setTraceOn(config.isTraceOn());
073             checkJavaVersion();
074             createAllNecessaryDirectories();
075             checkIfApplicationIsAlreadyRunningAndLockFile();
076             KernelContext.this.services = moduleServices;
077             QedeqLog.getInstance().logMessage("--------------------------------------------------"
078                  "---------------------------------------");
079             QedeqLog.getInstance().logMessage("This is "
080                 + KernelContext.getInstance().getDescriptiveKernelVersion());
081             QedeqLog.getInstance().logMessage("  see \"http://www.qedeq.org\" for more "
082                 "information");
083             QedeqLog.getInstance().logMessage("  supports rules till version "
084                 + KernelContext.getInstance().getMaximalRuleVersion());
085             QedeqLog.getInstance().logMessage("  Java version: "
086                 + StringUtility.alignRight(System.getProperty("java.version""unknown")10));
087             QedeqLog.getInstance().logMessage("  used memory:  "
088                 + StringUtility.alignRight(Runtime.getRuntime().totalMemory()
089                 - Runtime.getRuntime().freeMemory()10));
090             QedeqLog.getInstance().logMessage("  free memory:  "
091                 + StringUtility.alignRight(Runtime.getRuntime().freeMemory()10));
092             QedeqLog.getInstance().logMessage("  total memory: "
093                 + StringUtility.alignRight(Runtime.getRuntime().totalMemory()10));
094             QedeqLog.getInstance().logMessage("  max. memory:  "
095                 + StringUtility.alignRight(Runtime.getRuntime().maxMemory()10));
096             QedeqLog.getInstance().logMessage("  processors/cores: "
097                 + StringUtility.alignRight(Runtime.getRuntime().availableProcessors()6));
098             currentState = initializedState;
099         }
100 
101         public void startup() {
102             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
103         }
104 
105         public void shutdown() {
106             currentState = initialState;
107             // close stream and associated channel
108             IoUtility.close(lockStream);
109             lockStream = null;
110         }
111 
112         public void removeAllModules() {
113             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
114         }
115 
116         public void removeModule(final ModuleAddress address) {
117             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
118         }
119 
120         public boolean clearLocalBuffer() {
121             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
122         }
123 
124         public QedeqBo loadModule(final ModuleAddress address) {
125             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
126         }
127 
128         public boolean loadAllModulesFromQedeq() {
129             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
130         }
131 
132         public boolean loadRequiredModules(final ModuleAddress address) {
133             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
134         }
135 
136         public ModuleAddress[] getAllLoadedModules() {
137             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
138         }
139 
140         public QedeqBo getQedeqBo(final ModuleAddress address) {
141             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
142         }
143 
144         public ModuleAddress getModuleAddress(final URL url) {
145             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
146         }
147 
148         public ModuleAddress getModuleAddress(final String url) {
149             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
150         }
151 
152         public ModuleAddress getModuleAddress(final File file) {
153             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
154         }
155 
156         public String getSource(final ModuleAddress address) {
157             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
158         }
159 
160         public boolean checkWellFormedness(final ModuleAddress address) {
161             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
162         }
163 
164         public boolean checkFormallyProved(final ModuleAddress address) {
165             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
166         }
167 
168         public Plugin[] getPlugins() {
169             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
170         }
171 
172         public Object executePlugin(final String pluginName, final ModuleAddress address,
173                 final Object data) {
174             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
175         }
176 
177         public void clearAllPluginResults(final ModuleAddress address) {
178             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
179         }
180 
181         public ServiceProcess[] getServiceProcesses() {
182             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
183         }
184 
185         public ServiceProcess[] getRunningServiceProcesses() {
186             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
187         }
188 
189         public void stopAllPluginExecutions() {
190             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
191         }
192 
193     };
194 
195     /** Initial kernel state. */
196     private final KernelState initializedState = new KernelState() {
197 
198         public void init(final QedeqConfig config, final ServiceModule moduleServices,
199                 final KernelProperties basicthrows IOException {
200             throw new IllegalStateException("Kernel is already initialized");
201         }
202 
203         public void startup() {
204             services.startupServices();
205             currentState = readyState;
206             QedeqLog.getInstance().logMessage("QEDEQ kernel opened.");
207         }
208 
209         public void shutdown() {
210             services.shutdownServices();
211             KernelContext.this.services = null;
212             initialState.shutdown();
213             QedeqLog.getInstance().logMessage("QEDEQ Kernel closed.");
214         }
215 
216         public void removeAllModules() {
217             throw new IllegalStateException(KERNEL_NOT_STARTED);
218         }
219 
220         public void removeModule(final ModuleAddress address) {
221             throw new IllegalStateException(KERNEL_NOT_STARTED);
222         }
223 
224         public boolean clearLocalBuffer() {
225             throw new IllegalStateException(KERNEL_NOT_STARTED);
226         }
227 
228         public QedeqBo loadModule(final ModuleAddress address) {
229             throw new IllegalStateException(KERNEL_NOT_STARTED);
230         }
231 
232         public boolean loadAllModulesFromQedeq() {
233             throw new IllegalStateException(KERNEL_NOT_STARTED);
234         }
235 
236         public boolean loadRequiredModules(final ModuleAddress address) {
237             throw new IllegalStateException(KERNEL_NOT_STARTED);
238         }
239 
240         public ModuleAddress[] getAllLoadedModules() {
241             throw new IllegalStateException(KERNEL_NOT_STARTED);
242         }
243 
244         public QedeqBo getQedeqBo(final ModuleAddress address) {
245             throw new IllegalStateException(KERNEL_NOT_STARTED);
246         }
247 
248         public ModuleAddress getModuleAddress(final URL url) {
249             throw new IllegalStateException(KERNEL_NOT_STARTED);
250         }
251 
252         public ModuleAddress getModuleAddress(final String url) {
253             throw new IllegalStateException(KERNEL_NOT_STARTED);
254         }
255 
256         public ModuleAddress getModuleAddress(final File file) {
257             throw new IllegalStateException(KERNEL_NOT_STARTED);
258         }
259 
260         public String getSource(final ModuleAddress address) {
261             throw new IllegalStateException(KERNEL_NOT_STARTED);
262         }
263 
264         public boolean checkWellFormedness(final ModuleAddress address) {
265             throw new IllegalStateException(KERNEL_NOT_STARTED);
266         }
267 
268         public boolean checkFormallyProved(final ModuleAddress address) {
269             throw new IllegalStateException(KERNEL_NOT_INITIALIZED);
270         }
271 
272         public Plugin[] getPlugins() {
273             return services.getPlugins();
274         }
275 
276         public Object executePlugin(final String pluginName, final ModuleAddress address,
277                 final Object data) {
278             throw new IllegalStateException(KERNEL_NOT_STARTED);
279         }
280 
281         public void clearAllPluginResults(final ModuleAddress address) {
282             throw new IllegalStateException(KERNEL_NOT_STARTED);
283         }
284 
285         public ServiceProcess[] getServiceProcesses() {
286             throw new IllegalStateException(KERNEL_NOT_STARTED);
287         }
288 
289         public ServiceProcess[] getRunningServiceProcesses() {
290             throw new IllegalStateException(KERNEL_NOT_STARTED);
291         }
292 
293         public void stopAllPluginExecutions() {
294             throw new IllegalStateException(KERNEL_NOT_STARTED);
295         }
296 
297     };
298 
299     /** State for ready kernel. */
300     private final KernelState readyState = new KernelState() {
301 
302         public void init(final QedeqConfig config, final ServiceModule moduleServices,
303                 final KernelProperties basicthrows IOException {
304             // we are already ready
305         }
306 
307         public void startup() {
308             // we are already ready
309         }
310 
311         public void shutdown() {
312             try {
313                 final ModuleAddress[] addresses = services.getAllLoadedModules();
314                 final String[] buffer = new String[addresses.length];
315                 for (int i = 0; i < addresses.length; i++) {
316                     buffer[i= addresses[i].toString();
317                 }
318                 getConfig().setPreviouslyLoadedModules(buffer);
319                 getConfig().store();
320                 QedeqLog.getInstance().logMessage("Current config file successfully saved.");
321             catch (IOException e) {
322                 Trace.trace(CLASS, this, "shutdown()", e);
323                 QedeqLog.getInstance().logMessage("Saving current config file failed.");
324             }
325             initializedState.shutdown();
326         }
327 
328         public void removeAllModules() {
329             services.removeAllModules();
330         }
331 
332         public void removeModule(final ModuleAddress address) {
333             services.removeModule(address);
334         }
335 
336         public boolean clearLocalBuffer() {
337             return services.clearLocalBuffer();
338         }
339 
340         public QedeqBo loadModule(final ModuleAddress address) {
341             return services.loadModule(address);
342         }
343 
344         public boolean loadAllModulesFromQedeq() {
345             return services.loadAllModulesFromQedeq();
346         }
347 
348         public boolean loadRequiredModules(final ModuleAddress address) {
349             return services.loadRequiredModules(address);
350         }
351 
352         public ModuleAddress[] getAllLoadedModules() {
353             return services.getAllLoadedModules();
354         }
355 
356         public QedeqBo getQedeqBo(final ModuleAddress address) {
357             return services.getQedeqBo(address);
358         }
359 
360         public ModuleAddress getModuleAddress(final URL urlthrows IOException {
361             return services.getModuleAddress(url);
362         }
363 
364         public ModuleAddress getModuleAddress(final String urlthrows IOException {
365             return services.getModuleAddress(url);
366         }
367 
368         public ModuleAddress getModuleAddress(final File filethrows IOException {
369             return services.getModuleAddress(file);
370         }
371 
372         public String getSource(final ModuleAddress addressthrows IOException {
373             return services.getSource(address);
374         }
375 
376         public boolean checkWellFormedness(final ModuleAddress address) {
377             return services.checkWellFormedness(address);
378         }
379 
380         public boolean checkFormallyProved(final ModuleAddress address) {
381             return services.checkFormallyProved(address);
382         }
383 
384         public Plugin[] getPlugins() {
385             return services.getPlugins();
386         }
387 
388         public Object executePlugin(final String pluginName, final ModuleAddress address,
389                 final Object data) {
390             return services.executePlugin(pluginName, address, data);
391         }
392 
393         public void clearAllPluginResults(final ModuleAddress address) {
394             services.clearAllPluginResults(address);
395         }
396 
397         public ServiceProcess[] getServiceProcesses() {
398             return services.getServiceProcesses();
399         }
400 
401         public ServiceProcess[] getRunningServiceProcesses() {
402             return services.getRunningServiceProcesses();
403         }
404 
405         public void stopAllPluginExecutions() {
406             services.stopAllPluginExecutions();
407         }
408 
409     };
410 
411     /** Kernel configuration. */
412     private QedeqConfig config;
413 
414     /** Initial kernel state. */
415     private KernelState currentState = initialState;
416 
417     /** For basic kernel informations. */
418     private KernelProperties basic;
419 
420     /** This object can service QEDEQ modules. */
421     private ServiceModule services;
422 
423     /**
424      * Constructor.
425      */
426     private KernelContext() {
427         basic = new BasicKernel();
428     }
429 
430     /**
431      * Get instance of kernel context.
432      *
433      @return  Singleton, which is responsible for the kernel access.
434      */
435     public static final KernelContext getInstance() {
436         return INSTANCE;
437     }
438 
439     public String getBuildId() {
440         return basic.getBuildId();
441     }
442 
443     public final String getKernelVersion() {
444         return basic.getKernelVersion();
445     }
446 
447     public final String getKernelCodeName() {
448         return basic.getKernelCodeName();
449     }
450 
451     public final String getKernelVersionDirectory() {
452         return basic.getKernelVersionDirectory();
453     }
454 
455     public final String getDescriptiveKernelVersion() {
456         return basic.getDescriptiveKernelVersion();
457     }
458 
459     public final String getDedication() {
460         return basic.getDedication();
461     }
462 
463     public final String getMaximalRuleVersion() {
464         return basic.getMaximalRuleVersion();
465     }
466 
467     public final boolean isRuleVersionSupported(final String ruleVersion) {
468         return basic.isRuleVersionSupported(ruleVersion);
469     }
470 
471     public boolean isSetConnectionTimeOutSupported() {
472         return basic.isSetConnectionTimeOutSupported();
473     }
474 
475     public boolean isSetReadTimeoutSupported() {
476         return basic.isSetReadTimeoutSupported();
477     }
478 
479     public QedeqConfig getConfig() {
480         return config;
481     }
482 
483     /**
484      * Init the kernel.
485      *
486      @param   config          Configuration access.
487      @param   moduleServices  Services for the kernel.
488      @throws  IOException     Initialization failure.
489      */
490     public void init(final QedeqConfig config, final ServiceModule moduleServicesthrows IOException {
491         currentState.init(config, moduleServices, basic);
492     }
493 
494     /**
495      * Startup the kernel.
496      */
497     public void startup() {
498         currentState.startup();
499     }
500 
501     /**
502      * Shutdown the kernel.
503      */
504     public void shutdown() {
505         currentState.shutdown();
506     }
507 
508     public void removeAllModules() {
509         currentState.removeAllModules();
510     }
511 
512     public void removeModule(final ModuleAddress address) {
513         currentState.removeModule(address);
514     }
515 
516     public boolean clearLocalBuffer() {
517         return currentState.clearLocalBuffer();
518     }
519 
520     public QedeqBo loadModule(final ModuleAddress address) {
521         return currentState.loadModule(address);
522     }
523 
524     public boolean loadAllModulesFromQedeq() {
525         return currentState.loadAllModulesFromQedeq();
526     }
527 
528     public boolean loadRequiredModules(final ModuleAddress address) {
529         return currentState.loadRequiredModules(address);
530     }
531 
532     public ModuleAddress[] getAllLoadedModules() {
533         return currentState.getAllLoadedModules();
534     }
535 
536     public QedeqBo getQedeqBo(final ModuleAddress address) {
537         return currentState.getQedeqBo(address);
538     }
539 
540     public ModuleAddress getModuleAddress(final URL urlthrows IOException {
541         return currentState.getModuleAddress(url);
542     }
543 
544     public ModuleAddress getModuleAddress(final String urlthrows IOException {
545         return currentState.getModuleAddress(url);
546     }
547 
548     public ModuleAddress getModuleAddress(final File filethrows IOException {
549         return currentState.getModuleAddress(file);
550     }
551 
552     public String getSource(final ModuleAddress addressthrows IOException {
553         return currentState.getSource(address);
554     }
555 
556     public boolean checkWellFormedness(final ModuleAddress address) {
557         return currentState.checkWellFormedness(address);
558     }
559 
560     public boolean checkFormallyProved(final ModuleAddress address) {
561         return currentState.checkFormallyProved(address);
562     }
563 
564     public Plugin[] getPlugins() {
565         return currentState.getPlugins();
566     }
567 
568     public Object executePlugin(final String pluginName, final ModuleAddress address,
569             final Object data) {
570         return currentState.executePlugin(pluginName, address, data);
571     }
572 
573     public void clearAllPluginResults(final ModuleAddress address) {
574         currentState.clearAllPluginResults(address);
575     }
576 
577     public ServiceProcess[] getServiceProcesses() {
578         return currentState.getServiceProcesses();
579     }
580 
581     public ServiceProcess[] getRunningServiceProcesses() {
582         return currentState.getRunningServiceProcesses();
583     }
584 
585     public void stopAllPluginExecutions() {
586         currentState.stopAllPluginExecutions();
587     }
588 
589     /**
590      * Check java version. We want to be sure that the kernel is run at least with java 1.4.2
591      *
592      @throws  IOException     Application is running below java 1.4.2.
593      */
594     private void checkJavaVersion() throws IOException {
595         final String method = "checkJavaVersion";
596         Trace.info(CLASS, this, method, "running on java version "
597             + System.getProperty("java.version"));
598         final int[] versions = IoUtility.getJavaVersion();
599         if (versions == null) {
600             Trace.fatal(CLASS, this, method, "running java version unknown"null);
601             // we try to continue
602             return;
603         }
604         final StringBuffer version = new StringBuffer();
605         for (int i = 0; i < versions.length; i++) {
606             if (i > 0) {
607                 version.append(".");
608             }
609             version.append(versions[i]);
610         }
611         Trace.paramInfo(CLASS, this, method, "version", version);
612         // >= 1
613         if (versions.length < || versions[01) {
614             throw new IOException("This application requires at least Java 1.4.2 but we got "
615                 + version);
616         }
617         if (versions[0== 1) {         // further checking
618             // >= 1.4
619             if (versions.length < || versions[14) {
620                 throw new IOException("This application requires at least Java 1.4.2 but we got "
621                     + version);
622             }
623             if (versions[1== 4) {     // further checking
624                 // >=1.4.2
625                 if (versions.length < || versions[22) {
626                     throw new IOException(
627                         "This application requires at least Java 1.4.2 but we got "
628                         + version);
629                 }
630             }
631         }
632     }
633 
634     /**
635      * Create all necessary directories for the kernel.
636      *
637      @throws  IOException     Creation was not possible.
638      */
639     void createAllNecessaryDirectories() throws IOException {
640         // log directory
641         final File logFile = getConfig().getLogFile();
642         final File logDir = logFile.getParentFile();
643         if (!logDir.exists() &&  !logDir.mkdirs()) {
644             throw new IOException("can't create directory: " + logDir.getAbsolutePath());
645         }
646         // buffer directory
647         final File bufferDir = getConfig().getBufferDirectory();
648         if (!bufferDir.exists() &&  !bufferDir.mkdirs()) {
649             throw new IOException("can't create directory: " + bufferDir.getAbsolutePath());
650         }
651         // generation directory
652         final File generationDir = getConfig().getGenerationDirectory();
653         if (!generationDir.exists() &&  !generationDir.mkdirs()) {
654             throw new IOException("can't create directory: " + generationDir.getAbsolutePath());
655         }
656     }
657 
658     /**
659      * Checks if the application is already running. To check that we create a file in the
660      * buffer directory, open a stream and write something into it. The stream is not closed
661      * until kernel shutdown.
662      *
663      @throws  IOException     Application is already running.
664      */
665     private void checkIfApplicationIsAlreadyRunningAndLockFile()
666             throws IOException {
667         lockFile = new File(getConfig().getBufferDirectory()"qedeq_lock.lck");
668         FileLock fl = null;
669         try {
670             lockStream = new FileOutputStream(lockFile);
671             lockStream.write("LOCKED".getBytes("UTF8"));
672             lockStream.flush();
673             fl = lockStream.getChannel().tryLock();
674         catch (IOException e) {
675             throw new IOException("It seems the application is already running.\n"
676                 "At least accessing the file \"" + lockFile.getAbsolutePath() "\" failed.");
677         }
678         if (fl == null) {
679             throw new IOException("It seems the application is already running.\n"
680                 "At least locking the file \"" + lockFile.getAbsolutePath() "\" failed.");
681         }
682     }
683 
684 }