1 package org.simantics.acorn.internal;
4 import java.io.IOException;
5 import java.nio.channels.FileChannel;
6 import java.nio.channels.FileLock;
7 import java.nio.file.DirectoryStream;
8 import java.nio.file.FileAlreadyExistsException;
9 import java.nio.file.FileVisitOption;
10 import java.nio.file.FileVisitResult;
11 import java.nio.file.Files;
12 import java.nio.file.Path;
13 import java.nio.file.SimpleFileVisitor;
14 import java.nio.file.StandardOpenOption;
15 import java.nio.file.attribute.BasicFileAttributes;
16 import java.util.EnumSet;
17 import java.util.Properties;
19 import org.simantics.acorn.GraphClientImpl2;
20 import org.simantics.db.Database;
21 import org.simantics.db.DatabaseUserAgent;
22 import org.simantics.db.ServiceLocator;
23 import org.simantics.db.server.DatabaseStartException;
24 import org.simantics.db.server.ProCoreException;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * @author Tuukka Lehtonen
31 public class AcornDatabase implements Database {
33 private static final Logger LOGGER = LoggerFactory.getLogger(AcornDatabase.class);
35 private static final String LOCK_FILE_NAME = "lock";
37 private final Path folder;
38 private final Path lockFile;
40 private GraphClientImpl2 currentClient;
42 private DatabaseUserAgent userAgent;
44 private FileChannel lockFileChannel;
46 private FileLock lock;
48 private boolean isRunning;
50 public AcornDatabase(Path folder) {
52 this.lockFile = folder.resolve(LOCK_FILE_NAME);
56 public DatabaseUserAgent getUserAgent() {
61 public void setUserAgent(DatabaseUserAgent dbUserAgent) {
62 userAgent = dbUserAgent;
66 public Status getStatus() {
71 public File getFolder() {
72 return folder.toFile();
76 public boolean isFolderOk() {
77 return isFolderOk(folder.toFile());
81 public boolean isFolderOk(File aFolder) {
82 if (!aFolder.isDirectory())
88 public boolean isFolderEmpty() {
89 return isFolderEmpty(folder.toFile());
93 public boolean isFolderEmpty(File aFolder) {
94 Path path = aFolder.toPath();
95 if (!Files.isDirectory(path))
97 try (DirectoryStream<Path> folderStream = Files.newDirectoryStream(path)) {
98 return !folderStream.iterator().hasNext();
99 } catch (IOException e) {
100 LOGGER.error("Failed to open folder stream. folder=" + path, e);
106 public void initFolder(Properties properties) throws ProCoreException {
108 Files.createDirectories(folder);
109 } catch (IOException e) {
110 throw new ProCoreException(e);
115 public void deleteFiles() throws ProCoreException {
120 public synchronized void start() throws ProCoreException {
123 lockFileChannel = lockFile.getFileSystem().provider().newFileChannel(lockFile,
124 EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE));
125 } catch (FileAlreadyExistsException e) {
126 throw new ProCoreException("The database in folder " + folder.toAbsolutePath() + " is already in use!", e);
129 lock = lockFileChannel.tryLock();
131 safeLoggingClose(lockFileChannel, lockFile);
132 throw new ProCoreException("The database in folder " + folder.toAbsolutePath() + " is already in use!");
136 } catch (IOException e) {
137 LOGGER.error("Failed to start database at " + folder.toAbsolutePath(), e);
138 safeLoggingClose(lockFileChannel, lockFile);
143 public boolean isRunning() throws ProCoreException {
148 public synchronized boolean tryToStop() throws ProCoreException {
152 safeLoggingClose(lock, lockFile);
154 safeLoggingClose(lockFileChannel, lockFile);
155 lockFileChannel = null;
156 Files.deleteIfExists(lockFile);
158 } catch (IOException e) {
159 LOGGER.error("Failed to start database at " + folder.toAbsolutePath(), e);
165 public void connect() throws ProCoreException {
169 public boolean isConnected() throws ProCoreException {
174 public String execute(String command) throws ProCoreException {
175 throw new UnsupportedOperationException("execute(" + command + ")");
179 public void disconnect() throws ProCoreException {
183 public void clone(File to, int revision, boolean saveHistory) throws ProCoreException {
185 throw new UnsupportedOperationException();
189 public Path createFromChangeSets(int revision) throws ProCoreException {
191 throw new UnsupportedOperationException();
195 public void deleteGuard() throws ProCoreException {
197 throw new UnsupportedOperationException();
201 public Path dumpChangeSets() throws ProCoreException {
203 throw new UnsupportedOperationException();
207 public void purgeDatabase() throws ProCoreException {
208 if(currentClient == null) throw new IllegalStateException("No current session.");
209 currentClient.purgeDatabase();
213 public long serverGetTailChangeSetId() throws ProCoreException {
214 if(currentClient == null) throw new IllegalStateException("No current session.");
215 return currentClient.getTailChangeSetId();
219 public Session newSession(ServiceLocator locator) throws ProCoreException {
221 if(currentClient != null) throw new DatabaseStartException(folder.toFile(), "A session is already running. Only one session is supported.");
222 currentClient = new GraphClientImpl2(this, folder, locator);
223 return currentClient;
224 } catch (IOException e) {
225 throw new ProCoreException(e);
230 public Journal getJournal() throws ProCoreException {
232 throw new UnsupportedOperationException();
235 private static void deleteTree(Path path) throws ProCoreException {
236 if (!Files.exists(path))
239 class Visitor extends SimpleFileVisitor<Path> {
241 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
244 } catch (IOException ioe) {
245 ioe.printStackTrace();
248 return FileVisitResult.CONTINUE;
251 public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
255 } catch (IOException ioe) {
256 ioe.printStackTrace();
259 return FileVisitResult.CONTINUE;
265 Visitor v = new Visitor();
266 EnumSet<FileVisitOption> opts = EnumSet.noneOf(FileVisitOption.class);
267 Files.walkFileTree(path, opts, Integer.MAX_VALUE, v);
268 } catch (IOException e) {
269 throw new ProCoreException("Could not delete " + path, e);
274 public String getCompression() {
278 private static void safeLoggingClose(AutoCloseable closeable, Path file) {
279 if (closeable == null)
281 try (AutoCloseable c = closeable) {
282 } catch (Exception e) {
283 LOGGER.error("Failed to close " + closeable.getClass() + " of " + file.toAbsolutePath());