/* * Copyright 2010 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. */ import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import ch.systemsx.cisd.common.collections.IKeyExtractor; import ch.systemsx.cisd.common.collections.TableMap; import ch.systemsx.cisd.openbis.dss.client.api.v1.DataSet; import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss; import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO; import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetMetadataDTO; import ch.systemsx.cisd.openbis.generic.client.cli.Login; import ch.systemsx.cisd.openbis.generic.shared.api.v1.filter.AndDataSetFilter; import ch.systemsx.cisd.openbis.generic.shared.api.v1.filter.PropertiesBasedDataSetFilter; import ch.systemsx.cisd.openbis.generic.shared.api.v1.filter.TypeBasedDataSetFilter; import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.IScreeningOpenbisServiceFacade; import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.IScreeningOpenbisServiceFacadeFactory; import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade; import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade.IImageOutputStreamProvider; import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacadeFactory; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ExperimentIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVector; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetWellReference; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorWithDescription; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.IFeatureCodesProvider; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageDatasetMetadata; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageDatasetReference; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.MaterialIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.MaterialTypeIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Plate; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateImageReference; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateMetadata; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateWellMaterialMapping; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition; /** * Simple Matlab interface for openBIS for Screening. It is meant to be used in one Matlab session * at a time, i.e. it is not multi-threading safe. *
 * While written in Java, the API is idiomatic for Matlab, i.e. values are returned as
 * multi-dimensional arrays. For the get... and load... methods the first
 * index will contain the actual data, while the second index will contain per-row annotations. For
 * getFeatureMatrix, the third index contains per-column annotations. This allows
 * simple access with Matlab's slicing operator, see doc of e.g.
 * {@link #getFeatureMatrix(String, String, String[])}.
 * 
* A typical Matlab session looks like: * *
 * % Add the API jar file to the classpath
 * javaaddpath('/home/brinn/matlab/openbis_screening_api-batteries_included.jar')
 * % Login to server
 * OpenBISScreeningML.login('user', 'secret', 'https://www.infectome.org')
 * 
 * % ...perform calls on the server...
 * 
 * % Logout to close the session on the server
 * OpenBISScreeningML.logout()
 * 
 * 
 * Note: using this login your password will end up in the Matlab command history. An alternative
 * that avoids this is to call the {@link ch.systemsx.cisd.openbis.generic.client.cli.Login} class.
 * Logging in on the console will grant this class access to the openBIS server.
 * 
 * To learn the API one needs to understand three basic notions: code, augmented code and perm id.
 * Space, project, experiment, plate and well have their own code, which is unique only in
 * the context of the parent.
 * That's why one needs augmented code to point e.g. to one experiment, because two different
 * projects can have experiments with the same code.
 * Such an augmented code for experiment has a form of "/space-code/project-code/experiment-code".
 * For plate it has a form of "/space-code/plate-code" (note that plate code is unique on the space
 * level). 
 * The drawback of an augmented code is that it's not persistent. If someone e.g. moves the
 * experiment from one space to the other augmented code of the experiment becomes invalid. That is
 * why experiments, plates and datasets have perm id (permament identifier) which never
 * change and allow to refer to them with one "magic" identifier, e.g. 20110516124520378-737166.
 * 
java.io.tmpdir is
     * used.
     */
    static File tempDir = new File(System.getProperty("java.io.tmpdir"));
    static final String TEMP_DIR_PREFIX = "openbis_";
    static final String TEMP_DIR_POSTFIX = "_temp_dir";
    //
    // Authentication methods
    //
    /**
     * Login to the openBIS server given as url.
     * * Matlab example: * *
     * OpenBISScreeningML.login('user', 'secret', 'https://www.infectome.org')
     * 
     * 
     * @param user The user id on the server
     * @param password The password on the server
     * @param url The URL, e.g. https://www.infectome.org
     */
    public static void login(String user, String password, String url)
    {
        System.setProperty("force-accept-ssl-certificate", "true");
        IScreeningOpenbisServiceFacade facade = facadeFactory.tryToCreate(user, password, url);
        if (facade == null)
        {
            throw new RuntimeException("Login failed.");
        }
        init(facade);
    }
    private static void init(IScreeningOpenbisServiceFacade openBisFacade)
    {
        openbis = openBisFacade;
        dataSetsDir = new File(tempDir, DATASETS_FOLDER);
        if (dataSetsDir.isDirectory() == false && dataSetsDir.mkdirs() == false)
        {
            throw new RuntimeException("Couldn't create a data set directory.");
        }
        temporarySessionDir =
                new File(tempDir, TEMP_DIR_PREFIX + System.currentTimeMillis() / 1000
                        + TEMP_DIR_POSTFIX);
        if (temporarySessionDir.mkdirs() == false)
        {
            throw new RuntimeException("Couldn't create a temporary directory.");
        }
        temporarySessionDir.deleteOnExit();
        loadedImages = new HashMap* Matlab example: * *
     * OpenBISScreeningML.logout()
     * 
     */
    public static void logout()
    {
        if (openbis == null)
        {
            return;
        }
        openbis.logout();
        if (Login.OPENBIS_TOKEN_FILE.exists())
        {
            Login.OPENBIS_TOKEN_FILE.delete();
        }
        delete(temporarySessionDir);
        openbis = null;
    }
    private static void delete(File file)
    {
        if (file.isDirectory())
        {
            File[] files = file.listFiles();
            for (File child : files)
            {
                delete(child);
            }
        }
        file.delete();
    }
    //
    // Information methods
    //
    /**
     * Lists all experiment.
     * * Matlab example: * *
     * % Get the experiments
     * exps = OpenBISScreeningML.listExperiments();
     * % How many experiments do we have?
     * length(exps)
     * % Get all information about experiment 3
     * exp3 = exps(3,:)
     * % Get the perm ids for all experiments
     * permids = exps(:,2)
     * 
     * 
     * @return Each row contains information about one experiment:
     *         
     *         { experiment augmented code, experiment perm id, experiment space code, 
     *         experiment project code, experiment code }
     */
    public static Object[][] listExperiments()
    {
        checkLoggedIn();
        final Object[][] result = new Object[experiments.size()][5];
        for (int i = 0; i < experiments.size(); ++i)
        {
            final Object[] annotations =
                    new Object[]
                        { experiments.get(i).getAugmentedCode(), experiments.get(i).getPermId(),
                                experiments.get(i).getSpaceCode(),
                                experiments.get(i).getProjectCode(),
                                experiments.get(i).getExperimentCode() };
            System.arraycopy(annotations, 0, result[i], 0, annotations.length);
        }
        return result;
    }
    /**
     * Lists all plates.
     * 
* Matlab example: * *
     * % Get the plates
     * plates = OpenBISScreeningML.listPlates();
     * % How many plates do we have?
     * length(plates)
     * % Get all information about plate 2
     * plate2 = plates(2,:)
     * % Get the simple plate codes for all plates
     * codes = plates(:,4)
     * 
     * 
     * @return Each row contains information about one plate:
     *         
     *         { plate augmented code, plate perm id, plate space code, plate code, 
     *         experiment augmented code, experiment perm id, experiment space code, 
     *         experiment project code, experiment code }
     */
    public static Object[][] listPlates()
    {
        checkLoggedIn();
        return listPlates(plates);
    }
    /**
     * Lists the plates of experiment.
     * 
* Matlab example: * *
     * % Get the plates of experiment MYEXP in project PROJ of space SPACE
     * plates = OpenBISScreeningML.listPlates('/SPACE/PROJ/MYEXP');
     * % How many plates do we have?
     * length(plates)
     * % Get all information about plate 2
     * plate2 = plates(2,:)
     * % Get the augmented plate codes for all plates
     * acodes = plates(:,1)
     * 
     * 
     * @param experiment The augmented code of the experiment to list the plates for
     * @return Each row contains information about one plate:
     *         
     *          
     * Matlab example:
     * 
     *  
     *          
     * Matlab example:
     * 
     *  
     *          
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     *          
     * Matlab example:
     * 
     *  
     *             
     * Matlab example:
     * 
     *  
     *             
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     *         Each of  
     *          
     * Matlab example:
     * 
     *  
     *         Each of  
     *          
     * Matlab example:
     * 
     *  
     *         Each of  
     *          
     * Matlab example:
     * 
     *  
     *         Each of  
     *          
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     *  
     * Matlab example:
     * 
     * { plate augmented code, plate perm id, plate space code, plate code, 
     *         experiment augmented code, experiment perm id, experiment space code, 
     *         experiment project code, experiment code }
     */
    public static Object[][] listPlates(String experiment)
    {
        checkLoggedIn();
        final List
     * % Get all plates having data sets with analysis procedure 'PROC' in the experiment MYEXP in project PROJ of space SPACE
     * plates = OpenBISScreeningML.listPlates('/SPACE/PROJ/MYEXP', 'PROC');
     * % Get all information about plate 2
     * plate2 = plates(2,:)
     * % Get the augmented plate codes for all plates
     * acodes = plates(:,1)
     * 
     * 
     * @param experiment The augmented code of the experiment to list the plates for
     * @param analysisProcedure The analysis procedure
     * @return Each row contains information about one plate:
     *         { plate augmented code, plate perm id, plate space code, plate code, 
     *         experiment augmented code, experiment perm id, experiment space code, 
     *         experiment project code, experiment code }
     */
    public static Object[][] listPlates(String experiment, String analysisProcedure)
    {
        checkLoggedIn();
        ExperimentIdentifier experimentIdentifier = getExperimentIdentifierOrFail(experiment);
        List
     * % Get the analysis procedures for experiment MYEXP in project PROJ of space SPACE
     * analysisProcedures = OpenBISScreeningML.listAnalysisProcedures('/SPACE/PROJ/MYEXP');
     * % How many analysis procedures do we have?
     * length(analysisProcedures)
     * % Get all the analysis procedure codes 
     * acodes = analysisProcedures(:,1)
     * 
     * 
     * @param experiment The augmented code of the experiment to list analysis procedures for
     * @return Each row contains information about one analysis procedure:
     *         { analysis procedure code }
     */
    public static Object[][] listAnalysisProcedures(String experiment)
    {
        checkLoggedIn();
        ExperimentIdentifier experimentIdentifier = getExperimentIdentifierOrFail(experiment);
        List
     * % Get properties for well A03 of plate P005 in space SPACE
     * properties = OpenBISScreeningML.getWellProperties('/SPACE/P005', 1, 3)
     * % Get property type code of first property
     * properties(1,1)
     * % Get property value of first property
     * properties(1,2)
     * 
     * 
     * @param augmentedPlateCode The augmented plate code
     * @param row The row in the plate to get the well properties for
     * @param column The column in the plate to get the well properties for
     * @return A two dimensional array where the first column contains the property codes and the
     *         second column the corresponding property values.
     */
    public static Object[][] getWellProperties(String augmentedPlateCode, int row, int column)
    {
        checkLoggedIn();
        WellPosition wellPosition = new WellPosition(row, column);
        WellIdentifier wellIdentifier = getWell(augmentedPlateCode, wellPosition);
        Map
     * % Updates properties DESCRIPTION and NUMBER for well A03 of plate P005 in space SPACE
     * properties = {'DESCRIPTION' 'hello example'; 'NUMBER' 3.14}
     * OpenBISScreeningML.updateWellProperties('/SPACE/P005', 1, 3, properties)
     * 
     * 
     * @param augmentedPlateCode The augmented plate code
     * @param row The row in the plate to get the well properties for
     * @param column The column in the plate to get the well properties for
     * @param properties A two dimensional array where the first column contains the property codes
     *            and the second column the corresponding property values.
     */
    public static void updateWellProperties(String augmentedPlateCode, int row, int column,
            Object[][] properties)
    {
        checkLoggedIn();
        WellPosition wellPosition = new WellPosition(row, column);
        WellIdentifier wellIdentifier = getWell(augmentedPlateCode, wellPosition);
        openbis.updateWellProperties(wellIdentifier, createMap(properties));
    }
    private static WellIdentifier getWell(String augmentedPlateCode, WellPosition wellPosition)
    {
        Plate plate = getPlate(augmentedPlateCode);
        List
     * % Get the metadata of image datasets of plate P005 from space SPACE
     * imagesMetadata = OpenBISScreeningML.getImagesMetadata('/SPACE/P005');
     * % How many image datasets do we have? Usually there will be just one.
     * length(imagesMetadata)
     * % What is the number of tiles in the first image dataset?
     * imagesMetadata(1, 3)
     * 
     * 
     * @param augmentedPlateCode The augmented plate code.
     * @return { images width, images height, number of tiles in the well, 
     *                 number of tiles rows, number of tiles columns, number of plate rows, number of plate columns }
     *         .
     */
    public static Object[][] getImagesMetadata(String augmentedPlateCode)
    {
        checkLoggedIn();
        final Plate plateId = getPlate(augmentedPlateCode);
        final List
     * % Get the channels of experiment MYEXP in project PROJ of space SPACE
     * channels = OpenBISScreeningML.listChannels('/SPACE/PROJ/MYEXP');
     * % How many channels do we have?
     * length(channels)
     * % What is the name of channel 1?
     * channels(1)
     * 
     * 
     * @param experiment The augmented code of the experiment to list the channels for
     * @return Each row contains information about one channel. Currently the only information
     *         available is the channel name.
     */
    public static Object[][] listChannels(String experiment)
    {
        checkLoggedIn();
        final List
     * % Get the features of experiment MYEXP in project PROJ of space SPACE
     * features = OpenBISScreeningML.listFeatures('/SPACE/PROJ/MYEXP', []);
     * % Get the features of experiment MYEXP in project PROJ of space SPACE which are computed
     * % with analysis procedure AP-4711
     * features = OpenBISScreeningML.listFeatures('/SPACE/PROJ/MYEXP', 'AP-4711');
     * % How many features do we have?
     * length(features)
     * % What is the name of features 1?
     * features(1)
     * 
     * 
     * @param experiment The augmented code of the experiment to list the features for
     * @param analysisProcedureOrNull The analysis procedure used to filter the result. That is, the
     *            result is restricted to feature vector data sets with a value of property
     *            ANALYSIS_PROCEDURE as specified. If null (or
     *            [] in MatLab) no restriction applies.
     * @return Each row contains information about one feature. Currently the only information
     *         available is the feature name.
     */
    public static Object[][] listFeatures(String experiment, String analysisProcedureOrNull)
    {
        checkLoggedIn();
        final List
     * If the same dataset is loaded for the second time in one session it will be immediately
     * returned from the local cache.
     * 
     * % Load all data sets of plate P005 in space SPACE
     * dsinfo = OpenBISScreeningML.loadDataSets('/SPACE/P005', 'HCS_ANALYSIS_CELL_FEATURES_CC_MAT', '/mount/openbis-store')
     * % Get the data set codes
     * dsinfo(:,1)
     * % Get root path of first data set (assuming there is at least one)
     * dsginfo(1,2)
     * % Get the properties for the first data set
     * props = dsginfo(1,3)
     * % Get property key of first property
     * props(1,1)
     * % Get property value of first property
     * props(1,2)
     * % Get all parents of first data set (assuming there is at least one)
     * dsInfo(1,4)
     * 
     * 
     * @param augmentedPlateCode The augmented plate code.
     * @param dataSetTypeCodePattern only datasets of the type which matches the specified pattern
     *            will be returned. To fetch all datasets specify ".*".
     * @param overrideStoreRootPathOrNull A path, in the context of the local file system mounts, to
     *            the DSS' store root. If null, paths are returned in the context of the DSS' file
     *            system mounts.
     * @return Each row contains information about one data set:
     *         { data set code, data set root path, { {key1, value1}, {key2, value2} ...}, parents }
     */
    public static Object[][] loadDataSets(String augmentedPlateCode, String dataSetTypeCodePattern,
            String overrideStoreRootPathOrNull)
    {
        return loadDataSets(augmentedPlateCode, dataSetTypeCodePattern, new Object[0][],
                overrideStoreRootPathOrNull);
    }
    /**
     * Loads data sets for specified plate code. For each data set the path to the root of the data
     * set is returned. If it is possible the path points directly into the data set store. No data
     * is copied. Otherwise the data is retrieved from the data store server.
     * If the same dataset is loaded for the second time in one session it will be immediately
     * returned from the local cache.
     * 
     * % Load all data sets of plate P005 in space SPACE
     * properties = {'ANALYSIS_PROCEDURE' 'AX87'}
     * dsinfo = OpenBISScreeningML.loadDataSets('/SPACE/P005', 'HCS_ANALYSIS_CELL_FEATURES_CC_MAT', properties, '/mount/openbis-store')
     * % Get the data set codes
     * dsinfo(:,1)
     * % Get root path of first data set (assuming there is at least one)
     * dsinfo(1,2)
     * % Get the properties for the first data set
     * props = dsinfo(1,3)
     * % Get property key of first property
     * props(1,1)
     * % Get property value of first property
     * props(1,2)
     * % Get all parents of first data set (assuming there is at least one)
     * dsInfo(1,4)
     * 
     * 
     * @param augmentedPlateCode The augmented plate code.
     * @param dataSetTypeCodePattern only data sets of the type which matches the specified pattern
     *            will be returned. To fetch all data sets specify ".*".
     * @param properties Only data set with specified property values will be returned. This is a
     *            two dimensional array where the first column contains the property codes and the
     *            second column the corresponding property values.
     * @return Each row contains information about one data set:
     * @param overrideStoreRootPathOrNull A path, in the context of the local file system mounts, to
     *            the DSS' store root. If null, paths are returned in the context of the DSS' file
     *            system mounts.
     *            { data set code, data set root path, { {key1, value1}, {key2, value2} ...}, parents }
     */
    public static Object[][] loadDataSets(String augmentedPlateCode,
            final String dataSetTypeCodePattern, final Object[][] properties,
            String overrideStoreRootPathOrNull)
    {
        checkLoggedIn();
        Plate plateIdentifier = getPlate(augmentedPlateCode);
        List
     * If the same dataset is loaded for the second time in one session it will be immediately
     * returned from the local cache.
     * 
     * % Load all data sets of experiment E005 in space SPACE and project PROJECT
     * properties = {'ANALYSIS_PROCEDURE' 'AX87'}
     * dsinfo = OpenBISScreeningML.loadDataSetsForExperiment('/SPACE/PROJECT/E005', 'HCS_ANALYSIS_CELL_FEATURES_CC_MAT', properties, '/mount/openbis-store')
     * % Get the data set codes
     * dsinfo(:,1)
     * % Get root path of first data set (assuming there is at least one)
     * dsinfo(1,2)
     * % Get the properties for the first data set
     * props = dsinfo(1,3)
     * % Get property key of first property
     * props(1,1)
     * % Get property value of first property
     * props(1,2)
     * % Get all parents of first data set (assuming there is at least one)
     * dsInfo(1,4)
     * 
     * 
     * @param augmentedExperimentCode The augmented experiment code.
     * @param dataSetTypeCodePattern only data sets of the type which matches the specified pattern
     *            will be returned. To fetch all data sets specify ".*".
     * @param properties Only data set with specified property values will be returned. This is a
     *            two dimensional array where the first column contains the property codes and the
     *            second column the corresponding property values.
     * @return Each row contains information about one data set:
     * @param overrideStoreRootPathOrNull A path, in the context of the local file system mounts, to
     *            the DSS' store root. If null, paths are returned in the context of the DSS' file
     *            system mounts.
     *            { data set code, data set root path, { {key1, value1}, {key2, value2} ...}, parents }
     */
    public static Object[][] loadDataSetsForExperiment(String augmentedExperimentCode,
            final String dataSetTypeCodePattern, final Object[][] properties,
            String overrideStoreRootPathOrNull)
    {
        checkLoggedIn();
        ExperimentIdentifier experimentIdentifier =
                getExperimentIdentifierOrFail(augmentedExperimentCode);
        List
     * % List all data sets of experiment E005 in space SPACE and project PROJECT. The query is restricted to data sets
     * % of a type starting with HCS_IMAGE
     * files = OpenBISScreeningML.listDataSetFilesForExperiment('/SPACE/PROJECT/E005', 'HCS_IMAGE.*')
     * % Codes of all found data sets
     * files(:,1)
     * % Code of third data set (assuming at least three data sets found)
     * files(3,1)
     * % Files of third data set (assuming at least three data sets found)
     * files(3,2,:)
     * 
     * 
     * @param augmentedExperimentCode The augmented experiment code.
     * @param dataSetTypeCodePattern only data sets of the type which matches the specified pattern
     *            will be returned. To fetch all data sets specify ".*".
     * @return {data set code, file/folder paths}
     */
    public static Object[][][] listDataSetFilesForExperiment(String augmentedExperimentCode,
            String dataSetTypeCodePattern)
    {
        checkLoggedIn();
        ExperimentIdentifier experimentIdentifier =
                getExperimentIdentifierOrFail(augmentedExperimentCode);
        List
     * % List all data sets of plate P005 in space SPACE. The query is restricted to data sets
     * % of a type starting with HCS_IMAGE
     * files = OpenBISScreeningML.listDataSetsFiles('/SPACE/P005', 'HCS_IMAGE.*')
     * % Load from the first data set (assuming at least one data set found) the third file/folder 
     * % (assuming at least three files/folders)
     * file = OpenBISScreeningML.loadDataSetFile(files(1,1), files(1,2,3), [])
     * 
     * 
     * @param dataSetCode The code of the data set.
     * @param pathInDataSet Path inside the data set pointing to the file/folder which should be
     *            down loaded. Use '/' if all files are requested.
     * @param overrideStoreRootPathOrNull A path, in the context of the local file system mounts, to
     *            the DSS' store root. If null, paths are returned in the context of the DSS' file
     *            system mounts.
     * @return path to the down loaded file/folder.
     */
    public static Object loadDataSetFile(String dataSetCode, String pathInDataSet,
            String overrideStoreRootPathOrNull)
    {
        checkLoggedIn();
        IDataSetDss dataSet = openbis.getDataSet(dataSetCode);
        return dataSet.getLinkOrCopyOfContent(overrideStoreRootPathOrNull, temporarySessionDir,
                pathInDataSet).toString();
    }
    /**
     * Lists all files of all data sets for specifies plate and data set type code matching
     * specified regular expression pattern.
     * 
     * % List all data sets of plate P005 in space SPACE. The query is restricted to data sets
     * % of a type starting with HCS_IMAGE
     * files = OpenBISScreeningML.listDataSetsFiles('/SPACE/P005', 'HCS_IMAGE.*')
     * % Codes of all found data sets
     * files(:,1)
     * % Code of third data set (assuming at least three data sets found)
     * files(3,1)
     * % Files of third data set (assuming at least three data sets found)
     * files(3,2,:)
     * 
     * 
     * @param augmentedPlateCode The augmented plate code.
     * @param dataSetTypeCodePattern only data sets of the type which matches the specified pattern
     *            will be returned. To fetch all data sets specify ".*".
     * @return {data set code, file/folder paths}
     */
    public static Object[][][] listDataSetsFiles(String augmentedPlateCode,
            String dataSetTypeCodePattern)
    {
        checkLoggedIn();
        Plate plateIdentifier = getPlate(augmentedPlateCode);
        List
     * % List meta data for data sets 20101006020318852-10 and 20110919083636428-236
     * metadata = OpenBISScreeningML.getDataSetMetaData({ '20101006020318852-10' '20110919083636428-236'})
     * % Codes of all data sets
     * metadata(:,1,1)
     * % Types of all data sets
     * metadata(:,1,2)
     * % Properties of first data set
     * metadata(1, 2)
     * % Parents of second data set
     * metadata(2, 3, :)
     * % Children of first data set
     * metadata(1, 4, :)
     * 
     * 
     * @param dataSetCodes Codes of data sets from whom meta data are queried.
     * @return For each data set:
     *         {{data set code, data set type}, { {key1, value1}, {key2, value2} ...}, parents, children }
     */
    public static Object[][][] getDataSetMetaData(String[] dataSetCodes)
    {
        checkLoggedIn();
        List
     * % Upload data set /path/to/my-data-set with properties DESCRIPTION and NUMBER for 
     * % plate P005 in space SPACE
     * properties = {'DESCRIPTION' 'hello example'; 'NUMBER' 3.14}
     * datasetcode = OpenBISScreeningML.uploadDataSet('/SPACE/P005', '/path/to/my-data-set', 'HCS_IMAGE', properties)
     * 
     * 
     * @param augmentedPlateCode The augmented plate code.
     * @param dataSetFilePath Path to the data set file/folder to be uploaded.
     * @param dataSetType Data set type.
     * @param dataSetProperties A two dimensional array where the first column contains the property
     *            codes and the second column the corresponding property values.
     */
    public static Object uploadDataSet(String augmentedPlateCode, String dataSetFilePath,
            String dataSetType, Object[][] dataSetProperties)
    {
        checkLoggedIn();
        Plate plateIdentifier = getPlate(augmentedPlateCode);
        File dataSetFile = new File(dataSetFilePath);
        if (dataSetFile.exists() == false)
        {
            throw new RuntimeException("Unknown data set file path '" + dataSetFilePath + "'.");
        }
        try
        {
            Map
     * % Upload data set /path/to/my-data-set with properties DESCRIPTION and NUMBER for 
     * % plate P005 in space SPACE
     * % with data set  201007091122-928 as the parent
     * properties = {'DESCRIPTION' 'hello example'; 'NUMBER' 3.14}
     * parents = {'201007091122-928' }
     * datasetcode = OpenBISScreeningML.uploadDataSetForPlateAndParents('/SPACE/P005', parents, '/path/to/my-data-set', 'HCS_IMAGE', properties)
     * 
     * 
     * @param augmentedPlateCode The augmented plate code.
     * @param parentDataSetCodeObjects The codes of the parents of this data set
     * @param dataSetFilePath Path to the data set file/folder to be uploaded.
     * @param dataSetType Data set type.
     * @param dataSetProperties A two dimensional array where the first column contains the property
     *            codes and the second column the corresponding property values.
     */
    public static Object uploadDataSetForPlateAndParents(String augmentedPlateCode,
            Object[] parentDataSetCodeObjects, String dataSetFilePath, String dataSetType,
            Object[][] dataSetProperties)
    {
        checkLoggedIn();
        Plate plateIdentifier = getPlate(augmentedPlateCode);
        List
     * % Upload data set /path/to/my-data-set (with property DESCRIPTION)
     * % to experiment E103 in project PROJECT and space SPACE,
     * % with data set  201007091122-928 as the parent
     * properties = {'DESCRIPTION' 'hello example' }
     * parents = {'201007091122-928' }
     * datasetcode = OpenBISScreeningML.uploadDataSetForExperimentAndParents('/SPACE/PROJECT/E103', parents, '/path/to/my-data-set', 'HCS_IMAGE', properties)
     * 
     * 
     * @param augmentedExperimentCode The augmented experiment code.
     * @param parentDataSetCodeObjects The codes of the parents of this data set
     * @param dataSetFilePath Path to the data set file/folder to be uploaded.
     * @param dataSetType Data set type.
     * @param dataSetProperties A two dimensional array where the first column contains the property
     *            codes and the second column the corresponding property values.
     */
    public static Object uploadDataSetForExperimentAndParents(String augmentedExperimentCode,
            Object[] parentDataSetCodeObjects, String dataSetFilePath, String dataSetType,
            Object[][] dataSetProperties)
    {
        checkLoggedIn();
        ExperimentIdentifier experimentIdentifier =
                getExperimentIdentifierOrFail(augmentedExperimentCode);
        List
     * % Load the images for all channels of well B10 of plate P005 in space SPACE
     * imginfo = OpenBISScreeningML.loadImages('/SPACE/P005', 2, 10)
     * % Get the plate-well descriptions of all locations
     * imginfo(2,:,3)
     * % Show the third image (assuming there are at least three images)
     * imtool(imginfo(1,3))
     * 
     * 
     * @param plate The augmented plate code
     * @param row The row in the plate to get the images for
     * @param col The column in the plate to get the images for
     * @return { names of TIFF files, image annotation }
     *         names of TIFF files and image annotation is a
     *         vector of length of the number of images.
     *         image annotation contains
     *         { channel name, tile number, plate well description, 
     *         plate augmented code, plate perm id, plate space code, plate code, row, column, 
     *         experiment augmented code, experiment perm id, experiment space code, 
     *         experiment project code, experiment code, data set code }
     */
    public static Object[][][] loadImages(String plate, int row, int col)
    {
        return loadImages(plate, row, col, (String[]) null);
    }
    /**
     * Loads the TIFF images for the given well location, tile number, and all channels and stores
     * them in temporary files. The temporary files will be removed automatically when the Java
     * Virtual Machine exits.
     * 
     * % Load the images for all channels of well B10 and tile 3 of plate P005 in space SPACE
     * imginfo = OpenBISScreeningML.loadImages('/SPACE/P005', 2, 10, 3)
     * % Get the plate-well descriptions of all locations
     * imginfo(2,:,3)
     * % Show the third image (assuming there are at least three images)
     * imtool(imginfo(1,3))
     * 
     * 
     * @param plate The augmented plate code
     * @param row The row in the plate to get the images for
     * @param col The column in the plate to get the images for
     * @param tile The tile number. Starts with 0.
     * @return { names of TIFF files, image annotation }
     *         names of TIFF files and image annotation is a
     *         vector of length of the number of images.
     *         image annotation contains
     *         { channel name, tile number, plate well description, 
     *         plate augmented code, plate perm id, plate space code, plate code, row, column, 
     *         experiment augmented code, experiment perm id, experiment space code, 
     *         experiment project code, experiment code, data set code }
     */
    public static Object[][][] loadImages(String plate, int row, int col, int tile)
    {
        return loadImages(plate, row, col, tile, (String[]) null);
    }
    /**
     * Loads the TIFF images for the given well location, list of channels, and all tiles and stores
     * them in temporary files. The temporary files will be removed automatically when the Java
     * Virtual Machine exits.
     * 
     * % Load the images for channel DAPI of well H10 of plate P005 in space SPACE
     * imginfo=OpenBISScreeningML.loadImages('/SPACE/P005', 8, 10, 'DAPI')
     * % Get the channel names and tile numbers of all locations
     * imginfo(2,:,1:2)
     * % Show the second image (assuming there are at least two images)
     * imtool(imginfo(1,2))
     * 
     * 
     * @param plate The augmented plate code
     * @param row The row in the plate to get the images for
     * @param col The column in the plate to get the images for
     * @param channels The names of the channels to get the images for
     * @return { names of TIFF files, image annotation }
     *         names of TIFF files and image annotation is a
     *         vector of length of the number of images.
     *         image annotation contains
     *         { channel name, tile number, plate well description, 
     *         plate augmented code, plate perm id, plate space code, plate code, row, column, 
     *         experiment augmented code, experiment perm id, experiment space code, 
     *         experiment project code, experiment code, data set code }
     */
    public static Object[][][] loadImages(String plate, int row, int col, String[] channels)
    {
        return loadRawImages(plate, row, col, channels, createAllTilesIterator());
    }
    /**
     * Has the same effect as {@link #loadImages(String, int, int, String[])}, but instead of
     * loading raw images loads their segmentation results if available.
     * 
     * @param objectNamesOrNull The names of the segmentation objects to get the images for. If
     *            null (or [] in MatLab) no restriction applies.
     * @param analysisProcedureOrNull The analysis procedure used to filter the result. That is, the
     *            result is restricted to feature vector data sets with a value of property
     *            ANALYSIS_PROCEDURE as specified. If null (or
     *            [] in MatLab) no restriction applies.
     */
    public static Object[][][] loadSegmentationImages(String plate, int row, int col,
            String[] objectNamesOrNull, String analysisProcedureOrNull)
    {
        return loadSegmentationImages(plate, row, col, objectNamesOrNull, createAllTilesIterator(),
                analysisProcedureOrNull);
    }
    private static ITileNumberIterable createAllTilesIterator()
    {
        return new ITileNumberIterable()
            {
                private int maximumNumberOfTiles;
                public void setMaximumNumberOfTiles(int numberOfTiles)
                {
                    this.maximumNumberOfTiles = numberOfTiles;
                }
                public int getMaximumNumberOfTiles()
                {
                    return maximumNumberOfTiles;
                }
                public Iterator
     * % Load the images for channel DAPI of well H10 and tile 3 of plate P005 in space SPACE
     * imginfo=OpenBISScreeningML.loadImages('/SPACE/P005', 8, 10, 3, 'DAPI')
     * % Get the channel names of all locations
     * imginfo(2,:,1)
     * % Show the second image (assuming there are at least two images)
     * imtool(imginfo(1,2))
     * 
     * 
     * @param plate The augmented plate code
     * @param row The row in the plate to get the images for
     * @param col The column in the plate to get the images for
     * @param tile The tile number. Starts with 0.
     * @param channels The names of the channels to get the images for
     * @return { names of TIFF files, image annotation }
     *         names of TIFF files and image annotation is a
     *         vector of length of the number of images.
     *         image annotation contains
     *         { channel name, tile number, plate well description, 
     *         plate augmented code, plate perm id, plate space code, plate code, row, column, 
     *         experiment augmented code, experiment perm id, experiment space code, 
     *         experiment project code, experiment code, data set code }
     */
    public static Object[][][] loadImages(String plate, int row, int col, final int tile,
            String[] channels)
    {
        return loadRawImages(plate, row, col, channels, createSingleTileIterator(tile));
    }
    /**
     * Has the same effect as {@link #loadImages(String, int, int, int, String[])}, but instead of
     * loading raw images loads their segmentation results if available.
     * 
     * @param objectNamesOrNull The names of the segmentation objects to get the images for. If
     *            null (or [] in MatLab) no restriction applies.
     * @param analysisProcedureOrNull The analysis procedure used to filter the result. That is, the
     *            result is restricted to feature vector data sets with a value of property
     *            ANALYSIS_PROCEDURE as specified. If null (or
     *            [] in MatLab) no restriction applies.
     */
    public static Object[][][] loadSegmentationImages(String plate, int row, int col,
            final int tile, String[] objectNamesOrNull, String analysisProcedureOrNull)
    {
        return loadSegmentationImages(plate, row, col, objectNamesOrNull,
                createSingleTileIterator(tile), analysisProcedureOrNull);
    }
    private static ITileNumberIterable createSingleTileIterator(final int tile)
    {
        return new ITileNumberIterable()
            {
                public void setMaximumNumberOfTiles(int numberOfTiles)
                {
                    if (tile >= numberOfTiles)
                    {
                        throw new IllegalArgumentException("Tile number " + tile
                                + " is not less than number of tiles " + numberOfTiles + ".");
                    }
                }
                public int getMaximumNumberOfTiles()
                {
                    return 1;
                }
                public Iterator
     * % Get the segmentation objects of plate P005 in space SPACE.
     * segmentationObjects = OpenBISScreeningML.listSegmentationObjects('/SPACE/P005', []);
     * % Get the segmentation objects of plate P005 in space SPACE for data sets calculated 
     * % with analysis procedure AP-42.
     * segmentationObjects = OpenBISScreeningML.listSegmentationObjects('/SPACE/P005', 'AP-42');
     * % How many segmentation objects do we have?
     * length(segmentationObjects)
     * % What is the name of segmentation objects 1?
     * segmentationObjects(1)
     * 
     * 
     * @param plate augmented code of the plate
     * @param analysisProcedureOrNull The analysis procedure used to filter the result. That is, the
     *            result is restricted to feature vector data sets with a value of property
     *            ANALYSIS_PROCEDURE as specified. If null (or
     *            [] in MatLab) no restriction applies.
     * @return Each row contains information about one segmentation object. Currently the only
     *         information available is the segmentation object name.
     */
    public static Object[][] listSegmentationObjects(String plate, String analysisProcedureOrNull)
    {
        checkLoggedIn();
        Plate plateId = getPlate(plate);
        final List[0], location annotations
     * in [1] and feature annotation in [2].
     * 
     * % Get feature matrix for experiment /SPACE/PROJ/MYEXP for locations connected to GENENAME
     * fmatrix = OpenBISScreeningML.getFeatureMatrix('/SPACE/PROJ/MYEXP', 'GENENAME', [], []);
     * % Get feature matrix for features F1, F2 and F3 for 
     * % experiment /SPACE/PROJ/MYEXP for locations connected to GENENAME
     * fmatrix = OpenBISScreeningML.getFeatureMatrix('/SPACE/PROJ/MYEXP', 'GENENAME', [], {'F1' 'F2' 'F3'));
     * % Get feature matrix for features F1 and F2 for experiment /SPACE/PROJ/MYEXP for locations 
     * % connected to GENENAME calculated with analysis procedure AP-42.
     * fmatrix = OpenBISScreeningML.getFeatureMatrix('/SPACE/PROJ/MYEXP', 'GENENAME', 'AP-42', {'F1' 'F2'));
     * % Get the feature vector for the second location (assuming that there are at least two locations) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(1,:,2,3)
     * % Get the values of the fourth feature for all locations (assuming that there are at least 4 features) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(1,4,:,3)
     * % Get code of the fourth feature (assuming that there are at least 4 features)
     * fmatrix(3,4)
     * % Get the plate-well descriptions for the second location (assuming that there are at least two locations) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(2,2,3,:)
     * 
     * 
     * @param experiment The augmented experiment code
     * @param gene The gene code (stored as material code in openBIS, usually it is gene id)
     * @param analysisProcedureOrNull The code of the analysis procedure used to calculate requested
     *            features. That is, the result is restricted to feature vector data sets with a
     *            value of property ANALYSIS_PROCEDURE as specified. If
     *            null (or [] in MatLab) no restriction applies.
     * @param featuresOrNull The codes of the features to contain the feature matrix. Unknown
     *            feature codes will be ignored. If null (or [] in MatLab)
     *            all features are returned.
     * @return a four dimensional matrix. The first dimension denotes the type in the following
     *         order: {feature matrix, annotations per location, feature codes}. The
     *         other dimensions depend on the value of the first dimension:
     *         
     *         
     */
    public static Object[][][][] getFeatureMatrix(String experiment, String gene,
            String analysisProcedureOrNull, String[] featuresOrNull)
    {
        checkLoggedIn();
        final ExperimentIdentifier experimentId = experimentCodeToExperimentMap.get(experiment);
        if (experimentId == null)
        {
            throw new RuntimeException("No experiment with that code found.");
        }
        final ListNaN will be
     *         returned. {plate
     *         well description, plate augmented code, plate perm id, plate space code, plate code,
     *         row, column, experiment augmented code, experiment perm id, experiment space code,
     *         experiment project code, experiment code, data set code, data set type} [0], location annotations in [1] and feature
     * annotation in [2].
     * 
     * % Get feature matrix for GENENAME
     * fmatrix = OpenBISScreeningML.getFeatureMatrix('GENENAME', [], []);
     * % Get feature matrix for features FEATURE1, FEATURE2 and FEATURE3 for GENENAME
     * fmatrix = OpenBISScreeningML.getFeatureMatrix('GENENAME', [], {'FEATURE1' 'FEATURE2' 'FEATURE3'});
     * % Get feature matrix for features FEATURE1 and FEATURE2 for GENENAME 
     * % computed with analysis procedure AP-42
     * fmatrix = OpenBISScreeningML.getFeatureMatrix('GENENAME', 'AP-42', {'FEATURE1' 'FEATURE2'});
     * % Get the feature vector for the second location (assuming that there are at least two locations) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(1,:,2,3)
     * % Get the values of the fourth feature for all locations (assuming that there are at least 4 features) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(1,4,:,3)
     * % Get code of the fourth feature (assuming that there are at least 4 features)
     * fmatrix(3,4)
     * % Get the plate-well descriptions for the second location (assuming that there are at least two locations) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(2,2,3,:)
     * 
     * 
     * @param gene The gene code (stored as material code in openBIS, usually it is gene id)
     * @param analysisProcedureOrNull The code of the analysis procedure used to calculate requested
     *            features. That is, the result is restricted to feature vector data sets with a
     *            value of property ANALYSIS_PROCEDURE as specified. If
     *            null (or [] in MatLab) no restriction applies.
     * @param featuresOrNull The codes of the features to contain the feature matrix. Unknown
     *            feature codes will be ignored. If null (or [] in MatLab)
     *            all features are returned.
     * @return a four dimensional matrix. The first dimension denotes the type in the following
     *         order: {feature matrix, annotations per location, feature codes}. The
     *         other dimensions depend on the value of the first dimension:
     *         
     *         
     */
    public static Object[][][][] getFeatureMatrix(String gene, String analysisProcedureOrNull,
            String[] featuresOrNull)
    {
        checkLoggedIn();
        final ListNaN will be
     *         returned. {plate
     *         well description, plate augmented code, plate perm id, plate space code, plate code,
     *         row, column, experiment augmented code, experiment perm id, experiment space code,
     *         experiment project code, experiment code, data set code, data set type} [0], location
     * annotations in [1] and feature annotation in [2].
     * 
     * % Get feature matrix for PLATECODE
     * fmatrix = OpenBISScreeningML.getFeatureMatrixForPlate('PLATECODE', [], []);
     * % Get feature matrix for features FEATURE1, FEATURE2 and FEATURE3 for PLATECODE.
     * fmatrix = OpenBISScreeningML.getFeatureMatrixForPlate('PLATECODE', [], {'FEATURE1' 'FEATURE2' 'FEATURE3'});
     * % Get feature matrix for features FEATURE1 and FEATURE2 for PLATECODE calculated by analysis procedure AP-42.
     * fmatrix = OpenBISScreeningML.getFeatureMatrixForPlate('PLATECODE', 'AP-42', {'FEATURE1' 'FEATURE2'});
     * % Get the feature vector for the second location (assuming that there are at least two locations) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(1,:,2,3)
     * % Get the values of the fourth feature for all locations (assuming that there are at least 4 features) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(1,4,:,3)
     * % Get code of the fourth feature (assuming that there are at least 4 features)
     * fmatrix(3,4)
     * % Get the plate-well descriptions for the second location (assuming that there are at least two locations) 
     * % of third data set (assuming that there are at least three data sets)
     * fmatrix(2,2,3,:)
     * 
     * 
     * @param plate augmented code of the plate for which features should be loaded
     * @param analysisProcedureOrNull The code of the analysis procedure used to calculate requested
     *            features. That is, the result is restricted to feature vector data sets with a
     *            value of property ANALYSIS_PROCEDURE as specified. If
     *            null (or [] in MatLab) no restriction applies.
     * @param featuresOrNull The codes of the features to contain the feature matrix. Unknown
     *            feature codes will be ignored. If null (or [] in MatLab)
     *            all features are returned.
     * @return a four dimensional matrix. The first dimension denotes the type in the following
     *         order: {feature matrix, annotations per location, feature codes}. The
     *         other dimensions depend on the value of the first dimension:
     *         
     *         
     */
    public static Object[][][][] getFeatureMatrixForPlate(String plate,
            String analysisProcedureOrNull, String[] featuresOrNull)
    {
        checkLoggedIn();
        final ListNaN will be
     *         returned. {plate
     *         well description, plate augmented code, plate perm id, plate space code, plate code,
     *         row, column, experiment augmented code, experiment perm id, experiment space code,
     *         experiment project code, experiment code, data set code, data set type}