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 7092f9a89acd54450edb3b9691351e80cc77d72f..09e820600e984be27bea0c227f9e15f7ba70fed3 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
@@ -505,6 +505,8 @@ public abstract class Dict
 
     public static final String SAMPLE_BATCH_REGISTRATION = "sample_batch_registration";
 
+    public static final String SAMPLE_BATCH_UPDATE = "sample_batch_update";
+
     public static final String SAMPLE_REGISTRATION = "sample_registration";
 
     public static final String SAMPLE_BROWSER = "sample_broser";
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 3c0a18479f182e057bf2d2c9232143fefa3c6157..3223f339c5d582cffcdb2640112af342a612926c 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
@@ -42,7 +42,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.propert
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.property_type.PropertyTypeAssignmentGrid;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.property_type.PropertyTypeGrid;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.property_type.PropertyTypeRegistrationForm;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.sample.SampleBatchRegistrationPanel;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.sample.SampleBatchRegisterUpdatePanel;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.sample.SampleBrowserGrid;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.sample.SampleRegistrationPanel;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.sample.SampleSearchHitGrid;
@@ -238,18 +238,39 @@ public final class ComponentProvider
 
     public final ITabItemFactory getSampleBatchRegistration()
     {
+        final boolean update = false;
         return new ITabItemFactory()
             {
                 public ITabItem create()
                 {
                     DatabaseModificationAwareComponent component =
-                            SampleBatchRegistrationPanel.create(viewContext);
+                            SampleBatchRegisterUpdatePanel.create(viewContext, update);
                     return createRegistrationTab(Dict.SAMPLE_BATCH_REGISTRATION, component);
                 }
 
                 public String getId()
                 {
-                    return SampleBatchRegistrationPanel.ID;
+                    return SampleBatchRegisterUpdatePanel.getId(update);
+                }
+            };
+    }
+
+    public final ITabItemFactory getSampleBatchUpdate()
+    {
+        final boolean update = true;
+
+        return new ITabItemFactory()
+            {
+                public ITabItem create()
+                {
+                    DatabaseModificationAwareComponent component =
+                            SampleBatchRegisterUpdatePanel.create(viewContext, true);
+                    return createRegistrationTab(Dict.SAMPLE_BATCH_UPDATE, component);
+                }
+
+                public String getId()
+                {
+                    return SampleBatchRegisterUpdatePanel.getId(update);
                 }
             };
     }
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 353e9a7dc4b0aebed466bd9dc1d32b86ae374df7..7cf304d4a1a6ecbcbc8f598c6f310dd9a4d1493f 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
@@ -63,7 +63,7 @@ public class TopMenu extends LayoutContainer
         MATERIAL_MENU_BROWSE, MATERIAL_MENU_IMPORT, MATERIAL_MENU_TYPES,
 
         SAMPLE_MENU_SEARCH, SAMPLE_MENU_BROWSE, SAMPLE_MENU_NEW, SAMPLE_MENU_IMPORT,
-        SAMPLE_MENU_TYPES,
+        SAMPLE_MENU_MASS_UPDATE, SAMPLE_MENU_TYPES,
 
         PROJECT_MENU_BROWSE, PROJECT_MENU_NEW,
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/sample/SampleMenu.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/sample/SampleMenu.java
index b77f095add7127729d089cdd83100f65aa85ba64..2abd8fe50eaba68e4e5fb07ab6eb7f0879c07564 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/sample/SampleMenu.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/menu/sample/SampleMenu.java
@@ -47,6 +47,8 @@ public class SampleMenu extends TopMenuItem
                 componentProvider.getSampleRegistration()));
         submenu.add(new ActionMenu(TopMenu.ActionMenuKind.SAMPLE_MENU_IMPORT, messageProvider,
                 componentProvider.getSampleBatchRegistration()));
+        submenu.add(new ActionMenu(TopMenu.ActionMenuKind.SAMPLE_MENU_MASS_UPDATE, messageProvider,
+                componentProvider.getSampleBatchUpdate()));
         submenu.add(new ActionMenu(TopMenu.ActionMenuKind.SAMPLE_MENU_TYPES, messageProvider,
                 componentProvider.getSampleTypeBrowser()));
         setMenu(submenu);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/plugin/ClientPluginAdapter.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/plugin/ClientPluginAdapter.java
index fb6064003778333d89b4a98787463807095178f3..00c72592206c5658c41257719f603d8d200470bd 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/plugin/ClientPluginAdapter.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/plugin/ClientPluginAdapter.java
@@ -42,6 +42,11 @@ public class ClientPluginAdapter<E extends EntityType, I extends IIdentifiable>
         throw new UnsupportedOperationException("Not yet implemented.");
     }
 
