From 193506f5ebfa546369b4cf214296ce9c3859e56a Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Tue, 10 Feb 2009 08:07:42 +0000
Subject: [PATCH] LMS-740 IETLLIMSService implemented but not yet tested in no
 respect

SVN: 9754
---
 .../server/CommonBusinessObjectFactory.java   |   7 +
 .../openbis/generic/server/CommonServer.java  |   5 +
 .../openbis/generic/server/ETLService.java    | 342 ++++++++++++++++++
 .../business/bo/AbstractBusinessObject.java   |  18 +
 .../server/business/bo/ExternalDataBO.java    | 226 ++++++++++++
 .../bo/ICommonBusinessObjectFactory.java      |   6 +
 .../server/business/bo/IExternalDataBO.java   |  45 +++
 .../server/dataaccess/IDAOFactory.java        |   9 +
 .../server/dataaccess/IDataSetTypeDAO.java    |  33 ++
 .../server/dataaccess/IExternalDataDAO.java   |  20 +
 .../server/dataaccess/IFileFormatTypeDAO.java |  33 ++
 .../server/dataaccess/ILocatorTypeDAO.java    |  33 ++
 .../server/dataaccess/db/DAOFactory.java      |  33 +-
 .../server/dataaccess/db/DataSetTypeDAO.java  |  48 +++
 .../server/dataaccess/db/ExternalDataDAO.java |  63 ++++
 .../dataaccess/db/FileFormatTypeDAO.java      |  48 +++
 .../server/dataaccess/db/LocatorTypeDAO.java  |  48 +++
 .../generic/shared/IETLLIMSService.java       |   6 +-
 18 files changed, 1017 insertions(+), 6 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataBO.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExternalDataBO.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataSetTypeDAO.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IFileFormatTypeDAO.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ILocatorTypeDAO.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DataSetTypeDAO.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/FileFormatTypeDAO.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/LocatorTypeDAO.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonBusinessObjectFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonBusinessObjectFactory.java
index ab7c6570dc9..af372714f8a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonBusinessObjectFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonBusinessObjectFactory.java
@@ -20,12 +20,14 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.AbstractBusinessObjec
 import ch.systemsx.cisd.openbis.generic.server.business.bo.EntityTypePropertyTypeBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ExperimentBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ExperimentTable;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.ExternalDataBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ExternalDataTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.GroupBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IEntityTypePropertyTypeBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IExperimentBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IExperimentTable;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IExternalDataBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IExternalDataTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IGroupBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IProcedureBO;
@@ -85,6 +87,11 @@ public final class CommonBusinessObjectFactory extends AbstractBusinessObjectFac
         return new SampleBO(getDaoFactory(), session);
     }
 
+    public IExternalDataBO createExternalDataBO(Session session)
+    {
+        return new ExternalDataBO(getDaoFactory(), session);
+    }
+
     public final IExternalDataTable createExternalDataTable(final Session session)
     {
         return new ExternalDataTable(getDaoFactory(), session);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index 61e476f7b0e..0b25d6acd18 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -93,6 +93,11 @@ public final class CommonServer extends AbstractServer<ICommonServer> implements
         this.authenticationService = authenticationService;
         this.businessObjectFactory = businessObjectFactory;
     }
