diff --git a/bds/source/java/ch/systemsx/cisd/bds/AbstractFormattedData.java b/bds/source/java/ch/systemsx/cisd/bds/AbstractFormattedData.java new file mode 100644 index 0000000000000000000000000000000000000000..46eed7a6625dd6d72d66d10e0028dfffc7732319 --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/AbstractFormattedData.java @@ -0,0 +1,55 @@ +/* + * 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; + + +/** + * Common code of implementations of {@link IFormattedData}. + * + * @author Franz-Josef Elmer + */ +abstract class AbstractFormattedData implements IFormattedData +{ + protected final IDirectory dataDirectory; + protected final Format format; + private final IFormatParameters formatParameters; + + protected AbstractFormattedData(FormattedDataContext context) + { + assert context != null : "Unspecified context."; + dataDirectory = context.getDataDirectory(); + format = context.getFormat(); + formatParameters = context.getFormatParameters(); + assertValidFormatAndFormatParameters(); + } + + public final IFormatParameters getFormatParameters() + { + return formatParameters; + } + + /** + * Asserts valid format and format parameters. Will be called at the end of the constructor. The format of + * the {@link FormattedDataContext} will be available by the protected attribute {@link #format}. The + * format parameters will be available by {@link #getFormatParameters()}. + * + * @throws DataStructureException if format of format parameters are invalid. + */ + protected abstract void assertValidFormatAndFormatParameters(); +} 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 8b50ddd75848a7a50401fc74e89f11681a0a683e..8b55dc2b65020e23f722a869f995af609ef438ec 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java +++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java @@ -42,6 +42,8 @@ public class DataStructureV1_0 extends AbstractDataStructure static final String CHECKSUM_DIRECTORY = "md5sum"; static final String DIR_METADATA = "metadata"; + + static final String DIR_PARAMETERS = "parameters"; static final String DIR_DATA = "data"; @@ -53,6 +55,7 @@ public class DataStructureV1_0 extends AbstractDataStructure private final ChecksumBuilder checksumBuilder = new ChecksumBuilder(new MD5ChecksumCalculator()); private final Map<String, Reference> standardOriginalMapping = new LinkedHashMap<String, Reference>(); + private final FormatParameters formatParameters = new FormatParameters(); private Format format; @@ -87,14 +90,15 @@ public class DataStructureV1_0 extends AbstractDataStructure * * @throws DataStructureException if this method has been invoked before the format has been set. */ - public IFormattedData getFormatedData() + public IFormattedData getFormattedData() { assertOpenOrCreated(); if (format == null) { - throw new DataStructureException("Couldn't create formated data because of undefined format."); + throw new DataStructureException("Couldn't create formated data because of unspecified format."); } - return FormatedDataFactory.createFormatedData(getMetaDataDirectory(), format, UnknownFormat1_0.UNKNOWN_1_0); + IDirectory metaData = getMetaDataDirectory(); + return FormatedDataFactory.createFormatedData(metaData, format, UnknownFormat1_0.UNKNOWN_1_0, formatParameters); } /** @@ -107,6 +111,17 @@ public class DataStructureV1_0 extends AbstractDataStructure this.format = format; } + /** + * Adds the specified format parameter. + * + * @throws IllegalArgumentException if they is already a parameter with same name as <code>parameter</code>. + */ + public void addFormatParameter(FormatParameter formatParameter) + { + assert formatParameter != null : "Unspecified format parameter."; + formatParameters.addParameter(formatParameter); + } + /** * Returns the experiment identifier. * @@ -279,7 +294,12 @@ public class DataStructureV1_0 extends AbstractDataStructure { IDirectory metaDataDirectory = getMetaDataDirectory(); setFormat(Format.loadFrom(metaDataDirectory)); - + formatParameters.loadFrom(getParametersDirectory()); + loadStandardOriginalMapping(metaDataDirectory); + } + + private void loadStandardOriginalMapping(IDirectory metaDataDirectory) + { StringReader stringReader = new StringReader(Utilities.getString(metaDataDirectory, MAPPING_FILE)); BufferedReader reader = new BufferedReader(stringReader); List<String> lines = new ArrayList<String>(); @@ -315,7 +335,7 @@ public class DataStructureV1_0 extends AbstractDataStructure standardOriginalMapping.put(path, new Reference(path, referenceDefinition.substring(i2 + 1), type)); } } - + @Override protected void performClosing() { @@ -324,6 +344,8 @@ public class DataStructureV1_0 extends AbstractDataStructure String checksumsOfOriginal = checksumBuilder.buildChecksumsForAllFilesIn(getOriginalData()); checksumDirectory.addKeyValuePair(DIR_ORIGINAL, checksumsOfOriginal); + formatParameters.saveTo(getParametersDirectory()); + StringWriter writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer, true); Collection<Reference> values = standardOriginalMapping.values(); @@ -352,4 +374,10 @@ public class DataStructureV1_0 extends AbstractDataStructure { return Utilities.getOrCreateSubDirectory(root, DIR_METADATA); } + + private IDirectory getParametersDirectory() + { + return Utilities.getOrCreateSubDirectory(getMetaDataDirectory(), DIR_PARAMETERS); + } + } diff --git a/bds/source/java/ch/systemsx/cisd/bds/FormatParameter.java b/bds/source/java/ch/systemsx/cisd/bds/FormatParameter.java new file mode 100644 index 0000000000000000000000000000000000000000..77a834c23a08faf20ef7c619537a4baf1b63a3be --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/FormatParameter.java @@ -0,0 +1,58 @@ +/* + * 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; + +/** + * A format parameter with a name and a string value. + * + * @author Franz-Josef Elmer + */ +public final class FormatParameter +{ + private final String name; + private final String value; + + /** + * Creates an instance for the specified name and value. + * + * @param name A non-empty string as the name of the parameter. + * @param value A non-<code>null</code> string as the value. + */ + public FormatParameter(String name, String value) + { + assert name != null && name.length() > 0 : "Unspecified parameter name."; + this.name = name; + assert value != null : "Unspecified parameter value."; + this.value = value; + } + + /** + * Returns the name of this parameter. + */ + public final String getName() + { + return name; + } + + /** + * Returns the value of this parameter. + */ + public final String getValue() + { + return value; + } +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/FormatParameters.java b/bds/source/java/ch/systemsx/cisd/bds/FormatParameters.java new file mode 100644 index 0000000000000000000000000000000000000000..94f6e217afe81c131ecf0e1fba1fdc19b99e450c --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/FormatParameters.java @@ -0,0 +1,87 @@ +/* + * 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.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import ch.systemsx.cisd.bds.storage.IDirectory; +import ch.systemsx.cisd.bds.storage.IFile; +import ch.systemsx.cisd.bds.storage.INode; + +/** + * Implementation of {@link IFormatParameters} which allows to add {@link FormatParameter} instances. + * + * @author Franz-Josef Elmer + */ +class FormatParameters implements IFormatParameters +{ + private final Map<String, FormatParameter> parameters = new LinkedHashMap<String, FormatParameter>(); + + void loadFrom(IDirectory directory) + { + parameters.clear(); + for (INode node : directory) + { + if (node instanceof IFile) + { + IFile file = (IFile) node; + addParameter(new FormatParameter(file.getName(), file.getStringContent().trim())); + } + } + } + + void saveTo(IDirectory directory) + { + for (FormatParameter parameter : parameters.values()) + { + directory.addKeyValuePair(parameter.getName(), parameter.getValue()); + } + } + + /** + * Adds the specified parameter. + * + * @throws IllegalArgumentException if they is already a parameter with same name as <code>parameter</code>. + */ + void addParameter(FormatParameter parameter) + { + String name = parameter.getName(); + if (parameters.containsKey(name)) + { + throw new IllegalArgumentException("There is already a parameter named '" + name + "'."); + } + parameters.put(name, parameter); + } + + public String getValue(String parameterName) + { + FormatParameter formatParameter = parameters.get(parameterName); + if (formatParameter == null) + { + throw new IllegalArgumentException("Unknown parameter '" + parameterName + "'."); + } + return formatParameter.getValue(); + } + + public Iterator<FormatParameter> iterator() + { + return parameters.values().iterator(); + } + +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/FormatedDataFactory.java b/bds/source/java/ch/systemsx/cisd/bds/FormatedDataFactory.java index 42505187763c9eb3de59afabcd7604c84baddd0e..b339b3054911df3037b8c4a76c426e7a1db379a1 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/FormatedDataFactory.java +++ b/bds/source/java/ch/systemsx/cisd/bds/FormatedDataFactory.java @@ -54,10 +54,13 @@ class FormatedDataFactory return factory.getClassFor(format.getVersion()); } - static IFormattedData createFormatedData(IDirectory dataDirectory, Format format, Format defaultFormat) + static IFormattedData createFormatedData(IDirectory dataDirectory, Format format, Format defaultFormat, + IFormatParameters formatParameters) { Factory<IFormattedData> factory = getFactory(format, defaultFormat); - return factory.create(IDirectory.class, dataDirectory, format.getVersion()); + Format f = chooseSupportedFormat(format, defaultFormat); + FormattedDataContext context = new FormattedDataContext(dataDirectory, f, formatParameters); + return factory.create(FormattedDataContext.class, context, format.getVersion()); } private static Factory<IFormattedData> getFactory(Format format, Format defaultFormat) @@ -79,4 +82,9 @@ class FormatedDataFactory return factory; } + private static Format chooseSupportedFormat(Format format, Format defaultFormat) + { + return factories.get(format.getCode()) == null ? defaultFormat : format; + } + } diff --git a/bds/source/java/ch/systemsx/cisd/bds/FormattedDataContext.java b/bds/source/java/ch/systemsx/cisd/bds/FormattedDataContext.java new file mode 100644 index 0000000000000000000000000000000000000000..876bb3e091a51675f4601d17f96bc2da3aeb576d --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/FormattedDataContext.java @@ -0,0 +1,57 @@ +/* + * 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; + +/** + * Context of {@link IFormattedData}. Argument of all constructores of concrete implementations of + * {@link IFormattedData}. + * + * @author Franz-Josef Elmer + */ +class FormattedDataContext +{ + private final IDirectory dataDirectory; + private final Format format; + private final IFormatParameters formatParameters; + + FormattedDataContext(IDirectory dataDirectory, Format format, IFormatParameters formatParameters) + { + assert dataDirectory != null : "Unspecified data directory."; + this.dataDirectory = dataDirectory; + assert format != null : "Unspecified format."; + this.format = format; + assert formatParameters != null : "Unspecified format parameters."; + this.formatParameters = formatParameters; + } + + final IDirectory getDataDirectory() + { + return dataDirectory; + } + + final Format getFormat() + { + return format; + } + + final IFormatParameters getFormatParameters() + { + return formatParameters; + } +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/IFormatParameters.java b/bds/source/java/ch/systemsx/cisd/bds/IFormatParameters.java new file mode 100644 index 0000000000000000000000000000000000000000..50b36d2701a88954d278d9133e07025aa0945c2c --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/IFormatParameters.java @@ -0,0 +1,32 @@ +/* + * 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; + +/** + * Read-only access interface for a set of {@link FormatParameter} objects. + * + * @author Franz-Josef Elmer + */ +public interface IFormatParameters extends Iterable<FormatParameter> +{ + /** + * Returns the value of the specified parameter. + * + * @throws IllegalArgumentException if there is no parameter named as specified. + */ + public String getValue(String parameterName); +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/IFormattedData.java b/bds/source/java/ch/systemsx/cisd/bds/IFormattedData.java index fac447014768b62accc5c3e8914580cbf84a558d..a12ba870d1647b5d5d34f49c95febbfeb0aaa2f5 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/IFormattedData.java +++ b/bds/source/java/ch/systemsx/cisd/bds/IFormattedData.java @@ -16,6 +16,7 @@ package ch.systemsx.cisd.bds; + /** * Interface common for all classes handling formated data. * @@ -27,4 +28,9 @@ public interface IFormattedData * Returns the format of data. */ public Format getFormat(); + + /** + * Returns the parameters of the data format. + */ + public IFormatParameters getFormatParameters(); } diff --git a/bds/source/java/ch/systemsx/cisd/bds/NoFormattedData.java b/bds/source/java/ch/systemsx/cisd/bds/NoFormattedData.java index d6aca4ea084dcc05f6dc7ee9f1643897ef7201f9..63da9b4c8b9a4939b4fb9ba59c0420f514f222ab 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/NoFormattedData.java +++ b/bds/source/java/ch/systemsx/cisd/bds/NoFormattedData.java @@ -16,29 +16,23 @@ package ch.systemsx.cisd.bds; -import ch.systemsx.cisd.bds.storage.IDirectory; /** * Most simplest implementation of {@link IFormattedData}. It is associated with {@link UnknownFormat1_0}. - * It can be subclassed provided {@link #getFormat()} will be overridden. * * @author Franz-Josef Elmer */ -public class NoFormattedData implements IFormattedData +public class NoFormattedData extends AbstractFormattedData { /** - * Root directory of formated data. + * Creates a new instance for the specified context. The format has to be backward-compatible with + * {@link UnknownFormat1_0}. The format parameters are ignored. */ - protected final IDirectory dataDirectory; - - /** - * Creates an instance for the specified data directory. - */ - public NoFormattedData(IDirectory dataDirectory) + public NoFormattedData(FormattedDataContext context) { - this.dataDirectory = dataDirectory; + super(context); } - + /** * Returns {@link UnknownFormat1_0#UNKNOWN_1_0}. */ @@ -46,5 +40,19 @@ public class NoFormattedData implements IFormattedData { return UnknownFormat1_0.UNKNOWN_1_0; } + + @Override + protected void assertValidFormatAndFormatParameters() + { + if (format.getCode().equals(getFormat().getCode()) == false) + { + throw new DataStructureException("Invalid format code: " + format.getCode()); + } + if (format.getVersion().isBackwardsCompatibleWith(getFormat().getVersion()) == false) + { + throw new DataStructureException("Incompatible format version: " + format.getVersion()); + + } + } } 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 12794eca5b709f90b999ad5d29dd182e6761ced2..2e6a3ed0553a660a6beccca5bec1c757fc4ad339 100644 --- a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java @@ -19,12 +19,14 @@ package ch.systemsx.cisd.bds; import static ch.systemsx.cisd.bds.DataStructureV1_0.CHECKSUM_DIRECTORY; import static ch.systemsx.cisd.bds.DataStructureV1_0.DIR_METADATA; import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.fail; import java.io.File; import java.io.IOException; import java.util.Date; +import java.util.Iterator; import java.util.Map; import org.apache.commons.io.FileUtils; @@ -76,7 +78,7 @@ public class DataStructureV1_0Test { dataStructure.create(); dataStructure.setFormat(UnknownFormat1_0.UNKNOWN_1_0); - IFormattedData formatedData = dataStructure.getFormatedData(); + IFormattedData formatedData = dataStructure.getFormattedData(); assertTrue(formatedData instanceof NoFormattedData); assertEquals(UnknownFormat1_0.UNKNOWN_1_0, formatedData.getFormat()); } @@ -87,11 +89,11 @@ public class DataStructureV1_0Test dataStructure.create(); try { - dataStructure.getFormatedData(); + dataStructure.getFormattedData(); fail("DataStructureException expected."); } catch (DataStructureException e) { - assertEquals("Couldn't create formated data because of undefined format.", e.getMessage()); + assertEquals("Couldn't create formated data because of unspecified format.", e.getMessage()); } } @@ -373,6 +375,8 @@ public class DataStructureV1_0Test dataStructure.setProcessingType(ProcessingType.RAW_DATA); dataStructure.addReference(new Reference("a/b/c", "a6b8/x.t", ReferenceType.IDENTICAL)); dataStructure.addReference(new Reference("a78/jjh", "a b/x\tt", ReferenceType.TRANSFORMED)); + dataStructure.addFormatParameter(new FormatParameter("plate_dimension", "16x24")); + checkFormattedData(dataStructure.getFormattedData()); IDirectory root = storage.getRoot(); dataStructure.close(); @@ -389,7 +393,6 @@ public class DataStructureV1_0Test DataStructureV1_0 reloadedDataStructure = new DataStructureV1_0(storage); reloadedDataStructure.open(); assertEquals("42\n", Utilities.getString(reloadedDataStructure.getOriginalData(), "answer")); - assertEquals(UnknownFormat1_0.UNKNOWN_1_0, reloadedDataStructure.getFormatedData().getFormat()); assertEquals(experimentIdentifier, reloadedDataStructure.getExperimentIdentifier()); assertEquals(experimentRegistratorDate, reloadedDataStructure.getExperimentRegistratorDate()); assertEquals(experimentRegistrator, reloadedDataStructure.getExperimentRegistrator()); @@ -405,6 +408,7 @@ public class DataStructureV1_0Test assertEquals("a78/jjh", reference.getPath()); assertEquals(ReferenceType.TRANSFORMED, reference.getReferenceType()); assertEquals("a b/x\tt", reference.getOriginalPath()); + checkFormattedData(reloadedDataStructure.getFormattedData()); IDirectory metaDataDir = Utilities.getSubDirectory(root, DIR_METADATA); IDirectory checksumDir = Utilities.getSubDirectory(metaDataDir, CHECKSUM_DIRECTORY); @@ -412,6 +416,18 @@ public class DataStructureV1_0Test Utilities.getString(checksumDir, DataStructureV1_0.DIR_ORIGINAL)); } + private void checkFormattedData(IFormattedData formattedData) + { + assertEquals(UnknownFormat1_0.UNKNOWN_1_0, formattedData.getFormat()); + IFormatParameters formatParameters = formattedData.getFormatParameters(); + Iterator<FormatParameter> iterator = formatParameters.iterator(); + assertTrue(iterator.hasNext()); + FormatParameter parameter = iterator.next(); + assertEquals("plate_dimension", parameter.getName()); + assertEquals("16x24", parameter.getValue()); + assertFalse(iterator.hasNext()); + } + @Test public void testOpenIfVersionMissing() { @@ -477,7 +493,7 @@ public class DataStructureV1_0Test new Format(UnknownFormat1_0.UNKNOWN_1_0.getCode(), new Version(1, 1), null).saveTo(metaData); storage.unmount(); dataStructure.open(); - assertEquals(UnknownFormat1_0.UNKNOWN_1_0, dataStructure.getFormatedData().getFormat()); + assertEquals(UnknownFormat1_0.UNKNOWN_1_0, dataStructure.getFormattedData().getFormat()); } @Test @@ -492,7 +508,7 @@ public class DataStructureV1_0Test dataStructure.open(); try { - dataStructure.getFormatedData(); + dataStructure.getFormattedData(); fail("DataStructureException expected."); } catch (DataStructureException e) { @@ -510,7 +526,7 @@ public class DataStructureV1_0Test new Format("another format", new Version(1, 1), null).saveTo(metaData); storage.unmount(); dataStructure.open(); - assertEquals(UnknownFormat1_0.UNKNOWN_1_0, dataStructure.getFormatedData().getFormat()); + assertEquals(UnknownFormat1_0.UNKNOWN_1_0, dataStructure.getFormattedData().getFormat()); } private void createExampleDataStructure()