+    public Widget createBatchUpdateForEntityType(E entityType)
+    {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
     public ITabItemFactory createEntityViewer(final I identifiable)
     {
         throw new UnsupportedOperationException("Not yet implemented.");
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/plugin/IClientPlugin.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/plugin/IClientPlugin.java
index e8c4918c585e0e98fb3628d617f515e4e7f1228b..f5b8116d3474b9ea3e1a0ea734f668d641d3165b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/plugin/IClientPlugin.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/plugin/IClientPlugin.java
@@ -52,6 +52,11 @@ public interface IClientPlugin<T extends EntityType, I extends IIdentifiable>
      */
     public Widget createBatchRegistrationForEntityType(final T entityType);
 
+    /**
+     * Shows a batch update form for entities of given <var>entityType</var>.
+     */
+    public Widget createBatchUpdateForEntityType(final T entityType);
+
     /**
      * Shows a editor of the specified entity..
      */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBatchRegistrationPanel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBatchRegisterUpdatePanel.java
similarity index 74%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBatchRegistrationPanel.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBatchRegisterUpdatePanel.java
index fc4e3368226a4d27708d45cf1df963f01b68fbd1..f89ceba7d80d85e7df256c533fd032378da8732b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBatchRegistrationPanel.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBatchRegisterUpdatePanel.java
@@ -22,6 +22,7 @@ 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 com.google.gwt.user.client.ui.Widget;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
@@ -36,31 +37,39 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 
 /**
- * The {@link LayoutContainer} extension for batch registering a sample.
+ * The {@link LayoutContainer} extension for batch registration and update of samples of certain
+ * type.
  * 
  * @author Christian Ribeaud
  */
-public final class SampleBatchRegistrationPanel extends LayoutContainer
+public final class SampleBatchRegisterUpdatePanel extends LayoutContainer
 {
     private static final String ID_SUFFIX = "sample-batch-registration";
 
-    public static final String ID = GenericConstants.ID_PREFIX + ID_SUFFIX;
+    private static final String ID = GenericConstants.ID_PREFIX + ID_SUFFIX;
 
     private final SampleTypeSelectionWidget sampleTypeSelection;
 
     private final IViewContext<ICommonClientServiceAsync> viewContext;
 
+    public static String getId(final boolean update)
+    {
+        return ID + "_" + (update == true ? "update" : "registration");
+    }
+
     public static DatabaseModificationAwareComponent create(
-            final IViewContext<ICommonClientServiceAsync> viewContext)
+            final IViewContext<ICommonClientServiceAsync> viewContext, final boolean update)
     {
-        SampleBatchRegistrationPanel panel = new SampleBatchRegistrationPanel(viewContext);
+        SampleBatchRegisterUpdatePanel panel =
+                new SampleBatchRegisterUpdatePanel(viewContext, update);
         return new DatabaseModificationAwareComponent(panel, panel.sampleTypeSelection);
     }
 
-    private SampleBatchRegistrationPanel(final IViewContext<ICommonClientServiceAsync> viewContext)
+    private SampleBatchRegisterUpdatePanel(
+            final IViewContext<ICommonClientServiceAsync> viewContext, final boolean update)
     {
         this.viewContext = viewContext;
-        setId(ID);
+        setId(getId(update));
         setScrollMode(Scroll.AUTO);
         sampleTypeSelection =
                 new SampleTypeSelectionWidget(viewContext, ID_SUFFIX, false, false, true);
@@ -89,8 +98,19 @@ public final class SampleBatchRegistrationPanel extends LayoutContainer
                                         viewContext.getClientPluginFactoryProvider()
                                                 .getClientPluginFactory(entityKind, sampleType)
                                                 .createClientPlugin(entityKind);
-                                add(createClientPlugin
-                                        .createBatchRegistrationForEntityType(sampleType));
+                                final Widget batchOperationWidget;
+                                if (update)
+                                {
+                                    batchOperationWidget =
+                                            createClientPlugin
+                                                    .createBatchUpdateForEntityType(sampleType);
+                                } else
+                                {
+                                    batchOperationWidget =
+                                            createClientPlugin
+                                                    .createBatchRegistrationForEntityType(sampleType);
+                                }
+                                add(batchOperationWidget);
                                 layout();
                             }
                         }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
index cd8f86dbfa698938a6098982bdf1dd6ea54dac8f..b23f93305e7bd573056fbacd908cbd37547e4075 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
@@ -269,10 +269,16 @@ public final class SampleBO extends AbstractSampleBusinessObject implements ISam
 
     public void update(SampleUpdatesDTO updates)
     {
-        loadDataByTechId(updates.getSampleId());
-        if (updates.getVersion().equals(sample.getModificationDate()) == false)
+        if (updates.getSampleIdOrNull() != null)
         {
-            throwModifiedEntityException("Sample");
+            loadDataByTechId(updates.getSampleIdOrNull());
+            if (updates.getVersion().equals(sample.getModificationDate()) == false)
+            {
+                throwModifiedEntityException("Sample");
+            }
+        } else
+        {
+            loadBySampleIdentifier(updates.getOldSampleIdentifierOrNull());
         }
         updateProperties(updates.getProperties());
         updateGroup(updates.getSampleIdentifier());
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/SampleUpdatesPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/SampleUpdatesPredicate.java
index ae0a920a75bea7adf20c405774dde1ae5f30cdee..1174ac7bd2090bc014b03d3e6e150e0762568e3d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/SampleUpdatesPredicate.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/SampleUpdatesPredicate.java
@@ -65,7 +65,7 @@ public class SampleUpdatesPredicate extends AbstractPredicate<SampleUpdatesDTO>
     {// TODO 2009-07-27, IA: tests needed
         assert sampleTechIdPredicate.initialized : "Predicate has not been initialized";
         Status status;
-        status = sampleTechIdPredicate.doEvaluation(person, allowedRoles, updates.getSampleId());
+        status = sampleTechIdPredicate.doEvaluation(person, allowedRoles, updates.getSampleIdOrNull());
         if (status.equals(Status.OK) == false)
         {
             return status;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/BasicSampleUpdates.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/BasicSampleUpdates.java
index 4f82526752a53e8772691c7954f80d9011cc17a9..142d32a569775b5cbe966f76ba17d8d79b5d7519 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/BasicSampleUpdates.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/BasicSampleUpdates.java
@@ -32,7 +32,8 @@ public class BasicSampleUpdates implements IsSerializable, Serializable
 
     private static final long serialVersionUID = ServiceVersionHolder.VERSION;
 
-    private TechId sampleId;
+    // if technical id is null old identifier must be provided by subclass
+    private TechId sampleIdOrNull;
 
     private List<IEntityProperty> properties;
 
@@ -69,21 +70,21 @@ public class BasicSampleUpdates implements IsSerializable, Serializable
     public BasicSampleUpdates(TechId sampleId, List<IEntityProperty> properties, Date version,
             String parentIdentifierOrNull, String containerIdentifierOrNull)
     {
-        this.sampleId = sampleId;
+        this.sampleIdOrNull = sampleId;
         this.properties = properties;
         this.version = version;
         this.parentIdentifierOrNull = parentIdentifierOrNull;
         this.containerIdentifierOrNull = containerIdentifierOrNull;
     }
 
-    public TechId getSampleId()
+    public TechId getSampleIdOrNull()
     {
-        return sampleId;
+        return sampleIdOrNull;
     }
 
     public void setSampleId(TechId sampleId)
     {
-        this.sampleId = sampleId;
+        this.sampleIdOrNull = sampleId;
     }
 
     public List<IEntityProperty> getProperties()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SampleUpdatesDTO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SampleUpdatesDTO.java
index 0a82f0e2d99019712e39cdb10be5d8d37a6c149c..b3854f6d2760a082f7d760b8328e319050ed102b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SampleUpdatesDTO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SampleUpdatesDTO.java
@@ -39,6 +39,8 @@ public class SampleUpdatesDTO extends BasicSampleUpdates
 
     private SampleIdentifier sampleIdentifier;
 
+    private SampleIdentifier oldSampleIdentifierOrNull;
+
     private Collection<NewAttachment> attachments;
 
     public SampleUpdatesDTO(TechId sampleId, List<IEntityProperty> properties,
@@ -52,6 +54,18 @@ public class SampleUpdatesDTO extends BasicSampleUpdates
         this.sampleIdentifier = sampleIdentifier;
     }
 
+    public SampleUpdatesDTO(SampleIdentifier oldSampleIdentifier, List<IEntityProperty> properties,
+            ExperimentIdentifier experimentIdentifierOrNull, Collection<NewAttachment> attachments,
+            Date version, SampleIdentifier sampleIdentifier, String parentIdentifierOrNull,
+            String containerIdentifierOrNull)
+    {
+        super(null, properties, version, parentIdentifierOrNull, containerIdentifierOrNull);
+        this.experimentIdentifierOrNull = experimentIdentifierOrNull;
+        this.attachments = attachments;
+        this.sampleIdentifier = sampleIdentifier;
+        this.oldSampleIdentifierOrNull = oldSampleIdentifier;
+    }
+
     public SampleIdentifier getSampleIdentifier()
     {
         return sampleIdentifier;
@@ -62,6 +76,16 @@ public class SampleUpdatesDTO extends BasicSampleUpdates
         this.sampleIdentifier = sampleIdentifier;
     }
 
+    public SampleIdentifier getOldSampleIdentifierOrNull()
+    {
+        return oldSampleIdentifierOrNull;
+    }
+
+    public void setOldSampleIdentifier(SampleIdentifier sampleIdentifier)
+    {
+        this.oldSampleIdentifierOrNull = sampleIdentifier;
+    }
+
     public ExperimentIdentifier getExperimentIdentifierOrNull()
     {
         return experimentIdentifierOrNull;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/ClientPluginFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/ClientPluginFactory.java
index 38c91e61753993176302e23010f96a3a1a8b4d3b..caf810f297976f689b610a149558351f9948274f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/ClientPluginFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/ClientPluginFactory.java
@@ -143,6 +143,11 @@ public final class ClientPluginFactory extends AbstractClientPluginFactory<IDemo
             return new DummyComponent();
         }
 
+        public final Widget createBatchUpdateForEntityType(final SampleType sampleType)
+        {
+            return new DummyComponent();
+        }
+
         public ITabItemFactory createEntityEditor(final IIdentifiable identifiable)
         {
             return new ITabItemFactory()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientService.java
index 2131af6008b5a132c5bda43ad10597563a8fb9f6..65d301d23eadb19eb69b01b1ccfa6a1c9d003e3a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientService.java
@@ -47,7 +47,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
  * unexpected exception.
  * </p>
  * 
- * @author     Franz-Josef Elmer
+ * @author Franz-Josef Elmer
  */
 public interface IGenericClientService extends IClientService
 {
@@ -78,6 +78,15 @@ public interface IGenericClientService extends IClientService
     public List<BatchRegistrationResult> registerSamples(final SampleType sampleType,
             final String sessionKey, String defaultGroupIdentifier) throws UserFailureException;
 
+    /**
+     * Updates samples from files which have been previously uploaded.
+     * <p>
+     * Uploaded files can be found as session attribute under given <var>sessionKey</var>.
+     * </p>
+     */
+    public List<BatchRegistrationResult> updateSamples(final SampleType sampleType,
+            final String sessionKey) throws UserFailureException;
+
     /**
      * For given <var>experimentIdentifier</var> returns corresponding {@link Experiment}.
      */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientServiceAsync.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientServiceAsync.java
index 8c7284e25c7db936a21ce1004bee0437f683f77f..a66fe36870ff04c4303f583e9560af966649feeb 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientServiceAsync.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientServiceAsync.java
@@ -44,7 +44,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 /**
  * Asynchronous version of {@link IGenericClientService}.
  * 
- * @author     Franz-Josef Elmer
+ * @author Franz-Josef Elmer
  */
 public interface IGenericClientServiceAsync extends IClientServiceAsync
 {
@@ -73,6 +73,13 @@ public interface IGenericClientServiceAsync extends IClientServiceAsync
             final AsyncCallback<List<BatchRegistrationResult>> asyncCallback)
             throws UserFailureException;
 
+    /**
+     * @see IGenericClientService#updateSamples(SampleType, String)
+     */
+    public void updateSamples(final SampleType sampleType, final String sessionKey,
+            final AsyncCallback<List<BatchRegistrationResult>> asyncCallback)
+            throws UserFailureException;
+
     /**
      * @see IGenericClientService#getExperimentInfo(String)
      */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/ClientPluginFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/ClientPluginFactory.java
index 56db96e27004287349c399486f2c37e5f2d7ef65..0c109c8b6e7a3de90f3b6da51314e8bc45a4d669 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/ClientPluginFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/ClientPluginFactory.java
@@ -52,6 +52,7 @@ import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.mat
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.material.GenericMaterialEditForm;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.material.GenericMaterialViewer;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample.GenericSampleBatchRegistrationForm;
+import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample.GenericSampleBatchUpdateForm;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample.GenericSampleEditForm;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample.GenericSampleRegistrationForm;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample.GenericSampleViewer;
@@ -169,6 +170,11 @@ public final class ClientPluginFactory extends
             return new GenericSampleBatchRegistrationForm(getViewContext(), sampleType);
         }
 
+        public final Widget createBatchUpdateForEntityType(final SampleType sampleType)
+        {
+            return new GenericSampleBatchUpdateForm(getViewContext(), sampleType);
+        }
+
         public ITabItemFactory createEntityEditor(final IIdentifiable identifiable)
         {
             return new ITabItemFactory()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleBatchUpdateForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleBatchUpdateForm.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d128cfe861eff75ad5c56dc4236f5084af77ef0
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleBatchUpdateForm.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2008 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.sample;
+
+import static ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.DatabaseModificationAwareField.wrapUnaware;
+
+import java.util.List;
+
+import com.extjs.gxt.ui.client.Style.Scroll;
+import com.extjs.gxt.ui.client.event.BaseEvent;
+import com.extjs.gxt.ui.client.event.ButtonEvent;
+import com.extjs.gxt.ui.client.event.Events;
+import com.extjs.gxt.ui.client.event.Listener;
+import com.extjs.gxt.ui.client.event.SelectionListener;
+import com.extjs.gxt.ui.client.widget.form.Field;
+import com.extjs.gxt.ui.client.widget.form.FileUploadField;
+import com.extjs.gxt.ui.client.widget.form.LabelField;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.FormPanelListener;
+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.UrlParamsHelper;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.renderer.LinkRenderer;
+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;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.WindowUtils;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.BatchRegistrationResult;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
+import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.IGenericClientServiceAsync;
+
+/**
+ * The <i>generic</i> sample batch update panel.
+ * 
+ * @author Piotr Buczek
+ */
+public final class GenericSampleBatchUpdateForm extends AbstractRegistrationForm
+{
+    private static final String PREFIX = "sample-batch-update";
+
+    public final static String ID = GenericConstants.ID_PREFIX + PREFIX;
+
+    private static final String SESSION_KEY = PREFIX;
+
+    private static final String FIELD_LABEL_TEMPLATE = "File";
+
+    private static final int DEFAULT_NUMBER_OF_FILES = 1;
+
+    private final BasicFileFieldManager fileFieldsManager;
+
+    private final IViewContext<IGenericClientServiceAsync> viewContext;
+
+    private final SampleType sampleType;
+
+    public GenericSampleBatchUpdateForm(final IViewContext<IGenericClientServiceAsync> viewContext,
+            final SampleType sampleType)
+    {
+        super(viewContext.getCommonViewContext(), ID);
+        this.viewContext = viewContext;
+        this.sampleType = sampleType;
+        fileFieldsManager =
+                new BasicFileFieldManager(SESSION_KEY, DEFAULT_NUMBER_OF_FILES,
+                        FIELD_LABEL_TEMPLATE);
+        fileFieldsManager.setMandatory();
+        setScrollMode(Scroll.AUTO);
+        addUploadFeatures(SESSION_KEY);
+    }
+
+    @Override
+    protected void resetFieldsAfterSave()
+    {
+        for (FileUploadField attachmentField : fileFieldsManager.getFields())
+        {
+            attachmentField.reset();
+        }
+    }
+
+    private final void addFormFields()
+    {
+        for (FileUploadField attachmentField : fileFieldsManager.getFields())
+        {
+            formPanel.add(wrapUnaware((Field<?>) attachmentField).get());
+        }
+        formPanel.add(createTemplateField());
+        formPanel.addListener(Events.Submit, new FormPanelListener(infoBox)
+            {
+                @Override
+                protected void onSuccessfullUpload()
+                {
+                    save();
+                }
+
+                @Override
+                protected void setUploadEnabled()
+                {
+                    GenericSampleBatchUpdateForm.this.setUploadEnabled(true);
+                }
+            });
+        redefineSaveListeners();
+    }
+
+    protected void save()
+    {
+        viewContext.getService().updateSamples(sampleType, SESSION_KEY,
+                new RegisterSamplesCallback(viewContext));
+    }
+
+    void redefineSaveListeners()
+    {
+        saveButton.removeAllListeners();
+        saveButton.addSelectionListener(new SelectionListener<ButtonEvent>()
+            {
+                @Override
+                public final void componentSelected(final ButtonEvent ce)
+                {
+                    if (formPanel.isValid())
+                    {
+                        if (fileFieldsManager.filesDefined() > 0)
+                        {
+                            setUploadEnabled(false);
+                            formPanel.submit();
+                        } else
+                        {
+                            save();
+                        }
+                    }
+                }
+            });
+    }
+
+    private final class RegisterSamplesCallback extends
+            AbstractRegistrationForm.AbstractRegistrationCallback<List<BatchRegistrationResult>>
+    {
+        RegisterSamplesCallback(final IViewContext<IGenericClientServiceAsync> viewContext)
+        {
+            super(viewContext);
+        }
+
+        @Override
+        protected String createSuccessfullRegistrationInfo(
+                final List<BatchRegistrationResult> result)
+        {
+            final StringBuilder builder = new StringBuilder();
+            for (final BatchRegistrationResult batchRegistrationResult : result)
+            {
+                builder.append("<b>" + batchRegistrationResult.getFileName() + "</b>:");
+                builder.append(batchRegistrationResult.getMessage());
+                builder.append("<br />");
+            }
+            return builder.toString();
+        }
+
+    }
+
+    @Override
+    protected final void submitValidForm()
+    {
+    }
+
+    @Override
+    protected final void onRender(final Element target, final int index)
+    {
+        super.onRender(target, index);
+        addFormFields();
+    }
+
+    private LabelField createTemplateField()
+    {
+        LabelField result =
+                new LabelField(LinkRenderer.renderAsLink(viewContext
+                        .getMessage(Dict.FILE_TEMPLATE_LABEL)));
+        result.sinkEvents(Event.ONCLICK);
+        result.addListener(Events.OnClick, new Listener<BaseEvent>()
+            {
+                public void handleEvent(BaseEvent be)
+                {
+                    WindowUtils.openWindow(UrlParamsHelper.createTemplateURL(EntityKind.SAMPLE,
+                            sampleType, false, true));
+                }
+            });
+        return result;
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java
index c64afd596f11816be19a02a13a3703a7cf504e0a..29f2d1a4e79bf406d9715cae5dfb4ff4b85eebd6 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java
@@ -162,7 +162,7 @@ public final class GenericClientService extends AbstractClientService implements
     {
         BatchSamplesRegistration info =
                 parseSamples(sampleType, sessionKey, defaultGroupIdentifier,
-                        defaultGroupIdentifier != null, true);
+                        defaultGroupIdentifier != null, true, "registered");
         try
         {
             final String sessionToken = getSessionToken();
@@ -175,6 +175,24 @@ public final class GenericClientService extends AbstractClientService implements
 
     }
 
+    public final List<BatchRegistrationResult> updateSamples(final SampleType sampleType,
+            final String sessionKey)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        BatchSamplesRegistration info =
+                parseSamples(sampleType, sessionKey, null, false, true, "updated");
+        try
+        {
+            final String sessionToken = getSessionToken();
+            genericServer.updateSamples(sessionToken, info.getSamples());
+            return info.getResultList();
+        } catch (final ch.systemsx.cisd.common.exceptions.UserFailureException e)
+        {
+            throw UserFailureExceptionTranslator.translate(e);
+        }
+
+    }
+
     public final Experiment getExperimentInfo(final String experimentIdentifier)
             throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
     {
@@ -247,7 +265,7 @@ public final class GenericClientService extends AbstractClientService implements
                     parseSamples(experiment.getSampleType(), samplesSessionKey,
                             new GroupIdentifier(identifier.getDatabaseInstanceCode(), identifier
                                     .getGroupCode()).toString(), experiment.isGenerateCodes(),
-                            false);
+                            false, "registered");
             experiment.setNewSamples(result.getSamples());
             experiment.setSamples(result.getCodes());
         }
@@ -263,7 +281,7 @@ public final class GenericClientService extends AbstractClientService implements
 
     private BatchSamplesRegistration parseSamples(final SampleType sampleType,
             final String sessionKey, String defaultGroupIdentifier,
-            final boolean isAutoGenerateCodes, final boolean allowExperiments)
+            final boolean isAutoGenerateCodes, final boolean allowExperiments, String operation)
     {
         HttpSession httpSession = getHttpSession();
         UploadedFilesBean uploadedFiles = null;
@@ -273,7 +291,7 @@ public final class GenericClientService extends AbstractClientService implements
                     tryGetSampleCodeGenerator(isAutoGenerateCodes);
             uploadedFiles = getUploadedFiles(sessionKey, httpSession);
             return SampleUploadSectionsParser.prepareSamples(sampleType, uploadedFiles,
-                    defaultGroupIdentifier, sampleCodeGeneratorOrNull, allowExperiments);
+                    defaultGroupIdentifier, sampleCodeGeneratorOrNull, allowExperiments, operation);
         } catch (final UserFailureException e)
         {
             throw UserFailureExceptionTranslator.translate(e);
@@ -394,7 +412,7 @@ public final class GenericClientService extends AbstractClientService implements
                     }
                     Date date =
                             genericServer.updateSample(sessionToken, new SampleUpdatesDTO(updates
-                                    .getSampleId(), updates.getProperties(),
+                                    .getSampleIdOrNull(), updates.getProperties(),
                                     convExperimentIdentifierOrNull, attachments, updates
                                             .getVersion(), sampleOwner, updates
                                             .getParentIdentifierOrNull(), updates
@@ -430,7 +448,8 @@ public final class GenericClientService extends AbstractClientService implements
             BatchSamplesRegistration info =
                     parseSamples(updates.getSampleType(), updates.getSamplesSessionKey(),
                             new GroupIdentifier(newProject.getDatabaseInstanceCode(), newProject
-                                    .getGroupCode()).toString(), updates.isGenerateCodes(), false);
+                                    .getGroupCode()).toString(), updates.isGenerateCodes(), false,
+                            "registered");
             updates.setNewSamples(info.getSamples());
             updates.setSampleCodes(info.getCodes());
         }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/parser/SampleUploadSectionsParser.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/parser/SampleUploadSectionsParser.java
index ab098768f5f4055deecfb853b55926b08cc05a52..1ea04297f1d3556eed0ea11c59596e76b8fb3fb6 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/parser/SampleUploadSectionsParser.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/parser/SampleUploadSectionsParser.java
@@ -87,13 +87,14 @@ public class SampleUploadSectionsParser
 
     public static BatchSamplesRegistration prepareSamples(final SampleType sampleType,
             final UploadedFilesBean uploadedFiles, String defaultGroupIdentifier,
-            final SampleCodeGenerator sampleCodeGeneratorOrNull, final boolean allowExperiments)
+            final SampleCodeGenerator sampleCodeGeneratorOrNull, final boolean allowExperiments,
+            String operation)
     {
         final List<NewSamplesWithTypes> newSamples = new ArrayList<NewSamplesWithTypes>();
         boolean isAutoGenerateCodes = (sampleCodeGeneratorOrNull != null);
         final List<BatchRegistrationResult> results =
                 loadSamplesFromFiles(uploadedFiles, sampleType, isAutoGenerateCodes, newSamples,
-                        allowExperiments);
+                        allowExperiments, operation);
         generateIdentifiersIfNecessary(defaultGroupIdentifier, sampleCodeGeneratorOrNull,
                 isAutoGenerateCodes, newSamples);
         return new BatchSamplesRegistration(newSamples, results, parseCodes(newSamples));
@@ -112,6 +113,7 @@ public class SampleUploadSectionsParser
         return codes.toArray(new String[0]);
     }
 
+    // TODO
     private static BisTabFileLoader<NewSample> createSampleLoader(final SampleType sampleType,
             final boolean isAutoGenerateCodes, final boolean allowExperiments)
     {
@@ -215,7 +217,7 @@ public class SampleUploadSectionsParser
 
     private static List<BatchRegistrationResult> loadSamplesFromFiles(
             UploadedFilesBean uploadedFiles, SampleType sampleType, boolean isAutoGenerateCodes,
-            final List<NewSamplesWithTypes> newSamples, boolean allowExperiments)
+            final List<NewSamplesWithTypes> newSamples, boolean allowExperiments, String operation)
     {
 
         final List<BatchRegistrationResult> results =
@@ -253,7 +255,7 @@ public class SampleUploadSectionsParser
                 }
             }
             results.add(new BatchRegistrationResult(multipartFile.getOriginalFilename(), String
-                    .format("%d sample(s) found and registered.", sampleCounter)));
+                    .format("%d sample(s) found and %s.", sampleCounter, operation)));
         }
         return results;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
