/* * Eoulsan development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public License version 2.1 or * later and CeCILL-C. This should be distributed with the code. * If you do not have a copy, see: * * http://www.gnu.org/licenses/lgpl-2.1.txt * http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt * * Copyright for this code is held jointly by the Genomic platform * of the Institut de Biologie de l'École normale supérieure and * the individual authors. These should be listed in @author doc * comments. * * For more information on the Eoulsan project and its aims, * or to join the Eoulsan Google group, visit the home page * at: * * http://outils.genomique.biologie.ens.fr/eoulsan * */ package fr.ens.biologie.genomique.eoulsan.core.workflow; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import java.io.Serializable; import java.util.Collections; import java.util.List; import com.google.common.base.Objects; import com.google.common.collect.Lists; import fr.ens.biologie.genomique.eoulsan.EoulsanRuntimeException; import fr.ens.biologie.genomique.eoulsan.data.Data; import fr.ens.biologie.genomique.eoulsan.data.DataFile; import fr.ens.biologie.genomique.eoulsan.data.DataFormat; import fr.ens.biologie.genomique.eoulsan.data.DataMetadata; import fr.ens.biologie.genomique.eoulsan.design.Design; /** * This class define a data element. * @since 2.0 * @author Laurent Jourdren */ class DataElement extends AbstractData implements Serializable { private static final long serialVersionUID = -8982205120365590676L; private final DataMetadata metadata; protected final List<DataFile> files; // Field required for multi-files Data creation private final StepOutputPort port; private boolean canRename = true; @Override public void setName(final String name) { if (!this.canRename) { throw new EoulsanRuntimeException( "Data cannot be renamed once it has been used"); } super.setName(name); // Update datafiles updateDataFiles(); } @Override void setPart(final int part) { if (!this.canRename) { throw new EoulsanRuntimeException( "Data cannot be renamed once it has been used"); } super.setPart(part); // Update dataFiles updateDataFiles(); } @Override public boolean isList() { return false; } @Override public List<Data> getListElements() { return Collections.singletonList((Data) this); } @Override public DataMetadata getMetadata() { return this.metadata; } @Override public Data addDataToList(final String name) { throw new UnsupportedOperationException(); } @Override public Data addDataToList(final String name, final int part) { throw new UnsupportedOperationException(); } @Override public String getDataFilename() { return getDataFile().getName(); } @Override public String getDataFilename(final int fileIndex) { if (getFormat().getMaxFilesCount() < 2) { throw new EoulsanRuntimeException( "Only multi-files DataFormat are handled by this method."); } return this.files.get(fileIndex).getName(); } @Override public DataFile getDataFile() { if (getFormat().getMaxFilesCount() > 1) { throw new EoulsanRuntimeException( "Multi-files DataFormat cannot be handled by this method, " + "use getDataFile(int) instead."); } this.canRename = false; return this.files.get(0); } /** * Set the first data file. * @param dataFile data file to set */ void setDataFile(final DataFile dataFile) { checkNotNull(dataFile, "DataFile to set cannot be null"); if (this.files.size() == 0) { throw new IllegalStateException( "Cannot set a DataFile if not already exists"); } this.files.set(0, dataFile); } /** * Set a DataFile. * @param fileIndex index of the data file * @param dataFile file to set */ void setDataFile(final int fileIndex, final DataFile dataFile) { checkArgument(fileIndex >= 0, "fileIndex argument must be >=0"); checkNotNull(dataFile, "DataFile to set cannot be null"); if (fileIndex >= this.files.size()) { throw new IllegalStateException( "Cannot set a DataFile if not already exists"); } this.files.set(fileIndex, dataFile); } /** * Set the DataFiles. * @param dataFiles files to set */ void setDataFiles(final List<DataFile> dataFiles) { checkNotNull(dataFiles, "dataFiles to set cannot be null"); for (DataFile file : dataFiles) { checkArgument(file != null, "dataFiles cannot contains null value"); checkArgument(Collections.frequency(dataFiles, file) == 1, "dataFiles cannot contains the same file: " + file); } this.files.clear(); this.files.addAll(dataFiles); } /** * Get the DataFiles of the data. * @return a list with the DataFiles */ List<DataFile> getDataFiles() { return Collections.unmodifiableList(Lists.newArrayList(this.files)); } @Override public DataFile getDataFile(final int fileIndex) { if (getFormat().getMaxFilesCount() < 2) { throw new EoulsanRuntimeException( "Only multi-files DataFormat are handled by this method, " + "use getDataFile() instead."); } if (fileIndex < 0) { throw new EoulsanRuntimeException( "File index parameter cannot be lower than 0"); } if (fileIndex > this.files.size()) { throw new EoulsanRuntimeException("Cannot create file index " + fileIndex + " as file index " + this.files.size() + " is not created"); } if (fileIndex >= getFormat().getMaxFilesCount()) { throw new EoulsanRuntimeException("The format " + getFormat().getName() + " does not support more than " + getFormat().getMaxFilesCount() + " multi-files"); } // Create DataFile is required if (fileIndex == this.files.size()) { this.files.add(createDataFile(fileIndex)); } return this.files.get(fileIndex); } @Override public int getDataFileCount() { return this.files.size(); } @Override public int getDataFileCount(final boolean existingFiles) { return this.files.size(); } private DataFile createDataFile(final int fileIndex) { return WorkflowFileNaming.file(this.port, this, fileIndex); } private void updateDataFiles() { // If DataFile object(s) has not been set in the constructor if (this.port != null) { // Update the DataFile filename if (this.port.getFormat().getMaxFilesCount() > 1) { // Multi-file formats for (int i = 0; i < this.files.size(); i++) { this.files.set(i, createDataFile(i)); } } else { // Mono-file formats this.files.set(0, createDataFile(-1)); } } } @Override public String toString() { return Objects.toStringHelper(this).add("name", getName()) .add("format", getFormat().getName()).add("metadata", getMetadata()) .add("list", isList()).add("content", this.files).toString(); } // // Constructor // DataElement(final DataFormat format, final List<DataFile> files, final Design design) { super(format); this.metadata = new SimpleDataMetadata(design); checkNotNull(format, "format argument cannot be null"); checkNotNull(files, "files argument cannot be null"); checkNotNull(design, "design argument cannot be null"); for (DataFile f : files) { if (f == null) { throw new IllegalArgumentException( "The files list argument cannot contains null elements"); } } this.files = Lists.newArrayList(files); this.port = null; } DataElement(final DataFormat format, final DataFile file, final Design design) { this(format, Collections.singletonList(file), design); } DataElement(final StepOutputPort port, final Design design) { super(port.getFormat()); checkNotNull(port, "port argument cannot be null"); checkNotNull(design, "design argument cannot be null"); this.metadata = new SimpleDataMetadata(design); this.port = port; if (getFormat().getMaxFilesCount() == 1) { this.files = Lists.newArrayList(createDataFile(-1)); } else { this.files = Lists.newArrayList(createDataFile(0)); } } }