diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
new file mode 100644
index 0000000000000000000000000000000000000000..77c354c491fc142cf005efc0c22db3c817bd162d
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011 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.api.v1;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Component;
+
+import ch.systemsx.cisd.authentication.ISessionManager;
+import ch.systemsx.cisd.common.spring.IInvocationLoggerContext;
+import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
+import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationChangingService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper;
+import ch.systemsx.cisd.openbis.plugin.generic.shared.IGenericServer;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+@Component(ResourceNames.GENERAL_INFORMATION_CHANGING_SERVICE_SERVER)
+public class GeneralInformationChangingService extends
+        AbstractServer<IGeneralInformationChangingService> implements
+        IGeneralInformationChangingService
+{
+    @Resource(name = ch.systemsx.cisd.openbis.plugin.generic.shared.ResourceNames.GENERIC_PLUGIN_SERVER)
+    private IGenericServer genericServer;
+
+    // Default constructor needed by Spring
+    public GeneralInformationChangingService()
+    {
+    }
+
+    GeneralInformationChangingService(ISessionManager<Session> sessionManager, IDAOFactory daoFactory,
+            IPropertiesBatchManager propertiesBatchManager, IGenericServer genericServer)
+    {
+        super(sessionManager, daoFactory, propertiesBatchManager);
+        this.genericServer = genericServer;
+    }
+
+    public IGeneralInformationChangingService createLogger(IInvocationLoggerContext context)
+    {
+        return new GeneralInformationChangingServiceLogger(sessionManager, context);
+    }
+    
+    public void updateSampleProperties(String sessionToken, long sampleID,
+            Map<String, String> properties)
+    {
+        TechId id = new TechId(sampleID);
+        Sample sample = genericServer.getSampleInfo(sessionToken, id).getParent();
+        for (Entry<String, String> entry : properties.entrySet())
+        {
+            EntityHelper.createOrUpdateProperty(sample, entry.getKey(), entry.getValue());
+        }
+        Experiment experiment = sample.getExperiment();
+        ExperimentIdentifier experimentIdentifier =
+                experiment == null ? null : ExperimentIdentifierFactory.parse(experiment
+                        .getIdentifier());
+        SampleIdentifier sampleIdentifier = SampleIdentifierFactory.parse(sample.getIdentifier());
+        Sample container = sample.getContainer();
+        String containerIdentifier = container == null ? null : container.getIdentifier();
+        SampleUpdatesDTO updates =
+                new SampleUpdatesDTO(id, sample.getProperties(), experimentIdentifier,
+                        Collections.<NewAttachment> emptySet(), sample.getModificationDate(),
+                        sampleIdentifier, containerIdentifier, null);
+        genericServer.updateSample(sessionToken, updates);
+    }
+
+    public int getMajorVersion()
+    {
+        return 1;
+    }
+    
+    public int getMinorVersion()
+    {
+        return 0;
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java
new file mode 100644
index 0000000000000000000000000000000000000000..0beb69b34ff8a167f97fe58a1acc9391045de9bf
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2011 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.api.v1;
+
+import java.util.Map;
+
+import ch.systemsx.cisd.authentication.ISessionManager;
+import ch.systemsx.cisd.common.spring.IInvocationLoggerContext;
+import ch.systemsx.cisd.openbis.generic.shared.AbstractServerLogger;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationChangingService;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+class GeneralInformationChangingServiceLogger extends AbstractServerLogger implements
+        IGeneralInformationChangingService
+{
+
+    public GeneralInformationChangingServiceLogger(ISessionManager<Session> sessionManagerNull,
+            IInvocationLoggerContext context)
+    {
+        super(sessionManagerNull, context);
+    }
+
+    public void updateSampleProperties(String sessionToken, long sampleID,
+            Map<String, String> properties)
+    {
+        logTracking(sessionToken, "update-sample-properties", "SAMPLE(%s)", sampleID);
+    }
+    
+    public int getMajorVersion()
+    {
+        return 0;
+    }
+
+    public int getMinorVersion()
+    {
+        return 0;
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b5dc8066e9a9e0f74654e4b4e0c07cd06549db13
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceServer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server.api.v1;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import ch.systemsx.cisd.common.api.server.AbstractApiServiceExporter;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationChangingService;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+@Controller
+@RequestMapping(
+    { IGeneralInformationChangingService.SERVICE_URL, "/openbis" + IGeneralInformationChangingService.SERVICE_URL })
+public class GeneralInformationChangingServiceServer extends AbstractApiServiceExporter
+{
+    @Resource(name = ResourceNames.GENERAL_INFORMATION_CHANGING_SERVICE_SERVER)
+    private IGeneralInformationChangingService service;
+
+    @Override
+    public void afterPropertiesSet()
+    {
+        establishService(IGeneralInformationChangingService.class, service,
+                IGeneralInformationChangingService.SERVICE_NAME, IGeneralInformationChangingService.SERVICE_URL);
+        super.afterPropertiesSet();
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/ResourceNames.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/ResourceNames.java
index 5ce924a871e6d191b5eac019f96e16564a68cdcd..1fdb8174c752653d561a0fd847cd27e59c39ee78 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/ResourceNames.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/ResourceNames.java
@@ -24,5 +24,6 @@ package ch.systemsx.cisd.openbis.generic.server.api.v1;
 public class ResourceNames
 {
     public final static String GENERAL_INFORMATION_SERVICE_SERVER = "general-information-api-server-v1";
+    public final static String GENERAL_INFORMATION_CHANGING_SERVICE_SERVER = "general-information-changing-api-server-v1";
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/Translator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/Translator.java
index 5b64b638eb98f3720b7b82295035dcf4713990c0..e634f79a7d25794dbd4fb0b182078e9bebb71bc8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/Translator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/Translator.java
@@ -73,7 +73,7 @@ public class Translator
         List<IEntityProperty> properties = privateSample.getProperties();
         for (IEntityProperty prop : properties)
         {
-            initializer.putProperty(prop.getPropertyType().getCode(), prop.getValue());
+            initializer.putProperty(prop.getPropertyType().getCode(), prop.tryGetAsString());
         }
 
         ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment experimentOrNull =
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/EntityPropertiesConverter.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/EntityPropertiesConverter.java
index 56566e83e8831ec945db588fe205a9f64bd02d72..6c290f75a73a0af8c2b5d7a1567f1ffe1e81440c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/EntityPropertiesConverter.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/EntityPropertiesConverter.java
@@ -413,7 +413,8 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
         final Set<T> set = new HashSet<T>();
         for (T newProperty : convertedProperties)
         {
-            T existingProperty = tryFind(oldProperties, newProperty);
+            PropertyTypePE propertyType = newProperty.getEntityTypePropertyType().getPropertyType();
+            T existingProperty = tryFind(oldProperties, propertyType);
             if (existingProperty != null)
             {
                 existingProperty.setUntypedValue(newProperty.getValue(),
@@ -478,12 +479,12 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
         return set;
     }
 
-    private static <T extends EntityPropertyPE> T tryFind(Collection<T> oldProperties, T p)
+    private static <T extends EntityPropertyPE> T tryFind(Collection<T> oldProperties, PropertyTypePE propertyType)
     {
         for (T oldProperty : oldProperties)
         {
             if (oldProperty.getEntityTypePropertyType().getPropertyType()
-                    .equals(p.getEntityTypePropertyType().getPropertyType()))
+                    .equals(propertyType))
             {
                 return oldProperty;
             }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce933733549ea883f8b713650aa44ac2c1577836
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011 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.api.v1;
+
+import java.util.Map;
+
+import org.springframework.transaction.annotation.Transactional;
+
+import ch.systemsx.cisd.common.api.IRpcService;
+import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+
+/**
+ * Service for changing general informations.
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IGeneralInformationChangingService extends IRpcService
+{
+    /**
+     * Name of this service for which it is registered at the RPC name server.
+     */
+    public static final String SERVICE_NAME = "general-information-changing";
+
+    /**
+     * Application part of the URL to access this service remotely.
+     */
+    public static final String SERVICE_URL = "/rmi-" + SERVICE_NAME + "-v1";
+    
+    @Transactional
+    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    public void updateSampleProperties(String sessionToken, long sampleID, Map<String, String> properties);
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
index ba17689f1a5e0bf83cc9df00da2250efe0ac7f40..bbbecc87376ea063307d33fcfa2420a1b76dfbd2 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
@@ -121,20 +121,25 @@ public class EntityHelper
     }
 
     /**
-     * Tries to set the value for a given property in an {@link IEntityPropertiesHolder} instance.
-     * Creates a new property if no property for the specified code is found.
+     * Creates a property with specified code and value. An already existing property with same
+     * code will be removed.
      */
     public static void createOrUpdateProperty(IEntityPropertiesHolder holder, String propertyCode,
             String propertyValue)
     {
-        IEntityProperty property = tryFindProperty(holder.getProperties(), propertyCode);
-
-        if (property == null)
+        IEntityProperty newProperty = createNewProperty(propertyCode, propertyValue);
+        List<IEntityProperty> properties = holder.getProperties();
+        for (int i = 0; i < properties.size(); i++)
         {
-            property = createNewProperty(propertyCode);
-            holder.getProperties().add(property);
+            IEntityProperty property = properties.get(i);
+            PropertyType propertyType = property.getPropertyType();
+            if (propertyType.getCode().equalsIgnoreCase(propertyCode))
+            {
+                properties.set(i, newProperty);
+                return;
+            }
         }
-        property.setValue(propertyValue);
+        properties.add(newProperty);
     }
 
     public static IEntityProperty createNewProperty(String propertyCode, String propertyValue)
diff --git a/screening/build/build.xml b/screening/build/build.xml
index 63ad0254d852b86be8742630f5d1ef0e4fb4fc03..51d39cd7777532e62ae30ba34eb17a303b4e0b1e 100644
--- a/screening/build/build.xml
+++ b/screening/build/build.xml
@@ -373,6 +373,79 @@
     </zip>
   	
   </target>
+	
+	<target name="screening-api-eclipse">
+    <mkdir dir="${dist.screening-api.lib}" />
+    <recursive-jar destfile="${dist.screening-api.jar}">
+      <fileset dir="${targets}/www/WEB-INF/classes">
+        <include name="OpenBISScreeningML*.class" />
+        <include name="ch/systemsx/cisd/common/api/**/*.class" />
+        <exclude name="ch/systemsx/cisd/common/api/server/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/dss/client/api/v1/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/dss/generic/shared/api/authorization/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/dss/screening/shared/api/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/generic/shared/basic/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/generic/shared/api/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/generic/shared/authorization/annotation/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/plugin/screening/shared/api/**/*.class" />
+       	<include name="ch/systemsx/cisd/openbis/plugin/screening/client/api/**/*.class" />
+       	<include name="ch/systemsx/cisd/openbis/plugin/screening/client/cli/**/*.class" />
+      </fileset>
+    	<manifest>
+      	<attribute name="Main-Class" value="ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningClientApiTest" />
+        <attribute name="Class-Path" value="spring-ext.jar" />
+        <attribute name="Version" value="${version.number}" />
+        <attribute name="Build-Number"
+                   value="${version.number} (r${revision.number},${clean.flag})" />
+      </manifest>
+    </recursive-jar>
+  	<jar update="true" destfile="${dist.screening-api.jar}">
+  		<fileset dir="../openbis/targets/www/WEB-INF/classes">
+  		     	<include name="ch/systemsx/cisd/openbis/generic/client/cli/Login*.class" />
+			     	<include name="ch/systemsx/cisd/openbis/generic/shared/api/v1/**/*.class" />
+  		</fileset> 
+  		<fileset dir="../datastore_server/targets/classes">
+      	<include name="ch/systemsx/cisd/openbis/dss/client/api/v1/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/**/*.class" />
+      	<include name="ch/systemsx/cisd/openbis/dss/generic/shared/api/authorization/**/*.class" />
+  		</fileset> 
+  		<fileset dir="../server-common/targets/classes">
+  		     	<include name="ch/systemsx/cisd/common/spring/HttpInvokerUtils.class" />
+			     	<include name="ch/systemsx/cisd/common/api/client/**/*.class" />
+  		</fileset> 
+      <fileset dir="../common/targets/classes">
+            <include name="ch/systemsx/cisd/common/exceptions/**/*.class" />
+		        <include name="ch/systemsx/cisd/common/api/*.class" />
+            <include name="ch/systemsx/cisd/common/io/ConcatenatedFileOutputStreamWriter.class" />
+            <include name="ch/systemsx/cisd/common/io/ConcatenatedContentInputStream.class" />
+            <include name="ch/systemsx/cisd/common/io/FileBasedContent.class" />
+            <include name="ch/systemsx/cisd/common/io/IContent.class" />
+      </fileset> 
+    </jar>
+		<zip update="true" destfile="${dist.screening-api.jar}">
+	    <zipfileset src="${lib}/gwt2.0/gwt-user.jar">
+	      <include name="com/google/gwt/user/client/rpc/IsSerializable.class" />
+	      <include name="com/google/gwt/user/client/rpc/SerializableException.class" />
+	    </zipfileset>
+	  </zip>
+    <recursive-jar destfile="${dist.screening-api.lib}/spring-ext.jar">
+      <zipfileset src="${lib}/spring/spring.jar" />
+      <zipfileset src="${lib}/spring/third-party/stream-supporting-httpinvoker.jar" />
+      <zipfileset src="${lib}/commons-logging/commons-logging.jar" />
+      <zipfileset src="${lib}/commons-httpclient/commons-httpclient.jar" />
+      <zipfileset src="${lib}/commons-codec/commons-codec.jar" />
+      <zipfileset src="${lib}/log4j/log4j.jar" />     
+      <zipfileset src="${lib}/jline/jline.jar" />     
+      <zipfileset src="${lib}/cisd-args4j/cisd-args4j.jar" />     
+      <zipfileset src="${lib}/cisd-base/cisd-base.jar" />     
+      <zipfileset src="${lib}/jython/standalone/jython.jar" />     
+  	</recursive-jar>
+  	<recursive-jar destfile="${dist.screening-api-batteries-included.jar}">
+      <zipfileset src="${dist.screening-api.lib}/spring-ext.jar" />
+      <zipfileset src="${dist.screening-api.jar}" />
+  	</recursive-jar>
+	</target>
 
   <!-- 
   		To test the API you can use
diff --git a/screening/source/java/OpenBISScreeningML.java b/screening/source/java/OpenBISScreeningML.java
index b6eb5b299b29a71db2d2fb3d721ee6a5b2e1f0f4..6c00533f8c58042989ff21b51264adf17ee54887 100644
--- a/screening/source/java/OpenBISScreeningML.java
+++ b/screening/source/java/OpenBISScreeningML.java
@@ -28,7 +28,6 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 
 import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetMetadataDTO;
@@ -49,6 +48,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Plate;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateImageReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateWellMaterialMapping;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition;
 
 /**
@@ -84,6 +84,9 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition;
  */
 public class OpenBISScreeningML
 {
+
+    static final String DATASETS_FOLDER = "openbis_datasets";
+
     private static interface ITileNumberIterable extends Iterable<Integer>
     {
         public void setMaximumNumberOfTiles(int numberOfTiles);
@@ -175,6 +178,15 @@ public class OpenBISScreeningML
 
     private static File dataSetsDir;
 
+    /**
+     * Root temporary directory for data sets and images. By default <code>java.io.tmpdir</code> is
+     * used.
+     */
+    static File tempDir = new File(System.getProperty("java.io.tmpdir"));
+
+    static final String TEMP_DIR_PREFIX = "openbis_";
+    static final String TEMP_DIR_POSTFIX = "_temp_dir";
+
     //
     // Authentication methods
     //
@@ -194,23 +206,23 @@ public class OpenBISScreeningML
      */
     public static void login(String user, String password, String url)
     {
-        openbis = ScreeningOpenbisServiceFacadeFactory.tryCreate(user, password, url);
-        if (openbis == null)
+        IScreeningOpenbisServiceFacade facade = ScreeningOpenbisServiceFacadeFactory.tryCreate(user, password, url);
+        if (facade == null)
         {
             throw new RuntimeException("Login failed.");
         }
-        init();
+        init(facade);
     }
 
-    private static void init()
+    public static void init(IScreeningOpenbisServiceFacade openBisFacade)
     {
-        File tempDir = new File(System.getProperty("java.io.tmpdir"));
-        dataSetsDir = new File(tempDir, "openbis_datasets");
+        openbis = openBisFacade;
+        dataSetsDir = new File(tempDir, DATASETS_FOLDER);
         if (dataSetsDir.isDirectory() == false && dataSetsDir.mkdirs() == false)
         {
             throw new RuntimeException("Couldn't create a data set directory.");
         }
-        temporarySessionDir = new File(tempDir, "openbis_" + System.currentTimeMillis() / 1000 + "_temp_dir");
+        temporarySessionDir = new File(tempDir, TEMP_DIR_PREFIX + System.currentTimeMillis() / 1000 + TEMP_DIR_POSTFIX);
         if (temporarySessionDir.mkdirs() == false)
         {
             throw new RuntimeException("Couldn't create a temporary directory.");
@@ -260,8 +272,22 @@ public class OpenBISScreeningML
         {
             Login.OPENBIS_TOKEN_FILE.delete();
         }
+        delete(temporarySessionDir);
         openbis = null;
     }
+    
+    private static void delete(File file)
+    {
+        if (file.isDirectory())
+        {
+            File[] files = file.listFiles();
+            for (File child : files)
+            {
+                delete(child);
+            }
+        }
+        file.delete();
+    }
 
     //
     // Information methods
@@ -330,21 +356,7 @@ public class OpenBISScreeningML
     public static Object[][] listPlates()
     {
         checkLoggedIn();
-        final Object[][] result = new Object[plates.size()][9];
-        for (int i = 0; i < plates.size(); ++i)
-        {
-            final Object[] annotations =
-                    new Object[]
-                        { plates.get(i).getAugmentedCode(), plates.get(i).getPermId(),
-                                plates.get(i).tryGetSpaceCode(), plates.get(i).getPlateCode(),
-                                plates.get(i).getExperimentIdentifier().getAugmentedCode(),
-                                plates.get(i).getExperimentIdentifier().getPermId(),
-                                plates.get(i).getExperimentIdentifier().getSpaceCode(),
-                                plates.get(i).getExperimentIdentifier().getProjectCode(),
-                                plates.get(i).getExperimentIdentifier().getExperimentCode(), };
-            System.arraycopy(annotations, 0, result[i], 0, annotations.length);
-        }
-        return result;
+        return listPlates(plates);
     }
     
     /**
@@ -378,27 +390,110 @@ public class OpenBISScreeningML
         {
             throw new RuntimeException("No experiment with that code found.");
         }
-        final Object[][] result = new Object[experimentPlates.size()][9];
-        for (int i = 0; i < experimentPlates.size(); ++i)
+        return listPlates(experimentPlates);
+    }
+
+    private static Object[][] listPlates(final List<Plate> list)
+    {
+        final Object[][] result = new Object[list.size()][9];
+        for (int i = 0; i < list.size(); ++i)
         {
             final Object[] annotations =
                     new Object[]
                         {
-                                experimentPlates.get(i).getAugmentedCode(),
+                                list.get(i).getAugmentedCode(),
                                 plates.get(i).getPermId(),
-                                experimentPlates.get(i).tryGetSpaceCode(),
+                                list.get(i).tryGetSpaceCode(),
                                 plates.get(i).getPlateCode(),
-                                experimentPlates.get(i).getExperimentIdentifier()
+                                list.get(i).getExperimentIdentifier()
                                         .getAugmentedCode(),
-                                experimentPlates.get(i).getExperimentIdentifier().getPermId(),
-                                experimentPlates.get(i).getExperimentIdentifier().getSpaceCode(),
-                                experimentPlates.get(i).getExperimentIdentifier().getProjectCode(),
-                                experimentPlates.get(i).getExperimentIdentifier()
+                                list.get(i).getExperimentIdentifier().getPermId(),
+                                list.get(i).getExperimentIdentifier().getSpaceCode(),
+                                list.get(i).getExperimentIdentifier().getProjectCode(),
+                                list.get(i).getExperimentIdentifier()
                                         .getExperimentCode(), };
             System.arraycopy(annotations, 0, result[i], 0, annotations.length);
         }
         return result;
     }
+    
+    /**
+     * Returns the properties of specified well for specified plate.
+     * <p>
+     * Matlab example:
+     * 
+     * <pre>
+     * % Get properties for well A03 of plate P005 in space SPACE
+     * properties = OpenBISScreeningML.getWellProperties('/SPACE/P005', 1, 3, properties)
+     * % Get property type code of first property
+     * properties(1,1)
+     * % Get property value of first property
+     * properties(1,2)
+     * </pre>
+     * 
+     * @param augmentedPlateCode The augmented plate code
+     * @param row The row in the plate to get the well properties for
+     * @param column The column in the plate to get the well properties for
+     * @return A two dimensional array where the first column contains the property
+     *            codes and the second column the corresponding property values.
+     */
+    public static Object[][] getWellProperties(String augmentedPlateCode, int row,
+            int column)
+    {
+        checkLoggedIn();
+        WellPosition wellPosition = new WellPosition(row, column);
+        WellIdentifier wellIdentifier = getWell(augmentedPlateCode, wellPosition);
+        List<Map.Entry<String, String>> list =
+                new ArrayList<Map.Entry<String, String>>(openbis.getWellProperties(wellIdentifier)
+                        .entrySet());
+        Object[][] result = new Object[list.size()][2];
+        for (int i = 0; i < list.size(); i++)
+        {
+            result[i] = new Object[] {list.get(i).getKey(), list.get(i).getValue()};
+        }
+        return result;
+    }
+    
+    /**
+     * Updates properties of specified well for specified plate.
+     * <p>
+     * Matlab example:
+     * 
+     * <pre>
+     * % Updates properties DESCRIPTION and NUMBER for well A03 of plate P005 in space SPACE
+     * properties = {'DESCRIPTION' 'hello example'; 'NUMBER' 3.14}
+     * OpenBISScreeningML.updateWellProperties('/SPACE/P005', 1, 3, properties)
+     * </pre>
+     * 
+     * @param augmentedPlateCode The augmented plate code
+     * @param row The row in the plate to get the well properties for
+     * @param column The column in the plate to get the well properties for
+     * @param properties A two dimensional array where the first column contains the property
+     *            codes and the second column the corresponding property values.
+     */
+    public static void updateWellProperties(String augmentedPlateCode, int row,
+            int column, Object[][] properties)
+    {
+        checkLoggedIn();
+        WellPosition wellPosition = new WellPosition(row, column);
+        WellIdentifier wellIdentifier = getWell(augmentedPlateCode, wellPosition);
+        openbis.updateWellProperties(wellIdentifier, createMap(properties));
+    }
+    
+    private static WellIdentifier getWell(String augmentedPlateCode, WellPosition wellPosition)
+    {
+        Plate plate = getPlate(augmentedPlateCode);
+        List<WellIdentifier> wells = openbis.listPlateWells(plate);
+        for (WellIdentifier wellIdentifier : wells)
+        {
+            if (wellIdentifier.getWellPosition().equals(wellPosition))
+            {
+                return wellIdentifier;
+            }
+        }
+        throw new RuntimeException("Plate '" + augmentedPlateCode + "' has now well at "
+                + wellPosition + ".");
+    }
 
     /**
      * Lists all channels measured in <var>experiment</var>.
@@ -522,7 +617,7 @@ public class OpenBISScreeningML
      * 
      * <pre>
      * % Load all data sets of plate P005 in space SPACE
-     * dsinfo = loadDataSets('/SPACE/P005')
+     * dsinfo = OpenBISScreeningML.loadDataSets('/SPACE/P005')
      * % Get the data set codes
      * dsinfo(:,1)
      * % Get root path of first data set (assuming there is at least one)
@@ -545,12 +640,13 @@ public class OpenBISScreeningML
             for (int i = 0; i < dataSets.size(); i++)
             {
                 IDataSetDss dataSet = dataSets.get(i);
-                File file = new File(dataSetsDir, dataSet.getCode());
+                String code = dataSet.getCode();
+                File file = new File(dataSetsDir, code);
                 if (file.exists() == false)
                 {
                     file = dataSet.getLinkOrCopyOfContents(null, dataSetsDir);
                 }
-                result[i] = new Object[] {dataSet.getCode(), file.getPath()};
+                result[i] = new Object[] {code, file.getPath()};
             }
             return result;
         } catch (Exception ex)
@@ -569,7 +665,7 @@ public class OpenBISScreeningML
      * % Upload data set /path/to/my-data-set with properties DESCRIPTION and NUMBER for 
      * % plate P005 in space SPACE
      * properties = {'DESCRIPTION' 'hello example'; 'NUMBER' 3.14}
-     * datasetcode = uploadDataSet('/SPACE/P005', '/path/to/my-data-set', 'HCS_IMAGE', properties)
+     * datasetcode = OpenBISScreeningML.uploadDataSet('/SPACE/P005', '/path/to/my-data-set', 'HCS_IMAGE', properties)
      * </pre>
      * 
      * @param augmentedPlateCode The augmented plate code.
@@ -590,14 +686,7 @@ public class OpenBISScreeningML
         }
         try
         {
-            HashMap<String, String> map = new HashMap<String, String>();
-            for (Object[] objects : dataSetProperties)
-            {
-                if (objects.length == 2)
-                {
-                    map.put(objects[0].toString(), objects[1].toString());
-                }
-            }
+            Map<String, String> map = createMap(dataSetProperties);
             IDataSetDss dataSet =
                     openbis.putDataSet(plateIdentifier, dataSetFile, new NewDataSetMetadataDTO(
                             dataSetType, map));
@@ -609,10 +698,20 @@ public class OpenBISScreeningML
         }
     }
 
-    public static Object testProperties(Properties properties)
+    private static Map<String, String> createMap(Object[][] properties)
     {
-        return properties.toString();
+        Map<String, String> map = new HashMap<String, String>();
+        for (Object[] objects : properties)
+        {
+            if (objects.length == 2)
+            {
+                Object value = objects[1];
+                map.put(objects[0].toString(), value == null ? null : value.toString());
+            }
+        }
+        return map;
     }
+    
     //
     // Images
     //
@@ -1502,12 +1601,12 @@ public class OpenBISScreeningML
                     final String serverUrl = br.readLine();
                     br.close();
                     br = null;
-                    openbis = ScreeningOpenbisServiceFacadeFactory.tryCreate(token, serverUrl);
-                    if (openbis == null)
+                    IScreeningOpenbisServiceFacade facade = ScreeningOpenbisServiceFacadeFactory.tryCreate(token, serverUrl);
+                    if (facade == null)
                     {
                         throw new RuntimeException("Login failed.");
                     }
-                    init();
+                    init(facade);
                 } catch (IOException ex)
                 {
                     if (openbis == null)
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
index 3337f157e649c43e7db31b290884c5cfe5ea0bb7..130c9cc4e28b9a20378b6115d24ff239bc961df6 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/IScreeningOpenbisServiceFacade.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.plugin.screening.client.api.v1;
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
+import java.util.Map;
 
 import ch.systemsx.cisd.base.image.IImageTransformerFactory;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
@@ -149,6 +150,16 @@ public interface IScreeningOpenbisServiceFacade
      * For the given <var>plateIdentifier</var> find all wells that are connected to it.
      */
     public List<WellIdentifier> listPlateWells(PlateIdentifier plateIdentifier);
+    
+    /**
+     * Returns all properties of specified well as a map.
+     */
+    public Map<String, String> getWellProperties(WellIdentifier wellIdentifier);
+    
+    /**
+     * Updates properties of specified well.
+     */
+    public void updateWellProperties(WellIdentifier wellIdentifier, Map<String, String> properties);
 
     /**
      * Get proxies to the data sets owned by specified well.
@@ -555,5 +566,5 @@ public interface IScreeningOpenbisServiceFacade
     public List<PlateWellMaterialMapping> listPlateMaterialMapping(
             List<? extends PlateIdentifier> plates,
             MaterialTypeIdentifier materialTypeIdentifierOrNull);
-
+    
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
index de265892d2a30413c53a28a770a90d97fd332328..069dcc63bcad811cb3119ba62fe254b723d96ec6 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacade.java
@@ -35,6 +35,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO.DataSetO
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO.DataSetOwnerType;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetMetadataDTO;
 import ch.systemsx.cisd.openbis.dss.screening.shared.api.v1.IDssServiceRpcScreening;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationChangingService;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationService;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSet;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Sample;
@@ -92,6 +93,8 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
     private final IScreeningApiServer openbisScreeningServer;
 
     private final IGeneralInformationService generalInformationService;
+    
+    private final IGeneralInformationChangingService generalInformationChangingService;
 
     private final IDssComponent dssComponent;
 
@@ -126,18 +129,12 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
             String serverUrl)
     {
         final IScreeningApiServer openbisServer = createScreeningOpenbisServer(serverUrl);
-        final IGeneralInformationService generalInformationService =
-                createGeneralInformationService(serverUrl);
-        final int minorVersion = openbisServer.getMinorVersion();
         final String sessionToken = openbisServer.tryLoginScreening(userId, userPassword);
         if (sessionToken == null)
         {
             return null;
         }
-        final IDssComponent dssComponent =
-                DssComponentFactory.tryCreate(sessionToken, serverUrl, SERVER_TIMEOUT_MILLIS);
-        return new ScreeningOpenbisServiceFacade(sessionToken, openbisServer, minorVersion,
-                DSS_SERVICE_FACTORY, dssComponent, generalInformationService);
+        return tryCreate(sessionToken, serverUrl, openbisServer);
     }
 
     /**
@@ -149,14 +146,22 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
      */
     public static IScreeningOpenbisServiceFacade tryCreate(String sessionToken, String serverUrl)
     {
-        final IScreeningApiServer openbisServer = createScreeningOpenbisServer(serverUrl);
+        return tryCreate(sessionToken, serverUrl, createScreeningOpenbisServer(serverUrl));
+    }
+
+    private static IScreeningOpenbisServiceFacade tryCreate(String sessionToken, String serverUrl,
+            final IScreeningApiServer openbisServer)
+    {
         final IGeneralInformationService generalInformationService =
                 createGeneralInformationService(serverUrl);
+        IGeneralInformationChangingService generalInformationChangingService =
+                createGeneralInformationChangingService(serverUrl);
         final int minorVersion = openbisServer.getMinorVersion();
         final IDssComponent dssComponent =
                 DssComponentFactory.tryCreate(sessionToken, serverUrl, SERVER_TIMEOUT_MILLIS);
         return new ScreeningOpenbisServiceFacade(sessionToken, openbisServer, minorVersion,
-                DSS_SERVICE_FACTORY, dssComponent, generalInformationService);
+                DSS_SERVICE_FACTORY, dssComponent, generalInformationService,
+                generalInformationChangingService);
     }
 
     private static IScreeningApiServer createScreeningOpenbisServer(String serverUrl)
@@ -175,12 +180,25 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
         return service;
     }
 
+    private static IGeneralInformationChangingService createGeneralInformationChangingService(
+            String serverUrl)
+    {
+        ServiceFinder generalInformationServiceFinder =
+                new ServiceFinder("openbis", IGeneralInformationChangingService.SERVICE_URL);
+        IGeneralInformationChangingService service =
+                generalInformationServiceFinder.createService(
+                        IGeneralInformationChangingService.class, serverUrl);
+        return service;
+    }
+    
     ScreeningOpenbisServiceFacade(String sessionToken, IScreeningApiServer screeningServer,
             int minorVersion, final IDssServiceFactory dssServiceFactory,
-            IDssComponent dssComponent, IGeneralInformationService generalInformationService)
+            IDssComponent dssComponent, IGeneralInformationService generalInformationService,
+            IGeneralInformationChangingService generalInformationChangingService)
     {
         this.openbisScreeningServer = screeningServer;
         this.generalInformationService = generalInformationService;
+        this.generalInformationChangingService = generalInformationChangingService;
         this.dssComponent = dssComponent;
         this.sessionToken = sessionToken;
         this.minorVersionApplicationServer = minorVersion;
@@ -365,6 +383,19 @@ public class ScreeningOpenbisServiceFacade implements IScreeningOpenbisServiceFa
         checkASMinimalMinorVersion("listPlateWells", PlateIdentifier.class);
         return openbisScreeningServer.listPlateWells(sessionToken, plateIdentifier);
     }
+    
+    public Map<String, String> getWellProperties(WellIdentifier wellIdentifier)
+    {
+        Sample wellSample = openbisScreeningServer.getWellSample(sessionToken, wellIdentifier);
+        Map<String, String> properties = wellSample.getProperties();
+        return properties;
+    }
+
+    public void updateWellProperties(WellIdentifier wellIdentifier, Map<String, String> properties)
+    {
+        Sample wellSample = openbisScreeningServer.getWellSample(sessionToken, wellIdentifier);
+        generalInformationChangingService.updateSampleProperties(sessionToken, wellSample.getId(), properties);
+    }
 
     /**
      * Get proxies to the data sets owned by specified well.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
index 7213a26b21c9d4c7d967857bd5878a4e32cb3c31..1f22d54c6627caa73f43d2b424970be5c74572d8 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
@@ -375,7 +375,7 @@ public final class ScreeningServer extends AbstractServer<IScreeningServer> impl
 
     public Sample getWellSample(String sessionToken, WellIdentifier wellIdentifier)
     {
-        return createScreeningApiImpl(sessionToken).getWellSample(wellIdentifier);
+        return createScreeningApiImpl(sessionToken).getWellSample(wellIdentifier, true);
     }
 
     public Sample getPlateSample(String sessionToken, PlateIdentifier plateIdentifier)
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java
index 63768caeeb1184935c53f62cf6901bed430b4063..8044637a04f1d3ad5117381415f269b64ceca88f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java
@@ -422,7 +422,7 @@ public class ScreeningApiImpl
         Sample sample;
         if (plateIdentifier.getPermId() != null)
         {
-            sample = loadSampleByPermId(plateIdentifier.getPermId());
+            sample = loadSampleByPermId(plateIdentifier.getPermId(), false);
         } else
         {
             SampleIdentifier sampleIdentifier = createSampleIdentifier(plateIdentifier);
@@ -434,9 +434,9 @@ public class ScreeningApiImpl
     }
 
     public ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Sample getWellSample(
-            WellIdentifier wellIdentifier)
+            WellIdentifier wellIdentifier, boolean enrichWithProperties)
     {
-        Sample sample = loadSampleByPermId(wellIdentifier.getPermId());
+        Sample sample = loadSampleByPermId(wellIdentifier.getPermId(), enrichWithProperties);
         return Translator.translate(sample);
     }
     
@@ -446,10 +446,14 @@ public class ScreeningApiImpl
         return Translator.translate(getSample(plateIdentifier));
     }
 
-    private Sample loadSampleByPermId(String permId)
+    private Sample loadSampleByPermId(String permId, boolean enrichWithProperties)
     {
         ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
         sampleBO.loadBySamplePermId(permId);
+        if (enrichWithProperties)
+        {
+            sampleBO.enrichWithProperties();
+        }
         SamplePE samplePE = sampleBO.getSample();
         return translate(samplePE);
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/IScreeningApiServer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/IScreeningApiServer.java
index 62b06910dc1bbb73e5f8382c92fab26762f21028..38f3ef90065d4700bd497d1dcd2059e6651c5a12 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/IScreeningApiServer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/IScreeningApiServer.java
@@ -231,7 +231,7 @@ public interface IScreeningApiServer extends IRpcService
             @AuthorizationGuard(guardClass = PlateIdentifierPredicate.class) PlateIdentifier plateIdentifier);
 
     /**
-     * For a given <var>wellIdentifier</var>, return the corresponding {@link Sample}.
+     * For a given <var>wellIdentifier</var>, return the corresponding {@link Sample} including properties.
      * 
      * @since 1.3
      */
diff --git a/screening/sourceTest/java/OpenBISScreeningMLTest.java b/screening/sourceTest/java/OpenBISScreeningMLTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fa28e23817b3ceb99c359aaf599f61a7a682cd9
--- /dev/null
+++ b/screening/sourceTest/java/OpenBISScreeningMLTest.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.Sequence;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
+import ch.systemsx.cisd.common.test.RecordingMatcher;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetMetadataDTO;
+import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.IScreeningOpenbisServiceFacade;
+import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade.IImageOutputStreamProvider;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ExperimentIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageDatasetMetadata;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageDatasetReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Plate;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateImageReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class OpenBISScreeningMLTest extends AbstractFileSystemTestCase
+{
+    private static final FilenameFilter FILTER_TEMP_DIR = new FilenameFilter()
+        {
+            public boolean accept(File dir, String name)
+            {
+                return name.startsWith(OpenBISScreeningML.TEMP_DIR_PREFIX)
+                        && name.endsWith(OpenBISScreeningML.TEMP_DIR_POSTFIX);
+            }
+        };
+
+   private Mockery context;
+    private IScreeningOpenbisServiceFacade openbis;
+
+    private File tempDir;
+
+    private ExperimentIdentifier eId1;
+
+    private ExperimentIdentifier eId2;
+
+    private IDataSetDss ds1;
+    
+    private IDataSetDss ds2;
+    
+    @BeforeMethod
+    public void beforeMethod()
+    {
+        context = new Mockery();
+        openbis = context.mock(IScreeningOpenbisServiceFacade.class);
+        ds1 = context.mock(IDataSetDss.class, "ds1");
+        ds2 = context.mock(IDataSetDss.class, "ds2");
+        FileUtilities.deleteRecursively(workingDirectory);
+        workingDirectory.mkdirs();
+        OpenBISScreeningML.tempDir = workingDirectory;
+        eId1 = new ExperimentIdentifier("E1", "P", "S", "e-1");
+        eId2 = new ExperimentIdentifier("E2", "P", "S", "e-2");
+        context.checking(new Expectations()
+            {
+                {
+                    one(openbis).listExperiments();
+                    will(returnValue(Arrays.asList(eId1, eId2)));
+                    
+                    one(openbis).listPlates();
+                    Plate p1 = new Plate("PLATE-1", "S", "s-1", eId1);
+                    Plate p2 = new Plate("PLATE-2", "S", "s-2", eId2);
+                    will(returnValue(Arrays.asList(p1, p2)));
+                }
+            });
+        OpenBISScreeningML.init(openbis);
+        tempDir = OpenBISScreeningML.tempDir.listFiles(FILTER_TEMP_DIR)[0];
+    }
+    
+    @AfterMethod
+    public void afterMethod()
+    {
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testLogout()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(openbis).logout();
+                }
+            });
+        File a = new File(tempDir, "a");
+        a.mkdirs();
+        FileUtilities.writeToFile(new File(a, "1.txt"), "one");
+        FileUtilities.writeToFile(new File(tempDir, "2.txt"), "two");
+        
+        OpenBISScreeningML.logout();
+        
+        assertEquals(false, tempDir.exists());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testListExperiments()
+    {
+        Object[][] experiments = OpenBISScreeningML.listExperiments();
+
+        sort(experiments);
+        assertEquals("/S/P/E1", experiments[0][0]);
+        assertEquals("e-1", experiments[0][1]);
+        assertEquals("S", experiments[0][2]);
+        assertEquals("P", experiments[0][3]);
+        assertEquals("E1", experiments[0][4]);
+        assertEquals("/S/P/E2", experiments[1][0]);
+        assertEquals("e-2", experiments[1][1]);
+        assertEquals("S", experiments[1][2]);
+        assertEquals("P", experiments[1][3]);
+        assertEquals("E2", experiments[1][4]);
+        assertEquals(2, experiments.length);
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testListPlates()
+    {
+        Object[][] plates = OpenBISScreeningML.listPlates();
+        
+        sort(plates);
+        assertEquals("/S/PLATE-1", plates[0][0]);
+        assertEquals("s-1", plates[0][1]);
+        assertEquals("S", plates[0][2]);
+        assertEquals("PLATE-1", plates[0][3]);
+        assertEquals("/S/P/E1", plates[0][4]);
+        assertEquals("e-1", plates[0][5]);
+        assertEquals("S", plates[0][6]);
+        assertEquals("P", plates[0][7]);
+        assertEquals("E1", plates[0][8]);
+        assertEquals("/S/PLATE-2", plates[1][0]);
+        assertEquals("s-2", plates[1][1]);
+        assertEquals("S", plates[1][2]);
+        assertEquals("PLATE-2", plates[1][3]);
+        assertEquals("/S/P/E2", plates[1][4]);
+        assertEquals("e-2", plates[1][5]);
+        assertEquals("S", plates[1][6]);
+        assertEquals("P", plates[1][7]);
+        assertEquals("E2", plates[1][8]);
+        assertEquals(2, plates.length);
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testListPlatesByExperiment()
+    {
+        try
+        {
+            OpenBISScreeningML.listPlates("/S/P/E3");
+            fail("RuntimeException expected");
+        } catch (RuntimeException ex)
+        {
+            assertEquals("No experiment with that code found.", ex.getMessage());
+        }
+        
+        Object[][] plates = OpenBISScreeningML.listPlates("/S/P/E1");
+        
+        sort(plates);
+        assertEquals("/S/PLATE-1", plates[0][0]);
+        assertEquals("s-1", plates[0][1]);
+        assertEquals("S", plates[0][2]);
+        assertEquals("PLATE-1", plates[0][3]);
+        assertEquals("/S/P/E1", plates[0][4]);
+        assertEquals("e-1", plates[0][5]);
+        assertEquals("S", plates[0][6]);
+        assertEquals("P", plates[0][7]);
+        assertEquals("E1", plates[0][8]);
+        assertEquals(1, plates.length);
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testGetWellProperties()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    Plate plate1 = new Plate("PLATE-1", "S", "s-1", eId1);
+                    one(openbis).listPlateWells(plate1);
+                    WellIdentifier w1 = new WellIdentifier(plate1, new WellPosition(1, 1), "w1");
+                    WellIdentifier w2 = new WellIdentifier(plate1, new WellPosition(1, 2), "w2");
+                    WellIdentifier w3 = new WellIdentifier(plate1, new WellPosition(2, 1), "w3");
+                    will(returnValue(Arrays.asList(w1, w2, w3)));
+                    
+                    one(openbis).getWellProperties(w2);
+                    Map<String, String> properties = new LinkedHashMap<String, String>();
+                    properties.put("answer", "42");
+                    properties.put("name", "Albert");
+                    will(returnValue(properties));
+                }
+            });
+        
+        Object[][] wellProperties = OpenBISScreeningML.getWellProperties("/S/PLATE-1", 1, 2);
+        
+        assertEquals("answer", wellProperties[0][0]);
+        assertEquals("42", wellProperties[0][1]);
+        assertEquals("name", wellProperties[1][0]);
+        assertEquals("Albert", wellProperties[1][1]);
+        assertEquals(2, wellProperties.length);
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testUpdateWellProperties()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    Plate plate1 = new Plate("PLATE-1", "S", "s-1", eId1);
+                    one(openbis).listPlateWells(plate1);
+                    WellIdentifier w1 = new WellIdentifier(plate1, new WellPosition(1, 1), "w1");
+                    WellIdentifier w2 = new WellIdentifier(plate1, new WellPosition(1, 2), "w2");
+                    WellIdentifier w3 = new WellIdentifier(plate1, new WellPosition(2, 1), "w3");
+                    will(returnValue(Arrays.asList(w1, w2, w3)));
+
+                    Map<String, String> properties = new LinkedHashMap<String, String>();
+                    properties.put("A", "42");
+                    properties.put("B", "43");
+                    one(openbis).updateWellProperties(w2, properties);
+                }
+            });
+        
+        OpenBISScreeningML.updateWellProperties("/S/PLATE-1", 1, 2, new Object[][] {{"A", "42"}, {"B", "43"}});
+        
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testLoadDataSets()
+    {
+        final File dataSetFolder = new File(OpenBISScreeningML.tempDir, OpenBISScreeningML.DATASETS_FOLDER);
+        final File ds1Folder = new File(dataSetFolder, "ds-1");
+        File ds2Folder = new File(dataSetFolder, "ds-2");
+        ds2Folder.mkdirs();
+        context.checking(new Expectations()
+            {
+                {
+                    one(openbis).getDataSets(new Plate("PLATE-1", "S", "s-1", eId1));
+                    will(returnValue(Arrays.asList(ds1, ds2)));
+                    
+                    one(ds1).getCode();
+                    will(returnValue("ds-1"));
+                    
+                    one(ds1).getLinkOrCopyOfContents(null, dataSetFolder);
+                    will(returnValue(ds1Folder));
+                    
+                    one(ds2).getCode();
+                    will(returnValue("ds-2"));
+                }
+            });
+        
+        Object[][] result = OpenBISScreeningML.loadDataSets("/S/PLATE-1");
+        
+        assertEquals("ds-1", result[0][0]);
+        assertEquals(ds1Folder.getPath(), result[0][1]);
+        assertEquals("ds-2", result[1][0]);
+        assertEquals(ds2Folder.getPath(), result[1][1]);
+        assertEquals(2, result.length);
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testUpdateDataSet()
+    {
+        final File dataSetFolder = new File(OpenBISScreeningML.tempDir, OpenBISScreeningML.DATASETS_FOLDER);
+        final File ds1Folder = new File(dataSetFolder, "ds-1");
+        ds1Folder.mkdirs();
+        final RecordingMatcher<NewDataSetMetadataDTO> metaDataMatcher = new RecordingMatcher<NewDataSetMetadataDTO>();
+        context.checking(new Expectations()
+            {
+                {
+                    Map<String, String> properties = new LinkedHashMap<String, String>();
+                    properties.put("A", "42");
+                    properties.put("B", "43");
+                    try
+                    {
+                        one(openbis).putDataSet(with(new Plate("PLATE-1", "S", "s-1", eId1)),
+                                with(ds1Folder), with(metaDataMatcher));
+                        will(returnValue(ds1));
+                    } catch (Exception ex)
+                    {
+                        throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+                    }
+                    
+                    one(ds1).getCode();
+                    will(returnValue("DS-1"));
+                }
+            });
+        
+        Object code =
+                OpenBISScreeningML.uploadDataSet("/S/PLATE-1", ds1Folder.getPath(), "my-type",
+                        new Object[][] {{"A", "42"}, {"B", "43"}});
+        
+        assertEquals("DS-1", code);
+        assertEquals("my-type", metaDataMatcher.recordedObject().tryDataSetType());
+        assertEquals("{A=42, B=43}", metaDataMatcher.recordedObject().getProperties().toString());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testLoadImages()
+    {
+        final RecordingMatcher<List<PlateImageReference>> imgRefsMatcher1 =
+                new RecordingMatcher<List<PlateImageReference>>();
+        final RecordingMatcher<List<PlateImageReference>> imgRefsMatcher2 =
+            new RecordingMatcher<List<PlateImageReference>>();
+        final Sequence sequence = context.sequence("load");
+        context.checking(new Expectations()
+            {
+                {
+                    Plate plate = new Plate("PLATE-1", "S", "s-1", eId1);
+                    exactly(2).of(openbis).listRawImageDatasets(Arrays.asList(plate));
+                    ImageDatasetReference ds1Ref =
+                            new ImageDatasetReference("ds1", "", plate, eId1, null, null, null,
+                                    null);
+                    List<ImageDatasetReference> imageRefs = Arrays.asList(ds1Ref);
+                    will(returnValue(imageRefs));
+
+                    exactly(2).of(openbis).listImageMetadata(imageRefs);
+                    List<String> channelCodes = Arrays.asList("R", "G");
+                    List<String> channelLabels = Arrays.asList("red", "green");
+                    ImageDatasetMetadata metaData1 =
+                            new ImageDatasetMetadata(ds1Ref, channelCodes, channelLabels, 1, 2,
+                                    100, 60, 10, 6);
+                    will(returnValue(Arrays.asList(metaData1)));
+
+                    try
+                    {
+                        one(openbis).loadImages(with(imgRefsMatcher1),
+                                with(new BaseMatcher<IImageOutputStreamProvider>()
+                                    {
+                                        public boolean matches(Object item)
+                                        {
+                                            if (item instanceof IImageOutputStreamProvider)
+                                            {
+                                                IImageOutputStreamProvider provider =
+                                                        (IImageOutputStreamProvider) item;
+                                                List<PlateImageReference> recordedObject =
+                                                        imgRefsMatcher1.recordedObject();
+                                                for (PlateImageReference ref : recordedObject)
+                                                {
+                                                    try
+                                                    {
+                                                        OutputStream outputStream =
+                                                                provider.getOutputStream(ref);
+                                                        new PrintWriter(outputStream, true)
+                                                                .println(ref.toString() + " (1)");
+                                                    } catch (IOException ex)
+                                                    {
+                                                        throw CheckedExceptionTunnel
+                                                                .wrapIfNecessary(ex);
+                                                    }
+                                                }
+                                                return true;
+                                            }
+                                            return false;
+                                        }
+
+                                        public void describeTo(Description description)
+                                        {
+                                        }
+                                    }), with(false));
+                        inSequence(sequence);
+                        one(openbis).loadImages(with(imgRefsMatcher2),
+                                with(new BaseMatcher<IImageOutputStreamProvider>()
+                                    {
+                                        public boolean matches(Object item)
+                                        {
+                                            if (item instanceof IImageOutputStreamProvider)
+                                            {
+                                                IImageOutputStreamProvider provider =
+                                                        (IImageOutputStreamProvider) item;
+                                                List<PlateImageReference> recordedObject =
+                                                        imgRefsMatcher2.recordedObject();
+                                                for (PlateImageReference ref : recordedObject)
+                                                {
+                                                    try
+                                                    {
+                                                        OutputStream outputStream =
+                                                                provider.getOutputStream(ref);
+                                                        new PrintWriter(outputStream, true)
+                                                                .println(ref.toString() + " (2)");
+                                                    } catch (IOException ex)
+                                                    {
+                                                        throw CheckedExceptionTunnel
+                                                                .wrapIfNecessary(ex);
+                                                    }
+                                                }
+                                                return true;
+                                            }
+                                            return false;
+                                        }
+
+                                        public void describeTo(Description description)
+                                        {
+                                        }
+                                    }), with(false));
+                        inSequence(sequence);
+                    } catch (IOException ex)
+                    {
+                        throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+                    }
+                }
+            });
+        
+        Object[][][] result1 = OpenBISScreeningML.loadImages("/S/PLATE-1", 1, 2, 1, new String[] {"G"});
+        List<PlateImageReference> imgRefs1 = imgRefsMatcher1.recordedObject();
+        for (PlateImageReference plateImageReference : imgRefs1)
+        {
+            assertEquals("ds1", plateImageReference.getDatasetCode());
+            assertEquals(1, plateImageReference.getWellPosition().getWellRow());
+            assertEquals(2, plateImageReference.getWellPosition().getWellColumn());
+        }
+        assertEquals("G", imgRefs1.get(0).getChannel());
+        assertEquals(1, imgRefs1.get(0).getTile());
+        assertEquals(1, imgRefs1.size());
+        assertEquals(2, result1.length);
+        assertEquals("/images/img_PLATE-1_ds1_row1_col2_G_tile1.tiff", getImagePath(result1, 0));
+        assertEquals("Image for [dataset ds1, well [1, 2], channel G, tile 1] (1)", FileUtilities
+                .loadToString(new File(result1[0][0][0].toString())).trim());
+        assertEquals(1, result1[0].length);
+        assertEquals(
+                "[G, 1, PLATE-1:A2, /S/PLATE-1, s-1, S, PLATE-1, 1, 2, /S/P/E1, e-1, S, P, E1, ds1]",
+                Arrays.asList(result1[1][0]).toString());
+        assertEquals(1, result1[1].length);
+        
+        Object[][][] result2 = OpenBISScreeningML.loadImages("/S/PLATE-1", 1, 2);
+        List<PlateImageReference> imgRefs2 = imgRefsMatcher2.recordedObject();
+        for (PlateImageReference plateImageReference : imgRefs2)
+        {
+            assertEquals("ds1", plateImageReference.getDatasetCode());
+            assertEquals(1, plateImageReference.getWellPosition().getWellRow());
+            assertEquals(2, plateImageReference.getWellPosition().getWellColumn());
+        }
+        assertEquals("R", imgRefs2.get(0).getChannel());
+        assertEquals(0, imgRefs2.get(0).getTile());
+        assertEquals("R", imgRefs2.get(1).getChannel());
+        assertEquals(1, imgRefs2.get(1).getTile());
+        assertEquals("G", imgRefs2.get(2).getChannel());
+        assertEquals(0, imgRefs2.get(2).getTile());
+        assertEquals(3, imgRefs2.size());
+        
+        assertEquals(2, result2.length);
+        assertEquals("/images/img_PLATE-1_ds1_row1_col2_R_tile0.tiff", getImagePath(result2, 0));
+        assertEquals("Image for [dataset ds1, well [1, 2], channel R, tile 0] (2)", FileUtilities
+                .loadToString(new File(result2[0][0][0].toString())).trim());
+        assertEquals("/images/img_PLATE-1_ds1_row1_col2_R_tile1.tiff", getImagePath(result2, 1));
+        assertEquals("Image for [dataset ds1, well [1, 2], channel R, tile 1] (2)", FileUtilities
+                .loadToString(new File(result2[0][1][0].toString())).trim());
+        assertEquals("/images/img_PLATE-1_ds1_row1_col2_G_tile0.tiff", getImagePath(result2, 2));
+        assertEquals("Image for [dataset ds1, well [1, 2], channel G, tile 0] (2)", FileUtilities
+                .loadToString(new File(result2[0][2][0].toString())).trim());
+        assertEquals("/images/img_PLATE-1_ds1_row1_col2_G_tile1.tiff", getImagePath(result2, 3));
+        assertEquals("Image for [dataset ds1, well [1, 2], channel G, tile 1] (1)", FileUtilities
+                .loadToString(new File(result2[0][3][0].toString())).trim());
+        assertEquals(4, result2[0].length);
+        assertEquals(
+                "[R, 0, PLATE-1:A2, /S/PLATE-1, s-1, S, PLATE-1, 1, 2, /S/P/E1, e-1, S, P, E1, ds1]",
+                Arrays.asList(result2[1][0]).toString());
+        assertEquals(
+                "[R, 1, PLATE-1:A2, /S/PLATE-1, s-1, S, PLATE-1, 1, 2, /S/P/E1, e-1, S, P, E1, ds1]",
+                Arrays.asList(result2[1][1]).toString());
+        assertEquals(
+                "[G, 0, PLATE-1:A2, /S/PLATE-1, s-1, S, PLATE-1, 1, 2, /S/P/E1, e-1, S, P, E1, ds1]",
+                Arrays.asList(result2[1][2]).toString());
+        assertEquals(
+                "[G, 1, PLATE-1:A2, /S/PLATE-1, s-1, S, PLATE-1, 1, 2, /S/P/E1, e-1, S, P, E1, ds1]",
+                Arrays.asList(result2[1][3]).toString());
+        assertEquals(4, result2[1].length);
+        context.assertIsSatisfied();
+    }
+
+    private String getImagePath(Object[][][] result, int i)
+    {
+        return result[0][i][0].toString()
+                .substring(tempDir.getPath().length());
+    }
+    
+    private void sort(Object[][] entities)
+    {
+        Arrays.sort(entities, new Comparator<Object[]>()
+                {
+            public int compare(Object[] o1, Object[] o2)
+            {
+                return o1[0].toString().compareTo(o2[0].toString());
+            }
+                });
+    }
+
+}
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacadeTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacadeTest.java
index a734609c0dfe06c12605529e7ce1e293bff3f13c..e1f185bec004a07be15716e71206937ffec9b783 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacadeTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/api/v1/ScreeningOpenbisServiceFacadeTest.java
@@ -37,6 +37,7 @@ import ch.systemsx.cisd.common.io.IContent;
 import ch.systemsx.cisd.openbis.dss.client.api.v1.IDssComponent;
 import ch.systemsx.cisd.openbis.dss.screening.server.DssServiceRpcScreening;
 import ch.systemsx.cisd.openbis.dss.screening.shared.api.v1.IDssServiceRpcScreening;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationChangingService;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationService;
 import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade.IImageOutputStreamProvider;
 import ch.systemsx.cisd.openbis.plugin.screening.server.ScreeningServer;
@@ -118,12 +119,15 @@ public class ScreeningOpenbisServiceFacadeTest extends AssertJUnit
 
     private IImageTransformerFactory transformerFactory;
 
+    private IGeneralInformationChangingService generalInformationChangingService;
+
     @BeforeMethod
     public void beforeMethod()
     {
         context = new Mockery();
         screeningService = context.mock(IScreeningApiServer.class);
         generalInformationService = context.mock(IGeneralInformationService.class);
+        generalInformationChangingService = context.mock(IGeneralInformationChangingService.class);
         dssComponent = context.mock(IDssComponent.class);
         dssServiceFactory = context.mock(IDssServiceFactory.class);
         i1id = new ImageDatasetReference(DATA_SET1, URL1, null, null, null, null, null, null);
@@ -170,7 +174,7 @@ public class ScreeningOpenbisServiceFacadeTest extends AssertJUnit
         facade =
                 new ScreeningOpenbisServiceFacade(SESSION_TOKEN, screeningService,
                         ScreeningServer.MINOR_VERSION, dssServiceFactory, dssComponent,
-                        generalInformationService);
+                        generalInformationService, generalInformationChangingService);
     }
 
     @AfterMethod
diff --git a/screening/sourceTest/java/tests.xml b/screening/sourceTest/java/tests.xml
index f94a4e51e6a67b419f812d793786684c87708c5c..a51e0e7f7a657316b2e08f141241ca0a1daa6e52 100644
--- a/screening/sourceTest/java/tests.xml
+++ b/screening/sourceTest/java/tests.xml
@@ -9,5 +9,8 @@
       <package name="ch.systemsx.cisd.openbis.plugin.screening.*" />
       <package name="ch.systemsx.cisd.openbis.dss.*" />
    </packages>
+   <classes>
+     <class name="OpenBISScreeningMLTest"/>
+   </classes>
  </test>
 </suite>
diff --git a/screening/sourceTest/java/tests_fast.xml b/screening/sourceTest/java/tests_fast.xml
index e85dda9499724b398faca07d2646e9de8d415df9..6a5f4e0060c4026b1c586020cf584722f2c42db2 100644
--- a/screening/sourceTest/java/tests_fast.xml
+++ b/screening/sourceTest/java/tests_fast.xml
@@ -11,6 +11,9 @@
         <packages>
           <package name="ch.systemsx.cisd.openbis.plugin.screening.*" />
           <package name="ch.systemsx.cisd.openbis.dss.*" />
-       </packages>
+        </packages>
+        <classes>
+          <class name="OpenBISScreeningMLTest"/>
+        </classes>
     </test>
 </suite>