index 8bb2d1dce3603ae56955eee2de7ad70bc4064ff6..01c40b6f5e61eec0d96cf5b1563ce46c7b199315 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.openbis.plugin.generic.server;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashSet;
@@ -67,8 +68,11 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE;
 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.GroupIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.IdentifierHelper;
 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.dto.properties.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.translator.AttachmentTranslator;
 import ch.systemsx.cisd.openbis.generic.shared.translator.ExperimentTranslator;
@@ -246,6 +250,17 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
         }
     }
 
+    public void updateSamples(String sessionToken, List<NewSamplesWithTypes> newSamplesWithType)
+            throws UserFailureException
+    {
+        assert sessionToken != null : "Unspecified session token.";
+        final Session session = getSession(sessionToken);
+        for (NewSamplesWithTypes samples : newSamplesWithType)
+        {
+            updateSamples(session, samples);
+        }
+    }
+
     private void registerSamples(final Session session, final NewSamplesWithTypes newSamplesWithType)
     {
         final SampleType sampleType = newSamplesWithType.getSampleType();
@@ -280,6 +295,74 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
         getSampleTypeSlaveServerPlugin(sampleTypePE).registerSamples(session, newSamples);
     }
 
+    private void updateSamples(final Session session,
+            final NewSamplesWithTypes updatedSamplesWithType)
+    {
+        final SampleType sampleType = updatedSamplesWithType.getSampleType();
+        final List<NewSample> updatedSamples = updatedSamplesWithType.getNewSamples();
+        assert sampleType != null : "Unspecified sample type.";
+        assert updatedSamples != null : "Unspecified new samples.";
+
+        // Does nothing if samples list is empty.
+        if (updatedSamples.size() == 0)
+        {
+            return;
+        }
+        // Check uniqueness of given list based on sample identifier.
+        final HashSet<NewSample> sampleSet = new HashSet<NewSample>(updatedSamples);
+        if (sampleSet.size() != updatedSamples.size())
+        {
+            for (NewSample s : sampleSet)
+            {
+                updatedSamples.remove(s);
+            }
+            throw UserFailureException.fromTemplate("Following samples '%s' are duplicated.",
+                    CollectionUtils.abbreviate(updatedSamples, 20));
+        }
+        final String sampleTypeCode = sampleType.getCode();
+        final SampleTypePE sampleTypePE =
+                getDAOFactory().getSampleTypeDAO().tryFindSampleTypeByCode(sampleTypeCode);
+        if (sampleTypePE == null)
+        {
+            throw UserFailureException.fromTemplate("Sample type with code '%s' does not exist.",
+                    sampleTypeCode);
+        }
+
+        for (NewSample updatedSample : updatedSamples)
+        {
+            final SampleIdentifier oldSampleIdentifier =
+                    SampleIdentifierFactory.parse(updatedSample.getIdentifier());
+            final List<IEntityProperty> properties = Arrays.asList(updatedSample.getProperties());
+            final ExperimentIdentifier experimentIdentifierOrNull;
+            final SampleIdentifier newSampleIdentifier;
+            if (updatedSample.getExperimentIdentifier() != null)
+            {
+                // experiment is provided - new sample identifier takes experiment group
+                experimentIdentifierOrNull =
+                        new ExperimentIdentifierFactory(updatedSample.getExperimentIdentifier())
+                                .createIdentifier();
+                newSampleIdentifier =
+                        new SampleIdentifier(new GroupIdentifier(experimentIdentifierOrNull
+                                .getDatabaseInstanceCode(), experimentIdentifierOrNull
+                                .getGroupCode()), oldSampleIdentifier.getSampleCode()); // subcode?
+            } else
+            {
+                // FIXME looses experiment, parent and container information if there is no column
+                // no experiment - leave sample identifier unchanged
+                experimentIdentifierOrNull = null;
+                newSampleIdentifier = oldSampleIdentifier;
+            }
+            final Collection<NewAttachment> attachments = new ArrayList<NewAttachment>(0); // empty
+            final Date version = null; // no version check
+            final String parentIdentifierOrNull = updatedSample.getParentIdentifier();
+            final String containerIdentifierOrNull = updatedSample.getContainerIdentifier();
+
+            updateSample(session, new SampleUpdatesDTO(oldSampleIdentifier, properties,
+                    experimentIdentifierOrNull, attachments, version, newSampleIdentifier,
+                    parentIdentifierOrNull, containerIdentifierOrNull));
+        }
+    }
+
     public void registerExperiment(String sessionToken, NewExperiment newExperiment,
             final Collection<NewAttachment> attachments)
     {
@@ -435,6 +518,11 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
     public Date updateSample(String sessionToken, SampleUpdatesDTO updates)
     {
         final Session session = getSession(sessionToken);
+        return updateSample(session, updates);
+    }
+
+    private Date updateSample(Session session, SampleUpdatesDTO updates)
+    {
         final ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
         sampleBO.update(updates);
         sampleBO.save();
@@ -465,4 +553,5 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
         }
         return codes;
     }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerLogger.java
