1 package org.simantics.acorn;
3 import java.io.ByteArrayInputStream;
4 import java.io.IOException;
5 import java.io.OutputStream;
6 import java.nio.file.Files;
7 import java.nio.file.Path;
8 import java.security.MessageDigest;
9 import java.security.NoSuchAlgorithmException;
10 import java.util.ArrayList;
11 import java.util.Arrays;
13 import org.simantics.acorn.exception.InvalidHeadStateException;
14 import org.simantics.databoard.Bindings;
15 import org.simantics.databoard.adapter.AdapterConstructionException;
16 import org.simantics.databoard.binding.mutable.MutableVariant;
17 import org.simantics.databoard.serialization.Serializer;
18 import org.simantics.databoard.util.binary.BinaryMemory;
20 public class HeadState {
22 public static final String HEAD_STATE = "head.state";
23 public static final String SHA_1 = "SHA-1";
25 public int headChangeSetId = 0;
26 public long transactionId = 1;
27 public long reservedIds = 3;
29 public ArrayList<String> clusters = new ArrayList<>();
30 public ArrayList<String> files = new ArrayList<>();
31 public ArrayList<String> stream = new ArrayList<>();
32 public ArrayList<String> cs = new ArrayList<>();
33 // public ArrayList<String> ccs = new ArrayList<String>();
35 public long tailChangeSetId = 1;
37 public static HeadState load(Path directory) throws InvalidHeadStateException {
38 Path f = directory.resolve(HEAD_STATE);
41 byte[] bytes = Files.readAllBytes(f);
42 MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
43 int digestLength = sha1.getDigestLength();
45 sha1.update(bytes, digestLength, bytes.length - digestLength);
46 byte[] newChecksum = sha1.digest();
47 if (!Arrays.equals(newChecksum, Arrays.copyOfRange(bytes, 0, digestLength))) {
48 throw new InvalidHeadStateException(
49 "Checksum " + Arrays.toString(newChecksum) + " does not match excpected "
50 + Arrays.toString(Arrays.copyOfRange(bytes, 0, digestLength)) + " for " + f.toAbsolutePath());
52 try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes, digestLength, bytes.length - digestLength)) {
53 HeadState object = (HeadState) org.simantics.databoard.Files.readFile(bais, Bindings.getBindingUnchecked(HeadState.class));
56 } catch (IOException i) {
57 Throwable cause = i.getCause();
58 if(cause instanceof AdapterConstructionException) {
59 HeadState1 old = HeadState1.load(directory);
62 return new HeadState();
63 // throw new InvalidHeadStateException(i);
64 } catch (NoSuchAlgorithmException e) {
65 throw new Error("SHA-1 Algorithm not found", e);
66 } catch (Throwable t) {
67 throw new InvalidHeadStateException(t);
71 public void save(Path directory) throws IOException {
72 Path f = directory.resolve(HEAD_STATE);
74 BinaryMemory rf = new BinaryMemory(4096);
76 MutableVariant v = new MutableVariant(Bindings.getBindingUnchecked(HeadState.class), this);
77 Serializer s = Bindings.getSerializerUnchecked( Bindings.VARIANT );
83 byte[] bytes = rf.toByteBuffer().array();
85 MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
87 byte[] checksum = sha1.digest();
89 try (OutputStream out = Files.newOutputStream(f)) {
94 } catch (NoSuchAlgorithmException e) {
95 throw new Error("SHA-1 digest not found, should not happen", e);
99 public static void validateHeadStateIntegrity(Path headState) throws InvalidHeadStateException, IOException {
101 byte[] bytes = Files.readAllBytes(headState);
102 MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
103 int digestLength = sha1.getDigestLength();
104 sha1.update(bytes, digestLength, bytes.length - digestLength);
105 byte[] newChecksum = sha1.digest();
106 if (!Arrays.equals(newChecksum, Arrays.copyOfRange(bytes, 0, digestLength))) {
107 throw new InvalidHeadStateException(
108 "Checksum " + Arrays.toString(newChecksum) + " does not match excpected "
109 + Arrays.toString(Arrays.copyOfRange(bytes, 0, digestLength)) + " for " + headState.toAbsolutePath());
111 } catch (NoSuchAlgorithmException e) {
112 throw new Error("SHA-1 digest not found, should not happen", e);