diff --git a/common/source/java/ch/systemsx/cisd/common/io/ConcatenatedContentInputStream.java b/common/source/java/ch/systemsx/cisd/common/io/ConcatenatedContentInputStream.java
index 59987df8a8caf1b4cc42541d65bf4f2473a56fdb..ec2f3a0e3bbc9459289f3422a4bd450f643a8cef 100644
--- a/common/source/java/ch/systemsx/cisd/common/io/ConcatenatedContentInputStream.java
+++ b/common/source/java/ch/systemsx/cisd/common/io/ConcatenatedContentInputStream.java
@@ -73,7 +73,7 @@ public class ConcatenatedContentInputStream extends InputStream
      *            exception is thrown for a non-existing content.
      * @param contents InputStreams provided by these contents will be concatenated into one stream.
      */
-    ConcatenatedContentInputStream(boolean ignoreNonExistingContents,
+    public ConcatenatedContentInputStream(boolean ignoreNonExistingContents,
             IHierarchicalContentNode... contents)
     {
         this.ignoreNonExistingContents = ignoreNonExistingContents;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/DataSetTypeToRegistratorMapper.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/DataSetTypeToRegistratorMapper.java
index dd206b9749e8a7e878707643769869c61b0c73b9..5cb9427becd9d412503dd9410dcd3148af2bd850 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/DataSetTypeToRegistratorMapper.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/DataSetTypeToRegistratorMapper.java
@@ -44,6 +44,8 @@ class DataSetTypeToRegistratorMapper
 
     private final HashMap<String, ITopLevelDataSetRegistrator> handlerMap;
 
+    private final HashMap<String, ITopLevelDataSetRegistrator> dropboxToHandlerMap;
+
     private static final String DSS_RPC_SECTION_KEY = "dss-rpc";
 
     private static final String DEFAULT_THREAD_KEY = "put-default";
@@ -59,18 +61,30 @@ class DataSetTypeToRegistratorMapper
     {
         defaultHandler = plugin;
         handlerMap = new HashMap<String, ITopLevelDataSetRegistrator>();
+        dropboxToHandlerMap = new HashMap<String, ITopLevelDataSetRegistrator>();
     }
 
     DataSetTypeToRegistratorMapper(Parameters params, IEncapsulatedOpenBISService openBISService,
-            IMailClient mailClient,
-            IDataSetValidator dataSetValidator)
+            IMailClient mailClient, IDataSetValidator dataSetValidator)
     {
         DataSetTypeToTopLevelHandlerMapperInitializer initializer =
                 new DataSetTypeToTopLevelHandlerMapperInitializer(params, openBISService,
                         mailClient, dataSetValidator);
         initializer.initialize();
         defaultHandler = initializer.getDefaultHandler();
-        handlerMap = initializer.getHandlerMap();
+        dropboxToHandlerMap = initializer.getDropboxToHandlerMap();
+        handlerMap = initializer.getHandlerMap(dropboxToHandlerMap);
+    }
+
+    public ITopLevelDataSetRegistrator getRegistratorForDropbox(String dropboxName)
+    {
+        if (null == dropboxName)
+        {
+            return defaultHandler;
+        }
+
+        ITopLevelDataSetRegistrator plugin = dropboxToHandlerMap.get(dropboxName);
+        return plugin == null ? defaultHandler : plugin;
     }
 
     public ITopLevelDataSetRegistrator getRegistratorForType(String dataSetTypeOrNull)
@@ -151,21 +165,20 @@ class DataSetTypeToRegistratorMapper
             if (null == defaultThread)
             {
                 return ETLDaemon.createTopLevelDataSetRegistrator(params.getProperties(),
-                        firstThread, openBISService, mailClient, dataSetValidator, null,
-                        false,
+                        firstThread, openBISService, mailClient, dataSetValidator, null, false,
                         false, false, firstThread.tryGetPreRegistrationScript(),
                         firstThread.tryGetPostRegistrationScript(),
                         firstThread.tryGetValidationScripts(), PutDataSetServerPluginHolder.class);
             }
 
             return ETLDaemon.createTopLevelDataSetRegistrator(params.getProperties(),
-                    defaultThread, openBISService, mailClient, dataSetValidator, null,
-                    false, false, false, defaultThread.tryGetPreRegistrationScript(),
+                    defaultThread, openBISService, mailClient, dataSetValidator, null, false,
+                    false, false, defaultThread.tryGetPreRegistrationScript(),
                     defaultThread.tryGetPostRegistrationScript(),
                     defaultThread.tryGetValidationScripts(), PutDataSetServerPluginHolder.class);
         }
 
-        public HashMap<String, ITopLevelDataSetRegistrator> getHandlerMap()
+        public HashMap<String, ITopLevelDataSetRegistrator> getDropboxToHandlerMap()
         {
             HashMap<String, ITopLevelDataSetRegistrator> map =
                     new HashMap<String, ITopLevelDataSetRegistrator>();
@@ -179,9 +192,33 @@ class DataSetTypeToRegistratorMapper
                 ThreadParameters threadParams = threadParamMap.get(threadName);
                 if (null != threadParams)
                 {
-                    map.put(key.toUpperCase(), ETLDaemon.createTopLevelDataSetRegistrator(
-                            params.getProperties(), threadParams, openBISService,
-                            mailClient, dataSetValidator, null, false));
+                    ITopLevelDataSetRegistrator registrator =
+                            ETLDaemon.createTopLevelDataSetRegistrator(params.getProperties(),
+                                    threadParams, openBISService, mailClient, dataSetValidator,
+                                    null, false);
+                    map.put(threadName, registrator);
+                }
+            }
+            return map;
+        }
+
+        public HashMap<String, ITopLevelDataSetRegistrator> getHandlerMap(
+                @SuppressWarnings("hiding") HashMap<String, ITopLevelDataSetRegistrator> dropboxToHandlerMap)
+        {
+            HashMap<String, ITopLevelDataSetRegistrator> map =
+                    new HashMap<String, ITopLevelDataSetRegistrator>();
+
+            Properties putSection = section.getSubset(PUT_SECTION_KEY + ".", true);
+
+            for (Object keyObject : putSection.keySet())
+            {
+                String key = (String) keyObject;
+                String threadName = putSection.getProperty(key);
+                ThreadParameters threadParams = threadParamMap.get(threadName);
+                if (null != threadParams)
+                {
+                    ITopLevelDataSetRegistrator registrator = dropboxToHandlerMap.get(threadName);
+                    map.put(key.toUpperCase(), registrator);
                 }
             }
             return map;
@@ -204,4 +241,5 @@ class DataSetTypeToRegistratorMapper
         }
 
     }
+
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
index 7991973005ee781d4b5f17491855701202be93c2..eaea293bd952b4c39c4433a364043919d7faf470 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
@@ -143,7 +143,10 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
         // Check that the session owner has at least user access to the space the new data
         // set should belongs to
         SpaceIdentifier spaceId = getSpaceIdentifierForNewDataSet();
-        getOpenBisService().checkSpaceAccess(sessionToken, spaceId);
+        if (spaceId != null)
+        {
+            getOpenBisService().checkSpaceAccess(sessionToken, spaceId);
+        }
 
         writeDataSetToTempDirectory();
         overrideOrNull = null;
@@ -198,7 +201,9 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
 
     public String tryGetDataSetTypeCode(final DataSetInformation newOverride)
     {
-        String dataSetTypeCodeOrNull = (newOverride != null && newOverride.getDataSetType() != null) ? newOverride.getDataSetType().getCode() : null;
+        String dataSetTypeCodeOrNull =
+                (newOverride != null && newOverride.getDataSetType() != null) ? newOverride
+                        .getDataSetType().getCode() : null;
         return dataSetTypeCodeOrNull;
     }
 
