X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.acorn%2Fsrc%2Forg%2Fsimantics%2Facorn%2FMainState.java;fp=bundles%2Forg.simantics.acorn%2Fsrc%2Forg%2Fsimantics%2Facorn%2FMainState.java;h=77335289d73b446b6f10b20a0f1a03ce930ce4f0;hp=0000000000000000000000000000000000000000;hb=a0687ce02bac73aad9e0d7ddc85625016604f0db;hpb=be5eb160a811a04ecd6364ebb58f24e8218d3f9c diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java new file mode 100644 index 000000000..77335289d --- /dev/null +++ b/bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java @@ -0,0 +1,135 @@ +package org.simantics.acorn; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.simantics.databoard.file.RuntimeIOException; +import org.simantics.utils.FileUtils; + +public class MainState implements Serializable { + + private static final long serialVersionUID = 6237383147637270225L; + + public int headDir = 0; + + public MainState() { + } + + public MainState(int headDir) { + this.headDir = headDir; + } + + public static MainState load(Path directory) throws IOException { + Files.createDirectories(directory); + Path f = directory.resolve("main.state"); + try { + MainState state = null; + try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(f)))) { + state = (MainState) in.readObject(); + } + while (true) { + Path last = directory.resolve(Integer.toString(state.headDir - 1)); + try { + Path headState = last.resolve("head.state"); + HeadState.validateHeadStateIntegrity(headState); + break; + } catch (InvalidHeadStateException e) { + e.printStackTrace(); + state.headDir--; + uncheckedDeleteAll(last); + } + } + return state; + } catch(IOException i) { + return new MainState( findNewHeadState(directory) ); + } catch(ClassNotFoundException c) { + throw new Error("MainState class not found", c); + } finally { + if (Files.exists(f)) { + Files.delete(f); + } + } + } + + public void save(Path directory) throws IOException { + Path f = directory.resolve("main.state"); + try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(f)))) { + out.writeObject(this); + } + FileIO.syncPath(f); + } + + private static boolean isInteger(Path p) { + try { + Integer.parseInt(p.getFileName().toString()); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + /** + * TODO> shouldn't do two things in the same function, this does both head.state search and directory cleanup + * + * @param directory + * @return + * @throws IOException + */ + private static int findNewHeadState(Path directory) throws IOException { + try (Stream s = Files.walk(directory, 1)) { + List reverseSortedPaths = s + .filter(p -> !p.equals(directory) && isInteger(p) && Files.isDirectory(p)) + .sorted((p1, p2) -> { + int p1Name = Integer.parseInt(p1.getFileName().toString()); + int p2Name = Integer.parseInt(p2.getFileName().toString()); + return Integer.compare(p2Name, p1Name); + }).collect(Collectors.toList()); + + int largest = -1; + for (Path last : reverseSortedPaths) { + Path headState = last.resolve("head.state"); + if (Files.exists(headState)) { + try { + HeadState.validateHeadStateIntegrity(headState); + largest = safeParseInt(-1, last.getFileName().toString()); + break; + } catch (IOException | InvalidHeadStateException e) { + e.printStackTrace(); + uncheckedDeleteAll(last); + } + } else { + uncheckedDeleteAll(last); + } + } + // +1 because we want to return the next head version to use, + // not the latest existing version. + return largest + 1; + } + } + + private static int safeParseInt(int defaultValue, String s) { + try { + return Integer.parseInt(s); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + private static void uncheckedDeleteAll(Path path) { + try { + FileUtils.deleteAll(path.toFile()); + } catch (IOException e) { + throw new RuntimeIOException(e); + } + } + +}