]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.acorn/src/org/simantics/acorn/HeadState.java
a6a1622c80027d68b11b05a7de6b6d1891bb26f5
[simantics/platform.git] / bundles / org.simantics.acorn / src / org / simantics / acorn / HeadState.java
1 package org.simantics.acorn;
2
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;
12
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;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 public class HeadState {
23
24     private static transient final Logger LOGGER = LoggerFactory.getLogger(HeadState.class);
25     
26     public static final String HEAD_STATE = "head.state";
27     public static final String SHA_1 = "SHA-1";
28     
29     public int headChangeSetId = 0;
30     public long transactionId = 1;
31     public long reservedIds = 3;
32
33     public ArrayList<String> clusters = new ArrayList<>();
34     public ArrayList<String> files = new ArrayList<>();
35     public ArrayList<String> stream = new ArrayList<>();
36     public ArrayList<String> cs = new ArrayList<>();
37 //    public ArrayList<String> ccs = new ArrayList<String>();
38
39     public long tailChangeSetId = 1;
40
41     public static HeadState load(Path directory) throws InvalidHeadStateException {
42         Path f = directory.resolve(HEAD_STATE);
43         
44         try {
45             byte[] bytes = Files.readAllBytes(f);
46             MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
47             int digestLength = sha1.getDigestLength();
48             sha1.update(bytes, digestLength, bytes.length - digestLength);
49             byte[] newChecksum = sha1.digest();
50             if (!Arrays.equals(newChecksum, Arrays.copyOfRange(bytes, 0, digestLength))) {
51                 throw new InvalidHeadStateException(
52                         "Checksum " + Arrays.toString(newChecksum) + " does not match excpected "
53                                 + Arrays.toString(Arrays.copyOfRange(bytes, 0, digestLength)) + " for " + f.toAbsolutePath());
54             }
55             try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes, digestLength, bytes.length - digestLength)) {
56                 HeadState object = (HeadState) org.simantics.databoard.Files.readFile(bais, Bindings.getBindingUnchecked(HeadState.class));
57                 return object;
58             }
59         } catch (IOException i) {
60                 Throwable cause = i.getCause();
61                 if(cause instanceof AdapterConstructionException) {
62                         HeadState1 old = HeadState1.load(directory);
63                         return old.migrate();
64                 }
65             return new HeadState();
66 //            throw new InvalidHeadStateException(i);
67         } catch (NoSuchAlgorithmException e) {
68             throw new Error("SHA-1 Algorithm not found", e);
69         } catch (Throwable t) {
70             throw new InvalidHeadStateException(t);
71         }
72     }
73     
74     public void save(Path directory) throws IOException {
75         Path f = directory.resolve(HEAD_STATE);
76         try {
77             BinaryMemory rf = new BinaryMemory(4096);
78             try {
79                 MutableVariant v = new MutableVariant(Bindings.getBindingUnchecked(HeadState.class), this);
80                 Serializer s = Bindings.getSerializerUnchecked( Bindings.VARIANT );
81                 s.serialize(rf, v);
82             } finally {
83                 rf.close();
84             }
85             
86             byte[] bytes = rf.toByteBuffer().array();
87             
88             MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
89             sha1.update(bytes);
90             byte[] checksum = sha1.digest();
91             
92             try (OutputStream out = Files.newOutputStream(f)) {
93                 out.write(checksum);
94                 out.write(bytes);
95             }
96             FileIO.syncPath(f);
97         } catch (NoSuchAlgorithmException e) {
98             throw new Error("SHA-1 digest not found, should not happen", e);
99         }
100     }
101
102     public static boolean validateHeadStateIntegrity(Path headState) {
103         try {
104             byte[] bytes = Files.readAllBytes(headState);
105             MessageDigest sha1 = MessageDigest.getInstance(SHA_1);
106             int digestLength = sha1.getDigestLength();
107             sha1.update(bytes, digestLength, bytes.length - digestLength);
108             byte[] newChecksum = sha1.digest();
109             if (!Arrays.equals(newChecksum, Arrays.copyOfRange(bytes, 0, digestLength))) {
110                 LOGGER.error("Checksum " + Arrays.toString(newChecksum) + " does not match excpected " + Arrays.toString(Arrays.copyOfRange(bytes, 0, digestLength)) + " for " + headState.toAbsolutePath());
111                 return false;
112             }
113             return true;
114         } catch (IOException e) {
115             LOGGER.error("An I/O error occured while validating integrity of head.state", e);
116             return false;
117         } catch (NoSuchAlgorithmException e) {
118             LOGGER.error("SHA-1 digest not found, should not happen", e);
119             throw new Error("SHA-1 digest not found, should not happen", e);
120         }
121     }
122
123 }