index 74101158389eaa9b864e8b05e52954a8306a4842..6f356586e2ee60686e9d185eff8ef313c8494afc 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerLogger.java
@@ -40,7 +40,6 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewMaterial;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSamplesWithTypes;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleParentWithDerived;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
@@ -52,7 +51,7 @@ import ch.systemsx.cisd.openbis.plugin.generic.shared.IGenericServer;
 /**
  * Logger class for {@link GenericServer} which creates readable logs of method invocations.
  * 
- * @author     Franz-Josef Elmer
+ * @author Franz-Josef Elmer
  */
 final class GenericServerLogger extends AbstractServerLogger implements IGenericServer
 {
@@ -116,13 +115,6 @@ final class GenericServerLogger extends AbstractServerLogger implements IGeneric
         return null;
     }
 
-    public final void registerSamples(final String sessionToken, final SampleType sampleType,
-            final List<NewSample> newSamples) throws UserFailureException
-    {
-        logAccess(sessionToken, "register_samples", "SAMPLE_TYPE(%s) SAMPLES(%s)", sampleType,
-                CollectionUtils.abbreviate(newSamples, 20));
-    }
-
     public void registerExperiment(String sessionToken, NewExperiment experiment,
             final Collection<NewAttachment> attachments)
     {
@@ -188,7 +180,7 @@ final class GenericServerLogger extends AbstractServerLogger implements IGeneric
     public Date updateSample(String sessionToken, SampleUpdatesDTO updates)
     {
         logTracking(sessionToken, "edit_sample",
-                "SAMPLE(%s), CHANGE_TO_EXPERIMENT(%s) ATTACHMENTS(%s)", updates.getSampleId(),
+                "SAMPLE(%s), CHANGE_TO_EXPERIMENT(%s) ATTACHMENTS(%s)", updates.getSampleIdOrNull(),
                 updates.getExperimentIdentifierOrNull(), updates.getAttachments().size());
         return null;
     }
@@ -217,4 +209,19 @@ final class GenericServerLogger extends AbstractServerLogger implements IGeneric
 
     }
 