@@ -387,6 +392,11 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
     {
         SpaceIdentifier spaceId = null;
         DataSetOwner owner = getDataSetOwner();
+        if (owner == null)
+        {
+            return null;
+        }
+
         switch (owner.getType())
         {
             case EXPERIMENT:
@@ -568,8 +578,7 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
          * @param incomingDataSetFile The data set to register
          */
         public RegistrationHelper(PutDataSetService service, String shareId,
-                IETLServerPlugin plugin,
-                File incomingDataSetFile)
+                IETLServerPlugin plugin, File incomingDataSetFile)
         {
             super(incomingDataSetFile, shareId, new CleanAfterwardsAction(),
                     new PreRegistrationAction(), new PostRegistrationAction());
@@ -704,38 +713,42 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
                     plugin.getDataSetInfoExtractor().getDataSetInformation(incomingDataSetPath,
                             openbisService);
             DataSetOwner owner = getDataSetOwner();
-            switch (owner.getType())
+            if (owner != null)
             {
-                case EXPERIMENT:
-                    dataSetInfo.setExperimentIdentifier(tryExperimentIdentifier());
-                    break;
-                case SAMPLE:
-                    SampleIdentifier sampleId = trySampleIdentifier();
+                switch (owner.getType())
+                {
+                    case EXPERIMENT:
+                        dataSetInfo.setExperimentIdentifier(tryExperimentIdentifier());
+                        break;
+                    case SAMPLE:
+                        SampleIdentifier sampleId = trySampleIdentifier();
 
-                    dataSetInfo.setSampleCode(sampleId.getSampleCode());
-                    dataSetInfo.setSpaceCode(sampleId.getSpaceLevel().getSpaceCode());
-                    dataSetInfo.setInstanceCode(sampleId.getSpaceLevel().getDatabaseInstanceCode());
-                    break;
-                case DATA_SET:
-                    String dataSetCode = tryGetDataSetCode();
+                        dataSetInfo.setSampleCode(sampleId.getSampleCode());
+                        dataSetInfo.setSpaceCode(sampleId.getSpaceLevel().getSpaceCode());
+                        dataSetInfo.setInstanceCode(sampleId.getSpaceLevel()
+                                .getDatabaseInstanceCode());
+                        break;
+                    case DATA_SET:
+                        String dataSetCode = tryGetDataSetCode();
 
-                    ExternalData parentDataSet = openbisService.tryGetDataSet(dataSetCode);
-                    if (parentDataSet != null)
-                    {
-                        if (parentDataSet.getExperiment() != null)
-                        {
-                            dataSetInfo.setExperiment(parentDataSet.getExperiment());
-                        }
-                        if (parentDataSet.getSample() != null)
+                        ExternalData parentDataSet = openbisService.tryGetDataSet(dataSetCode);
+                        if (parentDataSet != null)
                         {
-                            dataSetInfo.setSample(parentDataSet.getSample());
+                            if (parentDataSet.getExperiment() != null)
+                            {
+                                dataSetInfo.setExperiment(parentDataSet.getExperiment());
+                            }
+                            if (parentDataSet.getSample() != null)
+                            {
+                                dataSetInfo.setSample(parentDataSet.getSample());
+                            }
+                            ArrayList<String> parentDataSetCodes = new ArrayList<String>();
+                            parentDataSetCodes.add(parentDataSet.getCode());
+                            parentDataSetCodes.addAll(dataSetInfo.getParentDataSetCodes());
+                            dataSetInfo.setParentDataSetCodes(parentDataSetCodes);
+                            break;
                         }
-                        ArrayList<String> parentDataSetCodes = new ArrayList<String>();
-                        parentDataSetCodes.add(parentDataSet.getCode());
-                        parentDataSetCodes.addAll(dataSetInfo.getParentDataSetCodes());
-                        dataSetInfo.setParentDataSetCodes(parentDataSetCodes);
-                        break;
-                    }
+                }
             }
             String typeCode = newDataSet.tryDataSetType();
             if (null != typeCode)
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetService.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetService.java
index 090d933ef8f8a0294e44abadba9290b33243e49a..4bb41c4ca6b565339618a00f6a9a9e2be8330770 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetService.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.etlserver.api.v1;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
 import java.util.List;
 import java.util.Properties;
 import java.util.concurrent.locks.Lock;
@@ -30,6 +31,8 @@ import org.apache.log4j.Logger;
 import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.io.ByteArrayBasedContentNode;
+import ch.systemsx.cisd.common.io.ConcatenatedContentInputStream;
 import ch.systemsx.cisd.common.mail.IMailClient;
 import ch.systemsx.cisd.common.mail.MailClient;
 import ch.systemsx.cisd.etlserver.DataStrategyStore;
@@ -40,11 +43,13 @@ import ch.systemsx.cisd.etlserver.validation.DataSetValidator;
 import ch.systemsx.cisd.etlserver.validation.IDataSetValidator;
 import ch.systemsx.cisd.openbis.dss.generic.shared.Constants;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.validation.ValidationScriptReader;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.DssPropertyParametersUtil;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.SegmentedStoreUtils;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance;
 
 /**
@@ -125,6 +130,70 @@ public class PutDataSetService
         isInitialized = true;
     }
 
+    public String putDataSet(String sessionToken, String dropboxName,
+            CustomImportFile customImportFile)
+    {
+        if (false == isInitialized)
+        {
+            doInitialization();
+        }
+
+        try
+        {
+            ITopLevelDataSetRegistrator registrator =
+                    registratorMap.getRegistratorForDropbox(dropboxName);
+
+            final List<DataSetInformation> infos;
+            // Branch -- use the old logic for the ETLServerPlugins
+            if (registrator instanceof PutDataSetServerPluginHolder)
+            {
+                infos =
+                        new PutDataSetExecutor(this,
+                                ((PutDataSetServerPluginHolder) registrator).getPlugin(),
+                                sessionToken, createNewDataSetDTO(customImportFile),
+                                getAsInputStream(customImportFile)).execute();
+            } else
+            {
+                infos =
+                        new PutDataSetTopLevelDataSetHandler(this, registrator, sessionToken,
+                                createNewDataSetDTO(customImportFile),
+                                getAsInputStream(customImportFile)).execute();
+            }
+            StringBuilder sb = new StringBuilder();
+            for (DataSetInformation info : infos)
+            {
+                sb.append(info.getDataSetCode());
+                sb.append(",");
+            }
+
+            // Remove the trailing comma
+            if (sb.length() > 0)
+            {
+                sb.deleteCharAt(sb.length() - 1);
+            }
+            return sb.toString();
+        } catch (UserFailureException e)
+        {
+            throw new IllegalArgumentException(e);
+        } catch (IOException e)
+        {
+            throw new IOExceptionUnchecked(e);
+        }
+    }
+
+    private InputStream getAsInputStream(CustomImportFile customImportFile)
+    {
+        return new ConcatenatedContentInputStream(false, new ByteArrayBasedContentNode(
+                customImportFile.getBytes(), customImportFile.getFileName()));
+    }
+
+    private NewDataSetDTO createNewDataSetDTO(CustomImportFile customImportFile)
+    {
+        return new NewDataSetDTO(null, null, Collections.singletonList(new FileInfoDssDTO(
+                customImportFile.getFileName(), customImportFile.getFileName(), false,
+                customImportFile.getBytes().length)));
+    }
+
     public String putDataSet(String sessionToken, NewDataSetDTO newDataSet, InputStream inputStream)
             throws IOExceptionUnchecked, IllegalArgumentException
     {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java
index 70c47e136b76bbcf8609faf769b380ccfcd67f5f..c5318270239fd9eb20ace03c47b1585c5f391285 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java
@@ -141,7 +141,10 @@ class PutDataSetTopLevelDataSetHandler
         // Check that the session owner has at least user access to the space the new data
         // set should belongs to
         SpaceIdentifier spaceId = getSpaceIdentifierForNewDataSet();
-        getOpenBisService().checkSpaceAccess(sessionToken, spaceId);
+        if (spaceId != null)
+        {
+            getOpenBisService().checkSpaceAccess(sessionToken, spaceId);
+        }
 
         writeDataSetToTempDirectory();
 
@@ -175,41 +178,43 @@ class PutDataSetTopLevelDataSetHandler
         dataSetInfo.setUploadingUserEmail(sessionContext.getUserEmail());
         dataSetInfo.setUploadingUserId(sessionContext.getUserName());
         DataSetOwner owner = getDataSetOwner();
-        switch (owner.getType())
+        if (owner != null)
         {
-            case EXPERIMENT:
-                dataSetInfo.setExperimentIdentifier(tryExperimentIdentifier());
-                break;
-            case SAMPLE:
-                SampleIdentifier sampleId = trySampleIdentifier();
-
-                dataSetInfo.setSampleCode(sampleId.getSampleCode());
-                dataSetInfo.setSpaceCode(sampleId.getSpaceLevel().getSpaceCode());
-                dataSetInfo.setInstanceCode(sampleId.getSpaceLevel().getDatabaseInstanceCode());
-                break;
-            case DATA_SET:
-                String dataSetCode = tryGetDataSetCode();
-
-                ExternalData parentDataSet = getOpenBisService().tryGetDataSet(dataSetCode);
-                if (parentDataSet != null)
-                {
-                    if (parentDataSet.getExperiment() != null)
-                    {
-                        dataSetInfo.setExperiment(parentDataSet.getExperiment());
-                    }
-                    if (parentDataSet.getSample() != null)
+            switch (owner.getType())
+            {
+                case EXPERIMENT:
+                    dataSetInfo.setExperimentIdentifier(tryExperimentIdentifier());
+                    break;
+                case SAMPLE:
+                    SampleIdentifier sampleId = trySampleIdentifier();
+
+                    dataSetInfo.setSampleCode(sampleId.getSampleCode());
+                    dataSetInfo.setSpaceCode(sampleId.getSpaceLevel().getSpaceCode());
+                    dataSetInfo.setInstanceCode(sampleId.getSpaceLevel().getDatabaseInstanceCode());
+                    break;
+                case DATA_SET:
+                    String dataSetCode = tryGetDataSetCode();
+
+                    ExternalData parentDataSet = getOpenBisService().tryGetDataSet(dataSetCode);
+                    if (parentDataSet != null)
                     {
-                        dataSetInfo.setSample(parentDataSet.getSample());
+                        if (parentDataSet.getExperiment() != null)
+                        {
+                            dataSetInfo.setExperiment(parentDataSet.getExperiment());
+                        }
+                        if (parentDataSet.getSample() != null)
+                        {
+                            dataSetInfo.setSample(parentDataSet.getSample());
+                        }
+
+                        ArrayList<String> parentDataSetCodes = new ArrayList<String>();
+                        // Add this parent as the first parent
+                        parentDataSetCodes.add(parentDataSet.getCode());
+                        parentDataSetCodes.addAll(dataSetInfo.getParentDataSetCodes());
+                        dataSetInfo.setParentDataSetCodes(parentDataSetCodes);
                     }
-
-                    ArrayList<String> parentDataSetCodes = new ArrayList<String>();
-                    // Add this parent as the first parent
-                    parentDataSetCodes.add(parentDataSet.getCode());
-                    parentDataSetCodes.addAll(dataSetInfo.getParentDataSetCodes());
-                    dataSetInfo.setParentDataSetCodes(parentDataSetCodes);
-                }
-                break;
-
+                    break;
+            }
         }
         String typeCode = newDataSet.tryDataSetType();
         if (null != typeCode)
@@ -296,42 +301,45 @@ class PutDataSetTopLevelDataSetHandler
     {
         SpaceIdentifier spaceId = null;
         DataSetOwner owner = getDataSetOwner();
-        switch (owner.getType())
+        if (owner != null)
         {
-            case EXPERIMENT:
-                ExperimentIdentifier experimentId = tryExperimentIdentifier();
-                spaceId =
-                        new SpaceIdentifier(experimentId.getDatabaseInstanceCode(),
-                                experimentId.getSpaceCode());
-                break;
-            case SAMPLE:
-                SampleIdentifier sampleId = trySampleIdentifier();
-                spaceId = sampleId.getSpaceLevel();
-                break;
-            case DATA_SET:
-                String dataSetCode = tryGetDataSetCode();
-
-                ExternalData parentDataSet = getOpenBisService().tryGetDataSet(dataSetCode);
-                if (parentDataSet != null)
-                {
-                    if (parentDataSet.getExperiment() != null)
-                    {
-                        experimentId =
-                                ExperimentIdentifierFactory.parse(parentDataSet.getExperiment()
-                                        .getIdentifier());
-                        spaceId =
-                                new SpaceIdentifier(experimentId.getDatabaseInstanceCode(),
-                                        experimentId.getSpaceCode());
-                    }
-                    if (parentDataSet.getSample() != null)
+            switch (owner.getType())
+            {
+                case EXPERIMENT:
+                    ExperimentIdentifier experimentId = tryExperimentIdentifier();
+                    spaceId =
+                            new SpaceIdentifier(experimentId.getDatabaseInstanceCode(),
+                                    experimentId.getSpaceCode());
+                    break;
+                case SAMPLE:
+                    SampleIdentifier sampleId = trySampleIdentifier();
+                    spaceId = sampleId.getSpaceLevel();
+                    break;
+                case DATA_SET:
+                    String dataSetCode = tryGetDataSetCode();
+
+                    ExternalData parentDataSet = getOpenBisService().tryGetDataSet(dataSetCode);
+                    if (parentDataSet != null)
                     {
-                        sampleId =
-                                SampleIdentifierFactory.parse(parentDataSet.getSample()
-                                        .getIdentifier());
-                        spaceId = sampleId.getSpaceLevel();
+                        if (parentDataSet.getExperiment() != null)
+                        {
+                            experimentId =
+                                    ExperimentIdentifierFactory.parse(parentDataSet.getExperiment()
+                                            .getIdentifier());
+                            spaceId =
+                                    new SpaceIdentifier(experimentId.getDatabaseInstanceCode(),
+                                            experimentId.getSpaceCode());
+                        }
+                        if (parentDataSet.getSample() != null)
+                        {
+                            sampleId =
+                                    SampleIdentifierFactory.parse(parentDataSet.getSample()
+                                            .getIdentifier());
+                            spaceId = sampleId.getSpaceLevel();
+                        }
                     }
-                }
-                break;
+                    break;
+            }
         }
         return spaceId;
     }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
index d7ecbab18615017e71fca7c82efacf0b139964f9..71782a1ee78e121ad64987b739c965e3a354d460 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
@@ -36,6 +36,7 @@ import ch.systemsx.cisd.common.exceptions.InvalidSessionException;
 import ch.systemsx.cisd.common.mail.MailClientParameters;
 import ch.systemsx.cisd.common.spring.AbstractServiceWithLogger;
 import ch.systemsx.cisd.common.spring.IInvocationLoggerContext;
+import ch.systemsx.cisd.etlserver.api.v1.PutDataSetService;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.ArchiverPluginFactory;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IProcessingPluginTask;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IReportingPluginTask;
@@ -54,6 +55,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.IShareIdManager;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ProcessingStatus;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
 import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatastoreServiceDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IDatasetLocation;
@@ -93,7 +95,9 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic
     private File commandQueueDirOrNull;
 
     private IDataSetCommandExecutor commandExecutor;
-    
+
+    private PutDataSetService putService;
+
     public DataStoreService(SessionTokenManager sessionTokenManager,
             MailClientParameters mailClientParameters, PluginTaskProviders pluginTaskParameters)
     {
@@ -367,7 +371,8 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic
         return new DataSetDirectoryProvider(storeRoot, getShareIdManager());
     }
 
-    public TableModel createReportFromAggregationService(String sessionToken, String userSessionToken, String serviceKey, Map<String, Object> parameters)
+    public TableModel createReportFromAggregationService(String sessionToken,
+            String userSessionToken, String serviceKey, Map<String, Object> parameters)
     {
         sessionTokenManager.assertValidSessionToken(sessionToken);
         PluginTaskProvider<IReportingPluginTask> reportingPlugins =
@@ -442,7 +447,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic
             return archiverTask.unarchive(datasets, archiverContext);
         }
     }
-    
+
     private static ArchiverTaskContext createContext(DataSetProcessingContext context)
     {
         return new ArchiverTaskContext(context.getDirectoryProvider(),
@@ -465,6 +470,24 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic
         return commandExecutor;
     }
 
+    public String putDataSet(String sessionToken, String dropboxName,
+            CustomImportFile customImportFile)
+    {
+        PutDataSetService service = getPutDataSetService();
+        return service.putDataSet(sessionToken, dropboxName, customImportFile);
+    }
+
+    private PutDataSetService getPutDataSetService()
+    {
+        if (putService == null)
+        {
+            this.putService =
+                    new PutDataSetService(ServiceProvider.getOpenBISService(), operationLog);
+            putService.setStoreDirectory(storeRoot);
+        }
+        return putService;
+    }
+
     private IShareIdManager getShareIdManager()
     {
         if (shareIdManager == null)
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
index fa2886616778e3851028e44108e88800eebb06e1..155833b6f6f62537380a263efde6dc19d74d3b35 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
@@ -26,6 +26,7 @@ import ch.systemsx.cisd.common.serviceconversation.ServiceMessage;
 import ch.systemsx.cisd.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.common.utilities.IInitializable;
 import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IDatasetLocation;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LinkModel;
@@ -85,7 +86,7 @@ class DataStoreServiceLogger implements IDataStoreService, IInitializable
         log("getVersion", "SESSION(%s)", sessionToken);
         return 0;
     }
-    
+
     public void send(ServiceMessage message)
     {
         log("send", "", message);
@@ -164,10 +165,18 @@ class DataStoreServiceLogger implements IDataStoreService, IInitializable
         return null;
     }
 
-    public TableModel createReportFromAggregationService(String sessionToken, String userSessionToken, String serviceKey, Map<String, Object> parameters)
+    public TableModel createReportFromAggregationService(String sessionToken,
+            String userSessionToken, String serviceKey, Map<String, Object> parameters)
+    {
+        log("createReportFromAggregationService", "USER_SESSION(%s) SERVICE(%s) PARAMETERS(%s)",
+                userSessionToken, serviceKey, parameters);
+        return null;
+    }
+
+    public String putDataSet(String sessionToken, String dropboxName,
+            CustomImportFile customImportFile)
     {
-        log("createReportFromAggregationService", "USER_SESSION(%s) SERVICE(%s) PARAMETERS(%s)", userSessionToken,
-                serviceKey, parameters);
+        log("putDataSet", "DROPBOX_NAME(%s), CUSTOM_IMPORT_FILE(%s)", dropboxName, customImportFile);
         return null;
     }
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssDTO.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssDTO.java
index b5d5d5f14398f510a81b2ac004e1b876412508ed..947846ae8bf7d764bbe467dd0450ec6f9442f7b0 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssDTO.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssDTO.java
@@ -50,7 +50,7 @@ public class FileInfoDssDTO implements Serializable
     }
 
     /**
-     * The the path of this file in the data set (i.e., the root of the data set has a path of "").
+     * The path of this file in the data set (i.e., the root of the data set has a path of "").
      */
     public String getPathInDataSet()
     {
@@ -58,7 +58,7 @@ public class FileInfoDssDTO implements Serializable
     }
 
     /**
-     * The the path of this file relative to the path of the request that produced this FileInfoDss
+     * The path of this file relative to the path of the request that produced this FileInfoDss
      */
     public String getPathInListing()
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IClientService.java
index 8eada3422bdab0546e4ef3050b5c0aeaca8152c7..f996fe693873e398ca181ffcf9bcb5695f3554f0 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IClientService.java
@@ -16,12 +16,15 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client;
 
+import java.util.List;
+
 import com.google.gwt.user.client.rpc.RemoteService;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ApplicationInfo;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SessionContext;
 import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImport;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DisplaySettings;
 
 /**
@@ -40,6 +43,11 @@ public interface IClientService extends RemoteService
      */
     public ApplicationInfo getApplicationInfo();
 
+    /**
+     * Returns list of available custom imports
+     */
+    public List<CustomImport> getCustomImports();
+
     /**
      * Tries to return the current session context. If failed <code>null</code> is returned.
      * 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IClientServiceAsync.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IClientServiceAsync.java
index d3e0d6dbb59f50b731dfc19577f8417bdf4e1235..1fb77305b6584d6532d661453d18b926c52f61c8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IClientServiceAsync.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IClientServiceAsync.java
@@ -16,11 +16,14 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client;
 
+import java.util.List;
+
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ApplicationInfo;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SessionContext;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImport;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DisplaySettings;
 
 /**
@@ -32,6 +35,9 @@ public interface IClientServiceAsync
     /** @see IClientService#getApplicationInfo() */
     public void getApplicationInfo(AsyncCallback<ApplicationInfo> callback);
 
+    /** @see IClientService#getCustomImports */
+    public void getCustomImports(AsyncCallback<List<CustomImport>> callback);
+
     /** @see IClientService#tryToGetCurrentSessionContext(boolean anonymous) */
     public void tryToGetCurrentSessionContext(boolean anonymous,
             AsyncCallback<SessionContext> callback);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
index a245656aca09e929e9ff25f8ca2eb5a3d59a542d..ca824c66a78e51fdd0dc9dfdb770e0b442e15917 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
@@ -1120,4 +1120,9 @@ public interface ICommonClientService extends IClientService
     public void emptyTrash(boolean forceNotExistingLocations, boolean forceDisallowedTypes)
             throws UserFailureException;
 
+    /**
+     * Performs custom import operation
+     */
+    public String performCustomImport(String sessionKey, String customImportCode)
+            throws UserFailureException;
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
index 21124c71da1df378a63a2fe437fe6595123b1289..42aaee6036ac1147d08bd6cdbe7efeb3ed8508d1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
@@ -1021,4 +1021,11 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
      */
     public void emptyTrash(boolean forceNotExistingLocations, boolean forceDisallowedTypes,
             AsyncCallback<Void> callback);
+
+    /**
+     * @see ICommonClientService#performCustomImport(String, String)
+     */
+    public void performCustomImport(String sessionKey, String customImportCode,
+            AsyncCallback<String> callback)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException;
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
index f7a1950d64e95b6db32efe74d103fda27fb41603..5ce82027b045b8cadcfaa62ede6e9fd3f272f6e7 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
@@ -711,6 +711,8 @@ public abstract class Dict
 
     public static final String MENU_GENERAL_IMPORT = "menu_general_import";
 
+    public static final String MENU_CUSTOM_IMPORT = "menu_custom_import";
+
     //
     // Tab Titles
     //
@@ -1224,6 +1226,8 @@ public abstract class Dict
     public static final String ADD_UNOFFICIAL_VOCABULARY_TERM_DIALOG_TITLE =
             "add_unofficial_vocabulary_term_dialog_title";
 
+    public static final String CUSTOM_IMPORT = "custom_import";
+
     // Material Viewer
 
     public static final String MATERIAL_PROPERTIES_HEADING = "material_properties_heading";
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/framework/ComponentProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/framework/ComponentProvider.java
index 3f6dfae4cb0f499e29c2699be71114dce6904b75..91c402b659ccfbe7843eeb75e840c11dd0c07a37 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/framework/ComponentProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/framework/ComponentProvider.java
@@ -27,6 +27,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.help.HelpP
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.help.HelpPageIdentifier.HelpPageAction;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.help.HelpPageIdentifier.HelpPageDomain;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.AuthorizationGroupGrid;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.CustomImportComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.GeneralImportComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.PersonGrid;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.RoleAssignmentGrid;
@@ -649,7 +650,6 @@ public final class ComponentProvider
                 {
                     return null;
                 }
-
             };
     }
 
