1 package org.simantics.databoard.container;
\r
3 import java.io.DataInput;
\r
4 import java.io.DataInputStream;
\r
5 import java.io.DataOutput;
\r
7 import java.io.FileInputStream;
\r
8 import java.io.IOException;
\r
9 import java.io.InputStream;
\r
10 import java.util.Map;
\r
11 import java.util.TreeMap;
\r
13 import org.simantics.databoard.Bindings;
\r
14 import org.simantics.databoard.binding.Binding;
\r
15 import org.simantics.databoard.binding.impl.TreeMapBinding;
\r
16 import org.simantics.databoard.binding.mutable.Variant;
\r
17 import org.simantics.databoard.serialization.Serializer;
\r
18 import org.simantics.databoard.type.Datatype;
\r
19 import org.simantics.databoard.util.binary.BinaryFile;
\r
22 * An utility class for reading files whose format follows
\r
23 * {@link DataContainer}.
\r
24 * @author Hannu Niemistö
\r
26 public class DataContainers {
\r
28 private static final Serializer STRING_SERIALIZER =
\r
29 Bindings.getSerializerUnchecked(Bindings.STRING);
\r
30 private static final Serializer INTEGER_SERIALIZER =
\r
31 Bindings.getSerializerUnchecked(Bindings.INTEGER);
\r
32 private static final Serializer METADATA_SERIALIZER =
\r
33 Bindings.getSerializerUnchecked(new TreeMapBinding(Bindings.STRING, Bindings.VARIANT));
\r
34 private static final Serializer DATATYPE_SERIALIZER =
\r
35 Bindings.getSerializerUnchecked(Datatype.class);
\r
36 private static final Serializer VARIANT_SERIALIZER =
\r
37 Bindings.getSerializerUnchecked(Bindings.VARIANT);
\r
38 private static final Serializer DATA_CONTAINER_SERIALIZER =
\r
39 Bindings.getSerializerUnchecked(DataContainer.class);
\r
42 * Binds a format name and a version together to form a format version
\r
43 * identifier string.
\r
49 public static String toFormatString(String formatName, int version) {
\r
50 return formatName + ":" + version;
\r
54 * Reads only the header of the data container. Returns
\r
55 * a DataContainer whose content-field is null.
\r
56 * @throws IOException
\r
58 public static DataContainer readHeader(DataInput input) throws IOException {
\r
59 String format = (String)STRING_SERIALIZER.deserialize(input);
\r
60 int version = (Integer)INTEGER_SERIALIZER.deserialize(input);
\r
61 @SuppressWarnings("unchecked")
\r
62 TreeMap<String,Variant> metadata = (TreeMap<String,Variant>)METADATA_SERIALIZER.deserialize(input);
\r
63 return new DataContainer(format, version, metadata, null);
\r
67 * Consumes a header from a given stream and checks that the header satisfies the given format and version.
\r
68 * Returns the obtained header if the check fails and null on success.
\r
69 * @throws IOException
\r
71 public static DataContainer requireHeader(DataInput input, String format, int version) {
\r
73 DataContainer header = readHeader(input);
\r
74 if(!format.equals(header.format) || version != header.version)
\r
77 } catch (Throwable t) {
\r
78 return new DataContainer("unknown", 0, null, null);
\r
83 * Consumes a header from a given stream and checks that the header satisfies the given format and version restrictions.
\r
84 * Returns the obtained header if the check fails and null on success.
\r
85 * @throws IOException
\r
87 public static DataContainer requireHeader(DataInput input, String... requiredFormatStrings) {
\r
89 DataContainer header = readHeader(input);
\r
90 String formatString = toFormatString(header.format, header.version);
\r
91 for (String requiredFormatString : requiredFormatStrings) {
\r
92 if(formatString.equals(requiredFormatString))
\r
96 } catch (Throwable t) {
\r
97 return new DataContainer("unknown", 0, null, null);
\r
102 * Checks that the given file satisfies the given format and version.
\r
103 * Returns the obtained header if the check fails and null on success.
\r
104 * @throws IOException
\r
106 public static DataContainer validateHeader(File file, String format, int version) throws IOException {
\r
108 InputStream stream = new FileInputStream( file );
\r
110 return DataContainers.requireHeader(new DataInputStream(stream), format, version);
\r
118 * Checks that the given file satisfies the given format and version.
\r
119 * Returns the obtained header if the check fails and null on success.
\r
120 * @throws IOException
\r
122 public static DataContainer validateHeader(File file, String... allowedFormatStrings) throws IOException {
\r
124 InputStream stream = new FileInputStream( file );
\r
126 return DataContainers.requireHeader(new DataInputStream(stream), allowedFormatStrings);
\r
134 * Reads only the header of the data container. Returns
\r
135 * a DataContainer whose content-field is null.
\r
136 * @throws IOException
\r
138 public static DataContainer readHeader(File input) throws IOException {
\r
139 BinaryFile rf = new BinaryFile( input, "r" );
\r
141 return readHeader(rf);
\r
148 * Reads a data container including the content data.
\r
149 * @throws IOException
\r
151 public static DataContainer readFile(DataInput input) throws IOException {
\r
152 DataContainer result = readHeader(input);
\r
153 result.content = (Variant)VARIANT_SERIALIZER.deserialize(input);
\r
158 * Process a data container using a format handler matching the format and version
\r
160 * @param handlers Map of handlers. Keys are strings of form "format:version".
\r
162 public static <T> T readFile(DataInput input, Map<String, FormatHandler<T>> handlers) throws Exception {
\r
163 DataContainer result = readHeader(input);
\r
165 FormatHandler<T> handler = handlers.get(result.format + ":" + result.version);
\r
166 if(handler == null)
\r
167 throw new DataFormatException("Unknown data format " + result.format + " version " + result.version + ".");
\r
168 Binding binding = handler.getBinding();
\r
170 Datatype contentType = (Datatype)DATATYPE_SERIALIZER.deserialize(input);
\r
171 if(!binding.type().equals(contentType))
\r
172 throw new DataFormatException("Content type didn't match the type expected for the format " + result.format + " version " + result.version + ".");
\r
174 Object value = Bindings.getSerializerUnchecked(binding).deserialize(input);
\r
176 result.content = new Variant(binding, value);
\r
177 return handler.process(result);
\r
181 * Reads a data container including the content data.
\r
182 * @throws IOException
\r
184 public static DataContainer readFile(File input) throws IOException {
\r
185 BinaryFile rf = new BinaryFile( input, "r" );
\r
187 return readFile(rf);
\r
194 * Process a data container using a format handler matching the format and version
\r
196 * @param handlers Map of handlers. Keys are strings of form "format:version".
\r
198 public static <T> T readFile(File input, Map<String, FormatHandler<T>> handlers) throws Exception {
\r
199 BinaryFile rf = new BinaryFile( input, "r" );
\r
201 return readFile(rf, handlers);
\r
208 * Writes header fields of a container to the given output. Content field is
\r
210 * @throws IOException
\r
212 public static void writeHeader(DataOutput output, DataContainer container) throws IOException {
\r
213 STRING_SERIALIZER.serialize(output, container.format);
\r
214 INTEGER_SERIALIZER.serialize(output, container.version);
\r
215 METADATA_SERIALIZER.serialize(output, container.metadata);
\r
219 * Writes a data container to the given output.
\r
220 * @throws IOException
\r
222 public static void writeFile(DataOutput output, DataContainer container) throws IOException {
\r
223 writeHeader(output, container);
\r
224 VARIANT_SERIALIZER.serialize(output, container.content);
\r
228 * Writes a data container to the given file
\r
229 * @throws IOException
\r
231 public static void writeFile(File output, DataContainer container) throws IOException {
\r
232 BinaryFile wf = new BinaryFile( output);
\r
234 writeFile(wf, container);
\r
240 public static byte[] writeFile(DataContainer container) throws IOException {
\r
241 return DATA_CONTAINER_SERIALIZER.serialize(container);
\r