]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.acorn/src/org/simantics/acorn/internal/AcornDatabase.java
Merge branch 'feature/funcwrite'
[simantics/platform.git] / bundles / org.simantics.acorn / src / org / simantics / acorn / internal / AcornDatabase.java
1 package org.simantics.acorn.internal;
2
3 import java.io.File;
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;
16
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.common.utils.Logger;
22 import org.simantics.db.exception.SDBException;
23 import org.simantics.db.server.DatabaseStartException;
24 import org.simantics.db.server.ProCoreException;
25 import org.simantics.db.server.internal.InternalException;
26
27 /**
28  * @author Tuukka Lehtonen
29  */
30 public class AcornDatabase implements Database {
31
32     private final Path folder;
33     
34     private GraphClientImpl2 currentClient;
35
36     private DatabaseUserAgent userAgent;
37
38     private RandomAccessFile raLockFile;
39
40     private FileLock lock;
41
42     private boolean isRunning;
43
44     public AcornDatabase(Path folder) {
45         this.folder = folder;
46     }
47
48     @Override
49     public DatabaseUserAgent getUserAgent() {
50         return userAgent;
51     }
52
53     @Override
54     public void setUserAgent(DatabaseUserAgent dbUserAgent) {
55         userAgent = dbUserAgent;
56     }
57
58     @Override
59     public Status getStatus() {
60         return Status.Local;
61     }
62
63     @Override
64     public File getFolder() {
65         return folder.toFile();
66     }
67
68     @Override
69     public boolean isFolderOk() {
70         return isFolderOk(folder.toFile());
71     }
72
73     @Override
74     public boolean isFolderOk(File aFolder) {
75         if (!aFolder.isDirectory())
76             return false;
77         return true;
78     }
79
80     @Override
81     public boolean isFolderEmpty() {
82         return isFolderEmpty(folder.toFile());
83     }
84
85     @Override
86     public boolean isFolderEmpty(File aFolder) {
87         Path path = aFolder.toPath();
88         if (!Files.isDirectory(path))
89             return false;
90         try (DirectoryStream<Path> folderStream = Files.newDirectoryStream(path)) {
91             return !folderStream.iterator().hasNext();
92         } catch (IOException e) {
93             Logger.defaultLogError("Failed to open folder stream. folder=" + path, e);
94             return false;
95         }
96     }
97
98     @Override
99     public void initFolder(Properties properties) throws ProCoreException {
100         try {
101             Files.createDirectories(folder);
102         } catch (IOException e) {
103             throw new ProCoreException(e);
104         }
105     }
106
107     @Override
108     public void deleteFiles() throws ProCoreException {
109         deleteTree(folder);
110     }
111
112     @Override
113     public void start() throws ProCoreException {
114         Path lockFile = folder.resolve("lock");
115         try {
116             if (!Files.exists(lockFile))
117                 Files.createFile(lockFile);
118             
119             raLockFile = new RandomAccessFile(lockFile.toFile(), "rw");
120             lock = raLockFile.getChannel().tryLock();
121             if (lock == null) {
122                 throw new ProCoreException("The database in folder " + folder.toAbsolutePath() + " is already in use!");
123             }
124             
125             isRunning = true;
126             
127         } catch (IOException e) {
128             e.printStackTrace();
129         }
130     }
131
132     @Override
133     public boolean isRunning() throws ProCoreException {
134         return isRunning;
135     }
136
137     @Override
138     public boolean tryToStop() throws ProCoreException {
139         try {
140             lock.release();
141             raLockFile.close();
142             
143             Files.deleteIfExists(folder.resolve("lock"));
144             
145             isRunning = false;
146             
147         } catch (IOException e) {
148             e.printStackTrace();
149         }
150         
151         return true;
152     }
153
154     @Override
155     public void connect() throws ProCoreException {
156     }
157
158     @Override
159     public boolean isConnected() throws ProCoreException {
160         return isRunning;
161     }
162
163     @Override
164     public String execute(String command) throws ProCoreException {
165         throw new UnsupportedOperationException("execute(" + command + ")");
166     }
167
168     @Override
169     public void disconnect() throws ProCoreException {
170     }
171
172     @Override
173     public void clone(File to, int revision, boolean saveHistory) throws ProCoreException {
174         // TODO: implement
175         throw new UnsupportedOperationException();
176     }
177
178     @Override
179     public Path createFromChangeSets(int revision) throws ProCoreException {
180         // TODO: implement
181         throw new UnsupportedOperationException();
182     }
183
184     @Override
185     public void deleteGuard() throws ProCoreException {
186         // TODO: implement
187         throw new UnsupportedOperationException();
188     }
189
190     @Override
191     public Path dumpChangeSets() throws ProCoreException {
192         // TODO: implement
193         throw new UnsupportedOperationException();
194     }
195
196     @Override
197     public void purgeDatabase() throws ProCoreException {
198         if(currentClient == null) throw new IllegalStateException("No current session.");
199         currentClient.purgeDatabase();
200     }
201
202     @Override
203     public long serverGetTailChangeSetId() throws ProCoreException {
204         if(currentClient == null) throw new IllegalStateException("No current session.");
205         return currentClient.getTailChangeSetId();
206     }
207
208     @Override
209     public Session newSession(ServiceLocator locator) throws ProCoreException {
210         try {
211                 if(currentClient != null) throw new DatabaseStartException(folder.toFile(), "A session is already running. Only one session is supported.");
212                 currentClient = new GraphClientImpl2(this, folder, locator); 
213             return currentClient;
214         } catch (IOException e) {
215             throw new ProCoreException(e);
216         }
217     }
218
219     @Override
220     public Journal getJournal() throws ProCoreException {
221         // TODO: implement
222         throw new UnsupportedOperationException();
223     }
224
225     private static void deleteTree(Path path) throws ProCoreException {
226         if (!Files.exists(path))
227             return;
228
229         class Visitor extends SimpleFileVisitor<Path> {
230             @Override
231             public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
232                 try {
233                     Files.delete(file);
234                 } catch (IOException ioe) {
235                     ioe.printStackTrace();
236                     throw ioe;
237                 }
238                 return FileVisitResult.CONTINUE;
239             }
240             @Override
241             public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
242                 if (e == null) {
243                     try {
244                         Files.delete(dir);
245                     } catch (IOException ioe) {
246                         ioe.printStackTrace();
247                         throw ioe;
248                     }
249                     return FileVisitResult.CONTINUE;
250                 }
251                 throw e;
252             }
253         }
254         try {
255             Visitor v = new Visitor();
256             EnumSet<FileVisitOption> opts = EnumSet.noneOf(FileVisitOption.class);
257             Files.walkFileTree(path, opts, Integer.MAX_VALUE, v);
258         } catch (IOException e) {
259             throw new ProCoreException("Could not delete " + path, e);
260         }
261     }
262
263         @Override
264         public String getCompression() {
265                 return "LZ4";
266         }
267
268 }