diff --git a/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java b/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java index 939286081f8532d8956ecb31952bc45acc2acb71..55adf96bcffc1db1a6bceace1feed1a5d338b650 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java +++ b/bds/source/java/ch/systemsx/cisd/bds/AbstractDataStructure.java @@ -16,24 +16,30 @@ package ch.systemsx.cisd.bds; +import java.util.ArrayList; +import java.util.List; + import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.IStorage; /** * Abstract superclass of classes implementing {@link IDataStructure}. - * + * * @author Franz-Josef Elmer */ -abstract class AbstractDataStructure implements IDataStructure +abstract class AbstractDataStructure implements IDataStructure, IDataStructureHandler { protected final IStorage storage; - + protected IDirectory root; - AbstractDataStructure(IStorage storage) + private final List<IDataStructureHandler> handlers; + + AbstractDataStructure(final IStorage storage) { - assert storage != null: "Unspecified storage."; + assert storage != null : "Unspecified storage."; this.storage = storage; + handlers = new ArrayList<IDataStructureHandler>(); } private void mountStorage() @@ -41,42 +47,71 @@ abstract class AbstractDataStructure implements IDataStructure storage.mount(); root = storage.getRoot(); } - + + protected final void registerHandler(final IDataStructureHandler handler) + { + assert handler != null : "Given handler can not be null."; + handlers.add(handler); + } + /** * Asserts that this instance is already opened or created otherwise a {@link IllegalStateException} is thrown. */ - protected void assertOpenOrCreated() + protected final 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()}. + * After-creation jobs that should be done. Kind of initialization for subclasses when they create a new data + * structure. + * <p> + * By default this method does nothing. + * </p> */ - protected abstract void performClosing(); - + protected void afterCreation() + { + } + + // + // IDataStructureHandler + // + + public void assertValid() + { + for (final IDataStructureHandler handler : handlers) + { + handler.assertValid(); + } + } + + public void performOpening() + { + for (final IDataStructureHandler handler : handlers) + { + handler.performOpening(); + } + } + + public void performClosing() + { + for (final IDataStructureHandler handler : handlers) + { + handler.performClosing(); + } + } + // // IDataStructure // - + public final void create() { mountStorage(); + afterCreation(); } public final void open() @@ -91,7 +126,7 @@ abstract class AbstractDataStructure implements IDataStructure } assertValid(); } - + public final void close() { assertOpenOrCreated(); 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 691d18834b4164dc97b4b53d1417c606729ec47c..532c330053ad72f8f9ccaeae9f2e59c707048b85 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java +++ b/bds/source/java/ch/systemsx/cisd/bds/DataStructureV1_0.java @@ -16,21 +16,12 @@ package ch.systemsx.cisd.bds; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; +import ch.systemsx.cisd.bds.handler.ChecksumHandler; +import ch.systemsx.cisd.bds.handler.MappingFileHandler; import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.IStorage; -import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; /** * Data structure Version 1.0. @@ -39,8 +30,6 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; */ public class DataStructureV1_0 extends AbstractDataStructure { - public static final String CHECKSUM_DIRECTORY = "md5sum"; - public static final String DIR_METADATA = "metadata"; public static final String DIR_PARAMETERS = "parameters"; @@ -53,23 +42,12 @@ public class DataStructureV1_0 extends AbstractDataStructure /** The directory where <i>standardized</i> data could be found. */ public static final String DIR_STANDARD = "standard"; - /** - * The mapping relating <i>standard</i> with <i>original</i> data. - * <p> - * Note that under format specific conditions this mapping file could be empty, meaning that the <i>standard</i> - * directory contains the real data and not only links. - * </p> - */ - public static final String MAPPING_FILE = "standard_original_mapping"; - private static final Version VERSION = new Version(1, 0); - 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 MappingFileHandler mappingFileHandler; + private Format format; /** @@ -80,12 +58,12 @@ public class DataStructureV1_0 extends AbstractDataStructure super(storage); } - /** - * Returns version 1.0. - */ - public Version getVersion() + private final void registerHandlers() { - return VERSION; + mappingFileHandler = new MappingFileHandler(getMetaDataDirectory(), getStandardData(), getOriginalData()); + registerHandler(mappingFileHandler); + registerHandler(new ChecksumHandler(getMetaDataDirectory().makeDirectory(ChecksumHandler.CHECKSUM_DIRECTORY), + getOriginalData())); } /** @@ -106,6 +84,24 @@ public class DataStructureV1_0 extends AbstractDataStructure return Utilities.getOrCreateSubDirectory(getDataDirectory(), DIR_STANDARD); } + public final IDirectory getDataDirectory() + { + assertOpenOrCreated(); + return Utilities.getOrCreateSubDirectory(root, DIR_DATA); + } + + public final IDirectory getMetaDataDirectory() + { + assertOpenOrCreated(); + return Utilities.getOrCreateSubDirectory(root, DIR_METADATA); + } + + public final IDirectory getParametersDirectory() + { + assertOpenOrCreated(); + return Utilities.getOrCreateSubDirectory(getMetaDataDirectory(), DIR_PARAMETERS); + } + /** * 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. @@ -251,36 +247,31 @@ public class DataStructureV1_0 extends AbstractDataStructure type.saveTo(getMetaDataDirectory()); } - /** - * Returns the standard-original mapping. - * - * @return an unmodifiable version of this map. - */ - public Map<String, Reference> getStandardOriginalMapping() + public final void addReference(final Reference reference) { - return Collections.unmodifiableMap(standardOriginalMapping); + assertOpenOrCreated(); + mappingFileHandler.addReference(reference); } - /** - * Adds a reference to the standard-original mapping. - * - * @throws DataStructureException if a reference with the same path has already been registered. - */ - public void addReference(Reference reference) + public final Map<String, Reference> getStandardOriginalMapping() { - assert reference != null : "Unspecified reference."; - assertOpenOrCreated(); - String path = reference.getPath(); - if (standardOriginalMapping.containsKey(path)) - { - throw new DataStructureException("There is already a reference for file '" + path + "'."); - } - standardOriginalMapping.put(path, reference); + return mappingFileHandler.getStandardOriginalMapping(); + } + + // + // AbstractDataStructure + // + + @Override + protected void afterCreation() + { + registerHandlers(); } @Override - protected void assertValid() + public final void assertValid() { + super.assertValid(); if (getOriginalData().iterator().hasNext() == false) { throw new DataStructureException("Empty original data directory."); @@ -313,94 +304,29 @@ public class DataStructureV1_0 extends AbstractDataStructure } @Override - protected void performOpening() + public final void performOpening() { - IDirectory metaDataDirectory = getMetaDataDirectory(); - setFormat(Format.loadFrom(metaDataDirectory)); + registerHandlers(); + super.performOpening(); + setFormat(Format.loadFrom(getMetaDataDirectory())); 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>(); - String line; - try - { - while ((line = reader.readLine()) != null) - { - lines.add(line); - } - } catch (IOException ex) - { - throw new EnvironmentFailureException("Unexpected IOException.", ex); - } - standardOriginalMapping.clear(); - for (int i = 0; i < lines.size(); i++) - { - String referenceDefinition = lines.get(i); - int i1 = referenceDefinition.indexOf('\t'); - if (i1 < 0) - { - throw new DataStructureException("Error in standard-original mapping line " + (i + 1) - + ": missing first tab character: " + referenceDefinition); - } - String path = referenceDefinition.substring(0, i1); - int i2 = referenceDefinition.indexOf('\t', i1 + 1); - if (i2 < 0) - { - throw new DataStructureException("Error in standard-original mapping line " + (i + 1) - + ": missing second tab character: " + referenceDefinition); - } - ReferenceType type = ReferenceType.tryToResolveByShortName(referenceDefinition.substring(i1 + 1, i2)); - standardOriginalMapping.put(path, new Reference(path, referenceDefinition.substring(i2 + 1), type)); - } } @Override - protected void performClosing() + public final void performClosing() { - IDirectory metaDataDirectory = getMetaDataDirectory(); - IDirectory checksumDirectory = metaDataDirectory.makeDirectory(CHECKSUM_DIRECTORY); - String checksumsOfOriginal = checksumBuilder.buildChecksumsForAllFilesIn(getOriginalData()); - checksumDirectory.addKeyValuePair(DIR_ORIGINAL, checksumsOfOriginal); - + super.performClosing(); + final IDirectory metaDataDirectory = getMetaDataDirectory(); formatParameters.saveTo(getParametersDirectory()); - - StringWriter writer = new StringWriter(); - PrintWriter printWriter = new PrintWriter(writer, true); - Collection<Reference> values = standardOriginalMapping.values(); - for (Reference reference : values) - { - String path = reference.getPath(); - String shortName = reference.getReferenceType().getShortName(); - String originalPath = reference.getOriginalPath(); - printWriter.println(path + "\t" + shortName + "\t" + originalPath); - } - printWriter.close(); - metaDataDirectory.addKeyValuePair(MAPPING_FILE, writer.toString()); - if (metaDataDirectory.tryToGetNode(Format.FORMAT_DIR) == null && format != null) { format.saveTo(metaDataDirectory); } } - private IDirectory getDataDirectory() - { - return Utilities.getOrCreateSubDirectory(root, DIR_DATA); - } - - private IDirectory getMetaDataDirectory() - { - return Utilities.getOrCreateSubDirectory(root, DIR_METADATA); - } - - private IDirectory getParametersDirectory() + public final Version getVersion() { - return Utilities.getOrCreateSubDirectory(getMetaDataDirectory(), DIR_PARAMETERS); + return VERSION; } } diff --git a/bds/source/java/ch/systemsx/cisd/bds/IDataStructureHandler.java b/bds/source/java/ch/systemsx/cisd/bds/IDataStructureHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..690bcc2e68c33dcb6b76115975367995a22188ab --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/IDataStructureHandler.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** + * The aim of this interface is to delegate the work that should be done in {@link AbstractDataStructure} to smaller + * parties. + * + * @author Christian Ribeaud + */ +public interface IDataStructureHandler +{ + + /** + * Validates this data structure and throws {@link DataStructureException} if invalid. + */ + public void assertValid() throws DataStructureException; + + /** + * Performs opening specific for the concrete data structure. Will be invoked after the common part of + * {@link IDataStructure#open()} but before validation with {@link #assertValid()}. + */ + public void performOpening(); + + /** + * Performs closing specific for the concrete data structure. Will be invoked before validation with + * {@link #assertValid()}. + */ + public void performClosing(); + +} \ No newline at end of file diff --git a/bds/source/java/ch/systemsx/cisd/bds/Reference.java b/bds/source/java/ch/systemsx/cisd/bds/Reference.java index 18dcbfa2fba569d9f989c4bb5deb27550bdf3ced..10e29533fbc7f234b70827976be8b1f62f72543c 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/Reference.java +++ b/bds/source/java/ch/systemsx/cisd/bds/Reference.java @@ -21,7 +21,7 @@ package ch.systemsx.cisd.bds; * * @author Franz-Josef Elmer */ -public class Reference +public final class Reference { /** The only accepted path separator (system independent). */ public final static char PATH_SEPARATOR = '/'; @@ -35,12 +35,14 @@ public class Reference /** * Creates an instance for the specified paths and reference type. * - * @param path Path which referes to <code>originalPath</code>. - * @param originalPath Path to which <code>path</code> referes. + * @param path Path which refers to <code>originalPath</code>. + * @param originalPath Path to which <code>path</code> refers. This can be <code>null</code>. * @param referenceType Type of reference. */ - public Reference(String path, String originalPath, ReferenceType referenceType) + public Reference(final String path, final String originalPath, final ReferenceType referenceType) { + assert path != null : "Path can not be null."; + assert originalPath != null : "Original path can not be null."; this.path = path; this.originalPath = originalPath; this.referenceType = referenceType; diff --git a/bds/source/java/ch/systemsx/cisd/bds/ReferenceType.java b/bds/source/java/ch/systemsx/cisd/bds/ReferenceType.java index 6a446339658fa611f4b87ed89138125ba9c4831c..4b159a53161a60abdee74db63f637a7e9aed9ada 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/ReferenceType.java +++ b/bds/source/java/ch/systemsx/cisd/bds/ReferenceType.java @@ -18,19 +18,17 @@ package ch.systemsx.cisd.bds; /** * Type of reference between a file in <tt>data/standard</tt> and <tt>data/original</tt>. - * + * * @author Franz-Josef Elmer */ public enum ReferenceType { IDENTICAL("I"), TRANSFORMED("T"); - + /** - * Tries to resolve the reference type from the specified short name. - * - * @return <code>null</code> if there is no reference type with the specified short name. + * Resolves the reference type from the specified short name. */ - public static ReferenceType tryToResolveByShortName(String shortName) + public final static ReferenceType resolveByShortName(final String shortName) { for (ReferenceType type : values()) { @@ -39,12 +37,12 @@ public enum ReferenceType return type; } } - return null; + throw new IllegalArgumentException(String.format("No type for short name '%s'", shortName)); } private final String shortName; - private ReferenceType(String shortName) + private ReferenceType(final String shortName) { this.shortName = shortName; } @@ -56,6 +54,5 @@ public enum ReferenceType { return shortName; } - - + } diff --git a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java index 1dd9765b4d744a2c58752f52cde3c5837cdb5839..ba177890da099a1ffaad490b9a6b814800368d98 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java +++ b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java @@ -16,6 +16,8 @@ package ch.systemsx.cisd.bds; +import java.util.List; + import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.IFile; import ch.systemsx.cisd.bds.storage.INode; @@ -85,10 +87,31 @@ public class Utilities * @throws DataStructureException if the requested file does not exist. */ public static String getString(final IDirectory directory, final String name) + { + final INode node = tryGetNode(directory, name); + final IFile file = (IFile) node; + return file.getStringContent(); + } + + /** + * Returns the string content of a file from the specified directory as list of <code>String</code> objects. + * + * @param directory Directory of the requested file. + * @param name Name of the file. + * @throws DataStructureException if the requested file does not exist. + */ + public static List<String> getStringList(final IDirectory directory, final String name) + { + final INode node = tryGetNode(directory, name); + final IFile file = (IFile) node; + return file.getStringContentList(); + } + + private final static INode tryGetNode(final IDirectory directory, final String name) { assert directory != null : String.format("Given directory can not be null."); assert name != null : String.format("Given name can not be null."); - INode node = directory.tryToGetNode(name); + final INode node = directory.tryToGetNode(name); if (node == null) { throw new DataStructureException("File '" + name + "' missing in '" + directory + "'."); @@ -97,8 +120,7 @@ public class Utilities { throw new DataStructureException(node + " is not a file."); } - IFile file = (IFile) node; - return file.getStringContent(); + return node; } private Utilities() diff --git a/bds/source/java/ch/systemsx/cisd/bds/ChecksumBuilder.java b/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumBuilder.java similarity index 95% rename from bds/source/java/ch/systemsx/cisd/bds/ChecksumBuilder.java rename to bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumBuilder.java index 4c800dca491d7e40ce3edda19ec2d59f77bce7bb..1c61153d728706990b04bf55ab49ab535eb3b439 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/ChecksumBuilder.java +++ b/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumBuilder.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package ch.systemsx.cisd.bds; +package ch.systemsx.cisd.bds.handler; import java.io.IOException; import java.io.InputStream; @@ -27,6 +27,7 @@ import java.util.List; import org.apache.commons.io.IOUtils; +import ch.systemsx.cisd.bds.Reference; import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.IFile; import ch.systemsx.cisd.bds.storage.INode; @@ -41,7 +42,7 @@ class ChecksumBuilder { private final IChecksumCalculator checksumCalculator; - ChecksumBuilder(IChecksumCalculator checksumCalculator) + ChecksumBuilder(final IChecksumCalculator checksumCalculator) { this.checksumCalculator = checksumCalculator; } diff --git a/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumHandler.java b/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..486330c615860cf20764250ddccd6fefe349d334 --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/handler/ChecksumHandler.java @@ -0,0 +1,65 @@ +/* + * 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.handler; + +import ch.systemsx.cisd.bds.DataStructureException; +import ch.systemsx.cisd.bds.DataStructureV1_0; +import ch.systemsx.cisd.bds.IDataStructureHandler; +import ch.systemsx.cisd.bds.storage.IDirectory; + +/** + * A <code>IDataStructureHandler</code> implementation for the <code>md5sum</code> directory. + * + * @author Christian Ribeaud + */ +public final class ChecksumHandler implements IDataStructureHandler +{ + + private final ChecksumBuilder checksumBuilder = new ChecksumBuilder(new MD5ChecksumCalculator()); + + private final IDirectory checksumDirectory; + + private final IDirectory dataDirectory; + + public static final String CHECKSUM_DIRECTORY = "md5sum"; + + public ChecksumHandler(final IDirectory checksumDirectory, final IDirectory dataDirectory) + { + this.checksumDirectory = checksumDirectory; + this.dataDirectory = dataDirectory; + } + + // + // IDataStructureHandler + // + + public final void assertValid() throws DataStructureException + { + // TODO 2007-11-29, Christian Ribeaud: validation of loaded checksums. + } + + public final void performClosing() + { + final String checksumsOfOriginal = checksumBuilder.buildChecksumsForAllFilesIn(dataDirectory); + checksumDirectory.addKeyValuePair(DataStructureV1_0.DIR_ORIGINAL, checksumsOfOriginal); + } + + public final void performOpening() + { + } + +} diff --git a/bds/source/java/ch/systemsx/cisd/bds/IChecksumCalculator.java b/bds/source/java/ch/systemsx/cisd/bds/handler/IChecksumCalculator.java similarity index 88% rename from bds/source/java/ch/systemsx/cisd/bds/IChecksumCalculator.java rename to bds/source/java/ch/systemsx/cisd/bds/handler/IChecksumCalculator.java index 25c71540f6ed1ee5cf5d3ea5d67e3b2988fa3a5d..40734d983f0868fb9724c723146253a000326ab3 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/IChecksumCalculator.java +++ b/bds/source/java/ch/systemsx/cisd/bds/handler/IChecksumCalculator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package ch.systemsx.cisd.bds; +package ch.systemsx.cisd.bds.handler; import java.io.IOException; import java.io.InputStream; @@ -24,7 +24,7 @@ import java.io.InputStream; * * @author Christian Ribeaud */ -public interface IChecksumCalculator +interface IChecksumCalculator { /** @@ -33,5 +33,5 @@ public interface IChecksumCalculator * @param inputStream Input stream from whom the bytes are read to calculate checksum. * @throws IOException if reading from <code>inputStream</code> causes an <code>IOException</code>. */ - public String calculateChecksum(InputStream inputStream) throws IOException; + String calculateChecksum(InputStream inputStream) throws IOException; } diff --git a/bds/source/java/ch/systemsx/cisd/bds/MD5ChecksumCalculator.java b/bds/source/java/ch/systemsx/cisd/bds/handler/MD5ChecksumCalculator.java similarity index 94% rename from bds/source/java/ch/systemsx/cisd/bds/MD5ChecksumCalculator.java rename to bds/source/java/ch/systemsx/cisd/bds/handler/MD5ChecksumCalculator.java index 69882272c27d94aa27c1a7de8954d3ee41ba1921..532e6893199c4a455afb71ad1962c1fb6bd34b68 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/MD5ChecksumCalculator.java +++ b/bds/source/java/ch/systemsx/cisd/bds/handler/MD5ChecksumCalculator.java @@ -1,4 +1,4 @@ -package ch.systemsx.cisd.bds; +package ch.systemsx.cisd.bds.handler; import java.io.IOException; import java.io.InputStream; @@ -6,6 +6,7 @@ import java.io.InputStream; import com.twmacinta.util.MD5; import com.twmacinta.util.MD5InputStream; + /** * A {@link IChecksumCalculator} implementation based on <i>MD5</i>. * diff --git a/bds/source/java/ch/systemsx/cisd/bds/handler/MappingFileHandler.java b/bds/source/java/ch/systemsx/cisd/bds/handler/MappingFileHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..405643b64452b4105934da5301f9c9fd3be072a5 --- /dev/null +++ b/bds/source/java/ch/systemsx/cisd/bds/handler/MappingFileHandler.java @@ -0,0 +1,160 @@ +/* + * 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.handler; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import ch.systemsx.cisd.bds.DataStructureException; +import ch.systemsx.cisd.bds.IDataStructureHandler; +import ch.systemsx.cisd.bds.Reference; +import ch.systemsx.cisd.bds.ReferenceType; +import ch.systemsx.cisd.bds.Utilities; +import ch.systemsx.cisd.bds.storage.IDirectory; + +/** + * A <code>IDataStructureHandler</code> implementation for the <code>standard_original_mapping</code> file. + * + * @author Christian Ribeaud + */ +public final class MappingFileHandler implements IDataStructureHandler +{ + private final Map<String, Reference> standardOriginalMapping = new LinkedHashMap<String, Reference>(); + + /** The directory the mapping is going to be written to. */ + private final IDirectory mappingDirectory; + + /** The root of {@link Reference#getPath()}. Usually the path to <code>standard</code> directory. */ + private final IDirectory pathRoot; + + /** The root of {@link Reference#getOriginalPath()}. Usually the path to <code>original</code> directory. */ + private final IDirectory originalPathRoot; + + /** + * The mapping relating <i>standard</i> with <i>original</i> data. + * <p> + * Note that under format specific conditions this mapping file could be empty, meaning that the <i>standard</i> + * directory contains the real data and not only links. + * </p> + */ + public static final String MAPPING_FILE = "standard_original_mapping"; + + public MappingFileHandler(final IDirectory mappingDirectory, final IDirectory pathRoot, + final IDirectory originalPathRoot) + { + assert mappingDirectory != null : "Given mapping directory can not be null."; + assert pathRoot != null : "Given path root can not be null."; + assert originalPathRoot != null : "Given original path root can not be null."; + this.mappingDirectory = mappingDirectory; + this.pathRoot = pathRoot; + this.originalPathRoot = originalPathRoot; + } + + /** + * Returns the standard-original mapping. + * + * @return an unmodifiable version of this map. + */ + public final Map<String, Reference> getStandardOriginalMapping() + { + return Collections.unmodifiableMap(standardOriginalMapping); + } + + /** + * Adds a reference to the standard-original mapping. + * + * @throws DataStructureException if a reference with the same path has already been registered. + */ + public final void addReference(final Reference reference) throws DataStructureException + { + assert reference != null : "Unspecified reference."; + final String path = reference.getPath(); + if (standardOriginalMapping.containsKey(path)) + { + throw new DataStructureException("There is already a reference for file '" + path + "'."); + } + standardOriginalMapping.put(path, reference); + } + + private final void loadStandardOriginalMapping() + { + final List<String> mappingLines = Utilities.getStringList(mappingDirectory, MAPPING_FILE); + standardOriginalMapping.clear(); + for (int i = 0; i < mappingLines.size(); i++) + { + String referenceDefinition = mappingLines.get(i); + int i1 = referenceDefinition.indexOf('\t'); + if (i1 < 0) + { + throw new DataStructureException("Error in standard-original mapping line " + (i + 1) + + ": missing first tab character: " + referenceDefinition); + } + String path = referenceDefinition.substring(0, i1); + int i2 = referenceDefinition.indexOf('\t', i1 + 1); + if (i2 < 0) + { + throw new DataStructureException("Error in standard-original mapping line " + (i + 1) + + ": missing second tab character: " + referenceDefinition); + } + final ReferenceType type = ReferenceType.resolveByShortName(referenceDefinition.substring(i1 + 1, i2)); + standardOriginalMapping.put(path, new Reference(path, referenceDefinition.substring(i2 + 1), type)); + } + } + + private final String createMappingFile() + { + final StringWriter writer = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(writer, true); + final Collection<Reference> values = standardOriginalMapping.values(); + for (final Reference reference : values) + { + final String path = reference.getPath(); + final String shortName = reference.getReferenceType().getShortName(); + final String originalPath = reference.getOriginalPath(); + printWriter.println(path + "\t" + shortName + "\t" + originalPath); + } + printWriter.close(); + return writer.toString(); + } + + // + // IDataStructureHandler + // + + public final void assertValid() throws DataStructureException + { + // TODO 2007-11-29, Christian Ribeaud: validation of loaded references. Note that this could interfere with + // checksum validation. To validate a checksum, the file must exist. So we would not need to check the original + // path existence here. + } + + public final void performClosing() + { + mappingDirectory.addKeyValuePair(MAPPING_FILE, createMappingFile()); + } + + public final void performOpening() + { + loadStandardOriginalMapping(); + } + +} 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 a943effb8a143e33ca2d353059652ee67f7a2e63..7f0ef500185812fbd3c13ab24db044ac9310604d 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/IDirectory.java @@ -30,7 +30,7 @@ public interface IDirectory extends INode, Iterable<INode> * * @return <code>null</code> if there is no child node named <code>name</code>. */ - public INode tryToGetNode(String name); + public INode tryToGetNode(final String name); /** * Makes a new subdirectory in this directory. Does nothing if the subdirectory already exists. @@ -58,10 +58,10 @@ public interface IDirectory extends INode, Iterable<INode> /** * Adds a plain file named <code>key</code> with content <code>value</code> to this directory. */ - public IFile addKeyValuePair(String key, String value); + public IFile addKeyValuePair(final String key, final 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); + public ILink addLink(final String name, final 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 9b8702c860fe132e54a5aa616852cd9c37af049f..1fce846462f27cdeddc1d5cd9dd82f82587a8094 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/IFile.java @@ -17,11 +17,11 @@ package ch.systemsx.cisd.bds.storage; import java.io.InputStream; -import java.io.Reader; +import java.util.List; /** * Node representing a file with some content. - * + * * @author Franz-Josef Elmer */ public interface IFile extends INode @@ -30,19 +30,20 @@ public interface IFile extends INode * Returns the content of this file node as a byte array. */ public byte[] getBinaryContent(); - + /** * Returns the content of this file node as an input stream. */ public InputStream getInputStream(); - + /** * Returns the content of this file node as a string. */ public String getStringContent(); - + /** - * Returns the content of this file node as a reader. + * Returns the content of this file node as a list of <code>String</code> objects. */ - public Reader getReader(); + public List<String> getStringContentList(); + } 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 2d9621d6d8e975c435d832ed72792e456d3a2bb9..24de1be2923df2b3792689f883bf0c88490945fd 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java @@ -35,6 +35,11 @@ public interface INode */ public IDirectory tryToGetParent(); + /** + * Whether this <code>INode</code> is valid. + */ + public boolean isValid(); + /** * Extracts this node to the specified directory of the file system. * <p> @@ -42,10 +47,10 @@ public interface INode * </p> */ public void extractTo(final File directory); - + /** - * Moves this node and all descendants to the specified directory of the file system. - * This node will be automatically removed from its parent. + * Moves this node and all descendants to the specified directory of the file system. This node will be + * automatically removed from its parent. */ public void moveTo(final File directory); } 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 f80754a8a5aa839b5bce4057143ae96ddf849127..f35e0adf9fa1a19a6d225301608fc9d052f847b4 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 @@ -87,6 +87,11 @@ abstract class AbstractNode implements INode moveFileToDirectory(nodeFile, directory); } + public boolean isValid() + { + return nodeFile.exists(); + } + // // Object // 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 5023956f7be5d05f7b12b34f7a6ffca7a3734bd0..c51790b7ba93cfb8248fef9d1587c26faadb0950 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 @@ -190,4 +190,10 @@ final class Directory extends AbstractNode implements IDirectory } } } + + @Override + public final boolean isValid() + { + return super.isValid() && FileUtilities.checkDirectoryFullyAccessible(nodeFile, "") == null; + } } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java index 25fbe30589470e49b5714e6ffe66df61544a19db..559e0c5c98bcc9443e447cba402d80407d4d3609 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java @@ -18,10 +18,9 @@ package ch.systemsx.cisd.bds.storage.filesystem; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; -import java.io.Reader; +import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; @@ -31,6 +30,8 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.utilities.FileUtilities; /** + * An <code>IFile</code> implementation. + * * @author Franz-Josef Elmer */ class File extends AbstractNode implements IFile @@ -56,7 +57,7 @@ class File extends AbstractNode implements IFile } } - public InputStream getInputStream() + public final InputStream getInputStream() { try { @@ -67,22 +68,16 @@ class File extends AbstractNode implements IFile } } - public String getStringContent() + public final String getStringContent() { return FileUtilities.loadToString(nodeFile); } - public Reader getReader() + public final List<String> getStringContentList() { - try - { - return new FileReader(nodeFile); - } catch (FileNotFoundException ex) - { - throw new EnvironmentFailureException("Couldn't open reader for file " + nodeFile.getAbsolutePath()); - } + return FileUtilities.loadToStringList(nodeFile); } - + public final void extractTo(final java.io.File directory) throws EnvironmentFailureException { assert directory != null && directory.isDirectory(); @@ -95,4 +90,10 @@ class File extends AbstractNode implements IFile nodeFile.getAbsolutePath(), directory.getAbsolutePath()); } } + + @Override + public final boolean isValid() + { + return super.isValid() && FileUtilities.checkPathFullyAccessible(nodeFile, "") == null; + } } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Link.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Link.java index 28565473b9a3c3c4e7fd853e44580a804ea957ac..604de64e9b8460f79f862bc7f9774c21ee38b7a3 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Link.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Link.java @@ -21,53 +21,76 @@ import java.io.File; import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.ILink; import ch.systemsx.cisd.bds.storage.INode; -import ch.systemsx.cisd.common.exceptions.NotImplementedException; /** + * An <code>ILink</code> implementation. + * * @author Franz-Josef Elmer */ -class Link implements ILink +final class Link implements ILink { private final String name; - private IDirectory parent; - private final INode reference; - Link(String name, INode reference) + private IDirectory parent; + + Link(final String name, final INode reference) { + assert name != null : "A name must be specified."; + assert reference != null : "Reference can not be null."; + assert reference instanceof ILink : "Link of link not supported."; this.name = name; this.reference = reference; } - public String getName() + /** Sets the parent of this {@link INode}. */ + final void setParent(final IDirectory parentOrNull) { - return name; + parent = parentOrNull; } - void setParent(IDirectory parentOrNull) + // + // ILink + // + + public final String getName() { - parent = parentOrNull; + return name; } - public IDirectory tryToGetParent() + public final IDirectory tryToGetParent() { return parent; } - public INode getReference() + public final INode getReference() { return reference; } - public void extractTo(final File directory) + public final void extractTo(final File directory) + { + reference.extractTo(directory); + } + + public final void moveTo(final File directory) { - throw new NotImplementedException(); + reference.moveTo(directory); } - public void moveTo(File directory) + public final boolean isValid() { - throw new NotImplementedException(); + if (reference.isValid() == false) + { + return false; + } + if (parent != null) + { + final INode node = parent.tryToGetNode(name); + return node != null && node.isValid(); + } + return true; } } 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 d4237b1ee297e7a7d7ac7a82b2bdd9ebde734b5a..389a4f8481708adaf0aff33b7ef38f3d4199d8ee 100644 --- a/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/DataStructureV1_0Test.java @@ -16,7 +16,6 @@ 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; @@ -31,6 +30,8 @@ import java.util.Map; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import ch.systemsx.cisd.bds.handler.ChecksumHandler; +import ch.systemsx.cisd.bds.handler.MappingFileHandler; import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.IStorage; import ch.systemsx.cisd.bds.storage.StorageException; @@ -413,7 +414,7 @@ public final class DataStructureV1_0Test extends AbstractFileSystemTestCase checkFormattedData(reloadedDataStructure.getFormattedData()); IDirectory metaDataDir = Utilities.getSubDirectory(root, DIR_METADATA); - IDirectory checksumDir = Utilities.getSubDirectory(metaDataDir, CHECKSUM_DIRECTORY); + IDirectory checksumDir = Utilities.getSubDirectory(metaDataDir, ChecksumHandler.CHECKSUM_DIRECTORY); assertEquals("a1d0c6e83f027327d8461063f4ac58a6 answer\n", Utilities.getString(checksumDir, DataStructureV1_0.DIR_ORIGINAL)); } @@ -550,7 +551,7 @@ public final class DataStructureV1_0Test extends AbstractFileSystemTestCase new ExperimentRegistratorDate(new Date(0)).saveTo(metaData); new ExperimentRegistrator("john", "doe", "j@doe").saveTo(metaData); new MeasurementEntity("a", "b").saveTo(metaData); - metaData.addKeyValuePair(DataStructureV1_0.MAPPING_FILE, ""); + metaData.addKeyValuePair(MappingFileHandler.MAPPING_FILE, ""); ProcessingType.COMPUTED_DATA.saveTo(metaData); storage.unmount(); } diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/ChecksumBuilderTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/handler/ChecksumBuilderTest.java similarity index 95% rename from bds/sourceTest/java/ch/systemsx/cisd/bds/ChecksumBuilderTest.java rename to bds/sourceTest/java/ch/systemsx/cisd/bds/handler/ChecksumBuilderTest.java index a2806d8ffa11656f415c25c7d8a660607268f673..0846e03942ddcc9777a17e81e828df64363dc6cd 100644 --- a/bds/sourceTest/java/ch/systemsx/cisd/bds/ChecksumBuilderTest.java +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/handler/ChecksumBuilderTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package ch.systemsx.cisd.bds; +package ch.systemsx.cisd.bds.handler; import static ch.systemsx.cisd.common.utilities.OSUtilities.LINE_SEPARATOR; import static org.testng.AssertJUnit.assertEquals; @@ -27,6 +27,8 @@ import java.util.Random; import org.apache.commons.io.IOUtils; import org.testng.annotations.Test; +import ch.systemsx.cisd.bds.handler.ChecksumBuilder; +import ch.systemsx.cisd.bds.handler.MD5ChecksumCalculator; import ch.systemsx.cisd.bds.storage.filesystem.FileStorage; import ch.systemsx.cisd.common.utilities.AbstractFileSystemTestCase; import ch.systemsx.cisd.common.utilities.FileUtilities;