diff --git a/pom.xml b/pom.xml index 7b229e5178141e8cd90f85328f77cf4e5b3b0531..35d14ef3cef93373b641ccc9ec759822232adf7a 100644 --- a/pom.xml +++ b/pom.xml @@ -117,11 +117,6 @@ <artifactId>reflections</artifactId> <version>0.9.11</version> </dependency> - <dependency> - <groupId>com.googlecode.lanterna</groupId> - <artifactId>lanterna</artifactId> - <version>2.1.9</version> - </dependency> <dependency> <groupId>org.antlr</groupId> <artifactId>antlr4</artifactId> diff --git a/src/main/java/org/caosdb/server/CaosDBServer.java b/src/main/java/org/caosdb/server/CaosDBServer.java index 996e1480a8158dd27e62e3af072a725698a3e5f3..c7b461d50ceb353ea3ac0881b40b391276caffea 100644 --- a/src/main/java/org/caosdb/server/CaosDBServer.java +++ b/src/main/java/org/caosdb/server/CaosDBServer.java @@ -78,13 +78,9 @@ import org.caosdb.server.resource.Webinterface; import org.caosdb.server.resource.WebinterfaceBuildNumber; import org.caosdb.server.resource.transaction.EntityNamesResource; import org.caosdb.server.resource.transaction.EntityResource; -import org.caosdb.server.terminal.CaosDBTerminal; -import org.caosdb.server.terminal.StatsPanel; -import org.caosdb.server.terminal.SystemErrPanel; import org.caosdb.server.transaction.ChecksumUpdater; import org.caosdb.server.utils.FileUtils; import org.caosdb.server.utils.Initialization; -import org.caosdb.server.utils.NullPrintStream; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; @@ -116,7 +112,6 @@ import org.slf4j.LoggerFactory; public class CaosDBServer extends Application { private static Logger logger = LoggerFactory.getLogger(CaosDBServer.class); - private static boolean START_GUI = true; private static Properties SERVER_PROPERTIES = null; private static Component component = null; private static ArrayList<Runnable> postShutdownHooks = new ArrayList<Runnable>(); @@ -164,13 +159,8 @@ public class CaosDBServer extends Application { private static void init(final String[] args) { // Important change: // Make silent the default option - START_GUI = false; for (final String s : args) { - if (s.equals("silent")) { - START_GUI = false; - } else if (s.equals("gui")) { - START_GUI = true; - } else if (s.equals("nobackend")) { + if (s.equals("nobackend")) { START_BACKEND = false; } else if (s.equals("insecure")) { INSECURE = true; @@ -354,32 +344,6 @@ public class CaosDBServer extends Application { } } - public static void initGUI() throws InterruptedException { - if (START_GUI) { - final CaosDBTerminal caosDBTerminal = new CaosDBTerminal(); - caosDBTerminal.setName("CaosDBTerminal"); - caosDBTerminal.start(); - - addPreShutdownHook( - new Runnable() { - - @Override - public void run() { - caosDBTerminal.shutDown(); - SystemErrPanel.close(); - } - }); - // wait until the terminal is initialized. - Thread.sleep(1000); - - // add Benchmark - StatsPanel.addStat("TransactionBenchmark", TransactionBenchmark.getRootInstance()); - } else { - logger.info("NO GUI"); - System.setOut(new NullPrintStream()); - } - } - private static void initDatatypes(final Access access) throws Exception { final RetrieveDatatypes t = new RetrieveDatatypes(); t.setAccess(access); diff --git a/src/main/java/org/caosdb/server/database/DatabaseAccessManager.java b/src/main/java/org/caosdb/server/database/DatabaseAccessManager.java new file mode 100644 index 0000000000000000000000000000000000000000..39db44b840e3e8a70dcc24f3a35ba52b15c687c6 --- /dev/null +++ b/src/main/java/org/caosdb/server/database/DatabaseAccessManager.java @@ -0,0 +1,297 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2018 Research Group Biomedical Physics, + * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ +package org.caosdb.server.database; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.ReentrantLock; +import org.caosdb.server.database.access.Access; +import org.caosdb.server.database.access.AccessControlAccess; +import org.caosdb.server.database.access.InfoAccess; +import org.caosdb.server.database.access.InitAccess; +import org.caosdb.server.database.access.TransactionAccess; +import org.caosdb.server.transaction.AccessControlTransaction; +import org.caosdb.server.transaction.TransactionInterface; +import org.caosdb.server.transaction.WriteTransactionInterface; +import org.caosdb.server.utils.Info; +import org.caosdb.server.utils.Initialization; +import org.caosdb.server.utils.Releasable; + +/** + * Acquire and release read access. DatabaseMonitor uses this class for managing access to entities + * during processing updates, inserts, deletions and retrievals. Read access will be granted + * immediately for every thread that requests it, unless one or more threads requested for blocking + * the read access (usually due to requesting for write access). If this happens, all threads that + * already have read access will proceed and release their read access as usual but no NEW permits + * will be granted. + * + * <p>This is a blockable {@link Semaphore}. Any number of threads may acquire a permit unless it is + * blocked. The blocking thread (requesting a {@link WriteAccessLock}) waits until all threads have + * released their permits. + * + * @author Timm Fitschen + */ +class ReadAccessSemaphore extends Semaphore implements Releasable { + + private static final long serialVersionUID = -262226321839837533L; + private int acquired = 0; // how many thread have read access + Semaphore block = new Semaphore(1, true); + + public ReadAccessSemaphore() { + // this is a fair semaphore with no initial permit. + super(1, true); + } + + /** + * Acquires a read access permit if and only if it has not been blocked via block(). If the + * ReadAccess is currently blocked, the thread wait until the unblock() method is invoked by any + * thread. + */ + @Override + public void acquire() throws InterruptedException { + super.acquire(); + if (this.acquired == 0) { + this.block.acquire(); + } + this.acquired++; + // notifyObservers(null); + super.release(); + } + + /** Releases a read access permit. */ + @Override + public void release() { + this.acquired--; + if (this.acquired <= 0) { + this.acquired = 0; + if (this.block.availablePermits() <= 0) { + this.block.release(); + } + } + } + + /** + * Acquires the permit of a block of read access if no thread currently has a read access and no + * thread currently has a block. I.e. it blocks the further permission of read access for any + * thread. Every thread that has a read access yet can proceed. The current thread waits until any + * thread has released its read access. If another thread has invoked this method yet the current + * thread waits until the unblock() method is called. + * + * @throws InterruptedException + */ + public void block() throws InterruptedException { + super.reducePermits(1); + this.block.acquire(); + } + + /** + * Unblock read access. + * + * @throws InterruptedException + */ + public void unblock() { + if (this.block.availablePermits() <= 0) { + this.block.release(); + } + super.release(); + } + + public int waitingAquireAccess() { + return getQueueLength(); + } +} + +/** + * Acquire and release write access. DatabaseMonitor uses this class for managing access to entities + * during processing updates, inserts, deletions and retrievals. Write access will be granted to one + * and only one thread if no other thread yet holds read or write access permits. The write access + * has to be allocated before requesting it to be permitted. See below. + * + * @author Timm Fitschen + */ +class WriteAccessLock extends ReentrantLock implements Releasable { + + private static final long serialVersionUID = -262226321839837533L; + private ReadAccessSemaphore wa = null; + private Thread reservedBy = null; + // private Thread acquiredBy = null; + + public WriteAccessLock(final ReadAccessSemaphore wa) { + super(); + this.wa = wa; + } + + /** + * Reserve the write access. While a write access is reserved but not yet acquired any read access + * may still be granted. When a write access is yet granted or another reservation is still + * active, the thread waits until the write access has been released. + * + * @throws InterruptedException + */ + public void reserve() throws InterruptedException { + super.lock(); + this.reservedBy = Thread.currentThread(); + } + + @Override + public void lockInterruptibly() throws InterruptedException { + if (!super.isHeldByCurrentThread()) { + super.lock(); + } + this.wa.block(); + } + + @Override + public void unlock() { + if (super.isHeldByCurrentThread()) { + this.wa.unblock(); + this.reservedBy = null; + super.unlock(); + } + } + + @Override + public void release() { + unlock(); + } + + public Thread whoHasReservedAccess() { + return this.reservedBy; + } +} + +/** + * Manages the read and write access to the database. + * + * @author tf + */ +public class DatabaseAccessManager { + + private DatabaseAccessManager() {} + + private static final DatabaseAccessManager instance = new DatabaseAccessManager(); + private final ReadAccessSemaphore readAccess = new ReadAccessSemaphore(); + private final WriteAccessLock writeAccess = new WriteAccessLock(this.readAccess); + + public static DatabaseAccessManager getInstance() { + return instance; + } + + /** + * Return the thread which has successfully reserved write access. This is the thread which will + * be the next to actually acquire write access. + * + * @return + */ + public static Thread whoHasReservedWriteAccess() { + return instance.writeAccess.whoHasReservedAccess(); + } + + /** + * Acquire read access. This method returns the Access object as soon as there is no write access + * acquired. + * + * <p>The returned Access object can be used to read in the data base back-end. + * + * <p>Read access can be acquired parallel to other threads having read access or while other + * thread only reserved write access. As soon as any thread has requested to acquire write access, + * all other threads have to wait. + * + * @param t the {@link TransactionInterface} which requests the read access + * @return {@link Access} object which holds and abstract away all connection details. + * @throws InterruptedException + */ + public Access acquireReadAccess(final TransactionInterface t) throws InterruptedException { + this.readAccess.acquire(); + return new TransactionAccess(t, this.readAccess); + } + + /** + * Reserve write access. This method returns the Access object as soon as there is no other thread + * which reserved or acquired the write access. Otherwise this thread waits in the queue until it + * can reserve the write access. + * + * <p>The returned Access object can be used to read in the data base back-end. + * + * <p>While a write access is reserved but not yet acquired any read access may still be granted. + * When a write access is yet granted or another reservation is still active, no read or write + * accesses can be granted and all other thread have to waits until this write access has been + * released. + * + * @param wt - the {@link WriteTransactionInterface} which request the reservation of the write + * access. + * @return {@link Access} object which holds and abstract away all connection details. + * @throws InterruptedException + */ + public Access reserveWriteAccess(final WriteTransactionInterface wt) throws InterruptedException { + this.writeAccess.reserve(); + return new TransactionAccess(wt, this.writeAccess); + } + + /** + * Acquire write access. This method returns the Access object ass soon as all already acquired + * read accesses have been released. When the write access is acquired, no other access can be + * acquired (read or write). + * + * <p>The returned Access object can be used to read and write in the data base back-end. + * + * @param wt - the {@link WriteTransactionInterface} which request the acquisition of the write + * access. + * @return {@link Access} object which holds and abstract away all connection details. + * @throws InterruptedException + */ + public Access acquireWriteAccess(final WriteTransactionInterface wt) throws InterruptedException { + this.writeAccess.lockInterruptibly(); + return wt.getAccess(); + } + + /** + * Special access to be used by {@link Info}. + * + * @param i + * @return + */ + public static Access getInfoAccess(final Info i) { + return new InfoAccess(i); + } + + /** + * Special access to be used during the {@link Initialization} of the caosdb server. + * + * @param initialization + * @return + */ + public static Access getInitAccess(final Initialization initialization) { + return new InitAccess(initialization); + } + + /** + * Special access to be used for {@link AccessControlTransaction}s, mainly authentication and + * authorization. + * + * @param t + * @return + */ + public static Access getAccountAccess(final AccessControlTransaction t) { + return new AccessControlAccess(t); + } +} diff --git a/src/main/java/org/caosdb/server/database/DatabaseMonitor.java b/src/main/java/org/caosdb/server/database/DatabaseMonitor.java deleted file mode 100644 index fb9d7685643deecf9bfaa2ab10777e32b3bff51b..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/database/DatabaseMonitor.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.database; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.concurrent.Semaphore; -import java.util.concurrent.locks.ReentrantLock; -import org.caosdb.server.database.access.Access; -import org.caosdb.server.database.access.AccessControlAccess; -import org.caosdb.server.database.access.InfoAccess; -import org.caosdb.server.database.access.InitAccess; -import org.caosdb.server.database.access.TransactionAccess; -import org.caosdb.server.transaction.AccessControlTransaction; -import org.caosdb.server.transaction.TransactionInterface; -import org.caosdb.server.transaction.WriteTransactionInterface; -import org.caosdb.server.utils.Info; -import org.caosdb.server.utils.Initialization; -import org.caosdb.server.utils.Observable; -import org.caosdb.server.utils.Observer; -import org.caosdb.server.utils.Releasable; - -/** - * Acquire and release weak access. DatabaseMonitor uses this class for managing access to entities - * during processing updates, inserts, deletions and retrievals. Weak access will be granted - * immediately for every thread that requests it, unless one or more threads requested for blocking - * the weak access (usually due to requesting for strong access). If this happens, all threads that - * already have weak access will proceed and release their weak access as usual but no NEW permits - * will be granted. - * - * @author Timm Fitschen - */ -class WeakAccessSemaphore extends Semaphore implements Observable, Releasable { - - private static final long serialVersionUID = -262226321839837533L; - private int acquired = 0; // how many thread have weak access - Semaphore block = new Semaphore(1, true); - - public WeakAccessSemaphore() { - // this is a fair semaphore with no initial permit. - super(1, true); - } - - /** - * Acquires a weak access permit if and only if it has not been blocked via block(). If the - * WeakAccess is currently blocked, the thread wait until the unblock() method is invoked by any - * thread. - */ - @Override - public void acquire() throws InterruptedException { - super.acquire(); - if (this.acquired == 0) { - this.block.acquire(); - } - this.acquired++; - notifyObservers(null); - super.release(); - } - - /** Releases a weak access permit. */ - @Override - public void release() { - this.acquired--; - notifyObservers(null); - if (this.acquired <= 0) { - this.acquired = 0; - if (this.block.availablePermits() <= 0) { - this.block.release(); - } - } - } - - /** - * Acquires the permit of a block of WeakAccess if no thread currently has a WeakAccess and no - * thread currently has a block. I.e. it blocks the further permission of weak access for any - * thread. Every thread that has a weak access yet can proceed. The current thread waits until any - * thread has released its weak access. If another thread has invoked this method yet the current - * thread waits until the unblock() method is called. - * - * @throws InterruptedException - */ - public void block() throws InterruptedException { - super.reducePermits(1); - this.block.acquire(); - } - - /** - * Unblock WeakAccess. - * - * @throws InterruptedException - */ - public void unblock() { - if (this.block.availablePermits() <= 0) { - this.block.release(); - } - super.release(); - } - - public int waitingAquireAccess() { - return getQueueLength(); - } - - public int acquiredAccess() { - return this.acquired; - } - - LinkedList<Observer> observers = new LinkedList<Observer>(); - - @Override - public boolean acceptObserver(final Observer o) { - return this.observers.add(o); - } - - @Override - public void notifyObservers(final String e) { - final Iterator<Observer> it = this.observers.iterator(); - while (it.hasNext()) { - final Observer o = it.next(); - if (!o.notifyObserver(e, this)) { - it.remove(); - } - } - } -} - -/** - * Acquire and release strong access. DatabaseMonitor uses this class for managing access to - * entities during processing updates, inserts, deletions and retrievals. Strong access will be - * granted to one and only one thread if no other thread yet holds weak or strong access permits. - * The strong access has to be allocated before requesting it to be permitted. See below. - * - * @author Timm Fitschen - */ -class StrongAccessLock extends ReentrantLock implements Observable, Releasable { - - private static final long serialVersionUID = -262226321839837533L; - private WeakAccessSemaphore wa = null; - private Thread allocator = null; - private Thread acquirer = null; - - public StrongAccessLock(final WeakAccessSemaphore wa) { - super(); - this.wa = wa; - } - - /** - * Allocates the strong access permits. While a strong access is allocated but not yet acquired - * any weak access may still be granted. When a strong access is yet granted or another allocation - * is still active, the thread waits until the strong access has been released. - * - * @throws InterruptedException - */ - public void allocate() throws InterruptedException { - super.lock(); - this.allocator = Thread.currentThread(); - notifyObservers(null); - } - - @Override - public void lockInterruptibly() throws InterruptedException { - if (!super.isHeldByCurrentThread()) { - super.lock(); - } - this.acquirer = Thread.currentThread(); - notifyObservers(null); - this.wa.block(); - } - - @Override - public void unlock() { - if (super.isHeldByCurrentThread()) { - this.wa.unblock(); - this.allocator = null; - this.acquirer = null; - notifyObservers(null); - super.unlock(); - } - } - - @Override - public void release() { - unlock(); - } - - LinkedList<Observer> observers = new LinkedList<Observer>(); - - @Override - public boolean acceptObserver(final Observer o) { - return this.observers.add(o); - } - - @Override - public void notifyObservers(final String e) { - final Iterator<Observer> it = this.observers.iterator(); - while (it.hasNext()) { - final Observer o = it.next(); - if (!o.notifyObserver(e, this)) { - it.remove(); - } - } - } - - public Thread whoHasAllocatedAccess() { - return this.allocator; - } - - public Thread whoHasAcquiredAccess() { - return this.acquirer; - } - - public int waitingAllocateAccess() { - return getQueueLength(); - } -} - -/** - * Manages the read and write access to the database. - * - * @author tf - */ -public class DatabaseMonitor { - - private DatabaseMonitor() {} - - private static final DatabaseMonitor instance = new DatabaseMonitor(); - private final WeakAccessSemaphore wa = new WeakAccessSemaphore(); - private final StrongAccessLock sa = new StrongAccessLock(this.wa); - - public static DatabaseMonitor getInstance() { - return instance; - } - - public void acquireWeakAccess() throws InterruptedException { - this.wa.acquire(); - } - - public void releaseWeakAccess() { - this.wa.release(); - } - - public void allocateStrongAccess() throws InterruptedException { - this.sa.allocate(); - } - - public void acquireStrongAccess() throws InterruptedException { - this.sa.lockInterruptibly(); - } - - public void releaseStrongAccess() { - this.sa.unlock(); - } - - public static final void acceptWeakAccessObserver(final Observer o) { - instance.wa.acceptObserver(o); - } - - public static final void acceptStrongAccessObserver(final Observer o) { - instance.sa.acceptObserver(o); - } - - public static int waitingAllocateStrongAccess() { - return instance.sa.waitingAllocateAccess(); - } - - public static int waitingAcquireWeakAccess() { - return instance.wa.waitingAquireAccess(); - } - - public static int acquiredWeakAccess() { - return instance.wa.acquiredAccess(); - } - - public static Thread whoHasAllocatedStrongAccess() { - return instance.sa.whoHasAllocatedAccess(); - } - - public static Thread whoHasAcquiredStrongAccess() { - return instance.sa.whoHasAcquiredAccess(); - } - - public Access acquiredWeakAccess(final TransactionInterface t) { - acquiredWeakAccess(); - return new TransactionAccess(t, this.wa); - } - - public Access allocateStrongAccess(final WriteTransactionInterface wt) - throws InterruptedException { - allocateStrongAccess(); - return new TransactionAccess(wt, this.sa); - } - - public Access acquireStrongAccess(final WriteTransactionInterface wt) - throws InterruptedException { - acquireStrongAccess(); - return wt.getAccess(); - } - - public static Access getInfoAccess(final Info i) { - return new InfoAccess(i); - } - - public static Access getInitAccess(final Initialization initialization) { - return new InitAccess(initialization); - } - - public static Access getAccountAccess(final AccessControlTransaction t) { - return new AccessControlAccess(t); - } -} diff --git a/src/main/java/org/caosdb/server/terminal/CaosDBTerminal.java b/src/main/java/org/caosdb/server/terminal/CaosDBTerminal.java deleted file mode 100644 index 96bd6315b7e32c03273a8b65bd489bfc061e0ef1..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/CaosDBTerminal.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.TerminalFacade; -import com.googlecode.lanterna.gui.GUIScreen; -import com.googlecode.lanterna.gui.GUIScreen.Position; -import com.googlecode.lanterna.screen.Screen; -import com.googlecode.lanterna.terminal.Terminal; -import com.googlecode.lanterna.terminal.text.UnixTerminal; -import java.nio.charset.Charset; - -/** - * @deprecated Soon to be removed - * @author Timm Fitschen (t.fitschen@indiscale.com) - */ -@Deprecated -public class CaosDBTerminal extends Thread { - - public CaosDBTerminal() { - if ((this.terminal = - TerminalFacade.createTerminal(System.in, System.out, Charset.forName("UTF8"))) - instanceof UnixTerminal) { - this.terminal = - new UnixTerminal( - System.in, - System.out, - Charset.forName("UTF8"), - null, - UnixTerminal.Behaviour.CTRL_C_KILLS_APPLICATION); - } - this.screen = new Screen(this.terminal); - this.guiScreen = new GUIScreen(this.screen); - } - - private Terminal terminal = null; - private Screen screen = null; - private GUIScreen guiScreen = null; - - @Override - public void run() { - this.guiScreen.getScreen().startScreen(); - final MainWindow m = new MainWindow(); - - this.guiScreen.showWindow(m, Position.FULL_SCREEN); - this.guiScreen.getScreen().stopScreen(); - } - - public void shutDown() { - this.guiScreen.getActiveWindow().close(); - } -} diff --git a/src/main/java/org/caosdb/server/terminal/DatabaseAccessPanel.java b/src/main/java/org/caosdb/server/terminal/DatabaseAccessPanel.java deleted file mode 100644 index 6877049605888682bd003f8382a931661e79602c..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/DatabaseAccessPanel.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.component.Label; -import com.googlecode.lanterna.gui.component.Panel; -import com.googlecode.lanterna.gui.component.Table; -import org.caosdb.server.database.DatabaseMonitor; -import org.caosdb.server.utils.Observable; -import org.caosdb.server.utils.Observer; - -public final class DatabaseAccessPanel extends Panel implements Observer { - - private static final DatabaseAccessPanel instance = new DatabaseAccessPanel(); - private final Table table = new Table(2); - private final Label label1 = new Label(); - private final Label label2 = new Label(); - private final Label label3 = new Label(); - private final Label label4 = new Label(); - private final Label label5 = new Label(); - - public static final DatabaseAccessPanel getInstance() { - return instance; - } - - private DatabaseAccessPanel() { - super(); - DatabaseMonitor.acceptWeakAccessObserver(this); - DatabaseMonitor.acceptStrongAccessObserver(this); - - this.table.addRow(new Label("Weak access, acquired:"), this.label1); - this.table.addRow(new Label("Weak access, waiting:"), this.label2); - this.table.addRow(new Label("Strong access, allocated:"), this.label3); - this.table.addRow(new Label("Strong access, acquired:"), this.label4); - this.table.addRow(new Label("Strong access, waiting:"), this.label5); - addComponent(this.table); - - notifyObserver(null, null); - } - - @Override - public boolean notifyObserver(final String e, final Observable o) { - try { - synchronized (this) { - if (getParent() != null) { - this.label1.setText(Integer.toString(DatabaseMonitor.acquiredWeakAccess())); - this.label2.setText(Integer.toString(DatabaseMonitor.waitingAcquireWeakAccess())); - this.label3.setText( - DatabaseMonitor.whoHasAllocatedStrongAccess() != null - ? DatabaseMonitor.whoHasAllocatedStrongAccess().getName() - : "None"); - this.label4.setText( - DatabaseMonitor.whoHasAcquiredStrongAccess() != null - ? DatabaseMonitor.whoHasAcquiredStrongAccess().getName() - : "None"); - this.label5.setText(Integer.toString(DatabaseMonitor.waitingAllocateStrongAccess())); - } - } - } catch (final Exception exc) { - exc.printStackTrace(); - } - return true; - } -} diff --git a/src/main/java/org/caosdb/server/terminal/EntitiesPanel.java b/src/main/java/org/caosdb/server/terminal/EntitiesPanel.java deleted file mode 100644 index b2f7489de66eeae9771e911b45e7d4546cb4f5b9..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/EntitiesPanel.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.component.Label; -import com.googlecode.lanterna.gui.component.Panel; -import com.googlecode.lanterna.gui.component.Table; -import org.caosdb.server.utils.Info; - -public final class EntitiesPanel extends Panel implements StatComponent { - - private static final EntitiesPanel instance = new EntitiesPanel(); - private boolean active = false; - private final Table table = new Table(2); - private final Label label1 = new Label(); - private final Label label2 = new Label(); - private final Label label3 = new Label(); - private final Label label4 = new Label(); - - public static final EntitiesPanel getInstance() { - return instance; - } - - private EntitiesPanel() { - super(); - - this.table.addRow(new Label("RecordTypes:"), this.label2); - this.table.addRow(new Label("Properties:"), this.label3); - this.table.addRow(new Label("Records:"), this.label4); - this.table.addRow(new Label("Files:"), this.label1); - addComponent(this.table); - - // init INFO - Info.getInstance().notifyObserver(null, null); - - // adds itself to StatsPanel - StatsPanel.addStat("Entities", this); - start(); - } - - @Override - public void start() { - this.active = true; - update(); - } - - @Override - public void stop() { - this.active = false; - } - - @Override - public void update() { - if (this.active) { - try { - this.label1.setText(Info.getFilesCount().toString()); - this.label2.setText(Info.getRecordTypesCount().toString()); - this.label3.setText(Info.getPropertiesCount().toString()); - this.label4.setText(Info.getRecordsCount().toString()); - } catch (final Exception e) { - e.printStackTrace(); - } - } - } -} diff --git a/src/main/java/org/caosdb/server/terminal/MainWindow.java b/src/main/java/org/caosdb/server/terminal/MainWindow.java deleted file mode 100644 index aa22f12b23bed00dfb46db8c7cd140fb05551eec..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/MainWindow.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.Action; -import com.googlecode.lanterna.gui.Border; -import com.googlecode.lanterna.gui.Window; -import com.googlecode.lanterna.gui.component.Button; -import com.googlecode.lanterna.gui.component.Label; -import com.googlecode.lanterna.gui.component.Panel; -import com.googlecode.lanterna.gui.dialog.DialogButtons; -import com.googlecode.lanterna.gui.dialog.DialogResult; -import com.googlecode.lanterna.gui.dialog.MessageBox; -import com.googlecode.lanterna.gui.layout.LinearLayout; -import com.googlecode.lanterna.input.Key; -import com.googlecode.lanterna.input.Key.Kind; -import org.caosdb.server.utils.Observer; - -public class MainWindow extends Window { - - // A panel at the top of the window which contains buttons to switch - // between several data panels which are to be shown in the dataPanel. - final Panel dataSelectorPanel = new Panel(new Border.Invisible(), Panel.Orientation.HORISONTAL); - - // A panel right below the dataSelectorPanel. Here the interesting - // data is to be show. The contained panels can be made visible or - // invisible via the buttons in the dataSelectorPanel. - final Panel dataPanel = new Panel(new Border.Bevel(true), Panel.Orientation.HORISONTAL); - - public final synchronized void setVisibleDataPanel(final Panel visibleDataPanel) { - this.dataPanel.removeAllComponents(); - this.dataPanel.addComponent(visibleDataPanel); - } - - public MainWindow() { - super("Caos DB"); - addComponent(this.dataSelectorPanel, LinearLayout.MAXIMIZES_HORIZONTALLY); - addComponent( - this.dataPanel, LinearLayout.MAXIMIZES_HORIZONTALLY, LinearLayout.MAXIMIZES_VERTICALLY); - - // initializing stream output panels. These pipe the output of - // System.out and System.err to a TextArea. - final SystemOutPanel systemOutPanel = SystemOutPanel.getInstance(); - final Thread systemOutThread = new Thread(systemOutPanel); - systemOutThread.setName("systemOutPanel"); - - final SystemErrPanel systemErrPanel = SystemErrPanel.getInstance(); - final Thread systemErrThread = new Thread(systemErrPanel); - systemErrThread.setName("systemErrPanel"); - - systemOutThread.start(); - systemErrThread.start(); - - // initializing DatabaseAccessPanel that shows which thread is accessing - // the database and how many threads are waiting for access. - final DatabaseAccessPanel databaseAccessPanel = DatabaseAccessPanel.getInstance(); - - // init StatsPanel - StatsPanel.getPanel(); - - // init entities stats - EntitiesPanel.getInstance(); - - // add all initialized panels to the main window - addDataPanel("System.out", systemOutPanel); - addDataPanel("System.err", systemErrPanel); - addDataPanel("DB Access", databaseAccessPanel); - addDataPanel("Misc", StatsPanel.getPanel()); - - // add a welcome panel - this.dataPanel.addComponent( - new Label("Welcome. This is CaosDB - An Open Scientific DataBase.")); - - // add shutdown button - this.dataSelectorPanel.addComponent(new ShutdownButton()); - - // set focus on the dataSelectorPanel - setFocus(this.dataSelectorPanel.nextFocus(null)); - } - - /** - * Add a panel to the dataPanel. A button is created within the dataSelectorPanel which shows the - * name of the panel - * - * @param name - * @param dataPanel - */ - private void addDataPanel(final String name, final Panel dataPanel) { - this.dataSelectorPanel.addComponent(new DataPanelSelectorButton(name, dataPanel)); - } - - /** - * A Button that causes the dataPanel to show a certain panel. - * - * @author tf - */ - class DataPanelSelectorButton extends Button { - public DataPanelSelectorButton(final String name, final Panel panel) { - super( - name, - new Action() { - - @Override - public void doAction() { - // show panel in dataPanel - setVisibleDataPanel(panel); - - // update panel if necessary - if (panel instanceof Observer) { - ((Observer) panel).notifyObserver(null, null); - } - - // move focus to panel - setFocus(panel.nextFocus(null)); - } - }); - } - } - - @Override - public void onKeyPressed(final Key key) { - if (key.getKind() == Kind.Escape) { - setFocus(this.dataSelectorPanel.nextFocus(null)); - } else { - super.onKeyPressed(key); - } - } - - /** - * A button that causes the server to shut down when pressed. - * - * @author tf - */ - class ShutdownButton extends Button { - public ShutdownButton() { - super( - "Shutdown Server", - new Action() { - @Override - public void doAction() { - final DialogResult result = - MessageBox.showMessageBox( - getOwner(), - "Server shutdown", - "Select [OK] to shut down the server now.", - DialogButtons.OK_CANCEL); - if (result == DialogResult.OK) { - System.exit(0); - } - } - }); - } - } -} diff --git a/src/main/java/org/caosdb/server/terminal/OutputStreamPanel.java b/src/main/java/org/caosdb/server/terminal/OutputStreamPanel.java deleted file mode 100644 index 50284f8a88e7d30596cc901be24108f3ea201d0a..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/OutputStreamPanel.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.Action; -import com.googlecode.lanterna.gui.component.Button; -import com.googlecode.lanterna.gui.component.Panel; -import com.googlecode.lanterna.gui.component.TextArea; -import com.googlecode.lanterna.gui.layout.LinearLayout; -import com.googlecode.lanterna.input.Key; -import com.googlecode.lanterna.input.Key.Kind; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.PrintStream; - -class PipedPrintStream extends PrintStream { - private final TextArea out; - int lines = 0; - - public PipedPrintStream(final TextArea out) { - super(new NullOutputStream()); - this.out = out; - } - - @Override - public void println(final String x) { - if (open) { - synchronized (this) { - out.appendLine(x); - if (lines >= 4000) { - out.removeLine(0); - } else { - lines++; - } - } - } - } - - @Override - public void print(final String x) {} - - private final boolean open = false; -} - -class NullOutputStream extends OutputStream { - - @Override - public void write(final int b) throws IOException {} -} - -public abstract class OutputStreamPanel extends Panel implements Runnable { - - private final TextArea logArea = new TextArea(); - private BufferedReader reader = null; - protected final PipedOutputStream panelOutputStream = new PipedOutputStream(); - - protected final PipedOutputStream getPanelOutputStream() { - return panelOutputStream; - } - - Button toogle = - new Button( - "on/off", - new Action() { - - @Override - public void doAction() { - toogle(); - } - }); - - private boolean on = true; - - void toogle() { - on = !on; - } - - public OutputStreamPanel() { - super(); - // addComponent(toogle); - addComponent(logArea, LinearLayout.MAXIMIZES_HORIZONTALLY, LinearLayout.MAXIMIZES_VERTICALLY); - } - - protected void init() throws IOException { - final PipedInputStream pIn = new PipedInputStream(panelOutputStream); - reader = new BufferedReader(new InputStreamReader(pIn)); - } - - @Override - public final void run() { - int lines = 0; - while (true) { - while (on) { - try { - if (reader.ready()) { - logArea.appendLine(reader.readLine()); - if (lines >= 4000) { - logArea.removeLine(0); - } else { - lines++; - } - try { - logArea.keyboardInteraction(new Key(Kind.End)); - } catch (final NullPointerException e) { - // this usually happens when the logArea is updated - // but - // not painted (while not being an active panel) - } - } else { - Thread.sleep(1000); - } - - } catch (final Exception e2) { - e2.printStackTrace(); - } - } - } - } - - @Override - protected void finalize() throws Throwable { - if (reader != null) { - reader.close(); - } - super.finalize(); - } -} diff --git a/src/main/java/org/caosdb/server/terminal/StatComponent.java b/src/main/java/org/caosdb/server/terminal/StatComponent.java deleted file mode 100644 index 90a9ac1125425bd23415abf3e4186f00695b9b2f..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/StatComponent.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.Component; - -public interface StatComponent extends Component { - - public void start(); - - public void stop(); - - public void update(); -} diff --git a/src/main/java/org/caosdb/server/terminal/StatLabel.java b/src/main/java/org/caosdb/server/terminal/StatLabel.java deleted file mode 100644 index 73a03ac31ed8874fc936807393701995130eaf7f..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/StatLabel.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.component.Label; -import org.caosdb.server.utils.Observable; -import org.caosdb.server.utils.Observer; - -public class StatLabel extends Label implements Observer, StatComponent { - - boolean active = false; - Object obj; - String name; - - @Override - public boolean notifyObserver(final String e, final Observable o) { - update(); - return true; - } - - public StatLabel(final Object obj) { - this(null, obj); - } - - public StatLabel(final String name, final Object obj) { - this.name = name; - this.obj = obj; - if (obj instanceof Observable) { - ((Observable) obj).acceptObserver(this); - } - start(); - update(); - } - - @Override - public void stop() { - this.active = false; - } - - @Override - public void start() { - this.active = true; - } - - @Override - public void update() { - if (this.active) { - setText((this.name == null ? "" : this.name + ": ") + this.obj.toString()); - } - } -} diff --git a/src/main/java/org/caosdb/server/terminal/StatTable.java b/src/main/java/org/caosdb/server/terminal/StatTable.java deleted file mode 100644 index e7234cdb8000a7c4dcc98463c3e9ca6cc8c9f19c..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/StatTable.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.Component; -import com.googlecode.lanterna.gui.component.Panel; - -public class StatTable extends Panel implements StatComponent { - - @Override - public void start() { - for (final Component c : components()) { - if (c instanceof StatComponent) { - ((StatComponent) c).start(); - } - } - } - - @Override - public void stop() { - for (final Component c : components()) { - if (c instanceof StatComponent) { - ((StatComponent) c).stop(); - } - } - } - - @Override - public void update() { - for (final Component c : components()) { - if (c instanceof StatComponent) { - ((StatComponent) c).update(); - } - } - } -} diff --git a/src/main/java/org/caosdb/server/terminal/StatsPanel.java b/src/main/java/org/caosdb/server/terminal/StatsPanel.java deleted file mode 100644 index 3b41ac6a9c4ae7366e85cffedbd71f83b30c6438..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/StatsPanel.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.Action; -import com.googlecode.lanterna.gui.Border; -import com.googlecode.lanterna.gui.component.Button; -import com.googlecode.lanterna.gui.component.Panel; -import com.googlecode.lanterna.gui.layout.LinearLayout; -import java.util.HashMap; - -public class StatsPanel extends Panel { - - private static StatsPanel instance = null; - - HashMap<String, StatTable> stats = new HashMap<String, StatTable>(); - Panel dataPanel = new Panel("Data", new Border.Bevel(true), Panel.Orientation.VERTICAL); - Panel selectorPanel = new Panel("Selector", new Border.Bevel(true), Panel.Orientation.VERTICAL); - StatComponent current = null; - - private StatsPanel() { - super(Panel.Orientation.HORISONTAL); - addComponent(this.selectorPanel, LinearLayout.MAXIMIZES_VERTICALLY); - addComponent( - this.dataPanel, LinearLayout.MAXIMIZES_VERTICALLY, LinearLayout.MAXIMIZES_HORIZONTALLY); - } - - public static void addStat(final String name, final Object obj) { - if (instance != null) { - instance.addStatComponent(name, new StatLabel(obj)); - } - } - - public static void addStat(final String name, final StatComponent statComponent) { - if (instance != null) { - instance.addStatComponent(name, statComponent); - } - } - - private void addStatComponent(final String name, final StatComponent statComponent) { - final StatTable c = this.stats.get(name); - if (c != null) { - c.addComponent(statComponent); - } else { - final StatTable table = new StatTable(); - table.addComponent(statComponent); - this.selectorPanel.addComponent(new SelectorButton(name, table)); - this.stats.put(name, table); - } - } - - private void setVisibleDataPanel(final StatComponent panel) { - this.dataPanel.removeAllComponents(); - - if (this.current != null) { - this.current.stop(); - } - this.current = panel; - this.current.start(); - this.current.update(); - - this.dataPanel.addComponent(this.current); - } - - class SelectorButton extends Button { - public SelectorButton(final String name, final StatComponent panel) { - super( - name, - new Action() { - - @Override - public void doAction() { - // show panel in dataPanel - setVisibleDataPanel(panel); - } - }); - } - } - - public static Panel getPanel() { - if (instance == null) { - instance = new StatsPanel(); - } - return instance; - } -} diff --git a/src/main/java/org/caosdb/server/terminal/SystemErrPanel.java b/src/main/java/org/caosdb/server/terminal/SystemErrPanel.java deleted file mode 100644 index 9bf800fdb3c755cd8ea2b2a55119cf4e093fde09..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/SystemErrPanel.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.component.Label; -import java.io.IOException; -import java.io.PrintStream; - -public final class SystemErrPanel extends OutputStreamPanel { - - private static final SystemErrPanel instance = new SystemErrPanel(); - private PrintStream err; - - public static final SystemErrPanel getInstance() { - return instance; - } - - private SystemErrPanel() { - super(); - try { - init(); - this.err = System.err; - final PrintStream newErr = new PrintStream(getPanelOutputStream()); - System.setErr(newErr); - } catch (final IOException e) { - addComponent(new Label("Sorry, could not initialize this SystemErrPanel")); - } - } - - public static void close() { - System.setErr(instance.err); - } -} diff --git a/src/main/java/org/caosdb/server/terminal/SystemOutPanel.java b/src/main/java/org/caosdb/server/terminal/SystemOutPanel.java deleted file mode 100644 index b34cdaf97d8088a97ea66932d9abc96d6e1589be..0000000000000000000000000000000000000000 --- a/src/main/java/org/caosdb/server/terminal/SystemOutPanel.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the CaosDB Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -package org.caosdb.server.terminal; - -import com.googlecode.lanterna.gui.component.Label; -import java.io.IOException; -import java.io.PrintStream; - -public final class SystemOutPanel extends OutputStreamPanel { - - private static final SystemOutPanel instance = new SystemOutPanel(); - - public static final SystemOutPanel getInstance() { - return instance; - } - - private SystemOutPanel() { - super(); - try { - init(); - System.setOut(new PrintStream(getPanelOutputStream())); - } catch (final IOException e) { - addComponent(new Label("Sorry, could not initialize this SystemOutPanel")); - } - } -} diff --git a/src/main/java/org/caosdb/server/transaction/AccessControlTransaction.java b/src/main/java/org/caosdb/server/transaction/AccessControlTransaction.java index 0a2d1363427d9e21504b421c88e7605af59634ac..4897cd65620577e36a98f2db5e5530a42b3f43d0 100644 --- a/src/main/java/org/caosdb/server/transaction/AccessControlTransaction.java +++ b/src/main/java/org/caosdb/server/transaction/AccessControlTransaction.java @@ -22,7 +22,7 @@ */ package org.caosdb.server.transaction; -import org.caosdb.server.database.DatabaseMonitor; +import org.caosdb.server.database.DatabaseAccessManager; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.misc.RollBackHandler; import org.caosdb.server.entity.Message; @@ -33,7 +33,7 @@ public abstract class AccessControlTransaction implements TransactionInterface { @Override public final void execute() throws Exception { - this.access = DatabaseMonitor.getAccountAccess(this); + this.access = DatabaseAccessManager.getAccountAccess(this); try { transaction(); diff --git a/src/main/java/org/caosdb/server/transaction/ChecksumUpdater.java b/src/main/java/org/caosdb/server/transaction/ChecksumUpdater.java index 53f7b58af3e5ac8763085aede75cf64ed8a7cae5..56fc07da22d9fac5bfbe713d1a9cd36b2d25a9ba 100644 --- a/src/main/java/org/caosdb/server/transaction/ChecksumUpdater.java +++ b/src/main/java/org/caosdb/server/transaction/ChecksumUpdater.java @@ -25,7 +25,7 @@ package org.caosdb.server.transaction; import java.io.IOException; import java.security.NoSuchAlgorithmException; import org.caosdb.server.CaosDBException; -import org.caosdb.server.database.DatabaseMonitor; +import org.caosdb.server.database.DatabaseAccessManager; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.transaction.GetUpdateableChecksums; import org.caosdb.server.database.backend.transaction.RetrieveSparseEntity; @@ -77,14 +77,14 @@ public class ChecksumUpdater extends WriteTransaction Access strongAccess = null; try { - strongAccess = DatabaseMonitor.getInstance().allocateStrongAccess(this); + strongAccess = DatabaseAccessManager.getInstance().reserveWriteAccess(this); if (wasChangedInTheMeantime(fileEntity, strongAccess, lastModified)) { continue; } fileEntity.getFileProperties().setChecksum(checksum); - DatabaseMonitor.getInstance().acquireStrongAccess(this); + DatabaseAccessManager.getInstance().acquireWriteAccess(this); // update execute(new SetFileChecksum(fileEntity), strongAccess); @@ -131,8 +131,8 @@ public class ChecksumUpdater extends WriteTransaction return null; } - private EntityInterface getNextUpdateableFileEntity() { - final Access weakAccess = DatabaseMonitor.getInstance().acquiredWeakAccess(this); + private EntityInterface getNextUpdateableFileEntity() throws InterruptedException { + final Access weakAccess = DatabaseAccessManager.getInstance().acquireReadAccess(this); try { synchronized (instance.running) { diff --git a/src/main/java/org/caosdb/server/transaction/FileStorageConsistencyCheck.java b/src/main/java/org/caosdb/server/transaction/FileStorageConsistencyCheck.java index 5d2a04b1e9f45360f47a93889f638eab23fbd512..ed93812d22eaad6bf448fa1dede2d92cea1d50a6 100644 --- a/src/main/java/org/caosdb/server/transaction/FileStorageConsistencyCheck.java +++ b/src/main/java/org/caosdb/server/transaction/FileStorageConsistencyCheck.java @@ -29,7 +29,7 @@ import java.util.List; import java.util.Map.Entry; import java.util.TimeZone; import org.caosdb.datetime.UTCDateTime; -import org.caosdb.server.database.DatabaseMonitor; +import org.caosdb.server.database.DatabaseAccessManager; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.transaction.FileConsistencyCheck; import org.caosdb.server.database.backend.transaction.GetFileIterator; @@ -64,8 +64,8 @@ public class FileStorageConsistencyCheck extends Thread @Override public void run() { - this.access = DatabaseMonitor.getInstance().acquiredWeakAccess(this); try { + this.access = DatabaseAccessManager.getInstance().acquireReadAccess(this); // test all files in file system. final Iterator<String> iterator = @@ -73,12 +73,12 @@ public class FileStorageConsistencyCheck extends Thread this.ts = System.currentTimeMillis(); while (iterator != null && iterator.hasNext()) { - if (DatabaseMonitor.whoHasAllocatedStrongAccess() != null) { + if (DatabaseAccessManager.whoHasReservedWriteAccess() != null) { // there is a thread waiting to write. pause this one and // apply for a new weak access which will be granted when // the write thread is ready. this.access.release(); - this.access = DatabaseMonitor.getInstance().acquiredWeakAccess(this); + this.access = DatabaseAccessManager.getInstance().acquireReadAccess(this); } final String path = iterator.next(); diff --git a/src/main/java/org/caosdb/server/transaction/InsertLogRecordTransaction.java b/src/main/java/org/caosdb/server/transaction/InsertLogRecordTransaction.java index be01d93086e65694313c0d97c6b1603aef6a6bc7..c1128135b8620ebfe08328cd4901e9c0e6062053 100644 --- a/src/main/java/org/caosdb/server/transaction/InsertLogRecordTransaction.java +++ b/src/main/java/org/caosdb/server/transaction/InsertLogRecordTransaction.java @@ -24,7 +24,7 @@ package org.caosdb.server.transaction; import java.util.List; import java.util.logging.LogRecord; -import org.caosdb.server.database.DatabaseMonitor; +import org.caosdb.server.database.DatabaseAccessManager; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.transaction.InsertLogRecord; @@ -38,7 +38,7 @@ public class InsertLogRecordTransaction implements TransactionInterface { @Override public void execute() throws Exception { - final Access access = DatabaseMonitor.getInstance().acquiredWeakAccess(this); + final Access access = DatabaseAccessManager.getInstance().acquireReadAccess(this); try { execute(new InsertLogRecord(this.toBeFlushed), access); } finally { diff --git a/src/main/java/org/caosdb/server/transaction/Retrieve.java b/src/main/java/org/caosdb/server/transaction/Retrieve.java index b54d7aedbdda1e1cf3fd1577de90a2182d9ede40..fd7bae8a82e95554d527135f76124d397c23f0c4 100644 --- a/src/main/java/org/caosdb/server/transaction/Retrieve.java +++ b/src/main/java/org/caosdb/server/transaction/Retrieve.java @@ -47,7 +47,7 @@ public class Retrieve extends Transaction<RetrieveContainer> { @Override protected void init() throws Exception { // acquire weak access - setAccess(getMonitor().acquiredWeakAccess(this)); + setAccess(getAccessManager().acquireReadAccess(this)); // resolve names final ResolveNames r = new ResolveNames(); diff --git a/src/main/java/org/caosdb/server/transaction/RetrieveLogRecordTransaction.java b/src/main/java/org/caosdb/server/transaction/RetrieveLogRecordTransaction.java index 49d850dbcb672767da33a7c855063b04e1099f29..7e6c527865566795c397377409b1fc63020ca1dd 100644 --- a/src/main/java/org/caosdb/server/transaction/RetrieveLogRecordTransaction.java +++ b/src/main/java/org/caosdb/server/transaction/RetrieveLogRecordTransaction.java @@ -27,7 +27,7 @@ import java.util.logging.Level; import java.util.logging.LogRecord; import org.apache.shiro.SecurityUtils; import org.caosdb.server.accessControl.ACMPermissions; -import org.caosdb.server.database.DatabaseMonitor; +import org.caosdb.server.database.DatabaseAccessManager; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.transaction.RetrieveLogRecord; @@ -60,7 +60,7 @@ public class RetrieveLogRecordTransaction implements TransactionInterface { @Override public void execute() throws Exception { SecurityUtils.getSubject().checkPermission(ACMPermissions.PERMISSION_RETRIEVE_SERVERLOGS); - final Access access = DatabaseMonitor.getInstance().acquiredWeakAccess(this); + final Access access = DatabaseAccessManager.getInstance().acquireReadAccess(this); try { this.logRecords = execute(new RetrieveLogRecord(this.logger, this.level, this.message), access) diff --git a/src/main/java/org/caosdb/server/transaction/RetrieveSparseEntityByPath.java b/src/main/java/org/caosdb/server/transaction/RetrieveSparseEntityByPath.java index d82985fe8060b3919d48c17a6bbd2994fc92c5bf..520787105388d8f1408c2d3b05090c761c8f687c 100644 --- a/src/main/java/org/caosdb/server/transaction/RetrieveSparseEntityByPath.java +++ b/src/main/java/org/caosdb/server/transaction/RetrieveSparseEntityByPath.java @@ -41,7 +41,7 @@ public class RetrieveSparseEntityByPath extends Transaction<TransactionContainer @Override protected void init() throws Exception { // acquire weak access - setAccess(getMonitor().acquiredWeakAccess(this)); + setAccess(getAccessManager().acquireReadAccess(this)); } @Override diff --git a/src/main/java/org/caosdb/server/transaction/Transaction.java b/src/main/java/org/caosdb/server/transaction/Transaction.java index 58db7911ceb86a68f949bafe89853f581b4f3291..c2bd7e0feb62fa31dadd5580990350b829ff4591 100644 --- a/src/main/java/org/caosdb/server/transaction/Transaction.java +++ b/src/main/java/org/caosdb/server/transaction/Transaction.java @@ -29,7 +29,7 @@ import java.util.List; import org.apache.shiro.subject.Subject; import org.caosdb.datetime.UTCDateTime; import org.caosdb.server.accessControl.Principal; -import org.caosdb.server.database.DatabaseMonitor; +import org.caosdb.server.database.DatabaseAccessManager; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.transaction.InsertTransactionHistory; import org.caosdb.server.database.exceptions.TransactionException; @@ -61,7 +61,7 @@ public abstract class Transaction<C extends TransactionContainer> extends Abstra return getContainer().getTransactionBenchmark(); } - private static final DatabaseMonitor monitor = DatabaseMonitor.getInstance(); + private static final DatabaseAccessManager monitor = DatabaseAccessManager.getInstance(); public static final String CLEAN_UP = "TransactionCleanUp"; private final C container; @@ -77,7 +77,7 @@ public abstract class Transaction<C extends TransactionContainer> extends Abstra if (o != null) acceptObserver(o); } - public static DatabaseMonitor getMonitor() { + public static DatabaseAccessManager getAccessManager() { return monitor; } diff --git a/src/main/java/org/caosdb/server/transaction/WriteTransaction.java b/src/main/java/org/caosdb/server/transaction/WriteTransaction.java index 86255f217c026f93c3023e3ec3074b35cdc916a0..2a43e71074318cddec0d4e503a48b2380588cc30 100644 --- a/src/main/java/org/caosdb/server/transaction/WriteTransaction.java +++ b/src/main/java/org/caosdb/server/transaction/WriteTransaction.java @@ -65,7 +65,7 @@ public class WriteTransaction extends Transaction<WritableContainer> protected final void preTransaction() throws InterruptedException { // acquire strong access. No other thread can have access until // it this strong access is released. - setAccess(getMonitor().acquireStrongAccess(this)); + setAccess(getAccessManager().acquireWriteAccess(this)); } @Override @@ -139,7 +139,7 @@ public class WriteTransaction extends Transaction<WritableContainer> // at a time. But weak access can still be acquired by other // thread until the allocated strong access is actually // acquired. - setAccess(getMonitor().allocateStrongAccess(this)); + setAccess(getAccessManager().reserveWriteAccess(this)); // retrieve a container which contains all id of those entities // which are to be updated. diff --git a/src/main/java/org/caosdb/server/utils/Info.java b/src/main/java/org/caosdb/server/utils/Info.java index 19f792cf625765924f02a7b734f2e57849584ffc..18ee09828006c0394dec315ca77483f8298ba86b 100644 --- a/src/main/java/org/caosdb/server/utils/Info.java +++ b/src/main/java/org/caosdb/server/utils/Info.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.caosdb.server.CaosDBServer; import org.caosdb.server.FileSystem; -import org.caosdb.server.database.DatabaseMonitor; +import org.caosdb.server.database.DatabaseAccessManager; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.transaction.GetInfo; import org.caosdb.server.database.backend.transaction.SyncStats; @@ -58,7 +58,7 @@ public class Info extends AbstractObservable implements Observer, TransactionInt } private Info() { - this.access = DatabaseMonitor.getInfoAccess(this); + this.access = DatabaseAccessManager.getInfoAccess(this); try { syncDatabase(); } catch (final Exception exc) { diff --git a/src/main/java/org/caosdb/server/utils/Initialization.java b/src/main/java/org/caosdb/server/utils/Initialization.java index baae53804f57433aa58da1ae1b9c58060c3db160..cb1a36307928a72b9da95b48737196e569c43346 100644 --- a/src/main/java/org/caosdb/server/utils/Initialization.java +++ b/src/main/java/org/caosdb/server/utils/Initialization.java @@ -24,7 +24,7 @@ */ package org.caosdb.server.utils; -import org.caosdb.server.database.DatabaseMonitor; +import org.caosdb.server.database.DatabaseAccessManager; import org.caosdb.server.database.access.Access; import org.caosdb.server.transaction.TransactionInterface; @@ -34,7 +34,7 @@ public final class Initialization implements TransactionInterface, AutoCloseable private static final Initialization instance = new Initialization(); private Initialization() { - this.access = DatabaseMonitor.getInitAccess(this); + this.access = DatabaseAccessManager.getInitAccess(this); } public static final Initialization setUp() { diff --git a/src/test/java/org/caosdb/server/database/DatabaseMonitorTest.java b/src/test/java/org/caosdb/server/database/DatabaseAccessManagerTest.java similarity index 74% rename from src/test/java/org/caosdb/server/database/DatabaseMonitorTest.java rename to src/test/java/org/caosdb/server/database/DatabaseAccessManagerTest.java index 554baec079ed17d332dff47f0afb57405913dc33..a53b1825113aa7d757033b2f6e0b0a241dafad86 100644 --- a/src/test/java/org/caosdb/server/database/DatabaseMonitorTest.java +++ b/src/test/java/org/caosdb/server/database/DatabaseAccessManagerTest.java @@ -25,18 +25,18 @@ package org.caosdb.server.database; import org.junit.Assert; import org.junit.Test; -public class DatabaseMonitorTest { - public static final WeakAccessSemaphore wa = new WeakAccessSemaphore(); - public static final StrongAccessLock sa = new StrongAccessLock(wa); +public class DatabaseAccessManagerTest { + public static final ReadAccessSemaphore readAccess = new ReadAccessSemaphore(); + public static final WriteAccessLock writeAccess = new WriteAccessLock(readAccess); /** - * Two read-, two write-threads. The read-threads request weak access, the write-threads request - * strong access.<br> - * The read-thread rt1 is started and gets weak access. Then the write-thread wt1 starts and - * allocates strong access.<br> - * A second read-thread rt2 starts and also gets weak access. A second write thread wt2 starts and - * requests allocation of strong access. It has to wait until wt2 releases it. <br> - * wt1 acquires strong access as soon as both read-threads released their weak-accesss.<br> + * Two read-, two write-threads. The read-threads request read access, the write-threads request + * write access.<br> + * The read-thread rt1 is started and gets read access. Then the write-thread wt1 starts and + * reserves write access.<br> + * A second read-thread rt2 starts and also gets read access. A second write thread wt2 starts and + * requests allocation of write access. It has to wait until wt2 releases it. <br> + * wt1 acquires write access as soon as both read-threads released their read-accesss.<br> * * @throws InterruptedException */ @@ -44,11 +44,11 @@ public class DatabaseMonitorTest { public void test1() throws InterruptedException { // first invoke a read thread final ReadThread rt1 = new ReadThread(); - rt1.start(); // paused, has acquired weak access now + rt1.start(); // paused, has acquired read access now // invoke a write thread final WriteThread wt1 = new WriteThread(); - wt1.start(); // paused, has allocated strong access now + wt1.start(); // paused, has reserved write access now synchronized (this) { this.wait(1000); } @@ -56,7 +56,7 @@ public class DatabaseMonitorTest { Assert.assertEquals(wt1.getState(), Thread.State.WAITING); final ReadThread rt2 = new ReadThread(); - rt2.start(); // paused, has acquired a second weak access now + rt2.start(); // paused, has acquired a second read access now synchronized (this) { this.wait(1000); } @@ -67,19 +67,19 @@ public class DatabaseMonitorTest { this.wait(1000); } - // rt2 was processed while wt1 has allocated but not yet acquired strong - // access. rt2 terminated after releasing its weak access. + // rt2 was processed while wt1 has reserved but not yet acquired write + // access. rt2 terminated after releasing its read access. Assert.assertEquals(rt2.getState(), Thread.State.TERMINATED); final WriteThread wt2 = new WriteThread(); - wt2.start(); // wt2 immediatelly allocates strong access and is block + wt2.start(); // wt2 immediatelly reserves write access and is block // since wt1 already yields it. synchronized (this) { this.wait(1000); } - // Assert.assertEquals(wt2.getState(), Thread.State.BLOCKED); + Assert.assertEquals(wt2.getState(), Thread.State.BLOCKED); - // wt1 request strong access. + // wt1 request write access. synchronized (wt1) { wt1.notify(); } @@ -94,8 +94,8 @@ public class DatabaseMonitorTest { synchronized (this) { this.wait(1000); } - // rt1 was notified an terminated, releasing the weak acccess. - // so wt1 acquires strong access and pauses the second time. + // rt1 was notified an terminated, releasing the read acccess. + // so wt1 acquires write access and pauses the second time. Assert.assertEquals(rt1.getState(), Thread.State.TERMINATED); synchronized (wt1) { @@ -104,11 +104,11 @@ public class DatabaseMonitorTest { synchronized (this) { this.wait(1000); } - // wt2 allocates strong access as wt1 released it now. + // wt2 reserves write access as wt1 released it now. Assert.assertEquals(wt1.getState(), Thread.State.TERMINATED); Assert.assertEquals(wt2.getState(), Thread.State.WAITING); - // while wt2 has not yet acquired strong access, rt3 acquires weak + // while wt2 has not yet acquired write access, rt3 acquires read // access final ReadThread rt3 = new ReadThread(); rt3.start(); @@ -123,7 +123,7 @@ public class DatabaseMonitorTest { synchronized (this) { this.wait(1000); } - // Assert.assertEquals(wt2.getState(), Thread.State.BLOCKED); + Assert.assertEquals(wt2.getState(), Thread.State.BLOCKED); synchronized (rt3) { rt3.notify(); @@ -150,14 +150,14 @@ public class DatabaseMonitorTest { final WriteThread wt1 = new WriteThread(); wt1.start(); // start another write-thread. It is blocked until wt1 releases the - // strong access. + // write access. final WriteThread wt2 = new WriteThread(); wt2.start(); synchronized (this) { this.wait(1000); } - // and interrupt wt1 after allocating, but before acquiring the strong + // and interrupt wt1 after allocating, but before acquiring the write // access. wt1.interrupt(); @@ -171,6 +171,7 @@ public class DatabaseMonitorTest { // read access should still be blocked. final ReadThread rt1 = new ReadThread(); rt1.start(); + Assert.assertEquals(rt1.getState(), Thread.State.BLOCKED); synchronized (this) { this.wait(1000); @@ -185,17 +186,17 @@ public class DatabaseMonitorTest { public void run() { try { System.out.println("T" + currentThread().getId() + " request allocation sa"); - sa.allocate(); - System.out.println("T" + currentThread().getId() + " allocates sa"); + writeAccess.reserve(); + System.out.println("T" + currentThread().getId() + " reserves sa"); pause(); - sa.lockInterruptibly(); + writeAccess.lockInterruptibly(); System.out.println("T" + currentThread().getId() + " acquires sa"); pause(); - sa.unlock(); + writeAccess.unlock(); System.out.println("T" + currentThread().getId() + " releases sa"); } catch (final InterruptedException e) { System.out.println("T" + currentThread().getId() + " was interrupted"); - sa.unlock(); + writeAccess.unlock(); } } @@ -209,10 +210,10 @@ public class DatabaseMonitorTest { public void run() { try { System.out.println("T" + currentThread().getId() + " requests wa"); - wa.acquire(); + readAccess.acquire(); System.out.println("T" + currentThread().getId() + " acquires wa"); pause(); - wa.release(); + readAccess.release(); System.out.println("T" + currentThread().getId() + " releases wa"); } catch (final InterruptedException e) { e.printStackTrace();