From ceb89bf8c9e1baae913a5f7993b27ab8b88dadd2 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Thu, 25 Oct 2007 12:58:26 +0000
Subject: [PATCH] IDataStructure changed

SVN: 2252
---
 .../cisd/bds/AbstractDataStructure.java       |  50 +++++++-
 .../cisd/bds/DataStructureLoader.java         |   4 +-
 .../systemsx/cisd/bds/DataStructureV1_0.java  |  44 ++++---
 .../ch/systemsx/cisd/bds/IDataStructure.java  |  27 +++-
 .../cisd/bds/DataStructureLoaderTest.java     |   5 +-
 .../cisd/bds/DataStructureV1_0Test.java       | 119 ++++++++++++------
 6 files changed, 183 insertions(+), 66 deletions(-)

diff --git a/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java b/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java
index dca7be2e5bb..939286081f8 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java
@@ -27,33 +27,77 @@ import ch.systemsx.cisd.bds.storage.IStorage;
 abstract class AbstractDataStructure implements IDataStructure
 {
     protected final IStorage storage;
-    protected final IDirectory root;
+    
+    protected IDirectory root;
 
     AbstractDataStructure(IStorage storage)
     {
         assert storage != null: "Unspecified storage.";
         this.storage = storage;
+    }
+
+    private void mountStorage()
+    {
         storage.mount();
         root = storage.getRoot();
     }
     
+    /**
+     * Asserts that this instance is already opened or created otherwise a {@link IllegalStateException} is thrown.
+     */
+    protected void assertOpenOrCreated()
+    {
+        if (root == null)
+        {
+            throw new IllegalStateException("Data structure should first be opened or created.");
+        }
+    }
+    
+    /**
+     * Validates this data structure and throws {@link DataStructureException} if invalid. 
+     */
+    protected abstract void assertValid(); 
+    
+    /**
+     * Performs opening specific for the concrete data structure. Will be invoked after the common part of
+     * {@link #open()} but before validation with {@link #assertValid()}. 
+     */
+    protected abstract void performOpening();
+    
+    /**
+     * Performs closing specific for the concrete data structure. Will be invoked before validation with
+     * {@link #assertValid()}.
+     */
+    protected abstract void performClosing();
+    
     //
     // IDataStructure
     //
+    
+    public final void create()
+    {
+        mountStorage();
+    }
 
-    public void load()
+    public final void open()
     {
+        mountStorage();
+        performOpening();
         Version loadedVersion = Version.loadFrom(root);
         if (loadedVersion.isBackwardsCompatibleWith(getVersion()) == false)
         {
             throw new DataStructureException("Version of loaded data structure is " + loadedVersion
                     + " which is not backward compatible with " + getVersion());
         }
+        assertValid();
     }
     
-    public void save()
+    public final void close()
     {
+        assertOpenOrCreated();
         getVersion().saveTo(root);
+        performClosing();
+        assertValid();
         storage.unmount();
     }
 }
diff --git a/bds/source/java/ch/systemsx/cisd/bds/DataStructureLoader.java b/bds/source/java/ch/systemsx/cisd/bds/DataStructureLoader.java
index 6c23fa41ac0..9f6ddd0e4bd 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/DataStructureLoader.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureLoader.java
@@ -49,7 +49,9 @@ public class DataStructureLoader
         IStorage storage = createStorage(name);
         storage.mount();
         Version version = Version.loadFrom(storage.getRoot());
-        return DataStructureFactory.createDataStructure(storage, version);
+        IDataStructure dataStructure = DataStructureFactory.createDataStructure(storage, version);
+        dataStructure.open();
+        return dataStructure;
     }
     
     private IStorage createStorage(String name)
diff --git a/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java b/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java
index 5f678739efc..22702846d0c 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java
@@ -57,6 +57,7 @@ public class DataStructureV1_0 extends AbstractDataStructure
      */
     public IDirectory getOriginalData()
     {
+        assertOpenOrCreated();
         return Utilities.getOrCreateSubDirectory(getDataDirectory(), DIR_ORIGINAL);
     }
 