@@ -1567,6 +1567,45 @@ public final class ComponentProvider
             };
     }
 
+    public AbstractTabItemFactory getCustomImport()
+    {
+        return new AbstractTabItemFactory()
+            {
+                @Override
+                public ITabItem create()
+                {
+                    CustomImportComponent customImportTab = new CustomImportComponent(viewContext);
+                    return createRegistrationTab(getTabTitle(),
+                            DatabaseModificationAwareComponent.wrapUnaware(customImportTab));
+                }
+
+                @Override
+                public String getId()
+                {
+                    return CustomImportComponent.ID;
+                }
+
+                @Override
+                public HelpPageIdentifier getHelpPageIdentifier()
+                {
+                    return new HelpPageIdentifier(HelpPageDomain.CUSTOM_IMPORT,
+                            HelpPageAction.IMPORT);
+                }
+
+                @Override
+                public String getTabTitle()
+                {
+                    return getMessage(Dict.CUSTOM_IMPORT);
+                }
+
+                @Override
+                public String tryGetLink()
+                {
+                    return null;
+                }
+            };
+    }
+
     public IMainPanel tryGetMainTabPanel()
     {
         return mainTabPanelOrNull;
@@ -1615,5 +1654,4 @@ public final class ComponentProvider
 
             };
     }
-
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/help/HelpPageIdentifier.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/help/HelpPageIdentifier.java
index dcca2a31db4a361f4e7e2df348a00cfe57bc929e..2e52fac178f8d5602de8a33978c4943d7b23634a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/help/HelpPageIdentifier.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/help/HelpPageIdentifier.java
@@ -65,6 +65,8 @@ public class HelpPageIdentifier
 
         GENERAL_IMPORT(ADMINISTRATION),
 
+        CUSTOM_IMPORT(ADMINISTRATION),
+
         // authorization subdomains
         USERS(AUTHORIZATION), ROLES(AUTHORIZATION), AUTHORIZATION_GROUPS(AUTHORIZATION),
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/TopMenu.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/TopMenu.java
index 170dc1a2904833c87b474a71612f35fe2fca3e3c..02cf78bf2ea33ea4d73cd13ff5c33a0104691712 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/TopMenu.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/TopMenu.java
@@ -78,7 +78,7 @@ public class TopMenu extends LayoutContainer
 
         USER_MENU_CHANGE_SETTINGS, USER_MENU_LOGOUT, USER_MENU_LOGIN, USER_MENU_ABOUT_BOX,
 
