1 package org.simantics.acorn;
3 import java.io.BufferedInputStream;
4 import java.io.BufferedOutputStream;
5 import java.io.IOException;
6 import java.io.ObjectInputStream;
7 import java.io.ObjectOutputStream;
8 import java.io.Serializable;
9 import java.nio.file.Files;
10 import java.nio.file.Path;
11 import java.util.List;
12 import java.util.stream.Collectors;
13 import java.util.stream.Stream;
15 import org.simantics.databoard.file.RuntimeIOException;
16 import org.simantics.utils.FileUtils;
18 public class MainState implements Serializable {
20 private static final long serialVersionUID = 6237383147637270225L;
22 public int headDir = 0;
27 public MainState(int headDir) {
28 this.headDir = headDir;
31 public static MainState load(Path directory) throws IOException {
32 Files.createDirectories(directory);
33 Path f = directory.resolve("main.state");
35 MainState state = null;
36 try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(f)))) {
37 state = (MainState) in.readObject();
40 Path last = directory.resolve(Integer.toString(state.headDir - 1));
42 Path headState = last.resolve("head.state");
43 HeadState.validateHeadStateIntegrity(headState);
45 } catch (InvalidHeadStateException e) {
48 uncheckedDeleteAll(last);
52 } catch(IOException i) {
53 return new MainState( findNewHeadState(directory) );
54 } catch(ClassNotFoundException c) {
55 throw new Error("MainState class not found", c);
57 if (Files.exists(f)) {
63 public void save(Path directory) throws IOException {
64 Path f = directory.resolve("main.state");
65 try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(f)))) {
66 out.writeObject(this);
71 private static boolean isInteger(Path p) {
73 Integer.parseInt(p.getFileName().toString());
75 } catch (NumberFormatException e) {
81 * TODO> shouldn't do two things in the same function, this does both head.state search and directory cleanup
87 private static int findNewHeadState(Path directory) throws IOException {
88 try (Stream<Path> s = Files.walk(directory, 1)) {
89 List<Path> reverseSortedPaths = s
90 .filter(p -> !p.equals(directory) && isInteger(p) && Files.isDirectory(p))
92 int p1Name = Integer.parseInt(p1.getFileName().toString());
93 int p2Name = Integer.parseInt(p2.getFileName().toString());
94 return Integer.compare(p2Name, p1Name);
95 }).collect(Collectors.toList());
98 for (Path last : reverseSortedPaths) {
99 Path headState = last.resolve("head.state");
100 if (Files.exists(headState)) {
102 HeadState.validateHeadStateIntegrity(headState);
103 largest = safeParseInt(-1, last.getFileName().toString());
105 } catch (IOException | InvalidHeadStateException e) {
107 uncheckedDeleteAll(last);
110 uncheckedDeleteAll(last);
113 // +1 because we want to return the next head version to use,
114 // not the latest existing version.
119 private static int safeParseInt(int defaultValue, String s) {
121 return Integer.parseInt(s);
122 } catch (NumberFormatException e) {
127 private static void uncheckedDeleteAll(Path path) {
129 FileUtils.deleteAll(path.toFile());
130 } catch (IOException e) {
131 throw new RuntimeIOException(e);