-/*******************************************************************************\r
- * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.history.impl;\r
-\r
-import java.io.DataInput;\r
-import java.io.DataOutput;\r
-import java.io.File;\r
-import java.io.FilenameFilter;\r
-import java.io.IOException;\r
-import java.nio.BufferUnderflowException;\r
-import java.nio.ByteBuffer;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-import java.util.logging.Logger;\r
-\r
-import org.simantics.databoard.Accessors;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.accessor.ArrayAccessor;\r
-import org.simantics.databoard.accessor.StreamAccessor;\r
-import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
-import org.simantics.databoard.accessor.error.AccessorException;\r
-import org.simantics.databoard.adapter.AdaptException;\r
-import org.simantics.databoard.adapter.Adapter;\r
-import org.simantics.databoard.adapter.AdapterConstructionException;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;\r
-import org.simantics.databoard.serialization.Serializer;\r
-import org.simantics.databoard.serialization.SerializerConstructionException;\r
-import org.simantics.databoard.type.ArrayType;\r
-import org.simantics.databoard.type.Component;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.databoard.type.NumberType;\r
-import org.simantics.databoard.type.RecordType;\r
-import org.simantics.databoard.util.Bean;\r
-import org.simantics.databoard.util.ObjectUtils;\r
-import org.simantics.databoard.util.URIUtil;\r
-import org.simantics.databoard.util.binary.BinaryMemory;\r
-import org.simantics.databoard.util.binary.ByteBufferWriteable;\r
-import org.simantics.history.HistoryException;\r
-import org.simantics.history.HistoryManager;\r
-import org.simantics.utils.FileUtils;\r
-\r
-/**\r
- * File history uses workarea (directory) to manage items.\r
- * There are two files for every item: stream file and metadata file.\r
- * Metadata file is JSON ascii file. \r
- * itemname.data\r
- * itemname.txt\r
- * \r
- * @author toni.kalajainen\r
- *\r
- */\r
-public class FileHistory implements HistoryManager {\r
-\r
- private static final boolean PROFILE = false;\r
- private static final boolean DEBUG = false;\r
-\r
- /** Logger */\r
- static Logger logger = Logger.getLogger(FileHistory.class.getName());\r
- \r
- static FilenameFilter txtFilter;\r
- \r
- static ArrayType INDEX_TYPE = Bindings.LONG_ARRAY.type();\r
- \r
- File workarea;\r
- \r
- /** Support async usage of the data */\r
- public boolean asyncUsage = true;\r
-\r
- public FileHistory(File workarea) {\r
- this.workarea = workarea;\r
- }\r
- \r
- public File getWorkarea() {\r
- return workarea;\r
- }\r
- \r
- @Override\r
- public void create(Bean... items) throws HistoryException {\r
- \r
- try {\r
- for (Bean item : items) {\r
- if (DEBUG)\r
- System.out.println("create(" + item + ")");\r
-// if ( !item.getFieldBinding("format").type().equals( Bindings.getBindingUnchecked(Datatype.class).type() ) )\r
-// System.err.println("Error");\r
- \r
- // Write meta data\r
- writeMetadata( item );\r
- \r
- // Create stream file\r
- String id = (String) item.getField("id");\r
- File dataFile = toDataFile( id );\r
- dataFile.createNewFile();\r
- \r
- Datatype type = (Datatype) item.getField("format");\r
- if ( isVariableWidth(type) ) {\r
- File indexFile = toIndexFile( id );\r
- indexFile.createNewFile();\r
- }\r
-// if ( !dataFile.createNewFile() ) {\r
-// throw new HistoryException("Could not create file "+dataFile);\r
-// }\r
- } \r
- } catch (BindingException e) {\r
- throw new HistoryException(e);\r
- } catch (IOException e) {\r
- throw new HistoryException(e);\r
- }\r
- }\r
-\r
- @Override\r
- public void delete(String... itemIds) throws HistoryException {\r
- for (String itemId : itemIds ) {\r
- File meta = toMetaFile( itemId );\r
- File data = toDataFile( itemId );\r
- File index = toIndexFile( itemId );\r
- if ( meta.exists() ) {\r
- if ( !meta.delete() ) {\r
- throw new HistoryException("Failed to delete "+meta);\r
- }\r
- }\r
- if ( data.exists() ) {\r
- if ( !data.delete() ) {\r
- throw new HistoryException("Failed to delete "+data);\r
- }\r
- }\r
- if ( index.exists() ) {\r
- if ( !index.delete() );\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void modify(Bean... items) throws HistoryException {\r
- \r
- try {\r
- for ( Bean item : items ) {\r
- if (DEBUG)\r
- System.out.println("modify(" + item + ")");\r
-// if ( !item.getFieldBinding("format").type().equals( Bindings.getBindingUnchecked(Datatype.class).type() ) )\r
-// System.err.println("Error");\r
-\r
- String id = (String) item.getField("id");\r
- File metaFile = toMetaFile( id );\r
- if ( !metaFile.exists() ) {\r
- create( item );\r
- } else {\r
- Bean oldItem = getItem( id );\r
- File dataFile = toDataFile( id );\r
- if ( dataFile.exists() ) {\r
- boolean enabled = item.hasField("enabled") ? (Boolean) item.getFieldUnchecked("enabled") : true;\r
- Datatype oldFormat = (Datatype) oldItem.getField( "format" );\r
- Datatype newFormat = (Datatype) item.getField( "format" );\r
- if (DEBUG)\r
- System.out.println("formats: " + oldFormat + " -> " + newFormat);\r
- Datatype unitStrippedOldFormat = stripUnitAnnotations(oldFormat);\r
- Datatype unitStrippedNewFormat = stripUnitAnnotations(newFormat);\r
- if (DEBUG)\r
- System.out.println("formats after unit strip: " + unitStrippedOldFormat + " -> " + unitStrippedNewFormat);\r
- if ( enabled && !unitStrippedOldFormat.equals(unitStrippedNewFormat) ) {\r
- try {\r
- Binding oldBinding = Bindings.getBeanBinding(unitStrippedOldFormat);\r
- Binding newBinding = Bindings.getBeanBinding(unitStrippedNewFormat);\r
- Serializer oldS = Bindings.getSerializer(oldBinding);\r
- Serializer newS = Bindings.getSerializer(newBinding);\r
- if (oldS.getConstantSize()==null || newS.getConstantSize()==null || oldS.getConstantSize()!=newS.getConstantSize())\r
- throw new HistoryException("Changing of file format is not supported to: "+dataFile);\r
- Adapter adapter = Bindings.getAdapter(oldBinding, newBinding);\r
- Object oldSample = oldBinding.createDefault();\r
- Object newSample = newBinding.createDefault();\r
- StreamAccessor sa = openStream(id, "rw");\r
- try {\r
- int c = sa.size();\r
- for (int i=0; i<c; i++) {\r
- sa.get(i, oldBinding, oldSample);\r
- newSample = adapter.adapt(oldSample);\r
- sa.set(i, newBinding, newSample);\r
- }\r
- } finally {\r
- sa.close();\r
- }\r
- } catch (AdapterConstructionException e) {\r
- throw new HistoryException("Changing of file format is not supported to: "+id);\r
- } catch (SerializerConstructionException e) {\r
- throw new HistoryException("Changing of file format is not supported to: "+id);\r
- } catch (AccessorException e) {\r
- throw new HistoryException("Changing of file format failed to: "+id);\r
- } catch (AdaptException e) {\r
- throw new HistoryException("Changing of file format failed to: "+id);\r
- }\r
- }\r
- } else {\r
- dataFile.createNewFile();\r
- }\r
-\r
- // Write new meta-data if necessary\r
- if (!equalsWithoutState(item, oldItem))\r
- writeMetadata( item );\r
- }\r
- }\r
- } catch (BindingException e) {\r
- throw new HistoryException( e );\r
- } catch (IOException e) {\r
- throw new HistoryException( e );\r
- }\r
- }\r
-\r
- @Override\r
- public Bean getItem(String itemId) throws HistoryException {\r
- return getItem( toMetaFile( itemId ) );\r
- }\r
- \r
- void writeMetadata( Bean item ) throws HistoryException {\r
- \r
-// long s = System.nanoTime();\r
- try {\r
- String id = (String) item.getField("id");\r
- String idEnc = URIUtil.encodeURI(id);\r
- File metaFile = new File(workarea, idEnc + ".txt");\r
- Serializer typeSerializer = Bindings.getSerializer( Bindings.getBindingUnchecked(Datatype.class) );\r
- Serializer beanSerializer = Bindings.getSerializer( item.getBinding() );\r
- int size = typeSerializer.getSize(item.getBinding().type()) +\r
- beanSerializer.getSize(item);\r
- byte data[] = new byte[size];\r
- DataOutput out = new ByteBufferWriteable( ByteBuffer.wrap(data) );\r
- \r
- if ( metaFile.exists() && asyncUsage ) {\r
- if (DEBUG)\r
- System.out.println("WARNING: FileHistory.writeMetadata: on SLOW path for " + item);\r
- File tmpFile = new File(workarea, idEnc + ".tmp");\r
- File tmp2File = new File(workarea, idEnc + ".tmp2");\r
- tmpFile.delete();\r
- \r
- typeSerializer.serialize(out, item.getBinding().type());\r
- beanSerializer.serialize(out, item);\r
- FileUtils.writeFile(tmpFile, data);\r
- metaFile.renameTo(tmp2File);\r
- tmpFile.renameTo(metaFile);\r
- tmp2File.delete();\r
- } else {\r
- typeSerializer.serialize(out, item.getBinding().type());\r
- beanSerializer.serialize(out, item);\r
- FileUtils.writeFile(metaFile, data);\r
- }\r
-\r
-// if (PROFILE)\r
-// System.out.println("PROFILE: FileHistory.writeMetadata( " + metaFile.getName() + " ) in " + ((System.nanoTime() - s)*1e-6) + " ms");\r
- } catch (BindingException e) {\r
- throw new HistoryException(e);\r
- } catch (IOException e) {\r
- throw new HistoryException(e);\r
- } catch (SerializerConstructionException e) {\r
- throw new HistoryException(e);\r
- }\r
- }\r
-\r
- Bean getItem(File file) throws HistoryException {\r
-// FileInputStream fis;\r
-// try {\r
-// fis = new FileInputStream(file);\r
-// } catch (FileNotFoundException e1) {\r
-// throw new HistoryException(e1);\r
-// }\r
- try {\r
- byte[] data = FileUtils.readFile(file);\r
- DataInput in = new BinaryMemory(data); \r
- Serializer typeSerializer = Bindings.getSerializer( Bindings.getBindingUnchecked(Datatype.class) ); \r
- Datatype type = (Datatype) typeSerializer.deserialize(in);\r
- Binding beanBinding = Bindings.getBeanBinding( type );\r
- Serializer s = Bindings.getSerializer( beanBinding );\r
- Bean bean = (Bean) s.deserialize(in);\r
- /*\r
- DataInput in = new InputStreamReadable( fis, file.length() );\r
- Serializer typeSerializer = Bindings.getSerializer( Bindings.getBindingUnchecked(Datatype.class) ); \r
- Datatype type = (Datatype) typeSerializer.deserialize(in);\r
- Binding beanBinding = Bindings.getBeanBinding( type );\r
- Serializer s = Bindings.getSerializer( beanBinding );\r
- Bean bean = (Bean) s.deserialize(in);\r
- */\r
- return bean;\r
-/* String txt = new String(data, UTF8.CHARSET); \r
- DataValueRepository repo = new DataValueRepository();\r
- String name = repo.addValueDefinition(txt);\r
- MutableVariant value = repo.get(name);\r
- Binding beanBinding = Bindings.getBeanBinding( value.type() );\r
- return (Bean) value.getValue(beanBinding);*/\r
- } catch(BufferUnderflowException e) {\r
- throw new HistoryException( e );\r
- } catch(IOException e) {\r
- throw new HistoryException( e );\r
-// } catch (DataTypeSyntaxError e) {\r
-// throw new HistoryException( e );\r
- } catch (RuntimeBindingConstructionException e) {\r
- throw new HistoryException( e );\r
- } catch (SerializerConstructionException e) {\r
- throw new HistoryException( e );\r
- } finally {\r
-// try {\r
-// fis.close();\r
-// } catch (IOException e) {\r
-// }\r
- }\r
- }\r
- \r
- File toMetaFile(String itemId)\r
- {\r
- String name = URIUtil.encodeURI(itemId) + ".txt";\r
- File f = new File(workarea, name);\r
- return f;\r
- }\r
-\r
- File toDataFile(String itemId)\r
- {\r
- String name = URIUtil.encodeURI(itemId) + ".data";\r
- File f = new File(workarea, name);\r
- return f;\r
- }\r
- \r
- File toIndexFile(String itemId)\r
- {\r
- String name = URIUtil.encodeURI(itemId) + ".index";\r
- File f = new File(workarea, name);\r
- return f;\r
- }\r
- \r
- boolean isVariableWidth(Datatype type) \r
- throws HistoryException {\r
- try {\r
- Binding beanBinding = Bindings.getBeanBinding(type);\r
- Serializer s = Bindings.getSerializer( beanBinding );\r
- return s.getConstantSize() == null;\r
- } catch (SerializerConstructionException e) {\r
- throw new HistoryException(e);\r
- }\r
- }\r
-\r
- @Override\r
- public Bean[] getItems() throws HistoryException {\r
- List<Bean> result = new ArrayList<Bean>();\r
- File[] files = workarea.listFiles(txtFilter);\r
- if ( files != null ) {\r
- for (File file : files) {\r
- result.add( getItem(file) );\r
- }\r
- }\r
- return result.toArray( new Bean[ result.size() ] );\r
- }\r
-\r
- @Override\r
- public void close() {\r
- // Nothing to do.\r
- }\r
-\r
- @Override\r
- public StreamAccessor openStream(String itemId, String mode) throws HistoryException {\r
- try {\r
- Bean bean = getItem(itemId);\r
- Datatype format = (Datatype) bean.getField("format");\r
- ArrayType arrayType = new ArrayType(format);\r
- File dataFile = toDataFile( itemId );\r
- if ( isVariableWidth(format) ) {\r
- File indexFile = toIndexFile( itemId );\r
- ArrayAccessor index = Accessors.openStream(indexFile, INDEX_TYPE, mode);\r
- return (StreamAccessor) Accessors.openStream(dataFile, arrayType, mode, index);\r
- } else {\r
- return (StreamAccessor) Accessors.openStream(dataFile, arrayType, mode);\r
- }\r
- } catch (AccessorConstructionException e) {\r
- throw new HistoryException(e);\r
- } catch (BindingException e) {\r
- throw new HistoryException(e);\r
- }\r
- }\r
-\r
- @Override\r
- public boolean exists(String itemId) throws HistoryException {\r
- return toMetaFile(itemId).exists();\r
- }\r
- \r
- @Override\r
- public int hashCode() {\r
- return workarea.hashCode();\r
- }\r
- \r
- @Override\r
- public boolean equals(Object obj) {\r
- if ( obj==null ) return false;\r
- if ( obj instanceof FileHistory == false ) return false;\r
- FileHistory other = (FileHistory) obj; \r
- return other.workarea.equals(workarea);\r
- }\r
- \r
- @Override\r
- public String toString() {\r
- return "FileHistory: "+workarea;\r
- }\r
-\r
- private boolean equalsWithoutState(Bean i1, Bean i2) {\r
- Component[] components1 = i1.getBinding().type().getComponents();\r
- Component[] components2 = i2.getBinding().type().getComponents();\r
- int components = Math.min(components1.length, components2.length);\r
- for (int c = 0; c < components; ++c) {\r
- Object o1 = i1.getFieldUnchecked(c);\r
- Object o2 = i2.getFieldUnchecked(c);\r
- if ("collectorState".equals(components1[c].name) && (o1 == null || o2 == null))\r
- continue;\r
- if (!ObjectUtils.objectEquals(o1, o2))\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
- static {\r
- txtFilter = new FilenameFilter() {\r
- public boolean accept(File dir, String name) {\r
- return name.toLowerCase().endsWith(".txt");\r
- }\r
- };\r
- }\r
-\r
- private static Datatype stripUnitAnnotations(Datatype datatype) {\r
- if (datatype instanceof NumberType) {\r
- NumberType nt = (NumberType) datatype;\r
- if (nt.getUnit() != null) {\r
- Binding dtb = Bindings.getBindingUnchecked(Datatype.class);\r
- datatype = nt = (NumberType) Bindings.cloneUnchecked(datatype, dtb, dtb);\r
- nt.setUnit(null);\r
- }\r
- } else if (datatype instanceof ArrayType) {\r
- ArrayType at = (ArrayType) datatype;\r
- Datatype ct = at.componentType();\r
- Datatype component = stripUnitAnnotations(ct);\r
- if (component != ct) {\r
- Binding dtb = Bindings.getBindingUnchecked(Datatype.class);\r
- datatype = at = (ArrayType) Bindings.cloneUnchecked(datatype, dtb, dtb);\r
- at.setComponentType(component);\r
- }\r
- } else if (datatype instanceof RecordType) {\r
- RecordType rt = (RecordType) datatype;\r
- int componentCount = rt.getComponentCount();\r
- Component[] newComponents = new Component[componentCount];\r
- for (int i = 0; i < componentCount; ++i) {\r
- Component c = rt.getComponent(i);\r
- Datatype ct = c.type;\r
- Datatype sct = stripUnitAnnotations(ct);\r
- newComponents[i] = new Component(c.name, sct);\r
- }\r
- return new RecordType(rt.isReferable(), newComponents);\r
- }\r
- return datatype;\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.history.impl;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.simantics.databoard.Accessors;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.accessor.ArrayAccessor;
+import org.simantics.databoard.accessor.StreamAccessor;
+import org.simantics.databoard.accessor.error.AccessorConstructionException;
+import org.simantics.databoard.accessor.error.AccessorException;
+import org.simantics.databoard.adapter.AdaptException;
+import org.simantics.databoard.adapter.Adapter;
+import org.simantics.databoard.adapter.AdapterConstructionException;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;
+import org.simantics.databoard.serialization.Serializer;
+import org.simantics.databoard.serialization.SerializerConstructionException;
+import org.simantics.databoard.type.ArrayType;
+import org.simantics.databoard.type.Component;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.type.NumberType;
+import org.simantics.databoard.type.RecordType;
+import org.simantics.databoard.util.Bean;
+import org.simantics.databoard.util.ObjectUtils;
+import org.simantics.databoard.util.URIUtil;
+import org.simantics.databoard.util.binary.BinaryMemory;
+import org.simantics.databoard.util.binary.ByteBufferWriteable;
+import org.simantics.history.HistoryException;
+import org.simantics.history.HistoryManager;
+import org.simantics.utils.FileUtils;
+
+/**
+ * File history uses workarea (directory) to manage items.
+ * There are two files for every item: stream file and metadata file.
+ * Metadata file is JSON ascii file.
+ * itemname.data
+ * itemname.txt
+ *
+ * @author toni.kalajainen
+ *
+ */
+public class FileHistory implements HistoryManager {
+
+ private static final boolean PROFILE = false;
+ private static final boolean DEBUG = false;
+
+ /** Logger */
+ static Logger logger = Logger.getLogger(FileHistory.class.getName());
+
+ static FilenameFilter txtFilter;
+
+ static ArrayType INDEX_TYPE = Bindings.LONG_ARRAY.type();
+
+ File workarea;
+
+ /** Support async usage of the data */
+ public boolean asyncUsage = true;
+
+ public FileHistory(File workarea) {
+ this.workarea = workarea;
+ }
+
+ public File getWorkarea() {
+ return workarea;
+ }
+
+ @Override
+ public void create(Bean... items) throws HistoryException {
+
+ try {
+ for (Bean item : items) {
+ if (DEBUG)
+ System.out.println("create(" + item + ")");
+// if ( !item.getFieldBinding("format").type().equals( Bindings.getBindingUnchecked(Datatype.class).type() ) )
+// System.err.println("Error");
+
+ // Write meta data
+ writeMetadata( item );
+
+ // Create stream file
+ String id = (String) item.getField("id");
+ File dataFile = toDataFile( id );
+ dataFile.createNewFile();
+
+ Datatype type = (Datatype) item.getField("format");
+ if ( isVariableWidth(type) ) {
+ File indexFile = toIndexFile( id );
+ indexFile.createNewFile();
+ }
+// if ( !dataFile.createNewFile() ) {
+// throw new HistoryException("Could not create file "+dataFile);
+// }
+ }
+ } catch (BindingException e) {
+ throw new HistoryException(e);
+ } catch (IOException e) {
+ throw new HistoryException(e);
+ }
+ }
+
+ @Override
+ public void delete(String... itemIds) throws HistoryException {
+ for (String itemId : itemIds ) {
+ File meta = toMetaFile( itemId );
+ File data = toDataFile( itemId );
+ File index = toIndexFile( itemId );
+ if ( meta.exists() ) {
+ if ( !meta.delete() ) {
+ throw new HistoryException("Failed to delete "+meta);
+ }
+ }
+ if ( data.exists() ) {
+ if ( !data.delete() ) {
+ throw new HistoryException("Failed to delete "+data);
+ }
+ }
+ if ( index.exists() ) {
+ if ( !index.delete() );
+ }
+ }
+ }
+
+ @Override
+ public void modify(Bean... items) throws HistoryException {
+
+ try {
+ for ( Bean item : items ) {
+ if (DEBUG)
+ System.out.println("modify(" + item + ")");
+// if ( !item.getFieldBinding("format").type().equals( Bindings.getBindingUnchecked(Datatype.class).type() ) )
+// System.err.println("Error");
+
+ String id = (String) item.getField("id");
+ File metaFile = toMetaFile( id );
+ if ( !metaFile.exists() ) {
+ create( item );
+ } else {
+ Bean oldItem = getItem( id );
+ File dataFile = toDataFile( id );
+ if ( dataFile.exists() ) {
+ boolean enabled = item.hasField("enabled") ? (Boolean) item.getFieldUnchecked("enabled") : true;
+ Datatype oldFormat = (Datatype) oldItem.getField( "format" );
+ Datatype newFormat = (Datatype) item.getField( "format" );
+ if (DEBUG)
+ System.out.println("formats: " + oldFormat + " -> " + newFormat);
+ Datatype unitStrippedOldFormat = stripUnitAnnotations(oldFormat);
+ Datatype unitStrippedNewFormat = stripUnitAnnotations(newFormat);
+ if (DEBUG)
+ System.out.println("formats after unit strip: " + unitStrippedOldFormat + " -> " + unitStrippedNewFormat);
+ if ( enabled && !unitStrippedOldFormat.equals(unitStrippedNewFormat) ) {
+ try {
+ Binding oldBinding = Bindings.getBeanBinding(unitStrippedOldFormat);
+ Binding newBinding = Bindings.getBeanBinding(unitStrippedNewFormat);
+ Serializer oldS = Bindings.getSerializer(oldBinding);
+ Serializer newS = Bindings.getSerializer(newBinding);
+ if (oldS.getConstantSize()==null || newS.getConstantSize()==null || oldS.getConstantSize()!=newS.getConstantSize())
+ throw new HistoryException("Changing of file format is not supported to: "+dataFile);
+ Adapter adapter = Bindings.getAdapter(oldBinding, newBinding);
+ Object oldSample = oldBinding.createDefault();
+ Object newSample = newBinding.createDefault();
+ StreamAccessor sa = openStream(id, "rw");
+ try {
+ int c = sa.size();
+ for (int i=0; i<c; i++) {
+ sa.get(i, oldBinding, oldSample);
+ newSample = adapter.adapt(oldSample);
+ sa.set(i, newBinding, newSample);
+ }
+ } finally {
+ sa.close();
+ }
+ } catch (AdapterConstructionException e) {
+ throw new HistoryException("Changing of file format is not supported to: "+id);
+ } catch (SerializerConstructionException e) {
+ throw new HistoryException("Changing of file format is not supported to: "+id);
+ } catch (AccessorException e) {
+ throw new HistoryException("Changing of file format failed to: "+id);
+ } catch (AdaptException e) {
+ throw new HistoryException("Changing of file format failed to: "+id);
+ }
+ }
+ } else {
+ dataFile.createNewFile();
+ }
+
+ // Write new meta-data if necessary
+ if (!equalsWithoutState(item, oldItem))
+ writeMetadata( item );
+ }
+ }
+ } catch (BindingException e) {
+ throw new HistoryException( e );
+ } catch (IOException e) {
+ throw new HistoryException( e );
+ }
+ }
+
+ @Override
+ public Bean getItem(String itemId) throws HistoryException {
+ return getItem( toMetaFile( itemId ) );
+ }
+
+ void writeMetadata( Bean item ) throws HistoryException {
+
+// long s = System.nanoTime();
+ try {
+ String id = (String) item.getField("id");
+ String idEnc = URIUtil.encodeURI(id);
+ File metaFile = new File(workarea, idEnc + ".txt");
+ Serializer typeSerializer = Bindings.getSerializer( Bindings.getBindingUnchecked(Datatype.class) );
+ Serializer beanSerializer = Bindings.getSerializer( item.getBinding() );
+ int size = typeSerializer.getSize(item.getBinding().type()) +
+ beanSerializer.getSize(item);
+ byte data[] = new byte[size];
+ DataOutput out = new ByteBufferWriteable( ByteBuffer.wrap(data) );
+
+ if ( metaFile.exists() && asyncUsage ) {
+ if (DEBUG)
+ System.out.println("WARNING: FileHistory.writeMetadata: on SLOW path for " + item);
+ File tmpFile = new File(workarea, idEnc + ".tmp");
+ File tmp2File = new File(workarea, idEnc + ".tmp2");
+ tmpFile.delete();
+
+ typeSerializer.serialize(out, item.getBinding().type());
+ beanSerializer.serialize(out, item);
+ FileUtils.writeFile(tmpFile, data);
+ metaFile.renameTo(tmp2File);
+ tmpFile.renameTo(metaFile);
+ tmp2File.delete();
+ } else {
+ typeSerializer.serialize(out, item.getBinding().type());
+ beanSerializer.serialize(out, item);
+ FileUtils.writeFile(metaFile, data);
+ }
+
+// if (PROFILE)
+// System.out.println("PROFILE: FileHistory.writeMetadata( " + metaFile.getName() + " ) in " + ((System.nanoTime() - s)*1e-6) + " ms");
+ } catch (BindingException e) {
+ throw new HistoryException(e);
+ } catch (IOException e) {
+ throw new HistoryException(e);
+ } catch (SerializerConstructionException e) {
+ throw new HistoryException(e);
+ }
+ }
+
+ Bean getItem(File file) throws HistoryException {
+// FileInputStream fis;
+// try {
+// fis = new FileInputStream(file);
+// } catch (FileNotFoundException e1) {
+// throw new HistoryException(e1);
+// }
+ try {
+ byte[] data = FileUtils.readFile(file);
+ DataInput in = new BinaryMemory(data);
+ Serializer typeSerializer = Bindings.getSerializer( Bindings.getBindingUnchecked(Datatype.class) );
+ Datatype type = (Datatype) typeSerializer.deserialize(in);
+ Binding beanBinding = Bindings.getBeanBinding( type );
+ Serializer s = Bindings.getSerializer( beanBinding );
+ Bean bean = (Bean) s.deserialize(in);
+ /*
+ DataInput in = new InputStreamReadable( fis, file.length() );
+ Serializer typeSerializer = Bindings.getSerializer( Bindings.getBindingUnchecked(Datatype.class) );
+ Datatype type = (Datatype) typeSerializer.deserialize(in);
+ Binding beanBinding = Bindings.getBeanBinding( type );
+ Serializer s = Bindings.getSerializer( beanBinding );
+ Bean bean = (Bean) s.deserialize(in);
+ */
+ return bean;
+/* String txt = new String(data, UTF8.CHARSET);
+ DataValueRepository repo = new DataValueRepository();
+ String name = repo.addValueDefinition(txt);
+ MutableVariant value = repo.get(name);
+ Binding beanBinding = Bindings.getBeanBinding( value.type() );
+ return (Bean) value.getValue(beanBinding);*/
+ } catch(BufferUnderflowException e) {
+ throw new HistoryException( e );
+ } catch(IOException e) {
+ throw new HistoryException( e );
+// } catch (DataTypeSyntaxError e) {
+// throw new HistoryException( e );
+ } catch (RuntimeBindingConstructionException e) {
+ throw new HistoryException( e );
+ } catch (SerializerConstructionException e) {
+ throw new HistoryException( e );
+ } finally {
+// try {
+// fis.close();
+// } catch (IOException e) {
+// }
+ }
+ }
+
+ File toMetaFile(String itemId)
+ {
+ String name = URIUtil.encodeURI(itemId) + ".txt";
+ File f = new File(workarea, name);
+ return f;
+ }
+
+ File toDataFile(String itemId)
+ {
+ String name = URIUtil.encodeURI(itemId) + ".data";
+ File f = new File(workarea, name);
+ return f;
+ }
+
+ File toIndexFile(String itemId)
+ {
+ String name = URIUtil.encodeURI(itemId) + ".index";
+ File f = new File(workarea, name);
+ return f;
+ }
+
+ boolean isVariableWidth(Datatype type)
+ throws HistoryException {
+ try {
+ Binding beanBinding = Bindings.getBeanBinding(type);
+ Serializer s = Bindings.getSerializer( beanBinding );
+ return s.getConstantSize() == null;
+ } catch (SerializerConstructionException e) {
+ throw new HistoryException(e);
+ }
+ }
+
+ @Override
+ public Bean[] getItems() throws HistoryException {
+ List<Bean> result = new ArrayList<Bean>();
+ File[] files = workarea.listFiles(txtFilter);
+ if ( files != null ) {
+ for (File file : files) {
+ result.add( getItem(file) );
+ }
+ }
+ return result.toArray( new Bean[ result.size() ] );
+ }
+
+ @Override
+ public void close() {
+ // Nothing to do.
+ }
+
+ @Override
+ public StreamAccessor openStream(String itemId, String mode) throws HistoryException {
+ try {
+ Bean bean = getItem(itemId);
+ Datatype format = (Datatype) bean.getField("format");
+ ArrayType arrayType = new ArrayType(format);
+ File dataFile = toDataFile( itemId );
+ if ( isVariableWidth(format) ) {
+ File indexFile = toIndexFile( itemId );
+ ArrayAccessor index = Accessors.openStream(indexFile, INDEX_TYPE, mode);
+ return (StreamAccessor) Accessors.openStream(dataFile, arrayType, mode, index);
+ } else {
+ return (StreamAccessor) Accessors.openStream(dataFile, arrayType, mode);
+ }
+ } catch (AccessorConstructionException e) {
+ throw new HistoryException(e);
+ } catch (BindingException e) {
+ throw new HistoryException(e);
+ }
+ }
+
+ @Override
+ public boolean exists(String itemId) throws HistoryException {
+ return toMetaFile(itemId).exists();
+ }
+
+ @Override
+ public int hashCode() {
+ return workarea.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( obj==null ) return false;
+ if ( obj instanceof FileHistory == false ) return false;
+ FileHistory other = (FileHistory) obj;
+ return other.workarea.equals(workarea);
+ }
+
+ @Override
+ public String toString() {
+ return "FileHistory: "+workarea;
+ }
+
+ private boolean equalsWithoutState(Bean i1, Bean i2) {
+ Component[] components1 = i1.getBinding().type().getComponents();
+ Component[] components2 = i2.getBinding().type().getComponents();
+ int components = Math.min(components1.length, components2.length);
+ for (int c = 0; c < components; ++c) {
+ Object o1 = i1.getFieldUnchecked(c);
+ Object o2 = i2.getFieldUnchecked(c);
+ if ("collectorState".equals(components1[c].name) && (o1 == null || o2 == null))
+ continue;
+ if (!ObjectUtils.objectEquals(o1, o2))
+ return false;
+ }
+ return true;
+ }
+
+ static {
+ txtFilter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.toLowerCase().endsWith(".txt");
+ }
+ };
+ }
+
+ private static Datatype stripUnitAnnotations(Datatype datatype) {
+ if (datatype instanceof NumberType) {
+ NumberType nt = (NumberType) datatype;
+ if (nt.getUnit() != null) {
+ Binding dtb = Bindings.getBindingUnchecked(Datatype.class);
+ datatype = nt = (NumberType) Bindings.cloneUnchecked(datatype, dtb, dtb);
+ nt.setUnit(null);
+ }
+ } else if (datatype instanceof ArrayType) {
+ ArrayType at = (ArrayType) datatype;
+ Datatype ct = at.componentType();
+ Datatype component = stripUnitAnnotations(ct);
+ if (component != ct) {
+ Binding dtb = Bindings.getBindingUnchecked(Datatype.class);
+ datatype = at = (ArrayType) Bindings.cloneUnchecked(datatype, dtb, dtb);
+ at.setComponentType(component);
+ }
+ } else if (datatype instanceof RecordType) {
+ RecordType rt = (RecordType) datatype;
+ int componentCount = rt.getComponentCount();
+ Component[] newComponents = new Component[componentCount];
+ for (int i = 0; i < componentCount; ++i) {
+ Component c = rt.getComponent(i);
+ Datatype ct = c.type;
+ Datatype sct = stripUnitAnnotations(ct);
+ newComponents[i] = new Component(c.name, sct);
+ }
+ return new RecordType(rt.isReferable(), newComponents);
+ }
+ return datatype;
+ }
+
+}