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