+    public void updateSamples(String sessionToken, List<NewSamplesWithTypes> updatedSamplesWithType)
+            throws UserFailureException
+    {
+        StringBuilder sb = new StringBuilder();
+        for (NewSamplesWithTypes s : updatedSamplesWithType)
+        {
+            if (sb.length() > 0)
+            {
+                sb.append(",");
+            }
+            sb.append(s.getSampleType().getCode() + ":" + s.getNewSamples().size());
+        }
+        logAccess(sessionToken, "update_samples", sb.toString());
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/shared/IGenericServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/shared/IGenericServer.java
index 3ac508922dbfa3963b87785f869687f9b9fe120c..c3562cb4be17ffc95611ae34b1ac3c48bc6e7e14 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/shared/IGenericServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/shared/IGenericServer.java
@@ -60,7 +60,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifi
 /**
  * Definition of the client-server interface.
  * 
- * @author     Franz-Josef Elmer
+ * @author Franz-Josef Elmer
  */
 public interface IGenericServer extends IPluginCommonServer
 {
@@ -117,6 +117,17 @@ public interface IGenericServer extends IPluginCommonServer
             @AuthorizationGuard(guardClass = NewSamplesWithTypePredicate.class) final List<NewSamplesWithTypes> newSamplesWithType)
             throws UserFailureException;
 
+    /**
+     * Updates samples of different types in batches.
+     */
+    @Transactional
+    @RolesAllowed(RoleSet.USER)
+    @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
+    public void updateSamples(
+            final String sessionToken,
+            @AuthorizationGuard(guardClass = NewSamplesWithTypePredicate.class) final List<NewSamplesWithTypes> newSamplesWithType)
+            throws UserFailureException;
+
     /**
      * Registers experiment.
      */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ClientPluginFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ClientPluginFactory.java
index 3e5459ea16be1da816dafa51608944666748669b..9c530becb9350a510e6f9fb6ce825fdba9418d94 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ClientPluginFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ClientPluginFactory.java
@@ -149,6 +149,11 @@ public final class ClientPluginFactory extends
             return new DummyComponent();
         }
 
