/* * 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.data.protocols; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import fr.ens.biologie.genomique.eoulsan.data.DataFile; import fr.ens.biologie.genomique.eoulsan.data.DataFileMetadata; import fr.ens.biologie.genomique.eoulsan.io.CompressionType; /** * This abstract class define a storage protocol. It is useful to easily access * common resources like genomes or annotations. * @since 1.1 * @author Laurent Jourdren */ public abstract class StorageDataProtocol extends AbstractDataProtocol { /** * Get the path where searching the files. * @return a string with the path where search the files */ protected abstract String getBasePath(); /** * Get the file extensions of the files to search. * @return a string with file extension of the files to search */ protected String getExtension() { throw new NullPointerException( "No extension has been defined for the storage protocol: " + getName()); } /** * Get the list of the file extensions of the files to search. * @return a list with file extensions of the files to search */ protected List<String> getExtensions() { return Collections.singletonList(getExtension()); } @Override public InputStream getData(final DataFile src) throws IOException { return getUnderLyingData(src).rawOpen(); } @Override public OutputStream putData(final DataFile dest) throws IOException { throw new IOException( "PutData() method is no supported by " + getName() + " protocol"); } @Override public boolean exists(final DataFile src, final boolean followLink) { try { return getUnderLyingData(src).exists(); } catch (IOException e) { return false; } } @Override public DataFileMetadata getMetadata(final DataFile src) throws IOException { return getUnderLyingData(src).getMetaData(); } @Override public boolean canRead() { return true; } @Override public boolean canWrite() { return false; } @Override public File getSourceAsFile(final DataFile src) { try { return getUnderLyingData(src).toFile(); } catch (IOException e) { return null; } } /** * Get the underlying Data. * @param src source to use * @return a the underlying DataFile * @throws IOException if an error occurs while getting the underlying * DataFile */ public DataFile getUnderLyingData(final DataFile src) throws IOException { final String basePath = getBasePath(); if (basePath == null) { throw new IOException(getName() + " storage is not configured"); } final DataFile baseDir = new DataFile(basePath); if (!baseDir.exists()) { throw new IOException( getName() + " storage base path does not exists: " + baseDir); } // List the content of the directory if it can be listed final List<DataFile> dirList; if (baseDir.getProtocol().canList()) { dirList = baseDir.list(); } else { dirList = Collections.emptyList(); } // Add no extension to the list of allowed extensions final List<String> extensions = new ArrayList<>(getExtensions()); extensions.add(""); for (String extension : extensions) { if (extension == null) { throw new NullPointerException( "One of the extensions of the storage protocol is null: " + getName()); } final String filename = src.getName().trim() + extension; for (CompressionType c : CompressionType.values()) { final DataFile file = new DataFile(baseDir, filename + c.getExtension()); // Check if the file in the right case exists if (file.exists()) { return canonicalize(file); } // Insensitive case search file in the directory list if (dirList.isEmpty()) { // Compare filename in lower case final String filenameLower = file.getName().toLowerCase(); for (DataFile f : dirList) { if (f.getName().toLowerCase().equals(filenameLower) && f.exists()) { return canonicalize(f); } } } else { // For non browsable base directory // Check if the directory exists in lower case final DataFile fileLower = new DataFile(baseDir, file.getName().toLowerCase()); if (fileLower.exists()) { return canonicalize(fileLower); } // Check if the directory exists in upper case final DataFile fileUpper = new DataFile(baseDir, file.getName().toUpperCase()); if (fileUpper.exists()) { return canonicalize(fileUpper); } } } } throw new IOException("No " + getName() + " found for: " + src.getName()); } /** * Canonicalize symbolic link. * @param file the file to Canonicalize. * @return a canonicalized file * @throws IOException if an error occurs while canonicalize the file */ private DataFile canonicalize(final DataFile file) throws IOException { if (!file.isLocalFile()) { return file; } return new DataFile(file.toFile().getCanonicalFile()); } }