]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java
77335289d73b446b6f10b20a0f1a03ce930ce4f0
[simantics/platform.git] / bundles / org.simantics.acorn / src / org / simantics / acorn / MainState.java
1 package org.simantics.acorn;
2
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;
14
15 import org.simantics.databoard.file.RuntimeIOException;
16 import org.simantics.utils.FileUtils;
17
18 public class MainState implements Serializable {
19
20     private static final long serialVersionUID = 6237383147637270225L;
21
22     public int headDir = 0;
23
24     public MainState() {
25     }
26
27     public MainState(int headDir) {
28         this.headDir = headDir;
29     }
30
31     public static MainState load(Path directory) throws IOException {
32         Files.createDirectories(directory);
33         Path f = directory.resolve("main.state");
34         try {
35             MainState state = null;
36             try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(f)))) {
37                 state = (MainState) in.readObject();
38             }
39             while (true) {
40                 Path last = directory.resolve(Integer.toString(state.headDir - 1));
41                 try {
42                     Path headState = last.resolve("head.state");
43                     HeadState.validateHeadStateIntegrity(headState);
44                     break;
45                 } catch (InvalidHeadStateException e) {
46                     e.printStackTrace();
47                     state.headDir--;
48                     uncheckedDeleteAll(last);
49                 }
50             }
51             return state;
52         } catch(IOException i) {
53             return new MainState( findNewHeadState(directory) );
54         } catch(ClassNotFoundException c) {
55             throw new Error("MainState class not found", c);
56         } finally {
57             if (Files.exists(f)) {
58                 Files.delete(f);
59             }
60         }
61     }
62
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);
67         }
68         FileIO.syncPath(f);
69     }
70
71     private static boolean isInteger(Path p) {
72         try {
73             Integer.parseInt(p.getFileName().toString());
74             return true;
75         } catch (NumberFormatException e) {
76             return false;
77         }
78     }
79
80     /**
81      * TODO> shouldn't do two things in the same function, this does both head.state search and directory cleanup
82      *  
83      * @param directory
84      * @return
85      * @throws IOException
86      */
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))
91             .sorted((p1, p2) -> {
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());
96
97             int largest = -1;
98             for (Path last : reverseSortedPaths) {
99                 Path headState = last.resolve("head.state");
100                 if (Files.exists(headState)) {
101                     try {
102                         HeadState.validateHeadStateIntegrity(headState);
103                         largest = safeParseInt(-1, last.getFileName().toString());
104                         break;
105                     } catch (IOException | InvalidHeadStateException e) {
106                         e.printStackTrace();
107                         uncheckedDeleteAll(last);
108                     }
109                 } else {
110                     uncheckedDeleteAll(last);
111                 }
112             }
113             // +1 because we want to return the next head version to use,
114             // not the latest existing version.
115             return largest + 1;
116         }
117     }
118
119     private static int safeParseInt(int defaultValue, String s) {
120         try {
121             return Integer.parseInt(s);
122         } catch (NumberFormatException e) {
123             return defaultValue;
124         }
125     }
126
127     private static void uncheckedDeleteAll(Path path) {
128         try {
129             FileUtils.deleteAll(path.toFile());
130         } catch (IOException e) {
131             throw new RuntimeIOException(e);
132         }
133     }
134
135 }