-        VOCABULARY_MENU_BROWSE, VOCABULARY_MENU_NEW, GENERAL_IMPORT_MENU;
+        VOCABULARY_MENU_BROWSE, VOCABULARY_MENU_NEW, GENERAL_IMPORT_MENU, CUSTOM_IMPORT_MENU;
 
         public String getMenuId()
         {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/top/ImportMenu.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/top/ImportMenu.java
index d6ad549d86736a9388f2f6ff9ea78c49a1d8aae6..e859e5522e7f1f5ff61a0d0ad445d9530d8141a8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/top/ImportMenu.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/top/ImportMenu.java
@@ -16,6 +16,13 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.top;
 
+import com.extjs.gxt.ui.client.event.MenuEvent;
+import com.extjs.gxt.ui.client.event.SelectionListener;
+import com.extjs.gxt.ui.client.widget.menu.Menu;
+import com.extjs.gxt.ui.client.widget.menu.MenuItem;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Window;
+
 import ch.systemsx.cisd.common.shared.basic.utils.StringUtils;
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
@@ -29,13 +36,6 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ApplicationInfo;
 import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
 import ch.systemsx.cisd.openbis.generic.shared.basic.URLMethodWithParameters;
 
-import com.extjs.gxt.ui.client.event.MenuEvent;
-import com.extjs.gxt.ui.client.event.SelectionListener;
-import com.extjs.gxt.ui.client.widget.menu.Menu;
-import com.extjs.gxt.ui.client.widget.menu.MenuItem;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.Window;
-
 /**
  * The Import menu of the top menu bar.
  * 
@@ -68,6 +68,14 @@ public class ImportMenu extends TopMenuItem
         submenu.add(new ActionMenu(TopMenu.ActionMenuKind.DATA_SET_MENU_MASS_UPDATE,
                 messageProvider, componentProvider.getDataSetBatchUpdate()));
 
+        ApplicationInfo applicationInfo = viewContext.getModel().getApplicationInfo();
+        if (applicationInfo.getCustomImports() != null
+                && applicationInfo.getCustomImports().size() > 0)
+        {
+            submenu.add(new ActionMenu(TopMenu.ActionMenuKind.CUSTOM_IMPORT_MENU, messageProvider,
+                    componentProvider.getCustomImport()));
+        }
+
         SelectionListener<? extends MenuEvent> listener = new SelectionListener<MenuEvent>()
             {
                 @Override
@@ -87,7 +95,6 @@ public class ImportMenu extends TopMenuItem
         submenu.add(new MenuItem(TopMenu.ActionMenuKind.DATA_SET_MENU_UPLOAD_CLIENT
                 .getMenuText(messageProvider), listener));
 
-        ApplicationInfo applicationInfo = viewContext.getModel().getApplicationInfo();
         boolean cifexConfigured =
                 StringUtils.isNotBlank(applicationInfo.getCifexRecipient())
                         && StringUtils.isNotBlank(applicationInfo.getCifexURL());
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/CustomImportComponent.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/CustomImportComponent.java
new file mode 100644
index 0000000000000000000000000000000000000000..0deb69a71e76c7688cbff934cc06ae3932ef4350
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/CustomImportComponent.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 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.client.web.client.application.ui;
+
+import com.extjs.gxt.ui.client.Style.Scroll;
+import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
+import com.extjs.gxt.ui.client.event.SelectionChangedListener;
+import com.extjs.gxt.ui.client.widget.LayoutContainer;
+import com.extjs.gxt.ui.client.widget.toolbar.LabelToolItem;
+import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericConstants;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.ModelDataPropertyNames;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.CustomImportTypeSelectionWidget.CustomImportModelData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImport;
+import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.CustomImportForm;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class CustomImportComponent extends LayoutContainer
+{
+    private static final String ID_SUFFIX = "custom-import";
+
+    public static final String ID = GenericConstants.ID_PREFIX + ID_SUFFIX;
+
+    private final CustomImportTypeSelectionWidget customImportTypeSelectionWidget;
+
+    private IViewContext<ICommonClientServiceAsync> viewContext;
+
+    private CustomImportForm customImportForm;
+
+    public CustomImportComponent(final IViewContext<ICommonClientServiceAsync> viewContext)
+    {
+        this.viewContext = viewContext;
+        setId(ID);
+        setScrollMode(Scroll.AUTO);
+        customImportTypeSelectionWidget =
+                new CustomImportTypeSelectionWidget(viewContext, ID_SUFFIX, null);
+        final ToolBar toolBar = createToolBar();
+        add(toolBar);
+        customImportTypeSelectionWidget
+                .addSelectionChangedListener(new SelectionChangedListener<CustomImportModelData>()
+                    {
+                        //
+                        // SelectionChangedListener
+                        //
+                        @Override
+                        public final void selectionChanged(
+                                final SelectionChangedEvent<CustomImportModelData> se)
+                        {
+                            final CustomImport customImport =
+                                    customImportTypeSelectionWidget.tryGetSelectedCustomImport();
+                            if (customImport != null)
+                            {
+                                removeAll();
+                                add(toolBar);
+                                customImportForm =
+                                        new CustomImportForm(viewContext, ID, (String) se
+                                                .getSelectedItem().get(ModelDataPropertyNames.CODE));
+                                add(customImportForm);
+                                layout();
+                            }
+                        }
+                    });
+    }
+
+    private final ToolBar createToolBar()
+    {
+        final ToolBar toolBar = new ToolBar();
+        toolBar.add(new LabelToolItem(viewContext.getMessage(Dict.CUSTOM_IMPORT)
+                + GenericConstants.LABEL_SEPARATOR));
+        toolBar.add(customImportTypeSelectionWidget);
+        return toolBar;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/CustomImportTypeSelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/CustomImportTypeSelectionWidget.java
new file mode 100644
index 0000000000000000000000000000000000000000..647cdf67e3a2d65caab9bc1eacfef988798306d0
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/CustomImportTypeSelectionWidget.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 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.client.web.client.application.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.ModelDataPropertyNames;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.SimplifiedBaseModelData;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.renderer.TooltipRenderer;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.CustomImportTypeSelectionWidget.CustomImportModelData;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.DropDownList;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.GWTUtils;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImport;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class CustomImportTypeSelectionWidget extends
+        DropDownList<CustomImportModelData, CustomImport>
+{
+    public static final String SUFFIX = "custom-import";
+
+    private IViewContext<?> viewContext;
+
+    public CustomImportTypeSelectionWidget(final IViewContext<?> viewContext,
+            final String idSuffix, final String initialCodeOrNullParameter)
+    {
+        super(viewContext, SUFFIX + idSuffix, Dict.CUSTOM_IMPORT, ModelDataPropertyNames.NAME,
+                "custom import", "custom import types");
+        this.viewContext = viewContext;
+        setAutoSelectFirst(false);
+        setTemplate(GWTUtils.getTooltipTemplate(ModelDataPropertyNames.NAME,
+                ModelDataPropertyNames.TOOLTIP));
+    }
+
+    public DatabaseModificationKind[] getRelevantModifications()
+    {
+        return new DatabaseModificationKind[] {};
+    }
+
+    @Override
+    protected void loadData(AbstractAsyncCallback<List<CustomImport>> callback)
+    {
+        viewContext.getCommonService().getCustomImports(callback);
+        callback.ignore();
+    }
+
+    @Override
+    protected List<CustomImportModelData> convertItems(List<CustomImport> items)
+    {
+        List<CustomImportModelData> results = new ArrayList<CustomImportModelData>();
+        for (CustomImport sp : items)
+        {
+            results.add(new CustomImportModelData(sp));
+        }
+        return results;
+    }
+
+    public static class CustomImportModelData extends SimplifiedBaseModelData
+    {
+        private static final long serialVersionUID = 1L;
+
+        public CustomImportModelData(final CustomImport customImport)
+        {
+            String customImportKey = customImport.getCode();
+            String customImportName =
+                    getProperty(customImport, CustomImport.PropertyNames.NAME.getName(),
+                            customImportKey);
+            set(ModelDataPropertyNames.CODE, customImportKey);
+            set(ModelDataPropertyNames.NAME, customImportName);
+            set(ModelDataPropertyNames.OBJECT, customImport);
+            set(ModelDataPropertyNames.TOOLTIP,
+                    TooltipRenderer.renderAsTooltip(
+                            customImportName,
+                            getProperty(customImport,
+                                    CustomImport.PropertyNames.DESCRIPTION.getName(), null)));
+        }
+
+        private static String getProperty(CustomImport customImport, String propName, String defVal)
+        {
+            String value = customImport.getProperties().get(propName);
+
+            return value == null ? defVal == null ? null : defVal : value;
+        }
+    }
+
+    /**
+     * Returns the {@link CustomImport} currently selected.
+     * 
+     * @return <code>null</code> if nothing is selected yet.
+     */
+    public CustomImport tryGetSelectedCustomImport()
+    {
+        return super.tryGetSelected();
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/ApplicationInfo.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/ApplicationInfo.java
index 10de72714e293ed8a4fcf50dd2d324bc48449af1..cb693b2988bf7731749b30e0a06be392b6f26046 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/ApplicationInfo.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/ApplicationInfo.java
@@ -16,11 +16,14 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.dto;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 import com.google.gwt.user.client.rpc.IsSerializable;
 
 import ch.systemsx.cisd.openbis.generic.shared.basic.annotation.DoNotEscape;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImport;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.WebClientConfiguration;
 
 /**
@@ -45,6 +48,8 @@ public final class ApplicationInfo implements IsSerializable
 
     private int maxResults = 100000;
 
+    private List<CustomImport> customImports;
+
     public int getMaxResults()
     {
         return maxResults;
@@ -118,4 +123,19 @@ public final class ApplicationInfo implements IsSerializable
         this.disabledTechnologies = disabledTechnologies;
     }
 
+    public void setCustomImports(List<CustomImport> customImports)
+    {
+        if (customImports == null)
+        {
+            this.customImports = new ArrayList<CustomImport>();
+        } else
+        {
+            this.customImports = customImports;
+        }
+    }
+
+    public List<CustomImport> getCustomImports()
+    {
+        return customImports;
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/SampleUpdates.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/SampleUpdates.java
index f80704cefd65ffb29736db71f4c9f24fc0096fa4..4a328d3bdd86ffb78acc287a831fa367d65bff63 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/SampleUpdates.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/SampleUpdates.java
@@ -50,10 +50,6 @@ public class SampleUpdates extends BasicSampleUpdates
         this.sampleIdentifier = sampleIdentifier;
     }
 
-    public SampleUpdates()
-    {
-    }
-
     public SampleUpdates(String sessionKey, TechId sampleId, List<IEntityProperty> properties,
             List<NewAttachment> attachments, ExperimentIdentifier experimentIdentifierOrNull,
             Date version, String sampleIdentifier, String containerIdentifierOrNull,
@@ -66,6 +62,10 @@ public class SampleUpdates extends BasicSampleUpdates
         this.sampleIdentifier = sampleIdentifier;
     }
 
+    public SampleUpdates()
+    {
+    }
+
     public String getSessionKey()
     {
         return sessionKey;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/AbstractClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/AbstractClientService.java
index d8b86a8ce45e376414a90733d4a3698264aa558f..6adab709c4676526ad5225b9d98c02bff4a8a67f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/AbstractClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/AbstractClientService.java
@@ -17,9 +17,12 @@
 package ch.systemsx.cisd.openbis.generic.client.web.server;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
@@ -34,6 +37,8 @@ import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.servlet.IRequestContextProvider;
 import ch.systemsx.cisd.common.spring.ExposablePropertyPlaceholderConfigurer;
+import ch.systemsx.cisd.common.utilities.PropertyParametersUtil;
+import ch.systemsx.cisd.common.utilities.PropertyParametersUtil.SectionProperties;
 import ch.systemsx.cisd.openbis.BuildAndEnvironmentInfo;
 import ch.systemsx.cisd.openbis.generic.client.web.client.IClientService;
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientService;
@@ -68,6 +73,7 @@ import ch.systemsx.cisd.openbis.generic.shared.IServer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImport;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DisplaySettings;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomColumn;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityPropertiesHolder;
@@ -434,11 +440,38 @@ public abstract class AbstractClientService implements IClientService,
         }
         applicationInfo.setDisabledTechnologies(ServerUtils.extractSet(getServiceProperties()
                 .getProperty("disabled-technologies")));
+        applicationInfo.setCustomImports(extractCustomImportProperties());
         applicationInfo.setArchivingConfigured(isArchivingConfigured());
         applicationInfo.setVersion(getVersion());
         return applicationInfo;
     }
 
+    private List<CustomImport> extractCustomImportProperties()
+    {
+        List<CustomImport> results = new ArrayList<CustomImport>();
+
+        SectionProperties[] sectionProperties =
+                PropertyParametersUtil.extractSectionProperties(getServiceProperties(),
+                        CustomImport.PropertyNames.CUSTOM_IMPORTS.getName(), false);
+
+        for (SectionProperties props : sectionProperties)
+        {
+            Map<String, String> properties = new HashMap<String, String>();
+            for (Map.Entry<Object, Object> entry : props.getProperties().entrySet())
+            {
+                properties.put((String) entry.getKey(), (String) entry.getValue());
+            }
+            results.add(new CustomImport(props.getKey(), properties));
+        }
+
+        return results;
+    }
+
+    public final List<CustomImport> getCustomImports()
+    {
+        return extractCustomImportProperties();
+    }
+
     protected WebClientConfiguration getWebClientConfiguration()
     {
         return webClientConfigurationProvider.getWebClientConfiguration();
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
index 2e212e17303b2321f8cdaffe353c7ddd96ac627e..002d4be5d44d277d1e52204a4a95eae45cf7ba47 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
@@ -29,7 +29,10 @@ import java.util.Set;
 
 import javax.servlet.http.HttpSession;
 
+import org.apache.commons.io.FileUtils;
+
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.common.io.DelegatedReader;
 import ch.systemsx.cisd.common.parser.AbstractParserObjectFactory;
 import ch.systemsx.cisd.common.parser.IParserObjectFactory;
@@ -118,6 +121,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicProjectIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchOperationKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Code;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelatedEntities;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelationshipRole;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
@@ -2266,4 +2270,71 @@ public final class CommonClientService extends AbstractClientService implements
                 forceDisallowedTypes);
     }
 
+    public String performCustomImport(String sessionKey, String customImportCode)
+    {
+        HttpSession httpSession = getHttpSession();
+        UploadedFilesBean uploadedFiles = null;
+        try
+        {
+            uploadedFiles = (UploadedFilesBean) httpSession.getAttribute(sessionKey);
+            abortIfMaxSizeExceeded(uploadedFiles);
+            return commonServer.performCustomImport(getSessionToken(), customImportCode,
+                    getCustomImportFile(uploadedFiles));
+        } catch (final UserFailureException e)
+        {
+            throw UserFailureExceptionTranslator.translate(e);
+        } finally
+        {
+            if (uploadedFiles != null)
+            {
+                uploadedFiles.deleteTransferredFiles();
+            }
+            if (httpSession != null)
+            {
+                httpSession.removeAttribute(sessionKey);
+            }
+        }
+    }
+
+    private static void abortIfMaxSizeExceeded(UploadedFilesBean uploadedFiles)
+    {
+        if (uploadedFiles != null)
+        {
+            for (final IUncheckedMultipartFile multipartFile : uploadedFiles.iterable())
+            {
+                long fileSize = multipartFile.getSize();
+                if (fileSize > FileUtils.ONE_GB)
+                {
+                    String maxSizeString = FileUtilities.byteCountToDisplaySize(FileUtils.ONE_GB);
+                    String fileSizeString = FileUtilities.byteCountToDisplaySize(fileSize);
+                    String errorMessage =
+                            String.format("The file %s(%s) is larger than the maximum (%s).",
+                                    multipartFile.getOriginalFilename(), fileSizeString,
+                                    maxSizeString);
+                    throw new UserFailureException(errorMessage);
+                }
+            }
+        }
+    }
+
+    private static CustomImportFile getCustomImportFile(UploadedFilesBean uploadedFiles)
+    {
+        if (uploadedFiles != null)
+        {
+            if (uploadedFiles.size() != 1)
+            {
+                throw new UserFailureException(String.format(
+                        "Expecting exactly one file, but %s found.", uploadedFiles.size()));
+            }
+            for (final IUncheckedMultipartFile multipartFile : uploadedFiles.iterable())
+            {
+                final String fileName = multipartFile.getOriginalFilename();
+                // NOTE: this will load the entire attachments in memory
+                final byte[] content = multipartFile.getBytes();
+                return new CustomImportFile(fileName, content);
+            }
+        }
+
+        return null;
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java
index da068ab8eacaf9fbe6f13fe630b31e5373f03478..af9c2d6ff3fc2b5ef0f86359a82a0a6a05c315eb 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java
@@ -45,6 +45,7 @@ import ch.systemsx.cisd.common.mail.IMailClient;
 import ch.systemsx.cisd.common.mail.MailClient;
 import ch.systemsx.cisd.common.mail.MailClientParameters;
 import ch.systemsx.cisd.common.spring.AbstractServiceWithLogger;
+import ch.systemsx.cisd.common.spring.ExposablePropertyPlaceholderConfigurer;
 import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
 import ch.systemsx.cisd.openbis.generic.server.business.PropertiesBatchManager;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.DataSetTable;
@@ -142,6 +143,9 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp
     @Resource(name = ResourceNames.MAIL_CLIENT_PARAMETERS)
     protected MailClientParameters mailClientParameters;
 
+    @Resource(name = ExposablePropertyPlaceholderConfigurer.PROPERTY_CONFIGURER_BEAN_NAME)
+    protected ExposablePropertyPlaceholderConfigurer configurer;
+
     private IPropertiesBatchManager propertiesBatchManager;
 
     private String userForAnonymousLogin;
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 2fb44513077a43248a9d79d46f71836d870a6b6c..adf146888f2ebbbc3fe52097665e69ef7dbd0204 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
@@ -23,6 +23,7 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.AuthorizationGroupBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.CorePluginTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.DataBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.DataSetTable;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.DataStoreBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.DeletedDataSetTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.DeletionTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.EntityTypeBO;
@@ -38,6 +39,7 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObject
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ICorePluginTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataSetTable;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataStoreBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDeletedDataSetTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDeletionTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IEntityTypeBO;
@@ -242,4 +244,8 @@ public final class CommonBusinessObjectFactory extends AbstractBusinessObjectFac
         return new CorePluginTable(getDaoFactory(), session, masterDataScriptRunner);
     }
 
+    public IDataStoreBO createDataStoreBO(Session session)
+    {
+        return new DataStoreBO(getDaoFactory(), session, getDSSFactory());
+    }
 }
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 a16b978087dbd415918283ad2150f6fc1e0928c1..070e2010de03c34aac3751757c08d5da2c16c649 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
@@ -38,6 +38,8 @@ import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.spring.IInvocationLoggerContext;
+import ch.systemsx.cisd.common.utilities.PropertyParametersUtil;
+import ch.systemsx.cisd.common.utilities.PropertyParametersUtil.SectionProperties;
 import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.DataAccessExceptionTranslator;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.EntityTypeBO;
@@ -47,6 +49,7 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObject
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ICorePluginTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataSetTable;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataStoreBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDeletedDataSetTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDeletionTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IEntityTypeBO;
@@ -103,6 +106,8 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchOperationKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Code;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CorePlugin;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImport;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSet;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelatedEntities;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelationshipRole;
@@ -2640,4 +2645,34 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
                 new SearchHelper(session, businessObjectFactory, getDAOFactory());
         return searchHelper.searchForMaterials(criteria);
     }
+
+    public String performCustomImport(String sessionToken, String customImportCode,
+            CustomImportFile customImportFile)
+    {
+        Session session = getSession(sessionToken);
+
+        SectionProperties[] sectionProperties =
+                PropertyParametersUtil.extractSectionProperties(configurer.getResolvedProps(),
+                        CustomImport.PropertyNames.CUSTOM_IMPORTS.getName(), false);
+
+        for (SectionProperties props : sectionProperties)
+        {
+            if (props.getKey().equals(customImportCode))
+            {
+                String dssCode =
+                        props.getProperties().getProperty(
+                                CustomImport.PropertyNames.DATASTORE_CODE.getName());
+                String dropboxName =
+                        props.getProperties().getProperty(
+                                CustomImport.PropertyNames.DROPBOX_NAME.getName());
+                IDataStoreBO dataStore = businessObjectFactory.createDataStoreBO(session);
+                dataStore.loadByCode(dssCode);
+                dataStore.uploadFile(dropboxName, customImportFile);
+                return customImportFile.getFileName();
+            }
+        }
+
+        throw new UserFailureException(String.format("Cannot upload file '%s' to the dss.",
+                customImportFile.getFileName()));
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
index 54b78475737adb2921e5286d8a47ab45d517ac8b..6aebf240e38bdfec52f0511829fdc72803cbc126 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
@@ -36,6 +36,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AuthorizationGroupUpdat
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchOperationKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CorePlugin;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelatedEntities;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelationshipRole;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
@@ -1227,4 +1228,12 @@ final class CommonServerLogger extends AbstractServerLogger implements ICommonSe
         return null;
     }
 
+    public String performCustomImport(String sessionToken, String customImportCode,
+            CustomImportFile customImportFile)
+    {
+        logAccess(sessionToken, "performCustomImport",
+                "CUSTOM_IMPORT_CODE(%s), CUSTOM_IMPORT_FILE(%s)", customImportCode,
+                customImportFile);
+        return null;
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataStoreBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataStoreBO.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6762ea24b78c4edefa10e33527c6eb3d6a30023
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataStoreBO.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012 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.server.business.IDataStoreServiceFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class DataStoreBO implements IDataStoreBO
+{
+    private IDAOFactory daoFactory;
+
+    private Session session;
+
+    private IDataStoreServiceFactory dssFactory;
+
+    private DataStorePE dataStore;
+
+    public DataStoreBO(IDAOFactory daoFactory, Session session, IDataStoreServiceFactory dssFactory)
+    {
+        this.daoFactory = daoFactory;
+        this.session = session;
+        this.dssFactory = dssFactory;
+    }
+
+    public void loadByCode(String dssCode)
+    {
+        this.dataStore = daoFactory.getDataStoreDAO().tryToFindDataStoreByCode(dssCode);
+    }
+
+    public void uploadFile(String dropboxName, CustomImportFile customImportFile)
+    {
+        assert dataStore != null : "data store not loaded.";
+
+        IDataStoreService service = dssFactory.create(dataStore.getRemoteUrl());
+        service.putDataSet(session.getSessionToken(), dropboxName, customImportFile);
+    }
+}
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 4fbea155413b36045efced9be7cc932fe25b0e2d..abed0522e86c000df2f6561bd9083b0b96f72eb1 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
@@ -80,6 +80,8 @@ public interface ICommonBusinessObjectFactory extends IAbstractBussinessObjectFa
     public ICorePluginTable createCorePluginTable(Session session,
             IMasterDataScriptRegistrationRunner masterDataScriptRunner);
 
+    public IDataStoreBO createDataStoreBO(Session session);
+
     // Fast listing operations
     public ISampleLister createSampleLister(Session session);
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataStoreBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataStoreBO.java
new file mode 100644
index 0000000000000000000000000000000000000000..0058fc6806838101a11fc7a8d6bafedc94bf6f9d
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataStoreBO.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012 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.basic.dto.CustomImportFile;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public interface IDataStoreBO
+{
+    void loadByCode(String dssCode);
+
+    public void uploadFile(String dropBoxName, CustomImportFile customImportFile);
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
index f3d96d40700754f255535a93b370b25bdb16255f..fc09df9995adc2bb391fe06d5ec045721f4d1bae 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
@@ -65,6 +65,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AuthorizationGroup;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AuthorizationGroupUpdates;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchOperationKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelatedEntities;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelationshipRole;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
@@ -266,8 +267,11 @@ public interface ICommonServer extends IServer
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.ROLE_ASSIGNMENT)
-    public void registerSpaceRole(String sessionToken, RoleCode roleCode,
-            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier identifier, Grantee grantee);
+    public void registerSpaceRole(
+            String sessionToken,
+            RoleCode roleCode,
+            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier identifier,
+            Grantee grantee);
 
     /**
      * Registers a new instance role.
@@ -283,8 +287,11 @@ public interface ICommonServer extends IServer
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.ROLE_ASSIGNMENT)
-    public void deleteSpaceRole(String sessionToken, RoleCode roleCode,
-            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier identifier, Grantee grantee);
+    public void deleteSpaceRole(
+            String sessionToken,
+            RoleCode roleCode,
+            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier identifier,
+            Grantee grantee);
 
     /**
      * Deletes role described by given role code and user id.
@@ -311,7 +318,8 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     @ReturnValueFilter(validatorClass = SampleValidator.class)
-    public List<Sample> listSamples(final String sessionToken,
+    public List<Sample> listSamples(
+            final String sessionToken,
             @AuthorizationGuard(guardClass = ListSampleCriteriaPredicate.class) final ListSampleCriteria criteria);
 
     /**
@@ -321,7 +329,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperiments(final String sessionToken,
+    public List<Experiment> listExperiments(
+            final String sessionToken,
             ExperimentType experimentType,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier project);
 
@@ -332,7 +341,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperimentsHavingDataSets(final String sessionToken,
+    public List<Experiment> listExperimentsHavingDataSets(
+            final String sessionToken,
             ExperimentType experimentType,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier project);
 
@@ -343,7 +353,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperimentsHavingSamples(final String sessionToken,
+    public List<Experiment> listExperimentsHavingSamples(
+            final String sessionToken,
             ExperimentType experimentType,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier project);
 
@@ -365,7 +376,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperiments(final String sessionToken,
+    public List<Experiment> listExperiments(
+            final String sessionToken,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) List<ExperimentIdentifier> experimentIdentifiers);
 
     /**
@@ -376,7 +388,8 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     public List<ExternalData> listSampleExternalData(final String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) final TechId sampleId, final boolean showOnlyDirectlyConnected);
+            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) final TechId sampleId,
+            final boolean showOnlyDirectlyConnected);
 
     /**
      * For given experiment {@link TechId} returns the corresponding list of {@link ExternalData}.
@@ -385,8 +398,10 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<ExternalData> listExperimentExternalData(final String sessionToken,
-            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) final TechId experimentId, boolean showOnlyDirectlyConnected);
+    public List<ExternalData> listExperimentExternalData(
+            final String sessionToken,
+            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) final TechId experimentId,
+            boolean showOnlyDirectlyConnected);
 
     /**
      * For given data set {@link TechId} in given relationship <var>role</var> returns corresponding
@@ -397,7 +412,8 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     public List<ExternalData> listDataSetRelationships(final String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) final TechId datasetId, final DataSetRelationshipRole role);
+            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) final TechId datasetId,
+            final DataSetRelationshipRole role);
 
     /**
      * Performs an <i>Hibernate Search</i> based on given parameters.
@@ -568,7 +584,8 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value = ObjectKind.PROJECT)
     @Capability("DELETE_PROJECT")
     public void deleteProjects(String sessionToken,
-            @AuthorizationGuard(guardClass = ProjectTechIdPredicate.class) List<TechId> projectIds, String reason);
+            @AuthorizationGuard(guardClass = ProjectTechIdPredicate.class) List<TechId> projectIds,
+            String reason);
 
     /**
      * Deletes specified spaces.
@@ -577,7 +594,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.INSTANCE_ADMIN)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.SPACE)
     public void deleteSpaces(String sessionToken,
-            @AuthorizationGuard(guardClass = SpaceTechIdPredicate.class) List<TechId> spaceIds, String reason);
+            @AuthorizationGuard(guardClass = SpaceTechIdPredicate.class) List<TechId> spaceIds,
+            String reason);
 
     /**
      * Deletes specified scripts.
@@ -643,9 +661,10 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.PROJECT)
     @Capability("REGISTER_PROJECT")
-    public void registerProject(String sessionToken,
-            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier projectIdentifier, String description, String leaderId,
-            Collection<NewAttachment> attachments);
+    public void registerProject(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier projectIdentifier,
+            String description, String leaderId, Collection<NewAttachment> attachments);
 
     /**
      * Performs an <i>Hibernate Search</i> based on given parameters.
@@ -670,7 +689,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     @Capability("WRITE_DATASET")
-    public DataSetUpdateResult updateDataSet(String sessionToken,
+    public DataSetUpdateResult updateDataSet(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DataSetUpdatesPredicate.class) DataSetUpdatesDTO updates);
 
     /**
@@ -801,8 +821,9 @@ public interface ICommonServer extends IServer
         { ObjectKind.DATA_SET, ObjectKind.DELETION })
     @Capability("DELETE_DATASET")
     public void deleteDataSets(String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes, String reason, DeletionType type,
-            boolean forceNotExistingLocations, boolean isTrashEnabled);
+            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes,
+            String reason, DeletionType type, boolean forceNotExistingLocations,
+            boolean isTrashEnabled);
 
     /**
      * Deletes/Trashes specified data sets. It CAN delete data sets with deletion_disallow flag set
@@ -815,8 +836,9 @@ public interface ICommonServer extends IServer
         { ObjectKind.DATA_SET, ObjectKind.DELETION })
     @Capability("FORCE_DELETE_DATASET")
     public void deleteDataSetsForced(String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes, String reason, DeletionType type,
-            boolean forceNotExistingLocations, boolean isTrashEnabled);
+            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes,
+            String reason, DeletionType type, boolean forceNotExistingLocations,
+            boolean isTrashEnabled);
 
     /**
      * Deletes/Trashes specified samples.
@@ -826,8 +848,10 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value =
         { ObjectKind.SAMPLE, ObjectKind.DELETION })
     @Capability("DELETE_SAMPLE")
-    public void deleteSamples(String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdCollectionPredicate.class) List<TechId> sampleIds, String reason, DeletionType type);
+    public void deleteSamples(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = SampleTechIdCollectionPredicate.class) List<TechId> sampleIds,
+            String reason, DeletionType type);
 
     /**
      * Deletes/Trashes specified experiments.
@@ -837,8 +861,10 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value =
         { ObjectKind.EXPERIMENT, ObjectKind.DELETION })
     @Capability("DELETE_EXPERIMENT")
-    public void deleteExperiments(String sessionToken,
-            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) List<TechId> experimentIds, String reason, DeletionType deletionType);
+    public void deleteExperiments(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) List<TechId> experimentIds,
+            String reason, DeletionType deletionType);
 
     /**
      * Deletes specified attachments (all versions with given file names) of specified experiment.
@@ -848,7 +874,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.EXPERIMENT)
     @Capability("DELETE_EXPERIMENT_ATTACHMENT")
     public void deleteExperimentAttachments(String sessionToken,
-            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId experimentId, List<String> fileNames, String reason);
+            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId experimentId,
+            List<String> fileNames, String reason);
 
     /**
      * Deletes specified attachments (all versions with given file names) of specified sample.
@@ -858,7 +885,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
     @Capability("DELETE_SAMPLE_ATTACHMENT")
     public void deleteSampleAttachments(String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId sampleId, List<String> fileNames, String reason);
+            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId sampleId,
+            List<String> fileNames, String reason);
 
     /**
      * Deletes specified attachments (all versions with given file names) of specified project.
@@ -868,7 +896,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.PROJECT)
     @Capability("DELETE_PROJECT_ATTACHMENT")
     public void deleteProjectAttachments(String sessionToken,
-            @AuthorizationGuard(guardClass = ProjectTechIdPredicate.class) TechId projectId, List<String> fileNames, String reason);
+            @AuthorizationGuard(guardClass = ProjectTechIdPredicate.class) TechId projectId,
+            List<String> fileNames, String reason);
 
     /**
      * Returns all attachments (all versions) of specified experiment.
@@ -945,7 +974,8 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     public SampleParentWithDerived getSampleInfo(final String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) final TechId sampleId) throws UserFailureException;
+            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) final TechId sampleId)
+            throws UserFailureException;
 
     /**
      * Saves changed sample.
@@ -962,7 +992,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public Experiment getExperimentInfo(String sessionToken,
+    public Experiment getExperimentInfo(
+            String sessionToken,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ExperimentIdentifier identifier);
 
     /**
@@ -981,7 +1012,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value =
         { ObjectKind.EXPERIMENT, ObjectKind.SAMPLE })
     @Capability("WRITE_EXPERIMENT_SAMPLE")
-    public ExperimentUpdateResult updateExperiment(String sessionToken,
+    public ExperimentUpdateResult updateExperiment(
+            String sessionToken,
             @AuthorizationGuard(guardClass = ExperimentUpdatesPredicate.class) ExperimentUpdatesDTO updates);
 
     /**
@@ -998,7 +1030,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public Project getProjectInfo(String sessionToken,
+    public Project getProjectInfo(
+            String sessionToken,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier projectIdentifier);
 
     /**
@@ -1015,7 +1048,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.PROJECT)
     @Capability("WRITE_PROJECT")
-    public Date updateProject(String sessionToken,
+    public Date updateProject(
+            String sessionToken,
             @AuthorizationGuard(guardClass = ProjectUpdatesPredicate.class) ProjectUpdatesDTO updates);
 
     /**
@@ -1196,7 +1230,8 @@ public interface ICommonServer extends IServer
 
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public TableModel createReportFromDatasets(String sessionToken,
+    public TableModel createReportFromDatasets(
+            String sessionToken,
             DatastoreServiceDescription serviceDescription,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
@@ -1207,7 +1242,8 @@ public interface ICommonServer extends IServer
 
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
-    public void processDatasets(String sessionToken,
+    public void processDatasets(
+            String sessionToken,
             DatastoreServiceDescription serviceDescription,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
@@ -1222,8 +1258,10 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     @Capability("ARCHIVE_DATASET")
-    public int archiveDatasets(String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes, boolean removeFromDataStore);
+    public int archiveDatasets(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes,
+            boolean removeFromDataStore);
 
     /**
      * Schedules unarchiving of specified data sets.
@@ -1234,7 +1272,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     @Capability("UNARCHIVE_DATASET")
-    public int unarchiveDatasets(String sessionToken,
+    public int unarchiveDatasets(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
     /**
@@ -1245,7 +1284,8 @@ public interface ICommonServer extends IServer
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
-    public int lockDatasets(String sessionToken,
+    public int lockDatasets(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
     /**
@@ -1256,7 +1296,8 @@ public interface ICommonServer extends IServer
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
-    public int unlockDatasets(String sessionToken,
+    public int unlockDatasets(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
     /**
@@ -1322,7 +1363,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.GRID_CUSTOM_FILTER)
     @Capability("DELETE_FILTER")
-    public void deleteFilters(String sessionToken,
+    public void deleteFilters(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DeleteGridCustomFilterPredicate.class) List<TechId> filterIds);
 
     /**
@@ -1332,7 +1374,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.GRID_CUSTOM_FILTER)
     @Capability("WRITE_FILTER")
-    public void updateFilter(String sessionToken,
+    public void updateFilter(
+            String sessionToken,
             @AuthorizationGuard(guardClass = UpdateGridCustomFilterPredicate.class) IExpressionUpdates updates);
 
     // columns
@@ -1361,7 +1404,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.GRID_CUSTOM_COLUMN)
     @Capability("DELETE_CUSTOM_COLUMN")
-    public void deleteGridCustomColumns(String sessionToken,
+    public void deleteGridCustomColumns(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DeleteGridCustomColumnPredicate.class) List<TechId> columnIds);
 
     /**
@@ -1371,7 +1415,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.GRID_CUSTOM_COLUMN)
     @Capability("WRITE_CUSTOM_COLUMN")
-    public void updateGridCustomColumn(String sessionToken,
+    public void updateGridCustomColumn(
+            String sessionToken,
             @AuthorizationGuard(guardClass = UpdateGridCustomColumnPredicate.class) IExpressionUpdates updates);
 
     /**
@@ -1467,7 +1512,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     @Capability("WRITE_DATASET_PROPERTIES")
     public void updateDataSetProperties(String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId entityId, List<PropertyUpdates> modifiedProperties);
+            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId entityId,
+            List<PropertyUpdates> modifiedProperties);
 
     /**
      * Updates properties of an experiment with given id.
@@ -1477,7 +1523,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.EXPERIMENT)
     @Capability("WRITE_EXPERIMENT_PROPERTIES")
     public void updateExperimentProperties(String sessionToken,
-            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId entityId, List<PropertyUpdates> modifiedProperties);
+            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId entityId,
+            List<PropertyUpdates> modifiedProperties);
 
     /**
      * Updates properties of a sample with given id.
@@ -1487,7 +1534,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
     @Capability("WRITE_SAMPLE_PROPERTIES")
     public void updateSampleProperties(String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId entityId, List<PropertyUpdates> modifiedProperties);
+            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId entityId,
+            List<PropertyUpdates> modifiedProperties);
 
     /**
      * Updates properties of a material with given id.
@@ -1518,7 +1566,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value =
         { ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     @Capability("RESTORE")
-    public void revertDeletions(final String sessionToken,
+    public void revertDeletions(
+            final String sessionToken,
             @AuthorizationGuard(guardClass = RevertDeletionPredicate.class) final List<TechId> deletionIds);
 
     /**
@@ -1531,8 +1580,10 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value =
         { ObjectKind.DELETION, ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     @Capability("PURGE")
-    public void deletePermanently(final String sessionToken,
-            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds, boolean forceNotExistingLocations);
+    public void deletePermanently(
+            final String sessionToken,
+            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds,
+            boolean forceNotExistingLocations);
 
     /**
      * Permanently deletes entities moved to trash in specified deletions. It CAN delete data sets
@@ -1544,8 +1595,10 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value =
         { ObjectKind.DELETION, ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     @Capability("FORCE_PURGE")
-    public void deletePermanentlyForced(final String sessionToken,
-            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds, boolean forceNotExistingLocations);
+    public void deletePermanentlyForced(
+            final String sessionToken,
+            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds,
+            boolean forceNotExistingLocations);
 
     /**
      * Performs an <i>Hibernate Search</i> based on given parameters.
@@ -1554,4 +1607,11 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     public List<Material> searchForMaterials(String sessionToken, DetailedSearchCriteria criteria);
 
+    /**
+     * Performs an import of file to the dss.
+     */
+    @Transactional
+    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    public String performCustomImport(String sessionToken, String customImportCode,
+            CustomImportFile customImportFile) throws UserFailureException;
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
index dc8a8cbe1bf94830b910b0f25dab51f9834e8d76..a89aa38fa135acefbdb9e49985a99fd2fd30a3b8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
@@ -20,6 +20,7 @@ import java.util.List;
 import java.util.Map;
 
 import ch.systemsx.cisd.common.exceptions.InvalidAuthenticationException;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IDatasetLocation;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LinkModel;
@@ -145,6 +146,9 @@ public interface IDataStoreService
      * @return A TableModel produced by the service.
      * @since 7
      */
-    public TableModel createReportFromAggregationService(String sessionToken, String userSessionToken,
-            String serviceKey, Map<String, Object> parameters);
+    public TableModel createReportFromAggregationService(String sessionToken,
+            String userSessionToken, String serviceKey, Map<String, Object> parameters);
+
+    public String putDataSet(String sessionToken, String dropboxName,
+            CustomImportFile customImportFile);
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/CustomImport.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/CustomImport.java
new file mode 100644
index 0000000000000000000000000000000000000000..a506cadf0a18b70cb693ab9b9819d0675fb6da9d
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/CustomImport.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 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.shared.basic.dto;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class CustomImport implements Serializable
+{
+    private static final long serialVersionUID = ServiceVersionHolder.VERSION;
+
+    public static enum PropertyNames
+    {
+        CUSTOM_IMPORTS("custom-imports"), NAME("name"), DATASTORE_CODE("dss-code"), DROPBOX_NAME(
+                "dropbox-name"), DESCRIPTION("description");
+
+        private final String name;
+
+        private PropertyNames(String name)
+        {
+            this.name = name;
+        }
+
+        public String getName()
+        {
+            return this.name;
+        }
+    }
+
+    private String code;
+
+    private Map<String, String> properties;
+
+    public CustomImport()
+    {
+    }
+
+    public CustomImport(String code, Map<String, String> properties)
+    {
+        this.code = code;
+        this.properties = properties;
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public void setCode(String name)
+    {
+        this.code = name;
+    }
+
+    public Map<String, String> getProperties()
+    {
+        return properties;
+    }
+
+    public void setProperties(Map<String, String> properties)
+    {
+        this.properties = properties;
+    }
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/CustomImportFile.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/CustomImportFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a5bcf21e9893842fbb9b7983e2daf2a25ff95b8
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/CustomImportFile.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012 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.shared.basic.dto;
+
+import java.io.Serializable;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class CustomImportFile implements Serializable
+{
+    private static final long serialVersionUID = ServiceVersionHolder.VERSION;
+
+    private String fileName;
+
+    private byte[] bytes;
+
+    public CustomImportFile(String fileName, byte[] bytes)
+    {
+        this.fileName = fileName;
+        this.bytes = bytes;
+    }
+
+    @SuppressWarnings("unused")
+    private CustomImportFile()
+    {
+    }
+
+    public String getFileName()
+    {
+        return fileName;
+    }
+
+    public void setFileName(String fileName)
+    {
+        this.fileName = fileName;
+    }
+
+    public byte[] getBytes()
+    {
+        return bytes;
+    }
+
+    public void setBytes(byte[] bytes)
+    {
+        this.bytes = bytes;
+    }
+
+    @Override
+    public String toString()
+    {
+        return fileName;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/AuthorizationGroupPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/AuthorizationGroupPE.java
index 1a7e84b15e1e3f4aa922bdc60c422a9f01bf8529..d26ecedf4f8e8d122fe7f8e2c796ff1730cfa11e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/AuthorizationGroupPE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/AuthorizationGroupPE.java
@@ -66,7 +66,7 @@ public class AuthorizationGroupPE extends HibernateAbstractRegistrationHolder im
 {
     private static final long serialVersionUID = IServer.VERSION;
 
-    private transient Long id;
+    private Long id;
 
     private DatabaseInstancePE databaseInstance;
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/CustomImportForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/CustomImportForm.java
new file mode 100644
index 0000000000000000000000000000000000000000..9463bbb232203561fca64d93519c6b7d59fac226
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/CustomImportForm.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 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.plugin.generic.client.web.client.application;
+
+import static ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.DatabaseModificationAwareField.wrapUnaware;
+
+import com.extjs.gxt.ui.client.event.Events;
+import com.extjs.gxt.ui.client.widget.form.Field;
+import com.extjs.gxt.ui.client.widget.form.FileUploadField;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.FormPanelListener;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.AbstractRegistrationForm;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.file.BasicFileFieldManager;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class CustomImportForm extends AbstractRegistrationForm
+{
+    private static final String FIELD_LABEL_TEMPLATE = "File";
+
+    private static final int NUMBER_OF_FIELDS = 1;
+
+    private final String sessionKey;
+
+    private final String customImportCode;
+
+    private final IViewContext<ICommonClientServiceAsync> viewContext;
+
+    private final BasicFileFieldManager fileFieldsManager;
+
+    /**
+     * @param viewContext
+     * @param id
+     */
+    public CustomImportForm(IViewContext<ICommonClientServiceAsync> viewContext, String id,
+            String customImportCode)
+    {
+        super(viewContext, id);
+
+        this.sessionKey = id + "-" + customImportCode;
+        this.customImportCode = customImportCode;
+        this.viewContext = viewContext;
+
+        fileFieldsManager =
+                new BasicFileFieldManager(sessionKey, NUMBER_OF_FIELDS, FIELD_LABEL_TEMPLATE);
+        fileFieldsManager.setMandatory();
+        for (FileUploadField field : fileFieldsManager.getFields())
+        {
+            formPanel.add(wrapUnaware((Field<?>) field).get());
+        }
+        addUploadFeatures(sessionKey);
+
+        formPanel.addListener(Events.Submit, new FormPanelListener(infoBox)
+            {
+                @Override
+                protected void setUploadEnabled()
+                {
+                    CustomImportForm.this.setUploadEnabled(true);
+                }
+
+                @Override
+                protected void onSuccessfullUpload()
+                {
+                    CustomImportForm.this.viewContext.getCommonService().performCustomImport(
+                            sessionKey,
+                            CustomImportForm.this.customImportCode,
+                            new AbstractRegistrationCallback<String>(
+                                    CustomImportForm.this.viewContext)
+                                {
+                                    @Override
+                                    protected String createSuccessfullRegistrationInfo(String result)
+                                    {
+                                        return result
+                                                + " succesfully uploaded to the datastore server.";
+                                    }
+                                });
+                    for (FileUploadField field : fileFieldsManager.getFields())
+                    {
+                        field.clear();
+                    }
+                    setUploadEnabled();
+                }
+            });
+    }
+
+    @Override
+    protected void submitValidForm()
+    {
+        CustomImportForm.this.setUploadEnabled(false);
+        formPanel.submit();
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
index 1ec3a0de3ba70ab5c6ff60ff7b957ef9224b76d9..c79c1c5e830391feb87eaf7de40fce75b435dbb9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
@@ -475,6 +475,8 @@ var common = {
   ARCHIVING_MENU_UNLOCK: "Enable",
   
   GENERAL_IMPORT_MENU: "General Batch Import",
+  
+  CUSTOM_IMPORT_MENU: "Custom Import",
   
   menu_modules: "Utilities",
     
@@ -503,7 +505,7 @@ var common = {
   confirm_title: "Confirmation",
   confirm_close_msg: "All unsaved changes will be lost. Are you sure?",
   general_import: "General Import",
-  
+  custom_import: "Custom Import",
   //
   // Help Page Titles
   //
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java.expected b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java.expected
index f3d96d40700754f255535a93b370b25bdb16255f..fc09df9995adc2bb391fe06d5ec045721f4d1bae 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java.expected
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java.expected
@@ -65,6 +65,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AuthorizationGroup;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AuthorizationGroupUpdates;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchOperationKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CustomImportFile;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelatedEntities;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelationshipRole;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
@@ -266,8 +267,11 @@ public interface ICommonServer extends IServer
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.ROLE_ASSIGNMENT)
-    public void registerSpaceRole(String sessionToken, RoleCode roleCode,
-            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier identifier, Grantee grantee);
+    public void registerSpaceRole(
+            String sessionToken,
+            RoleCode roleCode,
+            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier identifier,
+            Grantee grantee);
 
     /**
      * Registers a new instance role.
@@ -283,8 +287,11 @@ public interface ICommonServer extends IServer
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.ROLE_ASSIGNMENT)
-    public void deleteSpaceRole(String sessionToken, RoleCode roleCode,
-            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier identifier, Grantee grantee);
+    public void deleteSpaceRole(
+            String sessionToken,
+            RoleCode roleCode,
+            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier identifier,
+            Grantee grantee);
 
     /**
      * Deletes role described by given role code and user id.
@@ -311,7 +318,8 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     @ReturnValueFilter(validatorClass = SampleValidator.class)
-    public List<Sample> listSamples(final String sessionToken,
+    public List<Sample> listSamples(
+            final String sessionToken,
             @AuthorizationGuard(guardClass = ListSampleCriteriaPredicate.class) final ListSampleCriteria criteria);
 
     /**
@@ -321,7 +329,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperiments(final String sessionToken,
+    public List<Experiment> listExperiments(
+            final String sessionToken,
             ExperimentType experimentType,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier project);
 
@@ -332,7 +341,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperimentsHavingDataSets(final String sessionToken,
+    public List<Experiment> listExperimentsHavingDataSets(
+            final String sessionToken,
             ExperimentType experimentType,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier project);
 
@@ -343,7 +353,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperimentsHavingSamples(final String sessionToken,
+    public List<Experiment> listExperimentsHavingSamples(
+            final String sessionToken,
             ExperimentType experimentType,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier project);
 
@@ -365,7 +376,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperiments(final String sessionToken,
+    public List<Experiment> listExperiments(
+            final String sessionToken,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) List<ExperimentIdentifier> experimentIdentifiers);
 
     /**
@@ -376,7 +388,8 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     public List<ExternalData> listSampleExternalData(final String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) final TechId sampleId, final boolean showOnlyDirectlyConnected);
+            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) final TechId sampleId,
+            final boolean showOnlyDirectlyConnected);
 
     /**
      * For given experiment {@link TechId} returns the corresponding list of {@link ExternalData}.
@@ -385,8 +398,10 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<ExternalData> listExperimentExternalData(final String sessionToken,
-            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) final TechId experimentId, boolean showOnlyDirectlyConnected);
+    public List<ExternalData> listExperimentExternalData(
+            final String sessionToken,
+            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) final TechId experimentId,
+            boolean showOnlyDirectlyConnected);
 
     /**
      * For given data set {@link TechId} in given relationship <var>role</var> returns corresponding
@@ -397,7 +412,8 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     public List<ExternalData> listDataSetRelationships(final String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) final TechId datasetId, final DataSetRelationshipRole role);
+            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) final TechId datasetId,
+            final DataSetRelationshipRole role);
 
     /**
      * Performs an <i>Hibernate Search</i> based on given parameters.
@@ -568,7 +584,8 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value = ObjectKind.PROJECT)
     @Capability("DELETE_PROJECT")
     public void deleteProjects(String sessionToken,
-            @AuthorizationGuard(guardClass = ProjectTechIdPredicate.class) List<TechId> projectIds, String reason);
+            @AuthorizationGuard(guardClass = ProjectTechIdPredicate.class) List<TechId> projectIds,
+            String reason);
 
     /**
      * Deletes specified spaces.
@@ -577,7 +594,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.INSTANCE_ADMIN)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.SPACE)
     public void deleteSpaces(String sessionToken,
-            @AuthorizationGuard(guardClass = SpaceTechIdPredicate.class) List<TechId> spaceIds, String reason);
+            @AuthorizationGuard(guardClass = SpaceTechIdPredicate.class) List<TechId> spaceIds,
+            String reason);
 
     /**
      * Deletes specified scripts.
@@ -643,9 +661,10 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.PROJECT)
     @Capability("REGISTER_PROJECT")
-    public void registerProject(String sessionToken,
-            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier projectIdentifier, String description, String leaderId,
-            Collection<NewAttachment> attachments);
+    public void registerProject(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier projectIdentifier,
+            String description, String leaderId, Collection<NewAttachment> attachments);
 
     /**
      * Performs an <i>Hibernate Search</i> based on given parameters.
@@ -670,7 +689,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     @Capability("WRITE_DATASET")
-    public DataSetUpdateResult updateDataSet(String sessionToken,
+    public DataSetUpdateResult updateDataSet(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DataSetUpdatesPredicate.class) DataSetUpdatesDTO updates);
 
     /**
@@ -801,8 +821,9 @@ public interface ICommonServer extends IServer
         { ObjectKind.DATA_SET, ObjectKind.DELETION })
     @Capability("DELETE_DATASET")
     public void deleteDataSets(String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes, String reason, DeletionType type,
-            boolean forceNotExistingLocations, boolean isTrashEnabled);
+            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes,
+            String reason, DeletionType type, boolean forceNotExistingLocations,
+            boolean isTrashEnabled);
 
     /**
      * Deletes/Trashes specified data sets. It CAN delete data sets with deletion_disallow flag set
@@ -815,8 +836,9 @@ public interface ICommonServer extends IServer
         { ObjectKind.DATA_SET, ObjectKind.DELETION })
     @Capability("FORCE_DELETE_DATASET")
     public void deleteDataSetsForced(String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes, String reason, DeletionType type,
-            boolean forceNotExistingLocations, boolean isTrashEnabled);
+            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes,
+            String reason, DeletionType type, boolean forceNotExistingLocations,
+            boolean isTrashEnabled);
 
     /**
      * Deletes/Trashes specified samples.
@@ -826,8 +848,10 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value =
         { ObjectKind.SAMPLE, ObjectKind.DELETION })
     @Capability("DELETE_SAMPLE")
-    public void deleteSamples(String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdCollectionPredicate.class) List<TechId> sampleIds, String reason, DeletionType type);
+    public void deleteSamples(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = SampleTechIdCollectionPredicate.class) List<TechId> sampleIds,
+            String reason, DeletionType type);
 
     /**
      * Deletes/Trashes specified experiments.
@@ -837,8 +861,10 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value =
         { ObjectKind.EXPERIMENT, ObjectKind.DELETION })
     @Capability("DELETE_EXPERIMENT")
-    public void deleteExperiments(String sessionToken,
-            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) List<TechId> experimentIds, String reason, DeletionType deletionType);
+    public void deleteExperiments(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) List<TechId> experimentIds,
+            String reason, DeletionType deletionType);
 
     /**
      * Deletes specified attachments (all versions with given file names) of specified experiment.
@@ -848,7 +874,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.EXPERIMENT)
     @Capability("DELETE_EXPERIMENT_ATTACHMENT")
     public void deleteExperimentAttachments(String sessionToken,
-            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId experimentId, List<String> fileNames, String reason);
+            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId experimentId,
+            List<String> fileNames, String reason);
 
     /**
      * Deletes specified attachments (all versions with given file names) of specified sample.
@@ -858,7 +885,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
     @Capability("DELETE_SAMPLE_ATTACHMENT")
     public void deleteSampleAttachments(String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId sampleId, List<String> fileNames, String reason);
+            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId sampleId,
+            List<String> fileNames, String reason);
 
     /**
      * Deletes specified attachments (all versions with given file names) of specified project.
@@ -868,7 +896,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.PROJECT)
     @Capability("DELETE_PROJECT_ATTACHMENT")
     public void deleteProjectAttachments(String sessionToken,
-            @AuthorizationGuard(guardClass = ProjectTechIdPredicate.class) TechId projectId, List<String> fileNames, String reason);
+            @AuthorizationGuard(guardClass = ProjectTechIdPredicate.class) TechId projectId,
+            List<String> fileNames, String reason);
 
     /**
      * Returns all attachments (all versions) of specified experiment.
@@ -945,7 +974,8 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     public SampleParentWithDerived getSampleInfo(final String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) final TechId sampleId) throws UserFailureException;
+            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) final TechId sampleId)
+            throws UserFailureException;
 
     /**
      * Saves changed sample.
@@ -962,7 +992,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public Experiment getExperimentInfo(String sessionToken,
+    public Experiment getExperimentInfo(
+            String sessionToken,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ExperimentIdentifier identifier);
 
     /**
@@ -981,7 +1012,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value =
         { ObjectKind.EXPERIMENT, ObjectKind.SAMPLE })
     @Capability("WRITE_EXPERIMENT_SAMPLE")
-    public ExperimentUpdateResult updateExperiment(String sessionToken,
+    public ExperimentUpdateResult updateExperiment(
+            String sessionToken,
             @AuthorizationGuard(guardClass = ExperimentUpdatesPredicate.class) ExperimentUpdatesDTO updates);
 
     /**
@@ -998,7 +1030,8 @@ public interface ICommonServer extends IServer
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public Project getProjectInfo(String sessionToken,
+    public Project getProjectInfo(
+            String sessionToken,
             @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) ProjectIdentifier projectIdentifier);
 
     /**
@@ -1015,7 +1048,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.PROJECT)
     @Capability("WRITE_PROJECT")
-    public Date updateProject(String sessionToken,
+    public Date updateProject(
+            String sessionToken,
             @AuthorizationGuard(guardClass = ProjectUpdatesPredicate.class) ProjectUpdatesDTO updates);
 
     /**
@@ -1196,7 +1230,8 @@ public interface ICommonServer extends IServer
 
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public TableModel createReportFromDatasets(String sessionToken,
+    public TableModel createReportFromDatasets(
+            String sessionToken,
             DatastoreServiceDescription serviceDescription,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
@@ -1207,7 +1242,8 @@ public interface ICommonServer extends IServer
 
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
-    public void processDatasets(String sessionToken,
+    public void processDatasets(
+            String sessionToken,
             DatastoreServiceDescription serviceDescription,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
@@ -1222,8 +1258,10 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     @Capability("ARCHIVE_DATASET")
-    public int archiveDatasets(String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes, boolean removeFromDataStore);
+    public int archiveDatasets(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes,
+            boolean removeFromDataStore);
 
     /**
      * Schedules unarchiving of specified data sets.
@@ -1234,7 +1272,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     @Capability("UNARCHIVE_DATASET")
-    public int unarchiveDatasets(String sessionToken,
+    public int unarchiveDatasets(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
     /**
@@ -1245,7 +1284,8 @@ public interface ICommonServer extends IServer
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
-    public int lockDatasets(String sessionToken,
+    public int lockDatasets(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
     /**
@@ -1256,7 +1296,8 @@ public interface ICommonServer extends IServer
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
-    public int unlockDatasets(String sessionToken,
+    public int unlockDatasets(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes);
 
     /**
@@ -1322,7 +1363,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.GRID_CUSTOM_FILTER)
     @Capability("DELETE_FILTER")
-    public void deleteFilters(String sessionToken,
+    public void deleteFilters(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DeleteGridCustomFilterPredicate.class) List<TechId> filterIds);
 
     /**
@@ -1332,7 +1374,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.GRID_CUSTOM_FILTER)
     @Capability("WRITE_FILTER")
-    public void updateFilter(String sessionToken,
+    public void updateFilter(
+            String sessionToken,
             @AuthorizationGuard(guardClass = UpdateGridCustomFilterPredicate.class) IExpressionUpdates updates);
 
     // columns
@@ -1361,7 +1404,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseCreateOrDeleteModification(value = ObjectKind.GRID_CUSTOM_COLUMN)
     @Capability("DELETE_CUSTOM_COLUMN")
-    public void deleteGridCustomColumns(String sessionToken,
+    public void deleteGridCustomColumns(
+            String sessionToken,
             @AuthorizationGuard(guardClass = DeleteGridCustomColumnPredicate.class) List<TechId> columnIds);
 
     /**
@@ -1371,7 +1415,8 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
     @DatabaseUpdateModification(value = ObjectKind.GRID_CUSTOM_COLUMN)
     @Capability("WRITE_CUSTOM_COLUMN")
-    public void updateGridCustomColumn(String sessionToken,
+    public void updateGridCustomColumn(
+            String sessionToken,
             @AuthorizationGuard(guardClass = UpdateGridCustomColumnPredicate.class) IExpressionUpdates updates);
 
     /**
@@ -1467,7 +1512,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     @Capability("WRITE_DATASET_PROPERTIES")
     public void updateDataSetProperties(String sessionToken,
-            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId entityId, List<PropertyUpdates> modifiedProperties);
+            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId entityId,
+            List<PropertyUpdates> modifiedProperties);
 
     /**
      * Updates properties of an experiment with given id.
@@ -1477,7 +1523,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.EXPERIMENT)
     @Capability("WRITE_EXPERIMENT_PROPERTIES")
     public void updateExperimentProperties(String sessionToken,
-            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId entityId, List<PropertyUpdates> modifiedProperties);
+            @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId entityId,
+            List<PropertyUpdates> modifiedProperties);
 
     /**
      * Updates properties of a sample with given id.
@@ -1487,7 +1534,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
     @Capability("WRITE_SAMPLE_PROPERTIES")
     public void updateSampleProperties(String sessionToken,
-            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId entityId, List<PropertyUpdates> modifiedProperties);
+            @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId entityId,
+            List<PropertyUpdates> modifiedProperties);
 
     /**
      * Updates properties of a material with given id.
@@ -1518,7 +1566,8 @@ public interface ICommonServer extends IServer
     @DatabaseUpdateModification(value =
         { ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     @Capability("RESTORE")
-    public void revertDeletions(final String sessionToken,
+    public void revertDeletions(
+            final String sessionToken,
             @AuthorizationGuard(guardClass = RevertDeletionPredicate.class) final List<TechId> deletionIds);
 
     /**
@@ -1531,8 +1580,10 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value =
         { ObjectKind.DELETION, ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     @Capability("PURGE")
-    public void deletePermanently(final String sessionToken,
-            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds, boolean forceNotExistingLocations);
+    public void deletePermanently(
+            final String sessionToken,
+            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds,
+            boolean forceNotExistingLocations);
 
     /**
      * Permanently deletes entities moved to trash in specified deletions. It CAN delete data sets
@@ -1544,8 +1595,10 @@ public interface ICommonServer extends IServer
     @DatabaseCreateOrDeleteModification(value =
         { ObjectKind.DELETION, ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     @Capability("FORCE_PURGE")
-    public void deletePermanentlyForced(final String sessionToken,
-            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds, boolean forceNotExistingLocations);
+    public void deletePermanentlyForced(
+            final String sessionToken,
+            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds,
+            boolean forceNotExistingLocations);
 
     /**
      * Performs an <i>Hibernate Search</i> based on given parameters.
@@ -1554,4 +1607,11 @@ public interface ICommonServer extends IServer
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     public List<Material> searchForMaterials(String sessionToken, DetailedSearchCriteria criteria);
 
+    /**
+     * Performs an import of file to the dss.
+     */
+    @Transactional
+    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    public String performCustomImport(String sessionToken, String customImportCode,
+            CustomImportFile customImportFile) throws UserFailureException;
 }