+        public final Widget createBatchUpdateForEntityType(final SampleType sampleType)
+        {
+            return new DummyComponent();
+        }
+
         public ITabItemFactory createEntityEditor(final IIdentifiable identifiable)
         {
             return new ITabItemFactory()
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 299abad6a68823e6169ccb12735c62177ea4c95c..e1054f16ad5c62edcfcbba8dd25684deb3f5f37c 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
@@ -268,6 +268,7 @@ var common = {
   SAMPLE_MENU_BROWSE: "Browse",
   SAMPLE_MENU_NEW: "New",
   SAMPLE_MENU_IMPORT: "Import",
+  SAMPLE_MENU_MASS_UPDATE: "Mass Update",
   SAMPLE_MENU_TYPES: "Types",
   
   menu_project: "Project",
@@ -308,8 +309,9 @@ var common = {
   property_type_registration: "Property Type Registration",
   property_types: "Property Types",
   experiment_browser: "Experiment Browser",
-  vocabulary_registration: "Vocabulary Registration",
-  sample_batch_registration: "Sample Batch Registration",
+  vocabulary_registration: "Vocabulary Registration",
+  sample_batch_registration: "Sample Batch Registration",
+  sample_batch_update: "Sample Batch Update",
   sample_registration: "Sample Registration",
   sample_broser: "Sample Browser",
   list_groups: "Groups Browser",
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/shared/IGenericServer.java.expected b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/shared/IGenericServer.java.expected
index cb6350a1d40b040b8c987bc04f0e61eab936ef65..c3562cb4be17ffc95611ae34b1ac3c48bc6e7e14 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/shared/IGenericServer.java.expected
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/shared/IGenericServer.java.expected
@@ -117,6 +117,17 @@ public interface IGenericServer extends IPluginCommonServer
             @AuthorizationGuard(guardClass = NewSamplesWithTypePredicate.class) final List<NewSamplesWithTypes> newSamplesWithType)
             throws UserFailureException;
 
+    /**
+     * Updates samples of different types in batches.
+     */
+    @Transactional
+    @RolesAllowed(RoleSet.USER)
+    @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
+    public void updateSamples(
+            final String sessionToken,
+            @AuthorizationGuard(guardClass = NewSamplesWithTypePredicate.class) final List<NewSamplesWithTypes> newSamplesWithType)
+            throws UserFailureException;
+
     /**
      * Registers experiment.
      */