diff --git a/bds/.classpath b/bds/.classpath index c9772c5f8e35106dcf90c4daeec72c84270a137d..793fb285c3a64ac7ab7bce393720a9ac6489502f 100644 --- a/bds/.classpath +++ b/bds/.classpath @@ -6,5 +6,11 @@ <classpathentry combineaccessrules="false" kind="src" path="/common"/> <classpathentry kind="lib" path="/libraries/commons-io/commons-io.jar" sourcepath="/libraries/commons-io/src.zip"/> <classpathentry kind="lib" path="/libraries/testng/testng-jdk15.jar" sourcepath="/libraries/testng/src.zip"/> + <classpathentry kind="lib" path="/libraries/jmock/third-party-libs/cglib-2.1_3-src.jar"/> + <classpathentry kind="lib" path="/libraries/jmock/jmock.jar"/> + <classpathentry kind="lib" path="/libraries/jmock/third-party-libs/cglib-nodep-2.1_3.jar"/> + <classpathentry kind="lib" path="/libraries/jmock/third-party-libs/hamcrest-api-1.0.jar"/> + <classpathentry kind="lib" path="/libraries/jmock/third-party-libs/hamcrest-library-1.0.jar"/> + <classpathentry kind="lib" path="/libraries/jmock/third-party-libs/objenesis-1.0.jar"/> <classpathentry kind="output" path="targets/classes"/> </classpath> diff --git a/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java b/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java index 684ecd3d09df4ca68016d4c595629775f18244a6..234813bd0f7dfccc3917fb31e088ca1a560ed0a6 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java +++ b/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java @@ -21,11 +21,11 @@ import ch.systemsx.cisd.bds.storage.IStorage; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * + * Abstract superclass of classes implementing {@link IDataStructure}. * * @author Franz-Josef Elmer */ -public abstract class AbstractDataStructure implements IHasVersion +abstract class AbstractDataStructure implements IDataStructure { protected final IStorage storage; protected final IDirectory root; @@ -34,14 +34,14 @@ public abstract class AbstractDataStructure implements IHasVersion { assert storage != null: "Unspecified storage."; this.storage = storage; + storage.mount(); root = storage.getRoot(); } public void load() { - storage.mount(); Version loadedVersion = Version.loadFrom(root); - if (getVersion().isBackwardsCompatibleWith(loadedVersion) == false) + if (loadedVersion.isBackwardsCompatibleWith(getVersion()) == false) { throw new UserFailureException("Version of loaded data structure is " + loadedVersion + " which is not backward compatible with " + getVersion()); diff --git a/bds/source/java/ch/systemsx/cisd/bds/DataStructureFactory.java b/bds/source/java/ch/systemsx/cisd/bds/DataStructureFactory.java index 9a3c2d56438e47f2347c1f5cef0d91a6bf6dfbca..9c628089e66d801bcc9e0abd6cc870960ddd8dac 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/DataStructureFactory.java +++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureFactory.java @@ -16,66 +16,47 @@ package ch.systemsx.cisd.bds; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; - import ch.systemsx.cisd.bds.storage.IStorage; import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * + * Factory of data structures. + * Currently only structures compatible with Version 1.0 can be created. * * @author Franz-Josef Elmer */ public class DataStructureFactory { - private static final Map<Version, Class<? extends AbstractDataStructure>> repository = - new HashMap<Version, Class<? extends AbstractDataStructure>>(); + private static final Factory<IDataStructure> factory = new Factory<IDataStructure>(); - void register(Version version, Class<? extends AbstractDataStructure> clazz) + static { - repository.put(version, clazz); + factory.register(new Version(1, 0), DataStructureV1_0.class); } - public static Class<? extends AbstractDataStructure> getDataStructureClassFor(Version version) + /** + * Returns the class of the object returned after invoking {@link #createDataStructure(IStorage, Version)}. + * + * @param version Version of the data structure. + * @throws UserFailureException if no data structure can be created for the specified version. + */ + public static Class<? extends IDataStructure> getDataStructureClassFor(Version version) { - Class<? extends AbstractDataStructure> clazz = null; - for (Version v = version; v.getMinor() >= 0 && clazz == null; v = v.getPreviousMinorVersion()) - { - clazz = repository.get(v); - } - if (clazz == null) - { - throw new UserFailureException("No data structure class found for version " + version); - } - return clazz; + return factory.getClassFor(version); } - public static AbstractDataStructure createDataStructure(IStorage storage, Version version) + /** + * Creates a data structure for the specified version. + * + * @param storage Storage behind the data structure. + * @param version Version of the data structure to be created. + * @throws EnvironmentFailureException found data structure class has not an appropriated constructor. + * @throws UserFailureException if no data structure can be created for the specified version. + */ + public static IDataStructure createDataStructure(IStorage storage, Version version) { - Class<? extends AbstractDataStructure> clazz = getDataStructureClassFor(version); - Constructor<? extends AbstractDataStructure> constructor; - try - { - constructor = clazz.getConstructor(new Class[] {IStorage.class}); - } catch (Exception ex1) - { - throw new EnvironmentFailureException(clazz + " has no constructor with argument of type " - + IStorage.class.getCanonicalName()); - } - try - { - return constructor.newInstance(new Object[] {storage}); - } catch (InvocationTargetException ex) - { - throw new UserFailureException("Couldn't create data structure for version " + version, ex.getCause()); - } catch (Exception ex) - { - throw new UserFailureException("Couldn't create data structure for version " + version, ex); - } + return factory.create(IStorage.class, storage, version); } private DataStructureFactory() diff --git a/bds/source/java/ch/systemsx/cisd/bds/Container.java b/bds/source/java/ch/systemsx/cisd/bds/DataStructureLoader.java similarity index 84% rename from bds/source/java/ch/systemsx/cisd/bds/Container.java rename to bds/source/java/ch/systemsx/cisd/bds/DataStructureLoader.java index a3e88af305ae453d8cd3708ef5816fc59540ee33..1d8538b58ca24fc23a6784ea5352ca9842d03493 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/Container.java +++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureLoader.java @@ -24,22 +24,28 @@ import ch.systemsx.cisd.bds.storage.hdf5.HDF5Storage; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * + * Loader for {@link IDataStructure}s from the file system. * * @author Franz-Josef Elmer */ -public class Container +public class DataStructureLoader { private final File baseDir; - public Container(File baseDir) + /** + * Creates an instance for the specified base directory where all data structures to be loaded have to exist. + */ + public DataStructureLoader(File baseDir) { assert baseDir != null : "Unspecified base directory."; assert baseDir.isDirectory() : "Is not a directory : " + baseDir.getAbsolutePath(); this.baseDir = baseDir; } - - public AbstractDataStructure load(String name) + + /** + * Loads the data structure with specified name. + */ + public IDataStructure load(String name) { IStorage storage = createStorage(name); storage.mount(); 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 97139abbe4d12bf480bbe05056a187d595b1238b..e260248a5db3d6a2ca9b8ec85f54e56f3183b725 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java +++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java @@ -18,67 +18,159 @@ package ch.systemsx.cisd.bds; import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.IStorage; +import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * + * Data structure Version 1.0. * * @author Franz-Josef Elmer */ public class DataStructureV1_0 extends AbstractDataStructure { + static final String DIR_METADATA = "metadata"; + + static final String DIR_DATA = "data"; + + static final String DIR_ORIGINAL = "original"; + private static final Version VERSION = new Version(1, 0); + private Format format; + /** + * Creates a new instance relying on the specified storage. + */ public DataStructureV1_0(IStorage storage) { super(storage); } + /** + * Returns version 1.0. + */ public Version getVersion() { return VERSION; } + /** + * Returns the directory containing the original data. + */ public IDirectory getOriginalData() { - return Utilities.getSubDirectory(getDataDirectory(), "original"); + return Utilities.getOrCreateSubDirectory(getDataDirectory(), DIR_ORIGINAL); } + /** + * Returns the formated data. This method can be called only after method + * {@link #setFormat(Format)} has been invoked. If the format is not known {@link UnknownFormat1_0} will be + * assumed. + * + * @throws UserFailureException if this method has been invoked before the format has been set. + */ public IFormatedData getFormatedData() { - return null; + if (format == null) + { + throw new UserFailureException("Couldn't create formated data because of undefined format."); + } + return FormatedDataFactory.createFormatedData(getMetaDataDirectory(), format, UnknownFormat1_0.UNKNOWN_1_0); + } + + /** + * Sets the data format of this structure. + */ + public void setFormat(Format format) + { + assert format != null : "Unspecified format."; + this.format = format; } + /** + * Returns the experiment identifier. + * + * @throws UserFailureException if the experiment identifier hasn't be loaded nor hasn't be set by + * {@link #setExperimentIdentifier(ExperimentIdentifier)}. + */ public ExperimentIdentifier getExperimentIdentifier() { return ExperimentIdentifier.loadFrom(getMetaDataDirectory()); } + /** + * Sets the experiment identifier. Overwrites an already set or loaded value. + */ public void setExperimentIdentifier(ExperimentIdentifier id) { + assert id != null : "Unspecified experiment identifier"; id.saveTo(getMetaDataDirectory()); } + /** + * Returns the processing type. + * + * @throws UserFailureException if the processing type hasn't be loaded nor hasn't be set by + * {@link #setProcessingType(ProcessingType)}. + */ public ProcessingType getProcessingType() { return ProcessingType.loadFrom(getMetaDataDirectory()); } + /** + * Sets the processing type. Overwrites an already set or loaded value. + */ public void setProcessingType(ProcessingType type) { + assert type != null : "Unspecified processing type."; 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() + { + if (getOriginalData().iterator().hasNext() == false) + { + throw new UserFailureException("Empty orginal data directory."); + } + IDirectory metaDataDirectory = getMetaDataDirectory(); + if (metaDataDirectory.tryToGetNode(Format.FORMAT_DIR) == null) + { + if (format == null) + { + throw new UserFailureException("Unspecified format."); + } + format.saveTo(metaDataDirectory); + } + if (metaDataDirectory.tryToGetNode(ExperimentIdentifier.FOLDER) == null) + { + throw new UserFailureException("Unspecified experiment identifier."); + } + if (metaDataDirectory.tryToGetNode(ProcessingType.PROCESSING_TYPE) == null) + { + throw new UserFailureException("Unspecified processing type."); + } + super.save(); + } + private IDirectory getDataDirectory() { - IDirectory subDirectory = Utilities.getSubDirectory(root, "data"); - return subDirectory; + return Utilities.getOrCreateSubDirectory(root, DIR_DATA); } private IDirectory getMetaDataDirectory() { - IDirectory subDirectory = Utilities.getSubDirectory(root, "metadata"); - return subDirectory; + return Utilities.getOrCreateSubDirectory(root, DIR_METADATA); } } diff --git a/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java b/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java index 8ab5d894f934263be333324dceb641162acbb462..ae28ef200612fbd1f3e4eec4423f945260837000 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java +++ b/bds/source/java/ch/systemsx/cisd/bds/ExperimentIdentifier.java @@ -17,6 +17,7 @@ package ch.systemsx.cisd.bds; import ch.systemsx.cisd.bds.storage.IDirectory; +import ch.systemsx.cisd.common.exceptions.UserFailureException; /** * Identifier of the experiment which corresponds to the data. This is an immutable but extendable value object class. @@ -26,12 +27,17 @@ import ch.systemsx.cisd.bds.storage.IDirectory; */ public class ExperimentIdentifier { - private static final String FOLDER = "experiment_identifier"; - private static final String GROUP_CODE = "group_code"; - private static final String PROJECT_CODE = "project_code"; - private static final String EXPERIMENT_CODE = "experiment_code"; + static final String FOLDER = "experiment_identifier"; + static final String GROUP_CODE = "group_code"; + static final String PROJECT_CODE = "project_code"; + static final String EXPERIMENT_CODE = "experiment_code"; - public static ExperimentIdentifier loadFrom(IDirectory directory) + /** + * Loads the experiment identifier from the specified directory. + * + * @throws UserFailureException if file missing. + */ + static ExperimentIdentifier loadFrom(IDirectory directory) { IDirectory idFolder = Utilities.getSubDirectory(directory, FOLDER); String groupCode = Utilities.getTrimmedString(idFolder, GROUP_CODE); @@ -85,7 +91,10 @@ public class ExperimentIdentifier return experimentCode; } - public void saveTo(IDirectory directory) + /** + * Saves this instance to the specified directory. + */ + void saveTo(IDirectory directory) { IDirectory folder = directory.makeDirectory(FOLDER); folder.addKeyValuePair(GROUP_CODE, groupCode); diff --git a/bds/source/java/ch/systemsx/cisd/bds/Factory.java b/bds/source/java/ch/systemsx/cisd/bds/Factory.java new file mode 100644 index 0000000000000000000000000000000000000000..fccbdd3e8a9bc8fccb55254a415e787f34170157 --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/Factory.java @@ -0,0 +1,85 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.exceptions.UserFailureException; + +/** + * General purpose factory for versioned classes with one-argument constructors. + * + * @author Franz-Josef Elmer + */ +class Factory<T> +{ + private final Map<Version, Class<? extends T>> repository = new HashMap<Version, Class<? extends T>>(); + + void register(Version version, Class<? extends T> clazz) + { + repository.put(version, clazz); + } + + Class<? extends T> getClassFor(Version version) + { + + Version v = version; + while (true) + { + Class<? extends T> clazz = repository.get(v); + if (clazz != null) + { + return clazz; + } + if (v.getMinor() == 0) + { + throw new UserFailureException("No class found for version " + version); + } + v = v.getPreviousMinorVersion(); + } + } + + T create(Class<?> argumentClass, Object argument, Version version) + { + Class<? extends T> clazz = getClassFor(version); + Constructor<? extends T> constructor; + try + { + constructor = clazz.getConstructor(new Class[] {argumentClass}); + } catch (Exception ex1) + { + throw new EnvironmentFailureException(clazz + " has no constructor with argument of type " + + argumentClass.getCanonicalName()); + } + try + { + return constructor.newInstance(new Object[] {argument}); + } catch (InvocationTargetException ex) + { + throw new UserFailureException("Couldn't create instance of " + clazz + " for version " + version, ex + .getCause()); + } catch (Exception ex) + { + throw new UserFailureException("Couldn't create instance of " + clazz + " for version " + version, ex); + } + } + +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/Format.java b/bds/source/java/ch/systemsx/cisd/bds/Format.java new file mode 100644 index 0000000000000000000000000000000000000000..12b2b368e6bb866a0e3934188bc0f60272a5377f --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/Format.java @@ -0,0 +1,122 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds; + +import ch.systemsx.cisd.bds.storage.IDirectory; +import ch.systemsx.cisd.bds.storage.IFile; +import ch.systemsx.cisd.bds.storage.INode; +import ch.systemsx.cisd.common.exceptions.UserFailureException; + +/** + * Inmutable value object of a versioned format. + * + * @author Franz-Josef Elmer + */ +public class Format +{ + static final String FORMAT_CODE_FILE = "format_code"; + static final String FORMAT_DIR = "format"; + + /** + * Loads the format from the specified directory. + * + * @throws UserFailureException if the format could be loaded. + */ + static Format loadFrom(IDirectory directory) + { + INode dir = directory.tryToGetNode(FORMAT_DIR); + if (dir instanceof IDirectory == false) + { + throw new UserFailureException("Not a directory: " + dir); + } + IDirectory formatDir = (IDirectory) dir; + INode file = formatDir.tryToGetNode(FORMAT_CODE_FILE); + if (file instanceof IFile == false) + { + throw new UserFailureException("Not a plain file: " + file); + } + IFile codeFile = (IFile) file; + String formatCode = codeFile.getStringContent().trim(); + Version formatVersion = Version.loadFrom(formatDir); + return new Format(formatCode, formatVersion); + } + + private final String code; + private final Version version; + + /** + * Creates a new instance based on the specified format code and version. + */ + public Format(String code, Version version) + { + assert code != null : "Unspecified format code."; + assert version != null : "Unpsecified version."; + this.code = code; + this.version = version; + } + + /** + * Returns the format code. + */ + public final String getCode() + { + return code; + } + + /** + * Returns the format version. + */ + public final Version getVersion() + { + return version; + } + + void saveTo(IDirectory directory) + { + IDirectory dir = directory.makeDirectory(FORMAT_DIR); + dir.addKeyValuePair(FORMAT_CODE_FILE, code); + version.saveTo(dir); + } + + @Override + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof Format == false) + { + return false; + } + Format format = (Format) obj; + return format.code.equals(code) && format.version.equals(version); + } + + @Override + public int hashCode() + { + return code.hashCode() * 37 + version.hashCode(); + } + + @Override + public String toString() + { + return "Format: " + code + " " + version; + } + +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/FormatedDataFactory.java b/bds/source/java/ch/systemsx/cisd/bds/FormatedDataFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..707438aa69ae10220e3e346c2ce82d0ebda0764d --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/FormatedDataFactory.java @@ -0,0 +1,83 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds; + +import java.util.HashMap; +import java.util.Map; + +import ch.systemsx.cisd.bds.storage.IDirectory; +import ch.systemsx.cisd.common.exceptions.UserFailureException; + + +/** + * Factory for objects of type {@link IFormatedData}. + * + * @author Franz-Josef Elmer + */ +class FormatedDataFactory +{ + private static final Map<String, Factory<IFormatedData>> factories = new HashMap<String, Factory<IFormatedData>>(); + + static + { + register(UnknownFormat1_0.UNKNOWN_1_0, NoFormatedData.class); + } + + static void register(Format format, Class<? extends IFormatedData> clazz) + { + String code = format.getCode(); + Factory<IFormatedData> factory = factories.get(code); + if (factory == null) + { + factory = new Factory<IFormatedData>(); + factories.put(code, factory); + } + factory.register(format.getVersion(), clazz); + } + + static Class<? extends IFormatedData> getFormatedDataInterfaceFor(Format format, Format defaultFormat) + { + Factory<IFormatedData> factory = getFactory(format, defaultFormat); + return factory.getClassFor(format.getVersion()); + } + + static IFormatedData createFormatedData(IDirectory dataDirectory, Format format, Format defaultFormat) + { + Factory<IFormatedData> factory = getFactory(format, defaultFormat); + return factory.create(IDirectory.class, dataDirectory, format.getVersion()); + } + + private static Factory<IFormatedData> getFactory(Format format, Format defaultFormat) + { + assert format != null : "Unspecified format."; + String code = format.getCode(); + assert code != null : "Unspecified format code."; + assert format.getVersion() != null : "Unspecified version."; + + Factory<IFormatedData> factory = factories.get(code); + if (factory == null) + { + if (defaultFormat != null) + { + return getFactory(defaultFormat, null); + } + throw new UserFailureException("Unkown format code: " + code); + } + return factory; + } + +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/IFormat.java b/bds/source/java/ch/systemsx/cisd/bds/IDataStructure.java similarity index 75% rename from bds/source/java/ch/systemsx/cisd/bds/IFormat.java rename to bds/source/java/ch/systemsx/cisd/bds/IDataStructure.java index 27ecf2dc5d65e1c701ad36c63b6367c534a44413..5821f34154a939df1947894d32e662917f69a27d 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/IFormat.java +++ b/bds/source/java/ch/systemsx/cisd/bds/IDataStructure.java @@ -17,14 +17,20 @@ package ch.systemsx.cisd.bds; /** - * Format interface. + * Common interface of all data structures. * * @author Franz-Josef Elmer */ -public interface IFormat extends IHasVersion +public interface IDataStructure extends IHasVersion { /** - * Returns the code of this format. + * Loads the data structure. */ - public String getCode(); -} + public void load(); + + /** + * Saves the data structure. + */ + public void save(); + +} \ No newline at end of file diff --git a/bds/source/java/ch/systemsx/cisd/bds/IFormatedData.java b/bds/source/java/ch/systemsx/cisd/bds/IFormatedData.java index 30a933a6091b532e299bdfb6142f14bd381d5fdf..a029aeb633645864c7f1d8a8f467bb24d93e373c 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/IFormatedData.java +++ b/bds/source/java/ch/systemsx/cisd/bds/IFormatedData.java @@ -17,11 +17,14 @@ package ch.systemsx.cisd.bds; /** - * + * Interface common for all classes handling formated data. * * @author Franz-Josef Elmer */ public interface IFormatedData { - public IFormat getFormat(); + /** + * Returns the format of data. + */ + public Format getFormat(); } diff --git a/bds/source/java/ch/systemsx/cisd/bds/IFormatedDataFactory.java b/bds/source/java/ch/systemsx/cisd/bds/IFormatedDataFactory.java deleted file mode 100644 index 2de4b2fe467b94000809c077b08c7c7a9b58198c..0000000000000000000000000000000000000000 --- a/bds/source/java/ch/systemsx/cisd/bds/IFormatedDataFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2007 ETH Zuerich, CISD - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.systemsx.cisd.bds; - -import ch.systemsx.cisd.common.exceptions.UserFailureException; - -/** - * - * - * @author Franz-Josef Elmer - */ -public interface IFormatedDataFactory -{ - public Class<? extends IFormatedData> getFormatedDataInterfaceFor(IFormat format) throws UserFailureException; - - public IFormatedData createFormatedData(IFormat format) throws UserFailureException; - -} diff --git a/bds/source/java/ch/systemsx/cisd/bds/NoFormatedData.java b/bds/source/java/ch/systemsx/cisd/bds/NoFormatedData.java new file mode 100644 index 0000000000000000000000000000000000000000..e5bf25a010f0ac656a8a535b59578d81269b4126 --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/NoFormatedData.java @@ -0,0 +1,50 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds; + +import ch.systemsx.cisd.bds.storage.IDirectory; + +/** + * Most simplest implementation of {@link IFormatedData}. It is associated with {@link UnknownFormat1_0}. + * It can be subclassed provided {@link #getFormat()} will be overridden. + * + * @author Franz-Josef Elmer + */ +public class NoFormatedData implements IFormatedData +{ + /** + * Root directory of formated data. + */ + protected final IDirectory dataDirectory; + + /** + * Creates an instance for the specified data directory. + */ + public NoFormatedData(IDirectory dataDirectory) + { + this.dataDirectory = dataDirectory; + } + + /** + * Returns {@link UnknownFormat1_0#UNKNOWN_1_0}. + */ + public Format getFormat() + { + return UnknownFormat1_0.UNKNOWN_1_0; + } + +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java b/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java index 791c3822025bfe7910a458ca53149821089ecef3..86a0964bb387f8d558e3fbf336f3790166fd33f4 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java +++ b/bds/source/java/ch/systemsx/cisd/bds/ProcessingType.java @@ -28,7 +28,7 @@ public enum ProcessingType { OTHER, RAW_DATA, COMPUTED_DATA; - private static final String PROCESSING_TYPE = "processing_type"; + static final String PROCESSING_TYPE = "processing_type"; /** * Resolves the specified string representation of a processing type. @@ -37,16 +37,23 @@ public enum ProcessingType */ public static ProcessingType resolve(String processingTypeString) { - ProcessingType type = valueOf(processingTypeString); - return type == null ? OTHER : type; + ProcessingType[] values = values(); + for (ProcessingType type : values) + { + if (type.toString().equals(processingTypeString)) + { + return type; + } + } + return OTHER; } - public static ProcessingType loadFrom(IDirectory directory) + static ProcessingType loadFrom(IDirectory directory) { return resolve(Utilities.getTrimmedString(directory, PROCESSING_TYPE)); } - public void saveTo(IDirectory directory) + void saveTo(IDirectory directory) { directory.addKeyValuePair(PROCESSING_TYPE, toString()); } diff --git a/bds/source/java/ch/systemsx/cisd/bds/UnknownFormat1_0.java b/bds/source/java/ch/systemsx/cisd/bds/UnknownFormat1_0.java index 4714893b598e047ff7cfd8abcc74bca8fd3f1885..db7ca5f0e92488eee90c3b42cf1862425559289c 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/UnknownFormat1_0.java +++ b/bds/source/java/ch/systemsx/cisd/bds/UnknownFormat1_0.java @@ -21,21 +21,17 @@ package ch.systemsx.cisd.bds; * * @author Franz-Josef Elmer */ -public class UnknownFormat1_0 implements IFormat +public final class UnknownFormat1_0 extends Format { - private static final Version VERSION = new Version(1, 0); - /** - * Returns <code>UNKNOWN</code>. + * The one and only one instance. */ - public String getCode() - { - return "UNKNOWN"; - } + public static final Format UNKNOWN_1_0 = new UnknownFormat1_0(); - public Version getVersion() + private UnknownFormat1_0() { - return VERSION; + super("UNKNOWN", new Version(1, 0)); } + } diff --git a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java index bacac1b89dc89ffee443d3498be8fcf51f130af5..c519323e154a2af456d1bfd0d821ea8c35a31abf 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java +++ b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java @@ -28,6 +28,25 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException; */ public class Utilities { + /** + * Returns a subdirectory from the specified directory. If it does not exist it will be created. + * + * @throws UserFailureException if there is already a node named <code>name</code> but which isn't a directory. + */ + public static IDirectory getOrCreateSubDirectory(IDirectory directory, String name) + { + INode node = directory.tryToGetNode(name); + if (node == null) + { + return directory.makeDirectory(name); + } + if (node instanceof IDirectory) + { + return (IDirectory) node; + } + throw new UserFailureException("There is already a node named '" + name + "' but which isn't a directory."); + } + /** * Returns a subdirectory from the specified directory. * @@ -37,7 +56,11 @@ public class Utilities */ public static IDirectory getSubDirectory(IDirectory directory, String name) { - INode node = directory.getNode(name); + INode node = directory.tryToGetNode(name); + if (node == null) + { + throw new UserFailureException("No directory named '" + name + "' found in " + directory); + } if (node instanceof IDirectory == false) { throw new UserFailureException("Is not a directory: " + node); @@ -62,7 +85,7 @@ public class Utilities */ public static String getString(IDirectory directory, String name) { - INode node = directory.getNode(name); + INode node = directory.tryToGetNode(name); if (node == null) { throw new UserFailureException("File '" + name + "' missing in " + directory); diff --git a/bds/source/java/ch/systemsx/cisd/bds/Version.java b/bds/source/java/ch/systemsx/cisd/bds/Version.java index e71459aa7c281016b8b6429350308faab7110ccc..88cd8c45c126a858784543a45580b990bcffa0f7 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/Version.java +++ b/bds/source/java/ch/systemsx/cisd/bds/Version.java @@ -26,14 +26,14 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException; */ public final class Version { - private static final String VERSION = "version"; - private static final String MAJOR = "major"; - private static final String MINOR = "minor"; + static final String VERSION = "version"; + static final String MAJOR = "major"; + static final String MINOR = "minor"; /** * Loads the version from the specified directory. */ - public static Version loadFrom(IDirectory directory) + static Version loadFrom(IDirectory directory) { IDirectory versionFolder = Utilities.getSubDirectory(directory, VERSION); return new Version(getNumber(versionFolder, MAJOR), getNumber(versionFolder, MINOR)); @@ -85,7 +85,7 @@ public final class Version } /** - * Returns true if this version is backwards compatible to the specified version. That is, + * Returns <code>true</code> if this version is backwards compatible to the specified version. That is, * if <code>version.getMajor() == this.getMajor()</code> and <code>version.getMinor() <= this.getMinor()</code>. */ public boolean isBackwardsCompatibleWith(Version version) @@ -107,7 +107,7 @@ public final class Version return new Version(major, minor - 1); } - public void saveTo(IDirectory directory) + void saveTo(IDirectory directory) { IDirectory versionFolder = directory.makeDirectory(VERSION); versionFolder.addKeyValuePair(MAJOR, Integer.toString(major)); diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java b/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java index 607d7375f6e795db0926518ae1686daa38f2ec25..101f8c5ceb9845fa2c93754fd78caf4ee9f426d2 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java @@ -18,20 +18,48 @@ package ch.systemsx.cisd.bds.storage; import java.io.File; +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.exceptions.UserFailureException; + /** - * + * Node representing a directory. * * @author Franz-Josef Elmer */ public interface IDirectory extends INode, Iterable<INode> { - public INode getNode(String name); + /** + * Returns the child node with specified name. + * + * @return <code>null</code> if there is no child node named <code>name</code>. + */ + public INode tryToGetNode(String name); - public IDirectory makeDirectory(String name); + /** + * Makes a new subdirectory in this directory. Does nothing if the subdirectory already exists. + * + * @param name Name of the new subdirectory. + * @return the new subdirectory. + * @throws EnvironmentFailureException if the subdirectory cannot be created because of some other reason. + */ + public IDirectory makeDirectory(String name) throws UserFailureException, EnvironmentFailureException; + /** + * Adds the specified real file to this directory. The content of <code>file</code> will be copied. If it + * is a folder also its complete content including all subfolders will be copied. + * + * @return the new node. It will be a {@link ILink} if <code>file</code> is a symbolic link, a {@link IDirectory} + * if <code>file</code> is a folder, or {@link IFile} if <code>file</code> is a plain file. + */ public INode addFile(File file); + /** + * Adds a plain file named <code>key</code> with content <code>value</code> to this directory. + */ public IFile addKeyValuePair(String key, String value); + /** + * Adds the link named <code>name</code> to this directory which refers to the specified node. + */ public ILink addLink(String name, INode node); } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java b/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java index ffe6e069e413a36596a5e0377e8af08f6334cfd3..b063d0358944ec08aca86a25f236bd6cdc1794bb 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java @@ -17,7 +17,7 @@ package ch.systemsx.cisd.bds.storage; /** - * Role of a leaf node representing a file with some content. + * Node representing a file with some content. * * @author Franz-Josef Elmer */ diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java b/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java index 42cf6ca8943308ff5b585936432aa55027608339..c87af614b2079bd3a8ab6e6539dc352dc25be261 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java @@ -22,7 +22,7 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * Role of a node in the data structure. + * Abstraction of a node in a hierarchical data structure. * * @author Franz-Josef Elmer */ diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java index 073cd777486c9dc1d5e82b675415cf5489555122..7da7143c2e58728d539a7e50476b76fe830f45ce 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java @@ -54,5 +54,13 @@ abstract class AbstractNode implements INode File dir = nodeFile.getParentFile(); return dir == null ? null : new Directory(dir); } + + @Override + public String toString() + { + return nodeFile.getAbsolutePath(); + } + + } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java index d3b54e72311486c1001059f93c41df6442d41d5a..0be8ac35aa48e9ef0531d722d87df012dfc31f10 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java @@ -40,7 +40,7 @@ class Directory extends AbstractNode implements IDirectory } } - public INode getNode(String name) + public INode tryToGetNode(String name) { java.io.File[] files = nodeFile.listFiles(); for (java.io.File file : files) @@ -58,7 +58,11 @@ class Directory extends AbstractNode implements IDirectory java.io.File dir = new java.io.File(nodeFile, name); if (dir.exists()) { - throw new UserFailureException("There already exists a file named '" + name + "' in directory " + this); + if (dir.isDirectory() == false) + { + throw new UserFailureException("There already exists a file named '" + name + "' in directory " + this); + } + return new Directory(dir); } boolean successful = dir.mkdir(); if (successful == false) diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureFactoryTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureFactoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6a37f1476d820b46809d1bb3053ee583364a60fa --- /dev/null +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureFactoryTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.fail; + +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.bds.storage.IStorage; +import ch.systemsx.cisd.common.exceptions.UserFailureException; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class DataStructureFactoryTest +{ + private Mockery context; + private IStorage storage; + + @BeforeMethod + public void startUp() + { + context = new Mockery(); + storage = context.mock(IStorage.class); + } + + @Test + public void testGetDataStructureClassFor() + { + assertEquals(DataStructureV1_0.class, DataStructureFactory.getDataStructureClassFor(new Version(1, 0))); + assertEquals(DataStructureV1_0.class, DataStructureFactory.getDataStructureClassFor(new Version(1, 1))); + } + + @Test + public void testGetDataStructureClassForIncompatibleVersion() + { + try + { + DataStructureFactory.getDataStructureClassFor(new Version(2, 0)); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertEquals("No class found for version V2.0", e.getMessage()); + } + } + + @Test + public void testCreateDataStructure() + { + context.checking(new Expectations() + { + { + one(storage).mount(); + one(storage).getRoot(); + } + + }); + IDataStructure dataStructure = DataStructureFactory.createDataStructure(storage, new Version(1, 0)); + assertEquals(DataStructureV1_0.class, dataStructure.getClass()); + } +} diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f37ebc2fdfd5194dbd3c74732ea1b57ec07fdd21 --- /dev/null +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureLoaderTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds; + +import static ch.systemsx.cisd.bds.DataStructureV1_0Test.TEST_DIR; +import static org.testng.AssertJUnit.assertEquals; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.bds.storage.filesystem.FileStorage; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class DataStructureLoaderTest +{ + @BeforeMethod + public void setUp() throws IOException + { + TEST_DIR.mkdirs(); + FileUtils.cleanDirectory(TEST_DIR); + } + + @Test + public void testLoad() + { + File dir = new File(TEST_DIR, "ds"); + assert dir.mkdir(); + DataStructureV1_0 dataStructure = new DataStructureV1_0(new FileStorage(dir)); + 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(); + + IDataStructure ds = new DataStructureLoader(TEST_DIR).load("ds"); + assertEquals(DataStructureV1_0.class, ds.getClass()); + assertEquals(experimentIdentifier, ((DataStructureV1_0) ds).getExperimentIdentifier()); + } +} diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java new file mode 100644 index 0000000000000000000000000000000000000000..65987647074f8a9892a34f584716d65b14934af1 --- /dev/null +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java @@ -0,0 +1,356 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.fail; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.bds.storage.IDirectory; +import ch.systemsx.cisd.bds.storage.filesystem.FileStorage; +import ch.systemsx.cisd.common.exceptions.UserFailureException; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class DataStructureV1_0Test +{ + static final File TEST_DIR = new File("targets" + File.separator + "unit-test-wd" + File.separator + "ds"); + + private static void assertPartOfString(String part, String string) + { + assertTrue("Expected <" + part + "> is part of <" + string + ">", string.indexOf(part) >= 0); + } + + private FileStorage storage; + + private DataStructureV1_0 dataStructure; + + @BeforeMethod + public void setup() throws IOException + { + TEST_DIR.mkdirs(); + FileUtils.cleanDirectory(TEST_DIR); + storage = new FileStorage(TEST_DIR); + dataStructure = new DataStructureV1_0(storage); + } + + @Test + public void testGetOriginalData() + { + IDirectory dataFolder = dataStructure.getOriginalData(); + assertEquals(DataStructureV1_0.DIR_ORIGINAL, dataFolder.getName()); + assertEquals(DataStructureV1_0.DIR_DATA, dataFolder.tryToGetParent().getName()); + } + + @Test + public void testGetFormatedData() + { + dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0); + IFormatedData formatedData = dataStructure.getFormatedData(); + assertTrue(formatedData instanceof NoFormatedData); + assertEquals(UnknownFormat1_0.UNKNOWN_1_0, formatedData.getFormat()); + } + + @Test + public void testGetFormatedDataBeforeInvokingSetVersion() + { + try + { + dataStructure.getFormatedData(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertEquals("Couldn't create formated data because of undefined format.", e.getMessage()); + } + } + + @Test + public void testSetProcessingType() + { + dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA); + IDirectory root = storage.getRoot(); + IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA); + assertEquals("COMPUTED_DATA\n", Utilities.getString(metaData, ProcessingType.PROCESSING_TYPE)); + } + + @Test + public void testSetProcessingTypeTwice() + { + dataStructure.setProcessingType(ProcessingType.RAW_DATA); + dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA); + IDirectory root = storage.getRoot(); + IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA); + assertEquals("COMPUTED_DATA\n", Utilities.getString(metaData, ProcessingType.PROCESSING_TYPE)); + } + + @Test + public void testGetProcessingType() + { + dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA); + assertEquals(ProcessingType.COMPUTED_DATA, dataStructure.getProcessingType()); + } + + @Test + public void testGetUnknownProcessingType() + { + dataStructure.setProcessingType(ProcessingType.COMPUTED_DATA); + IDirectory s = Utilities.getSubDirectory(storage.getRoot(), DataStructureV1_0.DIR_METADATA); + s.addKeyValuePair(ProcessingType.PROCESSING_TYPE, "blabla"); + assertEquals(ProcessingType.OTHER, dataStructure.getProcessingType()); + } + + @Test + public void testSetExperimentIdentifier() + { + ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e"); + dataStructure.setExperimentIdentifier(id); + IDirectory root = storage.getRoot(); + IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA); + IDirectory idDir = Utilities.getSubDirectory(metaData, ExperimentIdentifier.FOLDER); + assertEquals("g\n", Utilities.getString(idDir, ExperimentIdentifier.GROUP_CODE)); + assertEquals("p\n", Utilities.getString(idDir, ExperimentIdentifier.PROJECT_CODE)); + assertEquals("e\n", Utilities.getString(idDir, ExperimentIdentifier.EXPERIMENT_CODE)); + } + + @Test + public void testSetExperimentIdentifierTwice() + { + dataStructure.setExperimentIdentifier(new ExperimentIdentifier("a", "b", "c")); + ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e"); + dataStructure.setExperimentIdentifier(id); + IDirectory root = storage.getRoot(); + IDirectory metaData = Utilities.getSubDirectory(root, DataStructureV1_0.DIR_METADATA); + IDirectory idDir = Utilities.getSubDirectory(metaData, ExperimentIdentifier.FOLDER); + assertEquals("g\n", Utilities.getString(idDir, ExperimentIdentifier.GROUP_CODE)); + assertEquals("p\n", Utilities.getString(idDir, ExperimentIdentifier.PROJECT_CODE)); + assertEquals("e\n", Utilities.getString(idDir, ExperimentIdentifier.EXPERIMENT_CODE)); + } + + @Test + public void testGetNonExistingExperimentIdentifier() + { + try + { + dataStructure.getExperimentIdentifier(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertPartOfString(ExperimentIdentifier.FOLDER, e.getMessage()); + } + } + + @Test + public void testGetExperimentIdentifier() + { + ExperimentIdentifier id = new ExperimentIdentifier("g", "p", "e"); + dataStructure.setExperimentIdentifier(id); + assertEquals(id, dataStructure.getExperimentIdentifier()); + } + + @Test + public void testGetVersion() + { + assertEquals(new Version(1, 0), dataStructure.getVersion()); + } + + @Test + public void testSaveForEmptyData() + { + try + { + dataStructure.save(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertEquals("Empty orginal data directory.", e.getMessage()); + } + } + + @Test + public void testSaveIfNoFormat() + { + dataStructure.getOriginalData().addKeyValuePair("answer", "42"); + try + { + dataStructure.save(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertEquals("Unspecified format.", e.getMessage()); + } + } + + @Test + public void testSaveIfNoExperimentID() + { + dataStructure.getOriginalData().addKeyValuePair("answer", "42"); + dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0); + try + { + dataStructure.save(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertEquals("Unspecified experiment identifier.", e.getMessage()); + } + } + + @Test + public void testSaveIfNoProcessingType() + { + dataStructure.getOriginalData().addKeyValuePair("answer", "42"); + dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0); + dataStructure.setExperimentIdentifier(new ExperimentIdentifier("g", "p", "e")); + try + { + dataStructure.save(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertEquals("Unspecified processing type.", e.getMessage()); + } + } + + @Test + public void testSave() + { + 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); + + IDirectory root = storage.getRoot(); + dataStructure.save(); + assertEquals(dataStructure.getVersion(), Version.loadFrom(root)); + try + { + storage.getRoot(); + fail("UserFailureException expected because save() should unmount storage."); + } catch (UserFailureException e) + { + assertEquals("Can not get root of an unmounted storage.", e.getMessage()); + } + + DataStructureV1_0 reloadedDataStructure = new DataStructureV1_0(storage); + reloadedDataStructure.load(); + assertEquals("42\n", Utilities.getString(reloadedDataStructure.getOriginalData(), "answer")); + assertEquals(UnknownFormat1_0.UNKNOWN_1_0, reloadedDataStructure.getFormatedData().getFormat()); + assertEquals(experimentIdentifier, reloadedDataStructure.getExperimentIdentifier()); + assertEquals(ProcessingType.RAW_DATA, reloadedDataStructure.getProcessingType()); + } + + @Test + public void testLoadIfVersionMissing() + { + try + { + dataStructure.load(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertPartOfString(Version.VERSION, e.getMessage()); + } + } + + @Test + public void testLoad() + { + 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(); + } + + @Test + public void testLoadVersion1_1() + { + 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(); + } + + @Test + public void testLoadVersion2_0() + { + IDirectory root = storage.getRoot(); + new Version(2, 0).saveTo(root); + try + { + dataStructure.load(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertEquals("Version of loaded data structure is V2.0 which is not backward compatible with V1.0", + e.getMessage()); + } + } + + @Test + public void testLoadWithUnknownFormat1_1() + { + IDirectory root = storage.getRoot(); + new Version(1, 0).saveTo(root); + IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA); + new Format(UnknownFormat1_0.UNKNOWN_1_0.getCode(), new Version(1, 1)).saveTo(metaData); + dataStructure.load(); + assertEquals(UnknownFormat1_0.UNKNOWN_1_0, dataStructure.getFormatedData().getFormat()); + } + + @Test + public void testLoadWithUnknownFormat2_0() + { + IDirectory root = storage.getRoot(); + new Version(1, 0).saveTo(root); + IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA); + new Format(UnknownFormat1_0.UNKNOWN_1_0.getCode(), new Version(2, 0)).saveTo(metaData); + try + { + dataStructure.load(); + dataStructure.getFormatedData(); + fail("UserFailureException expected."); + } catch (UserFailureException e) + { + assertEquals("No class found for version V2.0", e.getMessage()); + } + } + + @Test + public void testLoadWithAnotherFormat() + { + IDirectory root = storage.getRoot(); + new Version(1, 0).saveTo(root); + IDirectory metaData = root.makeDirectory(DataStructureV1_0.DIR_METADATA); + new Format("another format", new Version(1,1)).saveTo(metaData); + dataStructure.load(); + assertEquals(UnknownFormat1_0.UNKNOWN_1_0, dataStructure.getFormatedData().getFormat()); + } + +} diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java index 5cc91efe4ffbfe8380a73393cfe60f9bcbb42584..2d87700aa09052b386510d79b705d20a4846c7a2 100644 --- a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java @@ -63,10 +63,23 @@ public class DirectoryTest extends StorageTestCase { Directory directory = new Directory(TEST_DIR); directory.makeDirectory("sub-directory"); + IDirectory subdirectory = directory.makeDirectory("sub-directory"); + + assertEquals("sub-directory", subdirectory.getName()); + File subdir = new File(TEST_DIR, "sub-directory"); + assertEquals(true, subdir.exists()); + assertEquals(true, subdir.isDirectory()); + } + + @Test + public void testMakeDirectoryButThereIsAlreadyAFileWithSameName() + { + Directory directory = new Directory(TEST_DIR); + directory.addKeyValuePair("sub-directory", "value"); try { directory.makeDirectory("sub-directory"); - AssertJUnit.fail("UserFailureException because a directory can made only once."); + AssertJUnit.fail("UserFailureException expected."); } catch (UserFailureException e) { assertTrue(e.getMessage().indexOf("sub-directory") >= 0); @@ -124,16 +137,16 @@ public class DirectoryTest extends StorageTestCase File copiedRealDir = new File(dest, "dir"); assertTrue(copiedRealDir.isDirectory()); IDirectory cd = (IDirectory) copiedDir; - INode node = cd.getNode("p1"); + INode node = cd.tryToGetNode("p1"); assertNotNull(node); assertTrue(node instanceof IFile); assertEquals("property 1\n", ((IFile) node).getStringContent()); assertEquals("property 1\n", FileUtilities.loadToString(new File(copiedRealDir, "p1"))); - node = cd.getNode("subdir"); + node = cd.tryToGetNode("subdir"); assertEquals("subdir", node.getName()); assertNotNull(node); assertTrue(node instanceof IDirectory); - node = ((IDirectory) node).getNode("p2"); + node = ((IDirectory) node).tryToGetNode("p2"); File copiedRealSubDir = new File(copiedRealDir, "subdir"); assertTrue(copiedRealSubDir.isDirectory()); assertEquals("p2", node.getName());