X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.graph%2Fsrc%2Forg%2Fsimantics%2Fgraph%2Frepresentation%2FTransferableGraphFileReader.java;h=c7cc415045c490c7cb2f496a1db7af387a1c8035;hb=dac7a40d1cf85956aeac63ccbdf5b7a0d9977ac3;hp=56a112e4d02e7a7e768375618bf687bab437b3ef;hpb=bf495713dbc9dec325f3929889466fa6cd58b541;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphFileReader.java b/bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphFileReader.java index 56a112e4d..c7cc41504 100644 --- a/bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphFileReader.java +++ b/bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphFileReader.java @@ -5,13 +5,13 @@ import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.util.ArrayList; import java.util.List; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; +import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.error.RuntimeDatatypeConstructionException; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.container.DataContainer; @@ -26,9 +26,45 @@ import org.slf4j.LoggerFactory; /** * It is recommended to use {@link #read(File)} and {@link #read(InputStream)} * for reading to ensure proper resource handling. + * + *

+ * It is important to use the correct setting for + * {@link #sharedValueContext(boolean)} which depends on how the TG was + * serialized to begin with. See {@link #DEFAULT_SHARED_VALUE_CONTEXT} for more + * information on this. */ final public class TransferableGraphFileReader extends ByteFileReader { + /** + * Serializing TransferableGraph1 structures using the default {@link Binding} + * will use shared context for serializing the values Variant array. Thus all TG + * files produced by the graph compiler use a shared value context which means + * this class must be used with {@link #sharedValueContext(boolean)} set to + * true. As an example, true must be used if the corresponding TG + * file is written e.g. like this: + *

+     * DataContainers.writeFile(location 
+     *     new DataContainer(format,
+     *                       version,
+     *                       metadata,
+     *                       new Variant(TransferableGraph1.BINDING, tg)));
+     * 
+ * + *

+ * On the other hand, any TG files serialized using more optimized methods like + * ModelTransferableGraphSource do not use a shared value context + * when writing the file. This means those files cannot be read safely using + * standard {@link Binding} at all, and when using this class, + * {@link #sharedValueContext(boolean)} must be set to false to prevent the + * import from corrupting datatype values because the referable parts of + * datatypes may get bound to the wrong existing types if the data is read using + * shared context. + * + *

+ * true is the default setting. + */ + public static final boolean DEFAULT_SHARED_VALUE_CONTEXT = true; + private static final Logger LOGGER = LoggerFactory.getLogger(TransferableGraphFileReader.class); InputStream in = new InputStream() { @@ -53,49 +89,13 @@ final public class TransferableGraphFileReader extends ByteFileReader { } }; - - - final static class InputChannel implements ReadableByteChannel { - - final private InputStream stream; - - public InputChannel(InputStream stream) { - this.stream = stream; - } - @Override - public boolean isOpen() { - return true; - } - - @Override - public void close() throws IOException { - // NOTE: it is an intentional choice not to close the underlying stream here - // InputStreams given directly to TransferableGraphFileReader are expected to - // be closed outside of this implementation. - } - - @Override - public int read(ByteBuffer dst) throws IOException { - int nRead; - int size = 0; - int position = dst.position(); - int limit = dst.limit(); - // The users of this channel expect that the data is fully read at this point - while ((nRead = stream.read(dst.array(), position, limit - position)) != -1 && limit - position > 0) { - size += nRead; - position += nRead; - } - return size; - } - - } - private static boolean init = true; - + final private static int SIZE = 1<<18; final private static int HEADER = headerSize(); final private int header; + private boolean shareValueContext = true; /** * Reads a {@link DataContainer} containing a {@link TransferableGraph1} @@ -106,8 +106,34 @@ final public class TransferableGraphFileReader extends ByteFileReader { * @throws IOException */ public static TransferableGraph1 read(File file) throws IOException { + return read(file, DEFAULT_SHARED_VALUE_CONTEXT); + } + + /** + * Reads a {@link DataContainer} containing a {@link TransferableGraph1} + * structure from the specified InputStream. Note that this implementation does + * not close the specified input stream, it is expected to be + * closed by the caller. + * + * @param input the input stream to read from + * @return the TG contained by the stream + * @throws IOException + */ + public static TransferableGraph1 read(InputStream input) throws IOException { + return read(input, DEFAULT_SHARED_VALUE_CONTEXT); + } + + /** + * Reads a {@link DataContainer} containing a {@link TransferableGraph1} + * structure from the specified {@link File}. + * + * @param file the file to read from + * @return the TG contained by the file + * @throws IOException + */ + public static TransferableGraph1 read(File file, boolean sharedValueContext) throws IOException { try (TransferableGraphFileReader reader = new TransferableGraphFileReader(file)) { - return reader.readTG(); + return reader.sharedValueContext(sharedValueContext).readTG(); } } @@ -121,9 +147,9 @@ final public class TransferableGraphFileReader extends ByteFileReader { * @return the TG contained by the stream * @throws IOException */ - public static TransferableGraph1 read(InputStream input) throws IOException { + public static TransferableGraph1 read(InputStream input, boolean sharedValueContext) throws IOException { try (TransferableGraphFileReader reader = new TransferableGraphFileReader(input)) { - return reader.readTG(); + return reader.sharedValueContext(sharedValueContext).readTG(); } } @@ -172,6 +198,11 @@ final public class TransferableGraphFileReader extends ByteFileReader { this.header = HEADER; } + public TransferableGraphFileReader sharedValueContext(boolean share) { + this.shareValueContext = share; + return this; + } + private static int headerSize() { try { return Bindings.getSerializerUnchecked(Datatype.class).serialize(Datatypes.getDatatypeUnchecked(TransferableGraph1.class)).length; @@ -183,7 +214,7 @@ final public class TransferableGraphFileReader extends ByteFileReader { throw new Error("Failed to determine TransferableGraph1 header size. ", e); } } - + public TransferableGraph1 readTG() throws IOException { if(getSize() == 0) return null; @@ -306,7 +337,8 @@ final public class TransferableGraphFileReader extends ByteFileReader { for(int i=0;i