@@ -68,6 +69,7 @@ public class DataStructureV1_0 extends AbstractDataStructure
      */
     public IFormattedData getFormatedData()
     {
+        assertOpenOrCreated();
         if (format == null)
         {
             throw new DataStructureException("Couldn't create formated data because of undefined format.");
@@ -81,6 +83,7 @@ public class DataStructureV1_0 extends AbstractDataStructure
     public void setFormat(Format format)
     {
         assert format != null : "Unspecified format.";
+        assertOpenOrCreated();
         this.format = format;
     }
 
@@ -92,6 +95,7 @@ public class DataStructureV1_0 extends AbstractDataStructure
      */
     public ExperimentIdentifier getExperimentIdentifier()
     {
+        assertOpenOrCreated();
         return ExperimentIdentifier.loadFrom(getMetaDataDirectory());
     }
 
@@ -101,6 +105,7 @@ public class DataStructureV1_0 extends AbstractDataStructure
     public void setExperimentIdentifier(ExperimentIdentifier id)
     {
         assert id != null : "Unspecified experiment identifier";
+        assertOpenOrCreated();
         id.saveTo(getMetaDataDirectory());
     }
 
@@ -112,6 +117,7 @@ public class DataStructureV1_0 extends AbstractDataStructure
      */
     public ProcessingType getProcessingType()
     {
+        assertOpenOrCreated();
         return ProcessingType.loadFrom(getMetaDataDirectory());
     }
 
@@ -121,34 +127,21 @@ public class DataStructureV1_0 extends AbstractDataStructure
     public void setProcessingType(ProcessingType type)
     {
         assert type != null : "Unspecified processing type.";
+        assertOpenOrCreated();
         type.saveTo(getMetaDataDirectory());
     }
 
-    /**
-     * Loads the data structure from the storage and sets the format.
-     */
-    @Override
-    public void load()
-    {
-        super.load();
-        setFormat(Format.loadFrom(getMetaDataDirectory()));
-    }
-
     @Override
-    public void save()
+    protected void assertValid()
     {
         if (getOriginalData().iterator().hasNext() == false)
         {
             throw new DataStructureException("Empty original data directory.");
         }
         IDirectory metaDataDirectory = getMetaDataDirectory();
-        if (metaDataDirectory.tryToGetNode(Format.FORMAT_DIR) == null)
+        if (metaDataDirectory.tryToGetNode(Format.FORMAT_DIR) == null && format == null)
         {
-            if (format == null)
-            {
-                throw new DataStructureException("Unspecified format.");
-            }
-            format.saveTo(metaDataDirectory);
+            throw new DataStructureException("Unspecified format.");
         }
         if (metaDataDirectory.tryToGetNode(ExperimentIdentifier.FOLDER) == null)
         {
@@ -158,7 +151,22 @@ public class DataStructureV1_0 extends AbstractDataStructure
         {
             throw new DataStructureException("Unspecified processing type.");
         }
-        super.save();
+    }
+
+    @Override
+    protected void performOpening()
+    {
+        setFormat(Format.loadFrom(getMetaDataDirectory()));
+    }
+    
+    @Override
+    protected void performClosing()
+    {
+        IDirectory metaDataDirectory = getMetaDataDirectory();
+        if (metaDataDirectory.tryToGetNode(Format.FORMAT_DIR) == null && format != null)
+        {
+            format.saveTo(metaDataDirectory);
+        }
     }
 
     private IDirectory getDataDirectory()
diff --git a/bds/source/java/ch/systemsx/cisd/bds/IDataStructure.java b/bds/source/java/ch/systemsx/cisd/bds/IDataStructure.java
index c7dbd88c5ca..cfa80e22a7f 100644
--- a/bds/source/java/ch/systemsx/cisd/bds/IDataStructure.java
+++ b/bds/source/java/ch/systemsx/cisd/bds/IDataStructure.java
@@ -18,20 +18,37 @@ package ch.systemsx.cisd.bds;
 
 
 /**
- * Common interface of all data structures.
+ * Common interface of all data structures. Implementations of this interface provide methods to manipulate a data
+ * structure. These methods are specific for the version of the data structure. For each version there is a concrete
+ * class implementing this interface.
+ * <p>
+ * A data structure must first be created with {@link #create()} or opened with {@link #open()} before any other method
+ * can be invoked. An {@link IllegalStateException} is thrown otherwise. Finally a data structure has to be closed with
+ * {@link #close()} in order to commit all changes made since creation or opening.
  * 
  * @author Franz-Josef Elmer
  */
 public interface IDataStructure extends IHasVersion
 {
     /**
-     * Loads the data structure.
+     * Creates a new empty data structure.
      */
-    public void load();
+    public void create();
+    
+    /**
+     * Opens an existing data structure and validates it.
+     * 
+     * @throws DataStructureException if the data structure is invalid.
+     */
+    public void open();
 
     /**
-     * Saves the data structure.
+     * Closes the data structure. Before the data structure is closed it will be validated.
+     * 
+     * @throws DataStructureException if the data structure is invalid.
+     * @throws IllegalStateException if called before the first invocation of either {@link #create()} or
+     *             {@link #open()}.
      */
-    public void save();
+    public void close();
 
 }
\ No newline at end of file
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java
index f37ebc2fdfd..dad5c33423c 100644
--- a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java
@@ -43,17 +43,18 @@ public class DataStructureLoaderTest
     }
     
     @Test
-    public void testLoad()
+    public void testOpen()
     {
         File dir = new File(TEST_DIR, "ds");
         assert dir.mkdir();
         DataStructureV1_0 dataStructure = new DataStructureV1_0(new FileStorage(dir));
+        dataStructure.create();
         dataStructure.getOriginalData().addKeyValuePair("answer", "42");
         dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0);
         ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(experimentIdentifier);
         dataStructure.setProcessingType(ProcessingType.RAW_DATA);
-        dataStructure.save();
+        dataStructure.close();
         
         IDataStructure ds = new DataStructureLoader(TEST_DIR).load("ds");
         assertEquals(DataStructureV1_0.class, ds.getClass());
diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java
index 6e3a03d0c02..deda05911b9 100644
--- a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java
+++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java
@@ -61,6 +61,7 @@ public class DataStructureV1_0Test
     @Test
     public void testGetOriginalData()
     {
+        dataStructure.create();
         IDirectory dataFolder = dataStructure.getOriginalData();
         assertEquals(DataStructureV1_0.DIR_ORIGINAL, dataFolder.getName());
         assertEquals(DataStructureV1_0.DIR_DATA, dataFolder.tryToGetParent().getName());
@@ -69,6 +70,7 @@ public class DataStructureV1_0Test
     @Test
     public void testGetFormatedData()
     {
+        dataStructure.create();
         dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0);
         IFormattedData formatedData = dataStructure.getFormatedData();
         assertTrue(formatedData instanceof NoFormattedData);
@@ -78,6 +80,7 @@ public class DataStructureV1_0Test
     @Test
     public void testGetFormatedDataBeforeInvokingSetVersion()
     {
+        dataStructure.create();
         try
         {
             dataStructure.getFormatedData();
@@ -91,6 +94,7 @@ public class DataStructureV1_0Test
     @Test
     public void testSetProcessingType()
     {
+        dataStructure.create();
         dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA);
         IDirectory root = storage.getRoot();
         IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
@@ -100,6 +104,7 @@ public class DataStructureV1_0Test
     @Test
     public void testSetProcessingTypeTwice()
     {
+        dataStructure.create();
         dataStructure.setProcessingType(ProcessingType.RAW_DATA);
         dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA);
         IDirectory root = storage.getRoot();
@@ -110,6 +115,7 @@ public class DataStructureV1_0Test
     @Test
     public void testGetProcessingType()
     {
+        dataStructure.create();
         dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA);
         assertEquals(ProcessingType.COMPUTED_DATA, dataStructure.getProcessingType());
     }
@@ -117,6 +123,7 @@ public class DataStructureV1_0Test
     @Test
     public void testGetUnknownProcessingType()
     {
+        dataStructure.create();
         dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA);
         IDirectory s = Utilities.getSubDirectory(storage.getRoot(), DataStructureV1_0.DIR_METADATA);
         s.addKeyValuePair(ProcessingType.PROCESSING_TYPE, "blabla");
@@ -126,6 +133,7 @@ public class DataStructureV1_0Test
     @Test
     public void testSetExperimentIdentifier()
     {
+        dataStructure.create();
         ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(id);
         IDirectory root = storage.getRoot();
@@ -139,6 +147,7 @@ public class DataStructureV1_0Test
     @Test
     public void testSetExperimentIdentifierTwice()
     {
+        dataStructure.create();
         dataStructure.setExperimentIdentifier(new ExperimentIdentifier("a", "b", "c"));
         ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(id);
@@ -153,6 +162,7 @@ public class DataStructureV1_0Test
     @Test
     public void testGetNonExistingExperimentIdentifier()
     {
+        dataStructure.create();
         try
         {
             dataStructure.getExperimentIdentifier();
@@ -166,6 +176,7 @@ public class DataStructureV1_0Test
     @Test
     public void testGetExperimentIdentifier()
     {
+        dataStructure.create();
         ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e");
         dataStructure.setExperimentIdentifier(id);
         assertEquals(id, dataStructure.getExperimentIdentifier());
@@ -174,15 +185,17 @@ public class DataStructureV1_0Test
     @Test
     public void testGetVersion()
     {
+        dataStructure.create();
         assertEquals(new Version(1, 0), dataStructure.getVersion());
     }
     
     @Test
-    public void testSaveForEmptyData()
+    public void testCloseForEmptyData()
     {
+        dataStructure.create();
         try
         {
-            dataStructure.save();
+            dataStructure.close();
             fail("DataStructureException expected.");
         } catch (DataStructureException e)
         {
@@ -191,12 +204,13 @@ public class DataStructureV1_0Test
     }
     
     @Test
-    public void testSaveIfNoFormat()
+    public void testCloseIfNoFormat()
     {
+        dataStructure.create();
         dataStructure.getOriginalData().addKeyValuePair("answer", "42");
         try
         {
-            dataStructure.save();
+            dataStructure.close();
             fail("DataStructureException expected.");
         } catch (DataStructureException e)
         {
@@ -205,13 +219,14 @@ public class DataStructureV1_0Test
     }
     
     @Test
-    public void testSaveIfNoExperimentID()
+    public void testCloseIfNoExperimentID()
     {
+        dataStructure.create();
         dataStructure.getOriginalData().addKeyValuePair("answer", "42");
         dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0);
         try
         {
-            dataStructure.save();
+            dataStructure.close();
             fail("DataStructureException expected.");
         } catch (DataStructureException e)
         {
@@ -220,14 +235,15 @@ public class DataStructureV1_0Test
     }
     
     @Test
-    public void testSaveIfNoProcessingType()
+    public void testCloseIfNoProcessingType()
     {
+        dataStructure.create();
         dataStructure.getOriginalData().addKeyValuePair("answer", "42");
         dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0);
         dataStructure.setExperimentIdentifier(new ExperimentIdentifier("g", "p", "e"));
         try
         {
-            dataStructure.save();
+            dataStructure.close();
             fail("DataStructureException expected.");
         } catch (DataStructureException e)
         {
@@ -236,8 +252,9 @@ public class DataStructureV1_0Test
     }
     
     @Test
-    public void testSave()
+    public void testClose()
     {
+        dataStructure.create();
         dataStructure.getOriginalData().addKeyValuePair("answer", "42");
         dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0);
         ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("g", "p", "e");
@@ -245,7 +262,7 @@ public class DataStructureV1_0Test
         dataStructure.setProcessingType(ProcessingType.RAW_DATA);
         
         IDirectory root = storage.getRoot();
-        dataStructure.save();
+        dataStructure.close();
         assertEquals(dataStructure.getVersion(), Version.loadFrom(root));
         try
         {
@@ -257,7 +274,7 @@ public class DataStructureV1_0Test
         }
         
         DataStructureV1_0 reloadedDataStructure = new DataStructureV1_0(storage);
-        reloadedDataStructure.load();
+        reloadedDataStructure.open();
         assertEquals("42\n", Utilities.getString(reloadedDataStructure.getOriginalData(), "answer"));
         assertEquals(UnknownFormat1_0.UNKNOWN_1_0, reloadedDataStructure.getFormatedData().getFormat());
         assertEquals(experimentIdentifier, reloadedDataStructure.getExperimentIdentifier());
@@ -265,11 +282,16 @@ public class DataStructureV1_0Test
     }
     
     @Test
-    public void testLoadIfVersionMissing()
+    public void testOpenIfVersionMissing()
     {
+        createExampleDataStructure();
+        storage.mount();
+        IDirectory root = storage.getRoot();
+        root.removeNode(Utilities.getSubDirectory(root, Version.VERSION));
+        storage.unmount();
         try
         {
-            dataStructure.load();
+            dataStructure.open();
             fail("DataStructureException expected.");
         } catch (DataStructureException e)
         {
@@ -278,33 +300,34 @@ public class DataStructureV1_0Test
     }
     
     @Test
-    public void testLoad()
+    public void testOpen()
     {
-        IDirectory root = storage.getRoot();
-        new Version(1, 0).saveTo(root);
-        IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA);
-        UnknownFormat1_0.UNKNOWN_1_0.saveTo(metaData);
-        dataStructure.load();
+        createExampleDataStructure();
+        dataStructure.open();
     }
     
     @Test
-    public void testLoadVersion1_1()
+    public void testOpenVersion1_1()
     {
+        createExampleDataStructure();
+        storage.mount();
         IDirectory root = storage.getRoot();
         new Version(1, 1).saveTo(root);
-        IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA);
-        UnknownFormat1_0.UNKNOWN_1_0.saveTo(metaData);
-        dataStructure.load();
+        storage.unmount();
+        dataStructure.open();
     }
     
     @Test
-    public void testLoadVersion2_0()
+    public void testOpenVersion2_0()
     {
+        createExampleDataStructure();
+        storage.mount();
         IDirectory root = storage.getRoot();
         new Version(2, 0).saveTo(root);
+        storage.unmount();
         try
         {
-            dataStructure.load();
+            dataStructure.open();
             fail("DataStructureException expected.");
         } catch (DataStructureException e)
         {
@@ -314,26 +337,30 @@ public class DataStructureV1_0Test
     }
     
     @Test
-    public void testLoadWithUnknownFormat1_1()
+    public void testOpenWithUnknownFormat1_1()
     {
+        createExampleDataStructure();
+        storage.mount();
         IDirectory root = storage.getRoot();
-        new Version(1, 0).saveTo(root);
-        IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA);
+        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
         new Format(UnknownFormat1_0.UNKNOWN_1_0.getCode(), new Version(1, 1)).saveTo(metaData);
-        dataStructure.load();
+        storage.unmount();
+        dataStructure.open();
         assertEquals(UnknownFormat1_0.UNKNOWN_1_0, dataStructure.getFormatedData().getFormat());
     }
     
     @Test
-    public void testLoadWithUnknownFormat2_0()
+    public void testOpenWithUnknownFormat2_0()
     {
+        createExampleDataStructure();
+        storage.mount();
         IDirectory root = storage.getRoot();
-        new Version(1, 0).saveTo(root);
-        IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA);
+        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
         new Format(UnknownFormat1_0.UNKNOWN_1_0.getCode(), new Version(2, 0)).saveTo(metaData);
+        storage.unmount();
         try
         {
-            dataStructure.load();
+            dataStructure.open();
             dataStructure.getFormatedData();
             fail("DataStructureException expected.");
         } catch (DataStructureException e)
@@ -343,14 +370,32 @@ public class DataStructureV1_0Test
     }
     
     @Test
-    public void testLoadWithAnotherFormat()
+    public void testOpenWithAnotherFormat()
     {
+        createExampleDataStructure();
+        storage.mount();
         IDirectory root = storage.getRoot();
-        new Version(1, 0).saveTo(root);
-        IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA);
+        IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA);
         new Format("another format", new Version(1,1)).saveTo(metaData);
-        dataStructure.load();
+        storage.unmount();
+        dataStructure.open();
         assertEquals(UnknownFormat1_0.UNKNOWN_1_0, dataStructure.getFormatedData().getFormat());
     }
     
+    
+    private void createExampleDataStructure()
+    {
+        storage.mount();
+        IDirectory root = storage.getRoot();
+        new Version(1, 0).saveTo(root);
+        IDirectory data = root.makeDirectory(DataStructureV1_0.DIR_DATA);
+        IDirectory originalDataDir = data.makeDirectory(DataStructureV1_0.DIR_ORIGINAL);
+        originalDataDir.addKeyValuePair("hello", "world");
+        IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA);
+        new Format(UnknownFormat1_0.UNKNOWN_1_0.getCode(), new Version(2, 0)).saveTo(metaData);
+        new ExperimentIdentifier("g", "p", "e").saveTo(metaData);
+        ProcessingType.COMPUTED_DATA.saveTo(metaData);
+        storage.unmount();
+        
+    }
 }
-- 
GitLab