+    
+    ICommonBusinessObjectFactory getBusinessObjectFactory()
+    {
+        return businessObjectFactory;
+    }
 
     //
     // AbstractServer
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
new file mode 100644
index 00000000000..498e00b95fa
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2009 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.openbis.generic.server;
+
+import static ch.systemsx.cisd.openbis.generic.shared.dto.types.ProcedureTypeCode.DATA_ACQUISITION;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.utilities.BeanUtils;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IExperimentBO;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IExternalDataBO;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IProcedureBO;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.ISampleBO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExperimentAttachmentDAO;
+import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService;
+import ch.systemsx.cisd.openbis.generic.shared.IWebService;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProcedurePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProcessingInstructionDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePropertyPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SourceType;
+import ch.systemsx.cisd.openbis.generic.shared.dto.exception.UndefinedGroupException;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ETLService implements IETLLIMSService
+{
+    private static final String PROCESSING_PATH = "$processing-path-for-";
+    private static final String PROCESSING_PATH_TEMPLATE = PROCESSING_PATH + "%s";
+    private static final String PROCESSING_PARAMETERS_TEMPLATE = "$processing-parameters-for-%s";
+    private static final String PROCESSING_DESCRIPTION_TEMPLATE = "$processing-description-for-%s";
+    private static final String ENCODING = "utf-8";
+    
+    private final CommonServer commonServer;
+    private final IDAOFactory daoFactory;
+    private final ICommonBusinessObjectFactory boFactory;
+
+    public ETLService(CommonServer commonServer)
+    {
+        this.commonServer = commonServer;
+        this.daoFactory = commonServer.getDAOFactory();
+        boFactory = commonServer.getBusinessObjectFactory();
+    }
+    
+    public int getVersion()
+    {
+        return IWebService.VERSION;
+    }
+    
+    public DatabaseInstancePE getHomeDatabaseInstance()
+    {
+        return daoFactory.getHomeDatabaseInstance();
+    }
+    
+    public String authenticate(String user, String password) throws UserFailureException
+    {
+        Session session = commonServer.tryToAuthenticate(user, password);
+        return session == null ? null : session.getSessionToken();
+    }
+    
+    public void closeSession(String sessionToken) throws UserFailureException
+    {
+        commonServer.logout(sessionToken);
+    }
+    
+    public String createDataSetCode(String sessionToken) throws UserFailureException
+    {
+        return daoFactory.getExternalDataDAO().createDataSetCode();
+    }
+
+    public ExperimentPE tryToGetBaseExperiment(String sessionToken, SampleIdentifier sampleIdentifier)
+            throws UserFailureException
+    {
+        assert sessionToken != null : "Unspecified session token.";
+        assert sampleIdentifier != null : "Unspecified sample identifier.";
+
+        final Session session = commonServer.getSessionManager().getSession(sessionToken);
+        ExperimentPE experiment = tryToLoadExperimentBySampleIdentifier(session, sampleIdentifier);
+        enrichWithProcessingInstructions(experiment);
+        return experiment;
+        
+    }
+
+    private ExperimentPE tryToLoadExperimentBySampleIdentifier(final Session session,
+            SampleIdentifier sampleIdentifier)
+    {
+        final ISampleBO sampleBO = boFactory.createSampleBO(session);
+        sampleBO.loadBySampleIdentifier(sampleIdentifier);
+        sampleBO.enrichWithValidProcedure();
+        final SamplePE sample = sampleBO.getSample();
+        if (sample == null)
+        {
+            return null;
+        }
+        ProcedurePE procedure = sample.getValidProcedure();
+        return procedure == null ? null : procedure.getExperiment();
+    }
+    
+    private void enrichWithProcessingInstructions(ExperimentPE experiment)
+    {
+        if (experiment == null)
+        {
+            return;
+        }
+        final List<ProcessingInstructionDTO> instructions =
+                new ArrayList<ProcessingInstructionDTO>();
+        final IExperimentAttachmentDAO experimentAttachmentDAO =
+                daoFactory.getExperimentAttachmentDAO();
+        final List<AttachmentPE> attachments =
+                experimentAttachmentDAO.listExperimentAttachments(experiment);
+        for (final AttachmentPE attachment : attachments)
+        {
+            final String fileName = attachment.getFileName();
+            if (fileName.startsWith(PROCESSING_PATH))
+            {
+                final ProcessingInstructionDTO processingInstruction =
+                        new ProcessingInstructionDTO();
+                BeanUtils.fillBean(ProcessingInstructionDTO.class, processingInstruction,
+                        attachment);
+                processingInstruction.setProcedureTypeCode(fileName.substring(PROCESSING_PATH
+                        .length()));
+                instructions.add(processingInstruction);
+            }
+        }
+        for (final ProcessingInstructionDTO instruction : instructions)
+        {
+            final String procedureType = instruction.getProcedureTypeCode();
+            instruction.setPath(loadText(experiment, PROCESSING_PATH_TEMPLATE, procedureType));
+            instruction.setDescription(loadText(experiment, PROCESSING_DESCRIPTION_TEMPLATE,
+                    procedureType));
+            instruction.setParameters(load(experiment, PROCESSING_PARAMETERS_TEMPLATE,
+                    procedureType));
+        }
+        experiment.setProcessingInstructions(instructions.toArray(new ProcessingInstructionDTO[0]));
+    }
+    
+    private final String createKey(final String template, final String procedureTypeCode)
+    {
+        return String.format(template, procedureTypeCode);
+    }
+
+    private final String createText(final byte[] textBytes)
+    {
+        try
+        {
+            return textBytes == null ? null : new String(textBytes, ENCODING);
+        } catch (UnsupportedEncodingException ex)
+        {
+            throw new EnvironmentFailureException("Unsupported character encoding: " + ENCODING);
+        }
+    }
+
+    private final String loadText(final ExperimentPE experiment, final String template,
+            final String procedureTypeCode)
+    {
+        final byte[] value = load(experiment, template, procedureTypeCode);
+        return createText(value);
+    }
+
+    private final byte[] load(final ExperimentPE experiment, final String template,
+            final String procedureTypeCode)
+    {
+        final String key = createKey(template, procedureTypeCode);
+        final IExperimentAttachmentDAO experimentAttachmentDAO = daoFactory.getExperimentAttachmentDAO();
+        final AttachmentPE attachment =
+                experimentAttachmentDAO.tryFindExpAttachmentByExpAndFileName(experiment, key);
+        if (attachment != null)
+        {
+            return attachment.getAttachmentContent().getValue();
+        }
+        return null;
+    }
+
+    public SamplePropertyPE[] tryToGetPropertiesOfTopSampleRegisteredFor(String sessionToken,
+            SampleIdentifier sampleIdentifier) throws UserFailureException
+    {
+        assert sessionToken != null : "Unspecified session token.";
+        assert sampleIdentifier != null : "Unspecified sample identifier.";
+
+        final Session session = commonServer.getSessionManager().getSession(sessionToken);
+        final ISampleBO sampleBO = boFactory.createSampleBO(session);
+        sampleBO.loadBySampleIdentifier(sampleIdentifier);
+        SamplePE sample = sampleBO.getSample();
+        throwExceptionIfSampleEqualsNull(sample, sampleIdentifier);
+        SamplePE top = sample.getTop();
+        if (top == sample)
+        {
+            throw new UserFailureException("Missing top of sample " + sampleIdentifier);
+        }
+        HibernateUtils.initialize(top.getProperties());
+        return top.getProperties().toArray(new SamplePropertyPE[0]);
+    }
+
+    private void throwExceptionIfSampleEqualsNull(SamplePE sample, SampleIdentifier sampleIdentifier)
+    {
+        if (sample == null)
+        {
+            throw new UserFailureException("Couldn't find sample " + sampleIdentifier);
+        }
+    }
+
+    public DataStorePE getDataStore(String sessionToken, ExperimentIdentifier experimentIdentifier,
+            String dataSetTypeCode) throws UserFailureException
+    {
+        assert sessionToken != null : "Unspecified session token.";
+        assert experimentIdentifier != null : "Unspecified experiment identifier.";
+        
+        final Session session = commonServer.getSessionManager().getSession(sessionToken);
+        makeSureGroupCodeIsFilled(session, experimentIdentifier);
+        final IExperimentBO experimentBO = boFactory.createExperimentBO(session);
+        experimentBO.loadByExperimentIdentifier(experimentIdentifier);
+        ExperimentPE experiment = experimentBO.getExperiment();
+        DataStorePE result;
+        DataStorePE experimentDataStore = experiment.getDataStore();
+        if (experimentDataStore != null)
+        {
+            result = experimentDataStore;
+        } else
+        {
+            DataStorePE projectDataStore = experiment.getProject().getDataStore();
+            if (projectDataStore != null)
+            {
+                result = projectDataStore;
+            } else
+            {
+                DataStorePE groupDataStore = experiment.getProject().getGroup().getDataStore();
+                if (groupDataStore != null)
+                {
+                    result = groupDataStore;
+                } else
+                {
+                    DataStorePE databaseDataStore =
+                            experiment.getProject().getGroup().getDatabaseInstance().getDataStore();
+                    result = databaseDataStore;
+                }
+            }
+        }
+        return result;
+    }
+
+    private void makeSureGroupCodeIsFilled(final Session session,
+            ExperimentIdentifier experimentIdentifier)
+    {
+        if (experimentIdentifier.getGroupCode() == null)
+        {
+            final String homeGroupCode = session.tryGetHomeGroupCode();
+            if (StringUtils.isBlank(homeGroupCode))
+            {
+                throw new UndefinedGroupException();
+            } else
+            {
+                experimentIdentifier.setGroupCode(homeGroupCode);
+            }
+        }
+    }
+
+    public void registerDataSet(String sessionToken, SampleIdentifier sampleIdentifier,
+            String procedureTypeCode, ExternalData externalData) throws UserFailureException
+    {
+        assert sessionToken != null : "Unspecified session token.";
+        assert sampleIdentifier != null : "Unspecified sample identifier.";
+        
+        final Session session = commonServer.getSessionManager().getSession(sessionToken);
+        ExperimentPE experiment = tryToLoadExperimentBySampleIdentifier(session, sampleIdentifier);
+        if (experiment == null)
+        {
+            throw new UserFailureException("No experiment found for sample " + sampleIdentifier);
+        }
+        if (experiment.getInvalidation() != null)
+        {
+            throw new UserFailureException("Data set can not be registered because experiment '"
+                    + experiment.getCode() + "' is invalid.");
+        }
+        List<ProcedurePE> procedures = experiment.getProcedures();
+        ProcedurePE procedure = tryToFindProcedureByType(procedures, procedureTypeCode);
+        if (procedure == null)
+        {
+            final IProcedureBO procedureBO = boFactory.createProcedureBO(session);
+            procedureBO.define(experiment, procedureTypeCode);
+            procedureBO.save();
+            procedure = procedureBO.getProcedure();
+        }
+        final ISampleBO sampleBO = boFactory.createSampleBO(session);
+        sampleBO.loadBySampleIdentifier(sampleIdentifier);
+        sampleBO.enrichWithValidProcedure();
+        final SamplePE cellPlate = sampleBO.getSample();
+        assert cellPlate.getValidProcedure() != null : "Any cell plate should have been connected to one procedure.";
+        final IExternalDataBO externalDataBO = boFactory.createExternalDataBO(session);
+        final boolean dataAcquisition = procedureTypeCode.equals(DATA_ACQUISITION.getCode());
+        final SourceType type = dataAcquisition ? SourceType.MEASUREMENT : SourceType.DERIVED;
+        externalDataBO.define(externalData, procedure, cellPlate, type);
+        externalDataBO.save();
+        final String dataSetCode = externalDataBO.getExternalData().getCode();
+        assert dataSetCode != null : "Data set code not specified.";
+    }
+    
+    private ProcedurePE tryToFindProcedureByType(List<ProcedurePE> procedures, String procedureTypeCode)
+    {
+        for (ProcedurePE procedure : procedures)
+        {
+            if (procedure.getProcedureType().getCode().equals(procedureTypeCode))
+            {
+                return procedure;
+            }
+        }
+        return null;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
index 85676789aa0..e662624364a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
@@ -20,14 +20,17 @@ import org.springframework.dao.DataAccessException;
 
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataSetTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDatabaseInstanceDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IEntityPropertyTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IEntityTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExperimentAttachmentDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExperimentDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExternalDataDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IFileFormatTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IGroupDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IHibernateSearchDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.ILocatorTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IPersonDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IProcedureDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IProcedureTypeDAO;
@@ -168,4 +171,19 @@ abstract class AbstractBusinessObject implements IDAOFactory
     {
         return daoFactory.getExperimentAttachmentDAO();
     }
+
+    public IDataSetTypeDAO getDataSetTypeDAO()
+    {
+        return daoFactory.getDataSetTypeDAO();
+    }
+
+    public IFileFormatTypeDAO getFileFormatTypeDAO()
+    {
+        return daoFactory.getFileFormatTypeDAO();
+    }
+
+    public ILocatorTypeDAO getLocatorTypeDAO()
+    {
+        return daoFactory.getLocatorTypeDAO();
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataBO.java
new file mode 100644
index 00000000000..e206150d377
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataBO.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2009 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.openbis.generic.server.business.bo;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExternalDataDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IProcedureTypeDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IVocabularyDAO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetType;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.FileFormatType;
+import ch.systemsx.cisd.openbis.generic.shared.dto.FileFormatTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.LocatorType;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProcedurePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProcedureTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SourceType;
+import ch.systemsx.cisd.openbis.generic.shared.dto.StorageFormat;
+import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyTermPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.types.DataSetTypeCode;
+import ch.systemsx.cisd.openbis.generic.shared.dto.types.ProcedureTypeCode;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ExternalDataBO extends AbstractBusinessObject implements IExternalDataBO
+{
+    private ExternalDataPE externalData;
+    private SourceType sourceType;
+    
+    public ExternalDataBO(IDAOFactory daoFactory, Session session)
+    {
+        super(daoFactory, session);
+    }
+
+    public ExternalDataPE getExternalData()
+    {
+        return externalData;
+    }
+    
+    public void define(ExternalData data, ProcedurePE procedure, SamplePE sample,
+            SourceType type)
+    {
+        assert data != null : "Undefined data.";
+        final DataSetType dataSetType = data.getDataSetType();
+        assert dataSetType != null : "Undefined data set type.";
+        final FileFormatType fileFormatType = data.getFileFormatType();
+        assert fileFormatType != null : "Undefined file format type.";
+        final String location = data.getLocation();
+        assert location != null : "Undefined location.";
+        final LocatorType locatorType = data.getLocatorType();
+        assert locatorType != null : "Undefined location type.";
+        assert sourceType != null : "Undefined source type.";
+        assert procedure != null : "Unspecified procedure";
+
+        sourceType = type;
+        externalData = new ExternalDataPE();
+        externalData.setProcedure(procedure);
+        externalData.setDataProducerCode(data.getDataProducerCode());
+        externalData.setProductionDate(data.getProductionDate());
+        externalData.setCode(data.getCode());
+        externalData.setDataSetType(getDataSetType(dataSetType));
+        externalData.setFileFormatType(getFileFomatType(fileFormatType));
+        externalData.setComplete(data.getComplete());
+        externalData.setLocation(location);
+        externalData.setStorageFormatVocabularyTerm(tryToFindStorageFormatTerm(data.getStorageFormat()));
+        externalData.setLocatorType(getLocatorTypeDAO().tryToFindLocatorTypeByCode(
+                locatorType.getCode()));
+        final String parentDataSetCode = data.getParentDataSetCode();
+        if (parentDataSetCode != null)
+        {
+            final Set<DataPE> parents = new HashSet<DataPE>();
+            ExperimentPE experiment = procedure.getExperiment();
+            parents.add(getOrCreateParentData(parentDataSetCode, experiment, sample));
+            externalData.setParents(parents);
+        }
+        sourceType.setSample(externalData, sample);
+    }
+    
+    private VocabularyTermPE tryToFindStorageFormatTerm(StorageFormat storageFormat)
+    {
+        IVocabularyDAO vocabularyDAO = getVocabularyDAO();
+        VocabularyPE vocabulary = vocabularyDAO.tryFindVocabularyByCode(StorageFormat.VOCABULARY_CODE);
+        Set<VocabularyTermPE> terms = vocabulary.getTerms();
+        for (VocabularyTermPE term : terms)
+        {
+            if (storageFormat.getCode().equals(term.getCode()))
+            {
+                return term;
+            }
+        }
+        return null;
+    }
+
+    private final DataSetTypePE getDataSetType(final DataSetType dataSetType)
+    {
+        final String dataSetTypeCode = dataSetType.getCode();
+        final DataSetTypePE dataSetTypeOrNull =
+                getDataSetTypeDAO().tryToFindDataSetTypeByCode(dataSetTypeCode);
+        if (dataSetTypeOrNull == null)
+        {
+            throw UserFailureException.fromTemplate("There is no data set type with code '%s'",
+                    dataSetTypeCode);
+        }
+        return dataSetTypeOrNull;
+    }
+
+    private final FileFormatTypePE getFileFomatType(final FileFormatType fileFormatType)
+    {
+        final String fileFormatTypeCode = fileFormatType.getCode();
+        final FileFormatTypePE fileFormatTypeOrNull =
+                getFileFormatTypeDAO().tryToFindFileFormatTypeByCode(fileFormatTypeCode);
+        if (fileFormatTypeOrNull == null)
+        {
+            throw UserFailureException.fromTemplate("There is no file format type with code '%s'",
+                    fileFormatTypeCode);
+        }
+        return fileFormatTypeOrNull;
+    }
+    
+    private final ExternalDataPE getOrCreateParentData(final String parentDataSetCode,
+            ExperimentPE experiment, SamplePE sample)
+    {
+        assert parentDataSetCode != null : "Unspecified parent data set code.";
+
+        final IExternalDataDAO dataDAO = getExternalDataDAO();
+        ExternalDataPE parent = dataDAO.tryToFindDataSetByCode(parentDataSetCode);
+        if (parent == null)
+        {
+            final ProcedurePE procedure = getOrCreateUnknownProcedure(experiment);
+            parent = new ExternalDataPE();
+            parent.setCode(parentDataSetCode);
+            DataSetTypePE dataSetType = new DataSetTypePE();
+            dataSetType.setCode(DataSetTypeCode.UNKNOWN.getCode());
+            parent.setDataSetType(dataSetType);
+            parent.setProcedure(procedure);
+            parent.setSampleDerivedFrom(sample);
+            parent.setPlaceholder(true);
+            dataDAO.createDataSet(parent);
+        }
+        return parent;
+    }
+
+    private final ProcedurePE getOrCreateUnknownProcedure(ExperimentPE experiment)
+    {
+        List<ProcedurePE> procedures = experiment.getProcedures();
+        for (ProcedurePE procedure : procedures)
+        {
+            if (procedure.getProcedureType().getCode().equals(ProcedureTypeCode.UNKNOWN.getCode()))
+            {
+                return procedure;
+            }
+        }
+        ProcedurePE procedure = new ProcedurePE();
+        procedure.setExperiment(experiment);
+        final IProcedureTypeDAO procedureTypeDAO = getProcedureTypeDAO();
+        final String code = ProcedureTypeCode.UNKNOWN.getCode();
+        final ProcedureTypePE procedureTypeDTO = procedureTypeDAO.tryFindProcedureTypeByCode(code);
+        procedure.setProcedureType(procedureTypeDTO);
+        getProcedureDAO().createProcedure(procedure);
+        return procedure;
+    }
+
+    public void save() throws UserFailureException
+    {
+        assert externalData != null : "Undefined external data.";
+        IExternalDataDAO externalDataDAO = getExternalDataDAO();
+        String dataCode = externalData.getCode();
+        ExternalDataPE data = externalDataDAO.tryToFindDataSetByCode(dataCode);
+        if (data == null)
+        {
+            externalDataDAO.createDataSet(externalData);
+        } else
+        {
+            if (data.isPlaceholder() == false)
+            {
+                throw new UserFailureException("Already existing data set for code '"
+                        + dataCode + "' can not be updated by data set " + externalData);
+            }
+            data.setPlaceholder(false);
+            data.setComplete(externalData.getComplete());
+            data.setDataProducerCode(externalData.getDataProducerCode());
+            data.setDataSetType(externalData.getDataSetType());
+            data.setFileFormatType(externalData.getFileFormatType());
+            data.setLocatorType(externalData.getLocatorType());
+            data.setLocation(externalData.getLocation());
+            data.setProcedure(externalData.getProcedure());
+            data.setParents(externalData.getParents());
+            data.setProductionDate(externalData.getProductionDate());
+            data.setRegistrationDate(new Date());
+            data.setSampleAcquiredFrom(externalData.getSampleAcquiredFrom());
+            data.setSampleDerivedFrom(externalData.getSampleDerivedFrom());
+            data.setStorageFormatVocabularyTerm(externalData.getStorageFormatVocabularyTerm());
+            externalDataDAO.updateDataSet(externalData);
+        }
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ICommonBusinessObjectFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ICommonBusinessObjectFactory.java
index e4e8ad2d4bb..897693f39e4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ICommonBusinessObjectFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ICommonBusinessObjectFactory.java
@@ -37,6 +37,11 @@ public interface ICommonBusinessObjectFactory
      */
     public ISampleBO createSampleBO(final Session session);
 
+    /**
+     * Creates a {@link IExternalDataBO} <i>Business Object</i>.
+     */
+    public IExternalDataBO createExternalDataBO(Session session);
+    
     /**
      * Creates a {@link IExternalDataTable} <i>Business Object</i>.
      */
@@ -82,4 +87,5 @@ public interface ICommonBusinessObjectFactory
      * Creates a {@link IProjectBO} <i>Business Object</i>.
      */
     public IProjectBO createProjectBO(final Session session);
+    
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExternalDataBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExternalDataBO.java
new file mode 100644
index 00000000000..7e17dd55504
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExternalDataBO.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2009 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.openbis.generic.server.business.bo;
+
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProcedurePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SourceType;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IExternalDataBO extends IBusinessObject
+{
+    /**
+     * Returns the external data item which has been created by
+     * {@link #define(ExternalData, ProcedurePE, SamplePE, SourceType)}.
+     */
+    public ExternalDataPE getExternalData();
+    
+    /**
+     * Defines a new external data item. After invocation of this method {@link IExperimentBO#save()} should
+     * be invoked to store the new external data item in the Data Access Layer.
+     */
+    public void define(ExternalData externalData, ProcedurePE procedure, SamplePE sample,
+            SourceType sourceType);
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDAOFactory.java
index af5414e030b..0bc83b2aa8c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDAOFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDAOFactory.java
@@ -88,4 +88,13 @@ public interface IDAOFactory extends IAuthorizationDAOFactory
 
     /** Returns an implementation of {@link IExperimentAttachmentDAO}. */
     public IExperimentAttachmentDAO getExperimentAttachmentDAO();
+    
+    /** Returns an implementation of {@link IDataSetTypeDAO}. */
+    public IDataSetTypeDAO getDataSetTypeDAO();
+    
+    /** Returns an implementation of {@link IFileFormatTypeDAO}. */
+    public IFileFormatTypeDAO getFileFormatTypeDAO();
+    
+    /** Returns an implementation of {@link ILocatorTypeDAO}. */
+    public ILocatorTypeDAO getLocatorTypeDAO();
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataSetTypeDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataSetTypeDAO.java
new file mode 100644
index 00000000000..c912e19bac7
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataSetTypeDAO.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2009 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.openbis.generic.server.dataaccess;
+
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetTypePE;
+
+/**
+ * Interface to the data access layer for retrieving instances of {@link DataSetTypePE}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IDataSetTypeDAO
+{
+    /**
+     * Tries to find the {@link DataSetTypePE} for the specified code.
+     */
+    public DataSetTypePE tryToFindDataSetTypeByCode(String code);
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExternalDataDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExternalDataDAO.java
index bf5c2eaa415..a2d5f8267a7 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExternalDataDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExternalDataDAO.java
@@ -39,5 +39,25 @@ public interface IExternalDataDAO
      */
     public List<ExternalDataPE> listExternalData(final SamplePE sample, final SourceType sourceType)
             throws DataAccessException;
+    
+    /**
+     * Tries to get the data set for the specified code.
+     */
+    public ExternalDataPE tryToFindDataSetByCode(String dataSetCode);
+
+    /**
+     * Creates a unique data set code.
+     */
+    public String createDataSetCode();
 
+    /**
+     * Persists the specified data set.
+     */
+    public void createDataSet(ExternalDataPE dataset);
+
+    /**
+     * Updates the specified data set.
+     */
+    public void updateDataSet(ExternalDataPE dataset);
+    
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IFileFormatTypeDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IFileFormatTypeDAO.java
new file mode 100644
index 00000000000..e14d47f9ef6
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IFileFormatTypeDAO.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2009 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.openbis.generic.server.dataaccess;
+
+import ch.systemsx.cisd.openbis.generic.shared.dto.FileFormatTypePE;
+
+/**
+ * Interface to the data access layer for retrieving instances of {@link FileFormatTypePE}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IFileFormatTypeDAO
+{
+    /**
+     * Tries to find the {@link FileFormatTypePE} for the specified code.
+     */
+    public FileFormatTypePE tryToFindFileFormatTypeByCode(String code);
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ILocatorTypeDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ILocatorTypeDAO.java
new file mode 100644
index 00000000000..d3ff1e204e4
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/ILocatorTypeDAO.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2009 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.openbis.generic.server.dataaccess;
+
+import ch.systemsx.cisd.openbis.generic.shared.dto.LocatorTypePE;
+
+/**
+ * Interface to the data access layer for retrieving instances of {@link LocatorTypePE}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface ILocatorTypeDAO
+{
+    /**
+     * Tries to find the {@link LocatorTypePE} for the specified code.
+     */
+    public LocatorTypePE tryToFindLocatorTypeByCode(String code);
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DAOFactory.java
index c0d1616505b..356259b1125 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DAOFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DAOFactory.java
@@ -23,12 +23,15 @@ import org.hibernate.SessionFactory;
 
 import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataSetTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IEntityPropertyTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IEntityTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExperimentAttachmentDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExperimentDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExternalDataDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IFileFormatTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IHibernateSearchDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.ILocatorTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IProcedureDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IProcedureTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IProjectDAO;
@@ -69,11 +72,17 @@ public final class DAOFactory extends AuthorizationDAOFactory implements IDAOFac
 
     private final IVocabularyDAO vocabularyDAO;
 
-    private IProcedureTypeDAO procedureTypeDAO;
+    private final IProcedureTypeDAO procedureTypeDAO;
 
-    private IProcedureDAO procedureDAO;
+    private final IProcedureDAO procedureDAO;
 
-    private IExperimentAttachmentDAO experimentAttachmentDAO;
+    private final IExperimentAttachmentDAO experimentAttachmentDAO;
+
+    private final DataSetTypeDAO dataSetTypeDAO;
+
+    private final FileFormatTypeDAO fileFormatTypeDAO;
+
+    private final LocatorTypeDAO locatorTypeDAO;
 
     public DAOFactory(final DatabaseConfigurationContext context,
             final SessionFactory sessionFactory)
@@ -91,6 +100,9 @@ public final class DAOFactory extends AuthorizationDAOFactory implements IDAOFac
         procedureTypeDAO = new ProcedureTypeDAO(sessionFactory, databaseInstance);
         procedureDAO = new ProcedureDAO(sessionFactory, databaseInstance);
         experimentAttachmentDAO = new ExperimentAttachmentDAO(sessionFactory, databaseInstance);
+        dataSetTypeDAO = new DataSetTypeDAO(sessionFactory, databaseInstance);
+        fileFormatTypeDAO = new FileFormatTypeDAO(sessionFactory, databaseInstance);
+        locatorTypeDAO = new LocatorTypeDAO(sessionFactory, databaseInstance);
         final EntityKind[] entityKinds = EntityKind.values();
         for (final EntityKind entityKind : entityKinds)
         {
@@ -170,4 +182,19 @@ public final class DAOFactory extends AuthorizationDAOFactory implements IDAOFac
     {
         return experimentAttachmentDAO;
     }
+
+    public IDataSetTypeDAO getDataSetTypeDAO()
+    {
+        return dataSetTypeDAO;
+    }
+
+    public IFileFormatTypeDAO getFileFormatTypeDAO()
+    {
+        return fileFormatTypeDAO;
+    }
+
+    public ILocatorTypeDAO getLocatorTypeDAO()
+    {
+        return locatorTypeDAO;
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DataSetTypeDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DataSetTypeDAO.java
new file mode 100644
index 00000000000..cb5a6b21152
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DataSetTypeDAO.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 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.openbis.generic.server.dataaccess.db;
+
+import org.hibernate.SessionFactory;
+
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataSetTypeDAO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
+
+/**
+ * Data access object for {@link DataSetTypePE}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class DataSetTypeDAO extends AbstractTypeDAO<DataSetTypePE> implements IDataSetTypeDAO
+{
+    public DataSetTypeDAO(SessionFactory sessionFactory, DatabaseInstancePE databaseInstance)
+    {
+        super(sessionFactory, databaseInstance);
+    }
+
+    @Override
+    Class<?> getEntityClass()
+    {
+        return DataSetTypePE.class;
+    }
+
+    public DataSetTypePE tryToFindDataSetTypeByCode(String code)
+    {
+        return tryFindTypeByCode(code);
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExternalDataDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExternalDataDAO.java
index 735af0434f0..9f6cad195d4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExternalDataDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExternalDataDAO.java
@@ -16,18 +16,26 @@
 
 package ch.systemsx.cisd.openbis.generic.server.dataaccess.db;
 
+import java.util.Date;
 import java.util.List;
 
+import net.sf.beanlib.hibernate3.Hibernate3SequenceGenerator;
+
+import org.apache.commons.lang.time.DateFormatUtils;
 import org.apache.log4j.Logger;
 import org.hibernate.SessionFactory;
 import org.springframework.dao.DataAccessException;
+import org.springframework.orm.hibernate3.HibernateTemplate;
 
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.utilities.MethodUtils;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExternalDataDAO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.CodeConverter;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SequenceNames;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SourceType;
 
 /**
@@ -37,6 +45,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SourceType;
  */
 final class ExternalDataDAO extends AbstractDAO implements IExternalDataDAO
 {
+    private final static String DATA_CODE_DATE_FORMAT_PATTERN = "yyyyMMddHHmmssSSS";
+    
     private final static Class<ExternalDataPE> ENTITY_CLASS = ExternalDataPE.class;
 
     private static final Logger operationLog =
@@ -71,4 +81,57 @@ final class ExternalDataDAO extends AbstractDAO implements IExternalDataDAO
         }
         return list;
     }
+
+    public ExternalDataPE tryToFindDataSetByCode(String dataSetCode)
+    {
+        assert dataSetCode != null : "Unspecified data set code.";
+
+        final List<ExternalDataPE> list =
+                cast(getHibernateTemplate().find(
+                        String.format("select e from %s e where e.code = ?", ENTITY_CLASS.getSimpleName()),
+                        toArray(dataSetCode)));
+        final ExternalDataPE entity = tryFindEntity(list, "data set");
+        if (operationLog.isDebugEnabled())
+        {
+            String methodName = MethodUtils.getCurrentMethod().getName();
+            operationLog.debug(String.format("%s(%s): '%s'.", methodName, dataSetCode, entity));
+        }
+        return entity;
+    }
+
+    public String createDataSetCode()
+    {
+        long id =
+                Hibernate3SequenceGenerator.nextval(SequenceNames.DATA_SEQUENCE, getSession(true));
+        return DateFormatUtils.format(new Date(), DATA_CODE_DATE_FORMAT_PATTERN) + "-"
+                + Long.toString(id);
+    }
+
+    public void createDataSet(ExternalDataPE dataset)
+    {
+        assert dataset != null : "Unspecified data set.";
+        
+        dataset.setCode(CodeConverter.tryToDatabase(dataset.getCode()));
+        final HibernateTemplate template = getHibernateTemplate();
+        template.save(dataset);
+        template.flush();
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info(String.format("ADD: data set '%s'.", dataset));
+        }
+    }
+
+    public void updateDataSet(ExternalDataPE dataset)
+    {
+        assert dataset != null : "Given data set can not be null.";
+        validatePE(dataset);
+
+        final HibernateTemplate template = getHibernateTemplate();
+        template.update(dataset);
+        template.flush();
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info(String.format("UPDATE: data set '%s'.", dataset));
+        }
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/FileFormatTypeDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/FileFormatTypeDAO.java
new file mode 100644
index 00000000000..3322a453a5c
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/FileFormatTypeDAO.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 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.openbis.generic.server.dataaccess.db;
+
+import org.hibernate.SessionFactory;
+
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IFileFormatTypeDAO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.FileFormatTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
+
+/**
+ * Data access object for {@link FileFormatTypePE}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class FileFormatTypeDAO extends AbstractTypeDAO<FileFormatTypePE> implements IFileFormatTypeDAO
+{
+    public FileFormatTypeDAO(SessionFactory sessionFactory, DatabaseInstancePE databaseInstance)
+    {
+        super(sessionFactory, databaseInstance);
+    }
+
+    @Override
+    Class<?> getEntityClass()
+    {
+        return FileFormatTypePE.class;
+    }
+
+    public FileFormatTypePE tryToFindFileFormatTypeByCode(String code)
+    {
+        return tryFindTypeByCode(code);
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/LocatorTypeDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/LocatorTypeDAO.java
new file mode 100644
index 00000000000..b63087725b0
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/LocatorTypeDAO.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 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.openbis.generic.server.dataaccess.db;
+
+import org.hibernate.SessionFactory;
+
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.ILocatorTypeDAO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.LocatorTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
+
+/**
+ * Data access object for {@link LocatorTypePE}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class LocatorTypeDAO extends AbstractTypeDAO<LocatorTypePE> implements ILocatorTypeDAO
+{
+    public LocatorTypeDAO(SessionFactory sessionFactory, DatabaseInstancePE databaseInstance)
+    {
+        super(sessionFactory, databaseInstance);
+    }
+
+    @Override
+    Class<?> getEntityClass()
+    {
+        return LocatorTypePE.class;
+    }
+
+    public LocatorTypePE tryToFindLocatorTypeByCode(String code)
+    {
+        return tryFindTypeByCode(code);
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java
index 053fd0e2a36..52403090843 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java
@@ -41,9 +41,9 @@ public interface IETLLIMSService extends IWebService, IDataStoreInfoProvider
      * 
      * @param sessionToken the user authentication token. Must not be <code>null</code>.
      * @param sampleIdentifier an identifier which uniquely identifies the sample.
-     * @return <code>null</code> if no experiment could be found for given <var>dataSetInfo</var>.
+     * @return <code>null</code> if no experiment could be found for given <var>sampleIdentifier</var>.
      */
-    public ExperimentPE getBaseExperiment(final String sessionToken,
+    public ExperimentPE tryToGetBaseExperiment(final String sessionToken,
             final SampleIdentifier sampleIdentifier) throws UserFailureException;
 
     /**
@@ -55,7 +55,7 @@ public interface IETLLIMSService extends IWebService, IDataStoreInfoProvider
      * @return <code>null</code> if no appropriated sample found. Returns an empty array if a a
      *         sample found with no properties.
      */
-    public SamplePropertyPE[] getPropertiesOfTopSampleRegisteredFor(final String sessionToken,
+    public SamplePropertyPE[] tryToGetPropertiesOfTopSampleRegisteredFor(final String sessionToken,
             final SampleIdentifier sampleIdentifier) throws UserFailureException;
 
     /**
-- 
GitLab