1 package org.simantics.acorn.internal;
4 import java.io.IOException;
5 import java.io.RandomAccessFile;
6 import java.nio.channels.FileLock;
7 import java.nio.file.DirectoryStream;
8 import java.nio.file.FileVisitOption;
9 import java.nio.file.FileVisitResult;
10 import java.nio.file.Files;
11 import java.nio.file.Path;
12 import java.nio.file.SimpleFileVisitor;
13 import java.nio.file.attribute.BasicFileAttributes;
14 import java.util.EnumSet;
15 import java.util.Properties;
17 import org.simantics.acorn.GraphClientImpl2;
18 import org.simantics.db.Database;
19 import org.simantics.db.DatabaseUserAgent;
20 import org.simantics.db.ServiceLocator;
21 import org.simantics.db.server.DatabaseStartException;
22 import org.simantics.db.server.ProCoreException;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * @author Tuukka Lehtonen
29 public class AcornDatabase implements Database {
31 private static final Logger LOGGER = LoggerFactory.getLogger(AcornDatabase.class);
33 private static final String LOCK_FILE_NAME = "lock";
35 private final Path folder;
36 private final Path lockFile;
38 private GraphClientImpl2 currentClient;
40 private DatabaseUserAgent userAgent;
42 private RandomAccessFile raLockFile;
44 private FileLock lock;
46 private boolean isRunning;
48 public AcornDatabase(Path folder) {
50 this.lockFile = folder.resolve(LOCK_FILE_NAME);
54 public DatabaseUserAgent getUserAgent() {
59 public void setUserAgent(DatabaseUserAgent dbUserAgent) {
60 userAgent = dbUserAgent;
64 public Status getStatus() {
69 public File getFolder() {
70 return folder.toFile();
74 public boolean isFolderOk() {
75 return isFolderOk(folder.toFile());
79 public boolean isFolderOk(File aFolder) {
80 if (!aFolder.isDirectory())
86 public boolean isFolderEmpty() {
87 return isFolderEmpty(folder.toFile());
91 public boolean isFolderEmpty(File aFolder) {
92 Path path = aFolder.toPath();
93 if (!Files.isDirectory(path))
95 try (DirectoryStream<Path> folderStream = Files.newDirectoryStream(path)) {
96 return !folderStream.iterator().hasNext();
97 } catch (IOException e) {
98 LOGGER.error("Failed to open folder stream. folder=" + path, e);
104 public void initFolder(Properties properties) throws ProCoreException {
106 Files.createDirectories(folder);
107 } catch (IOException e) {
108 throw new ProCoreException(e);
113 public void deleteFiles() throws ProCoreException {
118 public synchronized void start() throws ProCoreException {
120 raLockFile = new RandomAccessFile(lockFile.toFile(), "rw");
121 lock = raLockFile.getChannel().tryLock();
123 safeLoggingClose(raLockFile, lockFile);
124 throw new ProCoreException("The database in folder " + folder.toAbsolutePath() + " is already in use!");
127 } catch (IOException e) {
128 LOGGER.error("Failed to start database at " + folder.toAbsolutePath(), e);
129 safeLoggingClose(raLockFile, lockFile);
130 throw new ProCoreException("Failed to start database at " + folder.toAbsolutePath(), e);
135 public boolean isRunning() throws ProCoreException {
140 public synchronized boolean tryToStop() throws ProCoreException {
144 safeLoggingClose(lock, lockFile);
146 safeLoggingClose(raLockFile, lockFile);
148 Files.deleteIfExists(lockFile);
150 } catch (IOException e) {
151 LOGGER.error("Failed to start database at " + folder.toAbsolutePath(), e);
157 public void connect() throws ProCoreException {
161 public boolean isConnected() throws ProCoreException {
166 public String execute(String command) throws ProCoreException {
167 throw new UnsupportedOperationException("execute(" + command + ")");
171 public void disconnect() throws ProCoreException {
175 public void clone(File to, int revision, boolean saveHistory) throws ProCoreException {
177 throw new UnsupportedOperationException();
181 public Path createFromChangeSets(int revision) throws ProCoreException {
183 throw new UnsupportedOperationException();
187 public void deleteGuard() throws ProCoreException {
189 throw new UnsupportedOperationException();
193 public Path dumpChangeSets() throws ProCoreException {
195 throw new UnsupportedOperationException();
199 public void purgeDatabase() throws ProCoreException {
200 if(currentClient == null) throw new IllegalStateException("No current session.");
201 currentClient.purgeDatabase();
205 public long serverGetTailChangeSetId() throws ProCoreException {
206 if(currentClient == null) throw new IllegalStateException("No current session.");
207 return currentClient.getTailChangeSetId();
211 public Session newSession(ServiceLocator locator) throws ProCoreException {
213 if(currentClient != null) throw new DatabaseStartException(folder.toFile(), "A session is already running. Only one session is supported.");
214 currentClient = new GraphClientImpl2(this, folder, locator);
215 return currentClient;
216 } catch (IOException e) {
217 throw new ProCoreException(e);
222 public Journal getJournal() throws ProCoreException {
224 throw new UnsupportedOperationException();
227 private static void deleteTree(Path path) throws ProCoreException {
228 if (!Files.exists(path))
231 class Visitor extends SimpleFileVisitor<Path> {
233 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
236 } catch (IOException ioe) {
237 ioe.printStackTrace();
240 return FileVisitResult.CONTINUE;
243 public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
247 } catch (IOException ioe) {
248 ioe.printStackTrace();
251 return FileVisitResult.CONTINUE;
257 Visitor v = new Visitor();
258 EnumSet<FileVisitOption> opts = EnumSet.noneOf(FileVisitOption.class);
259 Files.walkFileTree(path, opts, Integer.MAX_VALUE, v);
260 } catch (IOException e) {
261 throw new ProCoreException("Could not delete " + path, e);
266 public String getCompression() {
270 private static void safeLoggingClose(AutoCloseable closeable, Path file) {
271 if (closeable == null)
273 try (AutoCloseable c = closeable) {
274 } catch (Exception e) {
275 LOGGER.error("Failed to close " + closeable.getClass() + " of " + file.toAbsolutePath());