]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/container/DataContainers.java
Added graph.tg hash caching to FixExportedOntology
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / container / DataContainers.java
1 package org.simantics.databoard.container;
2
3 import java.io.DataInput;
4 import java.io.DataInputStream;
5 import java.io.DataOutput;
6 import java.io.File;
7 import java.io.FileInputStream;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.util.Map;
11 import java.util.TreeMap;
12
13 import org.simantics.databoard.Bindings;
14 import org.simantics.databoard.binding.Binding;
15 import org.simantics.databoard.binding.impl.TreeMapBinding;
16 import org.simantics.databoard.binding.mutable.Variant;
17 import org.simantics.databoard.serialization.Serializer;
18 import org.simantics.databoard.type.Datatype;
19 import org.simantics.databoard.util.binary.BinaryFile;
20
21 /**
22  * An utility class for reading files whose format follows
23  * {@link DataContainer}.
24  * @author Hannu Niemistö
25  */
26 public class DataContainers {
27
28     private static final Serializer STRING_SERIALIZER = 
29             Bindings.getSerializerUnchecked(Bindings.STRING);
30     private static final Serializer INTEGER_SERIALIZER = 
31             Bindings.getSerializerUnchecked(Bindings.INTEGER);
32     private static final Serializer METADATA_SERIALIZER = 
33             Bindings.getSerializerUnchecked(new TreeMapBinding(Bindings.STRING, Bindings.VARIANT));
34     private static final Serializer DATATYPE_SERIALIZER =
35             Bindings.getSerializerUnchecked(Datatype.class);
36     private static final Serializer VARIANT_SERIALIZER =
37             Bindings.getSerializerUnchecked(Bindings.VARIANT);
38     private static final Serializer DATA_CONTAINER_SERIALIZER =
39             Bindings.getSerializerUnchecked(DataContainer.class);
40
41     /**
42      * Binds a format name and a version together to form a format version
43      * identifier string.
44      * 
45      * @param formatName
46      * @param version
47      * @return
48      */
49     public static String toFormatString(String formatName, int version) {
50         return formatName + ":" + version;
51     }
52
53     /**
54      * Reads only the header of the data container. Returns
55      * a DataContainer whose content-field is null.
56      * @throws IOException 
57      */
58     public static DataContainer readHeader(DataInput input) throws IOException {
59         String format = (String)STRING_SERIALIZER.deserialize(input);
60         int version = (Integer)INTEGER_SERIALIZER.deserialize(input);
61         @SuppressWarnings("unchecked")
62         TreeMap<String,Variant> metadata = (TreeMap<String,Variant>)METADATA_SERIALIZER.deserialize(input); 
63         return new DataContainer(format, version, metadata, null);
64     }
65
66     /**
67      * Consumes a header from a given stream and checks that the header satisfies the given format and version.
68      * Returns the obtained header if the check fails and null on success.
69      * @throws IOException 
70      */
71     public static DataContainer requireHeader(DataInput input, String format, int version) {
72         try {
73             DataContainer header = readHeader(input);
74             if(!format.equals(header.format) || version != header.version)
75                 return header;
76             else return null;
77         } catch (Throwable t) {
78             return new DataContainer("unknown", 0, null, null);
79         }
80     }
81
82     /**
83      * Consumes a header from a given stream and checks that the header satisfies the given format and version restrictions.
84      * Returns the obtained header if the check fails and null on success.
85      * @throws IOException 
86      */
87     public static DataContainer requireHeader(DataInput input, String... requiredFormatStrings) {
88         try {
89             DataContainer header = readHeader(input);
90             String formatString = toFormatString(header.format, header.version);
91             for (String requiredFormatString : requiredFormatStrings) {
92                 if(formatString.equals(requiredFormatString))
93                     return null;
94             }
95             return header;
96         } catch (Throwable t) {
97             return new DataContainer("unknown", 0, null, null);
98         }
99     }
100
101     /**
102      * Checks that the given file satisfies the given format and version. 
103      * Returns the obtained header if the check fails and null on success.
104      * @throws IOException 
105      */
106     public static DataContainer validateHeader(File file, String format, int version) throws IOException {
107         try (InputStream stream = new FileInputStream( file )) {
108             return DataContainers.requireHeader(new DataInputStream(stream), format, version);
109         }
110     }
111
112     /**
113      * Checks that the given file satisfies the given format and version. 
114      * Returns the obtained header if the check fails and null on success.
115      * @throws IOException 
116      */
117     public static DataContainer validateHeader(File file, String... allowedFormatStrings) throws IOException {
118         try (InputStream stream = new FileInputStream( file )) {
119             return DataContainers.requireHeader(new DataInputStream(stream), allowedFormatStrings);
120         }
121     }
122
123     /**
124      * Reads only the header of the data container. Returns
125      * a DataContainer whose content-field is null.
126      * @throws IOException 
127      */
128     public static DataContainer readHeader(File input) throws IOException {
129         try (BinaryFile rf = new BinaryFile( input, "r" )) {
130             return readHeader(rf);
131         }
132     }
133
134     /**
135      * Reads a data container including the content data.
136      * @throws IOException 
137      */
138     public static DataContainer readFile(DataInput input) throws IOException {
139         DataContainer result = readHeader(input);
140         result.content = (Variant)VARIANT_SERIALIZER.deserialize(input);
141         return result;
142     }
143
144     /**
145      * Reads a data container including the content data.
146      * @throws IOException 
147      */
148     public static DataContainer readFile(DataInput input, Binding expectedBinding) throws IOException, DataFormatException {
149         DataContainer result = readHeader(input);
150         Datatype contentType = (Datatype) DATATYPE_SERIALIZER.deserialize(input);
151         if (!expectedBinding.type().equals(contentType))
152             throw new DataFormatException(
153                     "Content type didn't match the type expected for the binding " + expectedBinding
154                     + ":\nexpected type: " + expectedBinding.type()
155                     + "\nactual type: " + contentType);
156         Object value = Bindings.getSerializerUnchecked(expectedBinding).deserialize(input);
157         result.content = new Variant(expectedBinding, value);
158         return result;
159     }
160
161     /**
162      * Process a data container using a format handler matching the format and version
163      * of the file. 
164      * @param handlers Map of handlers. Keys are strings of form "format:version".
165      */
166     public static <T> T readFile(DataInput input, Map<String, FormatHandler<T>> handlers) throws Exception {
167         DataContainer result = readHeader(input);
168
169         FormatHandler<T> handler = handlers.get(result.format + ":" + result.version);
170         if(handler == null)
171             throw new DataFormatException("Unknown data format " + result.format + " version " + result.version + ".");
172         Binding binding = handler.getBinding();
173
174         Datatype contentType = (Datatype)DATATYPE_SERIALIZER.deserialize(input);
175         if(!binding.type().equals(contentType))
176             throw new DataFormatException("Content type didn't match the type expected for the format " + result.format + " version " + result.version + ".");
177
178         Object value = Bindings.getSerializerUnchecked(binding).deserialize(input);
179
180         result.content = new Variant(binding, value);
181         return handler.process(result);
182     }
183
184     /**
185      * Reads a data container including the content data.
186      * @throws IOException 
187      */
188     public static DataContainer readFile(File input) throws IOException {
189         try (BinaryFile rf = new BinaryFile( input, "r" )) {
190             return readFile(rf);
191         }
192     }
193
194     /**
195      * Reads a data container including the content data.
196      * @throws IOException 
197      * @throws DataFormatException 
198      */
199     public static DataContainer readFile(File input, Binding expectedBinding) throws IOException, DataFormatException {
200         try (BinaryFile rf = new BinaryFile( input, "r" )) {
201             return readFile(rf, expectedBinding);
202         }
203     }
204
205     /**
206      * Process a data container using a format handler matching the format and version
207      * of the file. 
208      * @param handlers Map of handlers. Keys are strings of form "format:version".
209      */
210     public static <T> T readFile(File input, Map<String, FormatHandler<T>> handlers) throws Exception {
211         try (BinaryFile rf = new BinaryFile( input, "r" )) {
212             return readFile(rf, handlers);
213         }
214     }
215
216     /**
217      * Writes header fields of a container to the given output. Content field is
218      * ignored.
219      * @throws IOException 
220      */
221     public static void writeHeader(DataOutput output, DataContainer container) throws IOException {
222         STRING_SERIALIZER.serialize(output, container.format);
223         INTEGER_SERIALIZER.serialize(output, container.version);
224         METADATA_SERIALIZER.serialize(output, container.metadata);
225     }
226
227     /**
228      * Writes a data container to the given output.
229      * @throws IOException 
230      */
231     public static void writeFile(DataOutput output, DataContainer container) throws IOException {
232         writeHeader(output, container);
233         VARIANT_SERIALIZER.serialize(output, container.content);
234     }
235
236     /**
237      * Writes a data container to the given file
238      * @throws IOException 
239      */
240     public static void writeFile(File output, DataContainer container) throws IOException {
241         try (BinaryFile wf = new BinaryFile(output)) {
242             writeFile(wf, container);
243             wf.setLength(wf.position());
244         }
245     }
246
247     public static byte[] writeFile(DataContainer container) throws IOException {
248         return DATA_CONTAINER_SERIALIZER.serialize(container);
249     }
250
251 }