From 719e185e1bb0e1a53200ead32640d47bc41dfcfd Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Thu, 10 Mar 2011 15:33:56 +0000
Subject: [PATCH] LMS-2103 Wizard framework and first useful version of an
 annotation wizard

SVN: 20294
---
 .../ui/grid/AbstractBrowserGrid.java          |  21 +-
 .../ui/grid/BrowserGridPagingToolBar.java     |  11 ++
 .../ui/wizard/IWizardDataModel.java           |  40 ++++
 .../application/ui/wizard/IWizardState.java   |  27 +++
 .../ui/wizard/IWizardStateChangeListener.java |  28 +++
 .../client/application/ui/wizard/Wizard.java  | 120 ++++++++++++
 .../application/ui/wizard/WizardPage.java     | 182 ++++++++++++++++++
 .../ui/wizard/WizardWorkflowModel.java        | 164 ++++++++++++++++
 .../cisd/openbis/public/common-dictionary.js  |   8 +
 .../phosphonetx/AbundanceHandler.java         |   3 +-
 .../etlserver/phosphonetx/Constants.java      |   2 -
 .../DataSetInfoExtractorForMSInjection.java   |   9 +-
 .../web/client/IPhosphoNetXClientService.java |  11 ++
 .../IPhosphoNetXClientServiceAsync.java       |  14 ++
 .../PhosphoNetXDisplayTypeIDGenerator.java    |   4 +
 .../client/application/PhosphoNetXModule.java |  46 ++++-
 .../wizard/BiologicalSampleChoosingPage.java  |  98 ++++++++++
 .../wizard/BiologicalSampleCreatingPage.java  |  41 ++++
 .../wizard/BiologicalSampleGrid.java          |  91 +++++++++
 .../MsInjectionAnnotationWizardState.java     |  29 +++
 .../MsInjectionSampleAnnotationModel.java     |  95 +++++++++
 .../MsInjectionSampleAnnotationWizard.java    |  41 ++++
 .../wizard/MsInjectionSampleChoosingPage.java | 107 ++++++++++
 .../ParentlessMsInjectionSampleGrid.java      |  92 +++++++++
 .../application/wizard/QuestionPage.java      |  67 +++++++
 .../dto/BiologicalSampleGridColumnIDs.java    |  30 +++
 ...entlessMsInjectionSampleGridColumnIDs.java |  30 +++
 .../web/public/phosphonetx-dictionary.js      |  10 +
 .../web/server/PhosphoNetXClientService.java  |  56 +++++-
 .../resultset/BiologicalSampleProvider.java   |  78 ++++++++
 .../ParentlessMsInjectionSampleProvider.java  |  83 ++++++++
 .../server/ProteomicsDataServiceInternal.java |  11 +-
 .../phosphonetx/shared/CommonConstants.java   |  31 +++
 .../phosphonetx/AbundanceHandlerTest.java     |   3 +-
 ...ataSetInfoExtractorForMSInjectionTest.java |  24 +--
 .../ResultDataSetUploaderTest.java            |   5 +-
 .../ProteomicsDataServiceInternalTest.java    |   8 +-
 37 files changed, 1674 insertions(+), 46 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardDataModel.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardState.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardStateChangeListener.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/Wizard.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/WizardPage.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/WizardWorkflowModel.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleChoosingPage.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleCreatingPage.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleGrid.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionAnnotationWizardState.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleAnnotationModel.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleAnnotationWizard.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleChoosingPage.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/ParentlessMsInjectionSampleGrid.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/QuestionPage.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/dto/BiologicalSampleGridColumnIDs.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/dto/ParentlessMsInjectionSampleGridColumnIDs.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/BiologicalSampleProvider.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ParentlessMsInjectionSampleProvider.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/CommonConstants.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
index 4ea4f5ce007..e398b4ec10d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
@@ -286,6 +286,16 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
             });
     }
 
+    public void removeConfigAndExportButtons()
+    {
+        pagingToolbar.removeConfigAndExportButtons();
+    }
+    
+    public void removeFiltersButtons()
+    {
+        pagingToolbar.removeFiltersButtons();
+    }
+    
     private ICellListener<T> createShowEntityViewerLinkClickListener()
     {
         return new ICellListener<T>()
@@ -879,8 +889,7 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
                     if (show)
                     {
                         int logId = log("adding filters");
-                        bottomToolbars.insert(filterToolbar, 0);
-                        bottomToolbars.layout();
+                        showFiltersBar();
                         viewContext.logStop(logId);
                     } else
                     {
@@ -893,6 +902,12 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
             };
     }
 
+    protected void showFiltersBar()
+    {
+        bottomToolbars.insert(filterToolbar, 0);
+        bottomToolbars.layout();
+    }
+
     protected static interface ISelectedEntityInvoker<M>
     {
         void invoke(M selectedItem, boolean keyPressed);
@@ -1039,7 +1054,7 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
             });
     }
 
-    private void addGridSelectionChangeListener(Listener<SelectionChangedEvent<ModelData>> listener)
+    public void addGridSelectionChangeListener(Listener<SelectionChangedEvent<ModelData>> listener)
     {
         grid.getSelectionModel().addListener(Events.SelectionChange, listener);
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/BrowserGridPagingToolBar.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/BrowserGridPagingToolBar.java
index abe91f90d61..da645626fad 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/BrowserGridPagingToolBar.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/BrowserGridPagingToolBar.java
@@ -138,7 +138,18 @@ public final class BrowserGridPagingToolBar extends PagingToolBar
         viewContext.logStop(logID);
         setPagingComponentsHidden(true);
     }
+    
+    public void removeConfigAndExportButtons()
+    {
+        configButton.removeFromParent();
+        exportButton.removeFromParent();
+    }
 
+    public void removeFiltersButtons()
+    {
+        showFiltersButton.removeFromParent();
+    }
+    
     @Override
     protected void onLoad(LoadEvent event)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardDataModel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardDataModel.java
new file mode 100644
index 00000000000..c1221037723
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardDataModel.java
@@ -0,0 +1,40 @@
+/*
+ * 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.client.web.client.application.ui.wizard;
+
+/**
+ * Basic interface to the data model behind a wizard.
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IWizardDataModel
+{
+    /**
+     * Returns the workflow model.
+     */
+    public WizardWorkflowModel getWorkflow();
+    
+    /**
+     * Determines at workflow branches the next state based on the specified current state.
+     */
+    public IWizardState determineNextState(IWizardState currentState);
+    
+    /**
+     * Finishes the wizard, submit/commit data and return a success message for the user.
+     */
+    public String finish();
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardState.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardState.java
new file mode 100644
index 00000000000..c016e2f28a3
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardState.java
@@ -0,0 +1,27 @@
+/*
+ * 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.client.web.client.application.ui.wizard;
+
+/**
+ * Marker interface for immutable value objects representing a state of a
+ * {@link WizardWorkflowModel}. 
+ * 
+ * @author Franz-Josef Elmer
+ */
+public interface IWizardState
+{
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardStateChangeListener.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardStateChangeListener.java
new file mode 100644
index 00000000000..289f1b96e6a
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/IWizardStateChangeListener.java
@@ -0,0 +1,28 @@
+/*
+ * 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.client.web.client.application.ui.wizard;
+
+/**
+ * Interface to be implemented by classes interested in {@link IWizardState} changes in
+ * {@link WizardWorkflowModel}.
+ * 
+ * @author Franz-Josef Elmer
+ */
+interface IWizardStateChangeListener
+{
+    void stateChanged(IWizardState previousStateOrNull, IWizardState currentStateOrNull);
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/Wizard.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/Wizard.java
new file mode 100644
index 00000000000..b77b997516b
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/Wizard.java
@@ -0,0 +1,120 @@
+/*
+ * 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.client.web.client.application.ui.wizard;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.extjs.gxt.ui.client.widget.LayoutContainer;
+import com.extjs.gxt.ui.client.widget.MessageBox;
+import com.extjs.gxt.ui.client.widget.TabItem;
+import com.extjs.gxt.ui.client.widget.layout.CardLayout;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Container of {@link WizardPage} instance. Manages changing between pages.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class Wizard<M extends IWizardDataModel> extends LayoutContainer
+{
+    private final CardLayout layout;
+    
+    private final M model;
+
+    private final WizardWorkflowModel workflowModel;
+
+    private final Map<IWizardState, WizardPage<M>> pages =
+            new HashMap<IWizardState, WizardPage<M>>();
+    
+    private final Set<WizardPage<M>> visitedPages = new HashSet<WizardPage<M>>();
+
+    /**
+     * Creates an instance for the specified wizard data model.
+     */
+    public Wizard(M model)
+    {
+        layout = new CardLayout();
+        setLayout(layout);
+        this.model = model;
+        workflowModel = model.getWorkflow();
+        workflowModel.addStateChangeListener(new IWizardStateChangeListener()
+            {
+                public void stateChanged(IWizardState previousStateOrNull,
+                        IWizardState currentStateOrNull)
+                {
+                    changePage(previousStateOrNull, currentStateOrNull);
+                }
+            });
+
+    }
+    
+    public M getWizardDataModel()
+    {
+        return model;
+    }
+
+    /**
+     * Registers specified wizard page.
+     */
+    public void register(WizardPage<M> page)
+    {
+        pages.put(page.getWizardState(), page);
+    }
+
+    /**
+     * Starts this wizard.
+     */
+    public void start()
+    {
+        workflowModel.nextState();
+    }
+
+    private void changePage(IWizardState previousStateOrNull, IWizardState currentStateOrNull)
+    {
+        if (currentStateOrNull != null)
+        {
+            WizardPage<M> nextPage = pages.get(currentStateOrNull);
+            if (nextPage != null)
+            {
+                nextPage.activate();
+                if (visitedPages.contains(nextPage) == false)
+                {
+                    nextPage.init();
+                    visitedPages.add(nextPage);
+                    add(nextPage);
+                }
+                layout.setActiveItem(nextPage);
+            }
+        } else if (workflowModel.hasNextState(currentStateOrNull) == false)
+        {
+            String message = model.finish();
+            MessageBox.info("Info", message, null);
+            for (WizardPage<M> page : visitedPages)
+            {
+                page.destroy();
+            }
+            Widget parent = getParent();
+            if (parent instanceof TabItem)
+            {
+                ((TabItem) parent).close();
+            }
+        }
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/WizardPage.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/WizardPage.java
new file mode 100644
index 00000000000..07a175e3ecc
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/WizardPage.java
@@ -0,0 +1,182 @@
+/*
+ * 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.client.web.client.application.ui.wizard;
+
+import com.extjs.gxt.ui.client.Style.LayoutRegion;
+import com.extjs.gxt.ui.client.event.ButtonEvent;
+import com.extjs.gxt.ui.client.event.SelectionListener;
+import com.extjs.gxt.ui.client.util.Margins;
+import com.extjs.gxt.ui.client.widget.Component;
+import com.extjs.gxt.ui.client.widget.ContentPanel;
+import com.extjs.gxt.ui.client.widget.LayoutContainer;
+import com.extjs.gxt.ui.client.widget.button.Button;
+import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
+import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
+import com.extjs.gxt.ui.client.widget.layout.CenterLayout;
+import com.extjs.gxt.ui.client.widget.layout.RowData;
+import com.extjs.gxt.ui.client.widget.layout.RowLayout;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMessageProvider;
+
+/**
+ * Base class of a page of a {@link Wizard}. Should be subclassed by overriding {@link #init()},
+ * {@link #deactivate()}, {@link #activate()}, {@link #destroy()} if needed.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public class WizardPage<M extends IWizardDataModel> extends LayoutContainer
+{
+    public static final String PREVIOUS_BUTTON_LABEL_KEY = "wizard_page_previous_button_label";
+    public static final String NEXT_BUTTON_LABEL_KEY = "wizard_page_next_button_label";
+    public static final String FINISH_BUTTON_LABEL_KEY = "wizard_page_finish_button_label";
+    
+    protected final M model;
+    private final IWizardState state;
+    private final LayoutContainer leftContent;
+    private final LayoutContainer rightContent;
+    private Button previousButton;
+    private Button nextOrFinishButton;
+
+    /**
+     * Creates an instance for specified message provider, wizard state and wizard data model.
+     * Subclasses should create in the constructor only widget components which do not need
+     * sever calls. Components created/populated by server callbacks should be created in
+     * {@link #init()}. 
+     */
+    public WizardPage(IMessageProvider messageProvider, IWizardState state, final M model)
+    {
+        super(new BorderLayout());
+        this.state = state;
+        this.model = model;
+        LayoutContainer leftCenterPanel = new LayoutContainer(new CenterLayout());
+        leftCenterPanel.setStyleAttribute("background-color", "white");
+        add(leftCenterPanel, new BorderLayoutData(LayoutRegion.WEST, 0.3f, 50, 200));
+        leftContent = new LayoutContainer(new RowLayout());
+        leftCenterPanel.add(leftContent);
+        ContentPanel rightPanel = new ContentPanel(new RowLayout());
+        rightPanel.setHeaderVisible(false);
+        add(rightPanel, new BorderLayoutData(LayoutRegion.CENTER));
+        LayoutContainer rightCenterPanel = new LayoutContainer(new RowLayout());
+        rightContent = new LayoutContainer(new RowLayout());
+        rightCenterPanel.add(rightContent, new RowData(1, 1, new Margins(10)));
+        rightPanel.add(rightCenterPanel);
+
+        final WizardWorkflowModel workflowModel = model.getWorkflow();
+        if (workflowModel.hasPreviousState(state))
+        {
+            previousButton = new Button(messageProvider.getMessage(PREVIOUS_BUTTON_LABEL_KEY));
+            previousButton.addSelectionListener(new SelectionListener<ButtonEvent>()
+                {
+                    @Override
+                    public void componentSelected(ButtonEvent ce)
+                    {
+                        workflowModel.previousState();
+                    }
+                });
+            rightPanel.addButton(previousButton);
+        }
+        String key =
+                workflowModel.hasNextState(state) ? NEXT_BUTTON_LABEL_KEY : FINISH_BUTTON_LABEL_KEY;
+        nextOrFinishButton = new Button(messageProvider.getMessage(key));
+        nextOrFinishButton.setEnabled(false);
+        nextOrFinishButton.addSelectionListener(new SelectionListener<ButtonEvent>()
+            {
+                @Override
+                public void componentSelected(ButtonEvent ce)
+                {
+                    deactivate();
+                    workflowModel.nextState();
+                }
+            });
+        rightPanel.addButton(nextOrFinishButton);
+    }
+    
+    IWizardState getWizardState()
+    {
+        return state;
+    }
+
+    /**
+     * Sets the content of the left hand part of this wizard page.
+     */
+    public void setLeftContentBy(Component component)
+    {
+        leftContent.removeAll();
+        leftContent.add(component, new RowData(1, 1, new Margins(10)));
+    }
+
+    /**
+     * Adds specified component to the right hand part of this wizard page. All components are
+     * layout by a vertical {@link RowLayout}.
+     */
+    public void addToRightContent(Component component, RowData layoutData)
+    {
+        rightContent.add(component, layoutData);
+    }
+    
+    /**
+     * Enables/disables next/finish button.
+     */
+    public void enableNextButton(boolean enabled)
+    {
+        nextOrFinishButton.setEnabled(enabled);
+    }
+    
+    /** 
+     * Initializes this wizard page when it is shown the first time in the wizard. 
+     * <p>
+     * This is a hook method which does nothing. It should be overridden if needed.
+     */
+    public void init()
+    {
+    }
+
+    /**
+     * Activates this page. This is called after {@link #deactivate()} has been invoked for the
+     * previous page (if any).
+     * <p>
+     * This is a hook method which does nothing. It should be overridden if needed.
+     */
+    public void activate()
+    {
+    }
+
+    /**
+     * Deactivates this page. This is called after the next/finish button has been pressed but
+     * before {@link #activate()} for the next page has been invoked. After invoking this method and
+     * before invocation of {@link #activate()} the method
+     * {@link IWizardDataModel#determineNextState(IWizardState)} will be invoked if more than one
+     * next states are possible.
+     * <p>
+     * This is a hook method which does nothing. It should be overridden if needed.
+     */
+    public void deactivate()
+    {
+    }
+    
+    /**
+     * Destroys this page. It will be invoked when the wizard has successfully be finished. That is,
+     * after {@link IWizardDataModel#finish()} has been invoked. This method can be used to release
+     * resources.
+     * <p>
+     * This is a hook method which does nothing. It should be overridden if needed.
+     */
+    public void destroy()
+    {
+        
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/WizardWorkflowModel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/WizardWorkflowModel.java
new file mode 100644
index 00000000000..52d0b3e90fe
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/wizard/WizardWorkflowModel.java
@@ -0,0 +1,164 @@
+/*
+ * 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.client.web.client.application.ui.wizard;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import com.google.gwt.core.client.JavaScriptException;
+
+/**
+ * Model of wizard workflow.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class WizardWorkflowModel
+{
+    private static final List<IWizardState> EMPTY_LIST = Arrays.<IWizardState>asList();
+    
+    private final List<IWizardStateChangeListener> changeListeners =
+            new ArrayList<IWizardStateChangeListener>();
+
+    private final Map<IWizardState, List<IWizardState>> transitionsToNext =
+            new HashMap<IWizardState, List<IWizardState>>();
+
+    private final Map<IWizardState, List<IWizardState>> transitionsToPrevious =
+            new HashMap<IWizardState, List<IWizardState>>();
+
+    private final Stack<IWizardState> visitedStates = new Stack<IWizardState>();
+
+    private final IWizardDataModel dataModel;
+    
+    private IWizardState initialState;
+    
+    /**
+     * Creates an instance for the specified data model. The data model is needed to make
+     * decision at workflow branches.
+     */
+    public WizardWorkflowModel(IWizardDataModel dataModel)
+    {
+        this.dataModel = dataModel;
+    }
+    
+    void addStateChangeListener(IWizardStateChangeListener stateChangeListener)
+    {
+        changeListeners.add(stateChangeListener);
+    }
+
+    /**
+     * Adds a transition from specified state to specified next state. For one state several
+     * transations can be added. In this branching case
+     * {@link IWizardDataModel#determineNextState(IWizardState)} will be invoked during execution
+     * of the workflow in order to determine which transition to follow.
+     */
+    public void addTransition(IWizardState state, IWizardState nextState)
+    {
+        List<IWizardState> nextStates = transitionsToNext.get(state);
+        if (nextStates == null)
+        {
+            nextStates = new ArrayList<IWizardState>();
+            transitionsToNext.put(state, nextStates);
+        }
+        nextStates.add(nextState);
+        List<IWizardState> previousStates = transitionsToPrevious.get(nextState);
+        if (previousStates == null)
+        {
+            previousStates = new ArrayList<IWizardState>();
+            transitionsToPrevious.put(nextState, previousStates);
+        }
+        previousStates.add(state);
+        if (initialState == null)
+        {
+            initialState = state;
+        }
+    }
+
+    void nextState()
+    {
+        List<IWizardState> nextStates = getNextStates();
+        if (nextStates.size() == 1)
+        {
+            setNextState(nextStates.get(0));
+        } else if (nextStates.size() > 1)
+        {
+            IWizardState nextState = dataModel.determineNextState(tryGetCurrentState());
+            if (nextStates.contains(nextState) == false)
+            {
+                throw new JavaScriptException("Error", "Next state " + nextState + " is not from "
+                        + nextStates);
+            }
+            setNextState(nextState);
+        } else
+        {
+            fireStateChangeEvent(tryGetCurrentState(), null);
+        }
+    }
+
+    private void setNextState(IWizardState nextState)
+    {
+        IWizardState oldState = tryGetCurrentState();
+        visitedStates.push(nextState);
+        fireStateChangeEvent(oldState, nextState);
+    }
+
+    private void fireStateChangeEvent(IWizardState oldState, IWizardState nextState)
+    {
+        for (IWizardStateChangeListener listener : changeListeners)
+        {
+            listener.stateChanged(oldState, nextState);
+        }
+    }
+
+    boolean hasNextState(IWizardState state)
+    {
+        return transitionsToNext.get(state) != null;
+    }
+    
+    private List<IWizardState> getNextStates()
+    {
+        IWizardState currentState = tryGetCurrentState();
+        if (currentState == null)
+        {
+            return initialState == null ? EMPTY_LIST : Arrays.asList(initialState);
+        }
+        List<IWizardState> nextStates = transitionsToNext.get(currentState);
+        return nextStates == null ? EMPTY_LIST : nextStates;
+    }
+
+    void previousState()
+    {
+        if (visitedStates.isEmpty() == false)
+        {
+            IWizardState oldState = visitedStates.pop();
+            fireStateChangeEvent(oldState, tryGetCurrentState());
+        }
+    }
+
+    boolean hasPreviousState(IWizardState state)
+    {
+        return transitionsToPrevious.get(state) != null;
+    }
+
+    IWizardState tryGetCurrentState()
+    {
+        return visitedStates.isEmpty() ? null : visitedStates.peek();
+    }
+}
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 d27e0acc9c5..f2b9d96dec9 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
@@ -299,6 +299,14 @@ var common = {
   default_update_value: "Update Value",
   default_update_value_tooltip: "The value of the assigned property for all currently existing entities that didn't have any value for this property.",
   
+  //
+  // Wizard
+  //
+  wizard_page_previous_button_label: "< Previous",
+  wizard_page_next_button_label: "Next >",
+  wizard_page_finish_button_label: "Finish",
+  
+  
   //
   // Menu Titles
   //
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandler.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandler.java
index 89e0906ad25..c296b81334b 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandler.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandler.java
@@ -32,6 +32,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.ListSamplesByPropertyCriteria
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
 
 /**
  * Handler of {@link Parameter} objects of type 'abundance'.
@@ -71,7 +72,7 @@ class AbundanceHandler extends AbstractHandler
         this.experiment = experiment;
         msData =
                 new SpaceIdentifier(experimentIdentifier.getDatabaseInstanceCode(),
-                        Constants.MS_DATA_SPACE);
+                        CommonConstants.MS_DATA_SPACE);
         sampleType = new SampleType();
         sampleType.setCode(Constants.SEARCH_SAMPLE_TYPE);
     }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/Constants.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/Constants.java
index 5f71ef1e0b3..23c6f7398e2 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/Constants.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/Constants.java
@@ -25,7 +25,5 @@ public class Constants
 {
     public static final String NAMESPACE = "http://regis-web.systemsbiology.net/protXML";
     
-    public static final String MS_DATA_SPACE = "MS_DATA";
-    
     public static final String SEARCH_SAMPLE_TYPE = "SEARCH";
 }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForMSInjection.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForMSInjection.java
index 93660860d5b..33497e439f5 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForMSInjection.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForMSInjection.java
@@ -45,6 +45,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
 
 /**
  * Data set info extractor for MS injection data sets. Information is extracted from a properties
@@ -77,8 +78,6 @@ public class DataSetInfoExtractorForMSInjection extends AbstractDataSetInfoExtra
 
     static final String EXPERIMENT_TYPE_CODE = "MS_INJECT";
 
-    static final String SAMPLE_TYPE_CODE = "MS_INJECTION";
-
     public DataSetInfoExtractorForMSInjection(Properties properties)
     {
         this(ServiceProvider.getOpenBISService());
@@ -96,7 +95,7 @@ public class DataSetInfoExtractorForMSInjection extends AbstractDataSetInfoExtra
         Properties sampleProperties =
                 Util.loadPropertiesFile(incomingDataSetPath, MS_INJECTION_PROPERTIES_FILE);
         DataSetInformation info = new DataSetInformation();
-        info.setSpaceCode(Constants.MS_DATA_SPACE);
+        info.setSpaceCode(CommonConstants.MS_DATA_SPACE);
         info.setSampleCode(PropertyUtils.getMandatoryProperty(sampleProperties, SAMPLE_CODE_KEY));
         SampleIdentifier sampleIdentifier = info.getSampleIdentifier();
         ExperimentIdentifier experimentIdentifier = getExperimentIdentifier(sampleProperties);
@@ -140,7 +139,7 @@ public class DataSetInfoExtractorForMSInjection extends AbstractDataSetInfoExtra
     private long registerOrUpdateSample(SampleIdentifier sampleIdentifier,
             ExperimentIdentifier experimentIdentifier, Properties properties)
     {
-        SampleType sampleType = service.getSampleType(SAMPLE_TYPE_CODE);
+        SampleType sampleType = service.getSampleType(CommonConstants.MS_INJECTION_SAMPLE_TYPE_CODE);
         Sample sample = service.tryGetSampleWithExperiment(sampleIdentifier);
         String biologicalSampleIdentifier = properties.getProperty(BIOLOGICAL_SAMPLE_IDENTIFIER_KEY);
         if (sample == null)
@@ -206,6 +205,6 @@ public class DataSetInfoExtractorForMSInjection extends AbstractDataSetInfoExtra
                 PropertyUtils.getMandatoryProperty(msInjectionProperties, PROJECT_CODE_KEY);
         String experimentCode =
                 PropertyUtils.getMandatoryProperty(msInjectionProperties, EXPERIMENT_CODE_KEY);
-        return new ExperimentIdentifier(null, Constants.MS_DATA_SPACE, projectCode, experimentCode);
+        return new ExperimentIdentifier(null, CommonConstants.MS_DATA_SPACE, projectCode, experimentCode);
     }
 }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/IPhosphoNetXClientService.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/IPhosphoNetXClientService.java
index b00ad140cb5..2dbdbfe6c6f 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/IPhosphoNetXClientService.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/IPhosphoNetXClientService.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client;
 import java.util.List;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.IClientService;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ResultSet;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
@@ -53,6 +54,16 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.SampleWithPr
  */
 public interface IPhosphoNetXClientService extends IClientService
 {
+    public TypedTableResultSet<Sample> listParentlessMsInjectionSamples(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Sample>> criteria)
+            throws UserFailureException;
+    
+    public TypedTableResultSet<Sample> listBiologicalSamples(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Sample>> criteria)
+            throws UserFailureException;
+    
+    public void linkSamples(Sample parentSample, List<Sample> childSamples) throws UserFailureException;
+    
     public Vocabulary getTreatmentTypeVocabulary() throws UserFailureException;
 
     public List<AbundanceColumnDefinition> getAbundanceColumnDefinitionsForProteinByExperiment(
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/IPhosphoNetXClientServiceAsync.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/IPhosphoNetXClientServiceAsync.java
index 091d210db1f..baa9472aebc 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/IPhosphoNetXClientServiceAsync.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/IPhosphoNetXClientServiceAsync.java
@@ -21,6 +21,7 @@ import java.util.List;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.IClientServiceAsync;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ResultSet;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
@@ -47,6 +48,19 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.SampleWithPr
  */
 public interface IPhosphoNetXClientServiceAsync extends IClientServiceAsync
 {
+    /** @see IPhosphoNetXClientService#listParentlessMsInjectionSamples(DefaultResultSetConfig) */
+    public void listParentlessMsInjectionSamples(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Sample>> criteria,
+            AsyncCallback<TypedTableResultSet<Sample>> callback);
+    
+    /** @see IPhosphoNetXClientService#listBiologicalSamples(DefaultResultSetConfig) */
+    public void listBiologicalSamples(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Sample>> criteria,
+            AsyncCallback<TypedTableResultSet<Sample>> callback);
+    
+    /** @see IPhosphoNetXClientService#linkSamples(Sample, List) */
+    public void linkSamples(Sample parentSample, List<Sample> childSamples, AsyncCallback<Void> callback);
+    
     /** @see IPhosphoNetXClientService#getTreatmentTypeVocabulary() */
     public void getTreatmentTypeVocabulary(AsyncCallback<Vocabulary> callback);
     
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/PhosphoNetXDisplayTypeIDGenerator.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/PhosphoNetXDisplayTypeIDGenerator.java
index d39c574f91f..e4813ecb22d 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/PhosphoNetXDisplayTypeIDGenerator.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/PhosphoNetXDisplayTypeIDGenerator.java
@@ -32,6 +32,10 @@ public enum PhosphoNetXDisplayTypeIDGenerator implements IDisplayTypeIDGenerator
     DATA_SET_PROTEIN_BROWSER_GRID("data-set-protein-browser-grid"), 
     
     RAW_DATA_SAMPLE_BROWSER_GRID("raw-data-sample-browser-grid"), 
+    
+    PARENT_LESS_MS_INJECTION_SAMPLE_BROWSER_GRID("parent-less-ms-injection-sample-browser-grid"), 
+    
+    BIOLOGICAL_SAMPLE_BROWSER_GRID("biological-sample-browser-grid"), 
     ;
 
     private final String genericNameOrPrefix;
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/PhosphoNetXModule.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/PhosphoNetXModule.java
index 06a95db17c9..9ebbb338054 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/PhosphoNetXModule.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/PhosphoNetXModule.java
@@ -17,8 +17,8 @@
 package ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
 import com.extjs.gxt.ui.client.widget.menu.MenuItem;
@@ -28,11 +28,15 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.Disposable
 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.framework.DatabaseModificationAwareComponent;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.locator.ViewLocator;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.ActionMenu;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.ITabActionMenuItemDefinition;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.TabActionMenuItemFactory;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.plugin.IModule;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolderWithIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.basic.URLMethodWithParameters;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.wizard.MsInjectionSampleAnnotationWizard;
 
 /**
  * @author Franz-Josef Elmer
@@ -50,31 +54,59 @@ public class PhosphoNetXModule implements IModule
 
     public List<? extends MenuItem> getMenuItems()
     {
-        return Collections.singletonList(TabActionMenuItemFactory.createActionMenu(viewContext, ID,
+        ActionMenu msInjectionSampleAnnotatingMenuItem = TabActionMenuItemFactory.createActionMenu(viewContext, ID,
                 new ITabActionMenuItemDefinition<IPhosphoNetXClientServiceAsync>()
                     {
 
                         public String getName()
                         {
-                            return "ALL_RAW_DATA_SAMPLES";
+                            return "ANNOTATE_MS_INJECTION_SAMPLES";
                         }
 
                         public String getHelpPageTitle()
                         {
-                            return "MS INJECTION Data Overview";
+                            return "Wizard for annotation MS INJECTION samples";
                         }
 
                         public DatabaseModificationAwareComponent createComponent(
                                 IViewContext<IPhosphoNetXClientServiceAsync> context)
                         {
-                            return RawDataSampleGrid.create(context);
+                            return DatabaseModificationAwareComponent.wrapUnaware(new MsInjectionSampleAnnotationWizard(context));
                         }
 
                         public String tryGetLink()
                         {
-                            return null;
+                            URLMethodWithParameters url = new URLMethodWithParameters("");
+                            url.addParameter(ViewLocator.ACTION_PARAMETER, getName());
+                            return url.toString().substring(1);
                         }
-                    }));
+                    });
+        ActionMenu msInjectionSampleBrowserMenuItem = TabActionMenuItemFactory.createActionMenu(viewContext, ID,
+                new ITabActionMenuItemDefinition<IPhosphoNetXClientServiceAsync>()
+                {
+            
+            public String getName()
+            {
+                return "ALL_RAW_DATA_SAMPLES";
+            }
+            
+            public String getHelpPageTitle()
+            {
+                return "MS INJECTION Data Overview";
+            }
+            
+            public DatabaseModificationAwareComponent createComponent(
+                    IViewContext<IPhosphoNetXClientServiceAsync> context)
+            {
+                return RawDataSampleGrid.create(context);
+            }
+            
+            public String tryGetLink()
+            {
+                return null;
+            }
+                });
+        return Arrays.asList(msInjectionSampleAnnotatingMenuItem, msInjectionSampleBrowserMenuItem);
     }
 
     public String getName()
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleChoosingPage.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleChoosingPage.java
new file mode 100644
index 00000000000..7f25c66295f
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleChoosingPage.java
@@ -0,0 +1,98 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import java.util.List;
+
+import com.extjs.gxt.ui.client.data.ModelData;
+import com.extjs.gxt.ui.client.event.Listener;
+import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
+import com.extjs.gxt.ui.client.util.Margins;
+import com.extjs.gxt.ui.client.widget.Html;
+import com.extjs.gxt.ui.client.widget.Label;
+import com.extjs.gxt.ui.client.widget.layout.RowData;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.BaseEntityModel;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.WizardPage;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+
+/**
+ * Wizard for guiding the user to annotate an MS_INJECTION sample.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class BiologicalSampleChoosingPage extends WizardPage<MsInjectionSampleAnnotationModel>
+{
+    private final IViewContext<IPhosphoNetXClientServiceAsync> viewContext;
+    
+    private BiologicalSampleGrid sampleGrid;
+
+    public BiologicalSampleChoosingPage(IViewContext<IPhosphoNetXClientServiceAsync> viewContext,
+            MsInjectionSampleAnnotationModel model)
+    {
+        super(viewContext, MsInjectionAnnotationWizardState.BIOLOGICAL_SAMPLE_CHOOSING, model);
+        this.viewContext = viewContext;
+        setLeftContentBy(new Html(
+                "Annotating <tt>MS_INJECTION</tt> sample by choosing one biological sample means " +
+                "that all properties of the biological sample is also for the <tt>MS_INJECTION</tt> to be annotated."));
+    }
+
+    @Override
+    public void init()
+    {
+        addToRightContent(
+                new Label(
+                        "Please choose a biological sample as annotation of the MS_INJECTION samples selected previously:"),
+                new RowData(1, -1, new Margins(10)));
+
+        sampleGrid = new BiologicalSampleGrid(viewContext);
+        sampleGrid.addGridSelectionChangeListener(new Listener<SelectionChangedEvent<ModelData>>()
+            {
+                public void handleEvent(SelectionChangedEvent<ModelData> se)
+                {
+                    List<ModelData> selection = se.getSelection();
+                    boolean enabled = selection.size() == 1;
+                    enableNextButton(enabled);
+                }
+
+            });
+        addToRightContent(sampleGrid, new RowData(1, 400, new Margins(20, 10, 10, 10)));
+    }
+
+    @Override
+    public void deactivate()
+    {
+        List<BaseEntityModel<TableModelRowWithObject<Sample>>> selectedItems =
+                sampleGrid.getSelectedItems();
+        if (selectedItems.isEmpty() == false)
+        {
+            model.setBiologicalSample(selectedItems.get(0).getBaseObject().getObjectOrNull());
+        }
+    }
+
+    @Override
+    public void destroy()
+    {
+        sampleGrid.dispose();
+    }
+    
+    
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleCreatingPage.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleCreatingPage.java
new file mode 100644
index 00000000000..6cf175b130e
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleCreatingPage.java
@@ -0,0 +1,41 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import com.extjs.gxt.ui.client.widget.Html;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.WizardPage;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+
+/**
+ * Wizard for guiding the user to annotate an MS_INJECTION sample.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class BiologicalSampleCreatingPage extends WizardPage<MsInjectionSampleAnnotationModel>
+{
+
+    public BiologicalSampleCreatingPage(IViewContext<IPhosphoNetXClientServiceAsync> viewContext,
+            MsInjectionSampleAnnotationModel model)
+    {
+        super(viewContext, MsInjectionAnnotationWizardState.BIOLOGICAL_SAMPLE_CREATING, model);
+        setLeftContentBy(new Html(
+                "Annotating <tt>MS_INJECTION</tt> sample by creating a new biological sample means ..."));
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleGrid.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleGrid.java
new file mode 100644
index 00000000000..05e13d3acab
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/BiologicalSampleGrid.java
@@ -0,0 +1,91 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
+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.ui.TypedTableGrid;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TypedTableResultSet;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.PhosphoNetXDisplayTypeIDGenerator;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.BiologicalSampleGridColumnIDs;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class BiologicalSampleGrid extends TypedTableGrid<Sample>
+{
+    private static final String PREFIX = GenericConstants.ID_PREFIX
+            + "biological_sample";
+
+    public static final String BROWSER_ID = PREFIX + "_main";
+
+    public static final String GRID_ID = PREFIX + TypedTableGrid.GRID_POSTFIX;
+
+    private final IViewContext<IPhosphoNetXClientServiceAsync> specificViewContext;
+
+    public BiologicalSampleGrid(IViewContext<IPhosphoNetXClientServiceAsync> viewContext)
+    {
+        super(viewContext.getCommonViewContext(), BROWSER_ID, true,
+                PhosphoNetXDisplayTypeIDGenerator.BIOLOGICAL_SAMPLE_BROWSER_GRID);
+        specificViewContext = viewContext;
+        removeConfigAndExportButtons();
+        removeFiltersButtons();
+        showFiltersBar();
+        setBorders(true);
+    }
+
+    @Override
+    protected void listTableRows(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Sample>> resultSetConfig,
+            AsyncCallback<TypedTableResultSet<Sample>> callback)
+    {
+        specificViewContext.getService().listBiologicalSamples(resultSetConfig, callback);
+    }
+
+    @Override
+    protected List<String> getColumnIdsOfFilters()
+    {
+        return Arrays.asList(BiologicalSampleGridColumnIDs.IDENTIFIER,
+                BiologicalSampleGridColumnIDs.REGISTRATION_DATE);
+    }
+
+    @Override
+    protected void prepareExportEntities(
+            TableExportCriteria<TableModelRowWithObject<Sample>> exportCriteria,
+            AbstractAsyncCallback<String> callback)
+    {
+    }
+    
+    public void dispose()
+    {
+        asDisposableWithoutToolbar().dispose();
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionAnnotationWizardState.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionAnnotationWizardState.java
new file mode 100644
index 00000000000..4afa1efd197
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionAnnotationWizardState.java
@@ -0,0 +1,29 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.IWizardState;
+
+/**
+ * States of wizard for annotating MS_INJECTION samples.
+ *
+ * @author Franz-Josef Elmer
+ */
+public enum MsInjectionAnnotationWizardState implements IWizardState
+{
+    MS_INJECTION_SAMPLE_CHOOSING, CHOOSE_OR_CREATE_QUESTION, BIOLOGICAL_SAMPLE_CHOOSING, BIOLOGICAL_SAMPLE_CREATING;
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleAnnotationModel.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleAnnotationModel.java
new file mode 100644
index 00000000000..b44484d5dcc
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleAnnotationModel.java
@@ -0,0 +1,95 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.wizard.MsInjectionAnnotationWizardState.BIOLOGICAL_SAMPLE_CHOOSING;
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.wizard.MsInjectionAnnotationWizardState.BIOLOGICAL_SAMPLE_CREATING;
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.wizard.MsInjectionAnnotationWizardState.CHOOSE_OR_CREATE_QUESTION;
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.wizard.MsInjectionAnnotationWizardState.MS_INJECTION_SAMPLE_CHOOSING;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.VoidAsyncCallback;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.IWizardDataModel;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.IWizardState;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.WizardWorkflowModel;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class MsInjectionSampleAnnotationModel implements IWizardDataModel
+{
+    private final IViewContext<IPhosphoNetXClientServiceAsync> context;
+    private final WizardWorkflowModel workflowModel;
+    private List<Sample> msInjectionSamples = new ArrayList<Sample>();
+    
+    private boolean chooseBiologicalSampleFlag;
+    private Sample biologicalSample;
+    
+    public MsInjectionSampleAnnotationModel(IViewContext<IPhosphoNetXClientServiceAsync> context)
+    {
+        this.context = context;
+        workflowModel = new WizardWorkflowModel(this);
+        workflowModel.addTransition(MS_INJECTION_SAMPLE_CHOOSING, CHOOSE_OR_CREATE_QUESTION);
+        workflowModel.addTransition(CHOOSE_OR_CREATE_QUESTION, BIOLOGICAL_SAMPLE_CHOOSING);
+        workflowModel.addTransition(CHOOSE_OR_CREATE_QUESTION, BIOLOGICAL_SAMPLE_CREATING);
+    }
+    
+    public WizardWorkflowModel getWorkflow()
+    {
+        return workflowModel;
+    }
+
+    public IWizardState determineNextState(IWizardState currentState)
+    {
+        return chooseBiologicalSampleFlag ? BIOLOGICAL_SAMPLE_CHOOSING : BIOLOGICAL_SAMPLE_CREATING;
+    }
+    
+    public void setSelectedMsInjectionSample(List<Sample> samples)
+    {
+        msInjectionSamples = samples;
+    }
+    
+    public List<Sample> getMsInjectionSamples()
+    {
+        return msInjectionSamples;
+    }
+    
+    public void setChooseBiologicalSampleFlag(boolean flag)
+    {
+        chooseBiologicalSampleFlag = flag;
+    }
+
+    public void setBiologicalSample(Sample biologicalSample)
+    {
+        this.biologicalSample = biologicalSample;
+    }
+
+    public String finish()
+    {
+        VoidAsyncCallback<Void> callback = new VoidAsyncCallback<Void>(context);
+        context.getService().linkSamples(biologicalSample, msInjectionSamples, callback);
+        return msInjectionSamples.size() + " MS_INJECTION samples have been annotated.";
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleAnnotationWizard.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleAnnotationWizard.java
new file mode 100644
index 00000000000..d4893777d37
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleAnnotationWizard.java
@@ -0,0 +1,41 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.Wizard;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class MsInjectionSampleAnnotationWizard extends Wizard<MsInjectionSampleAnnotationModel>
+{
+    public MsInjectionSampleAnnotationWizard(IViewContext<IPhosphoNetXClientServiceAsync> context)
+    {
+        super(new MsInjectionSampleAnnotationModel(context));
+        MsInjectionSampleAnnotationModel wizardDataModel = getWizardDataModel();
+        register(new MsInjectionSampleChoosingPage(context, wizardDataModel));
+        register(new QuestionPage(context, wizardDataModel));
+        register(new BiologicalSampleChoosingPage(context, wizardDataModel));
+        register(new BiologicalSampleCreatingPage(context, wizardDataModel));
+        start();
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleChoosingPage.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleChoosingPage.java
new file mode 100644
index 00000000000..1e8d921fa4c
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/MsInjectionSampleChoosingPage.java
@@ -0,0 +1,107 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.extjs.gxt.ui.client.data.ModelData;
+import com.extjs.gxt.ui.client.event.Listener;
+import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
+import com.extjs.gxt.ui.client.util.Margins;
+import com.extjs.gxt.ui.client.widget.Html;
+import com.extjs.gxt.ui.client.widget.Label;
+import com.extjs.gxt.ui.client.widget.layout.RowData;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.BaseEntityModel;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.WizardPage;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+
+/**
+ * Wizard for guiding the user to annotate an MS_INJECTION sample.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class MsInjectionSampleChoosingPage extends WizardPage<MsInjectionSampleAnnotationModel>
+{
+    private final IViewContext<IPhosphoNetXClientServiceAsync> viewContext;
+    
+    private ParentlessMsInjectionSampleGrid sampleGrid;
+
+    public MsInjectionSampleChoosingPage(IViewContext<IPhosphoNetXClientServiceAsync> viewContext,
+            MsInjectionSampleAnnotationModel model)
+    {
+        super(viewContext, MsInjectionAnnotationWizardState.MS_INJECTION_SAMPLE_CHOOSING, model);
+        this.viewContext = viewContext;
+        setLeftContentBy(new Html(
+                "MS data are added to openBIS in an automated process. "
+                        + "The corresponding data sets are associated with samples of type <tt>MS_INJECTION</tt>."
+                        + "<p>Before MS data of such samples can be processed in a protein identification pipeline "
+                        + "they have to be <b>annotated</b>. In the terminology of openBIS this means: "
+                        + "An <tt>MS_INJECTION</tt> sample is linked to biological sample where "
+                        + "the biological sample is the parent and the <tt>MS_INJECTION</tt> sample is the child. "
+                        + "The biological sample has all annotations. "
+                        + "They define the scientific context of proteins found. "
+                        + "<p>This wizard helps you add these important annotations to openBIS."));
+    }
+
+    @Override
+    public void init()
+    {
+        addToRightContent(new Label(
+                "Please choose one or more MS_INJECTION samples to be annotated:"), new RowData(1,
+                -1, new Margins(10)));
+
+        sampleGrid = new ParentlessMsInjectionSampleGrid(viewContext);
+        sampleGrid.addGridSelectionChangeListener(new Listener<SelectionChangedEvent<ModelData>>()
+            {
+                public void handleEvent(SelectionChangedEvent<ModelData> se)
+                {
+                    List<ModelData> selection = se.getSelection();
+                    boolean enabled = selection.size() > 0;
+                    enableNextButton(enabled);
+                }
+
+            });
+        addToRightContent(sampleGrid, new RowData(1, 500, new Margins(20, 10, 10, 10)));
+    }
+
+    @Override
+    public void deactivate()
+    {
+        List<BaseEntityModel<TableModelRowWithObject<Sample>>> selectedItems =
+                sampleGrid.getSelectedItems();
+        ArrayList<Sample> samples = new ArrayList<Sample>();
+        for (BaseEntityModel<TableModelRowWithObject<Sample>> item : selectedItems)
+        {
+            samples.add(item.getBaseObject().getObjectOrNull());
+        }
+        model.setSelectedMsInjectionSample(samples);
+    }
+
+    @Override
+    public void destroy()
+    {
+        sampleGrid.dispose();
+    }
+    
+    
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/ParentlessMsInjectionSampleGrid.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/ParentlessMsInjectionSampleGrid.java
new file mode 100644
index 00000000000..b66527acd85
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/ParentlessMsInjectionSampleGrid.java
@@ -0,0 +1,92 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
+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.ui.TypedTableGrid;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TypedTableResultSet;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.PhosphoNetXDisplayTypeIDGenerator;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.ParentlessMsInjectionSampleGridColumnIDs;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ParentlessMsInjectionSampleGrid extends TypedTableGrid<Sample>
+{
+    private static final String PREFIX = GenericConstants.ID_PREFIX
+            + "parentless_ms_injection_sample";
+
+    public static final String BROWSER_ID = PREFIX + "_main";
+
+    public static final String GRID_ID = PREFIX + TypedTableGrid.GRID_POSTFIX;
+
+    private final IViewContext<IPhosphoNetXClientServiceAsync> specificViewContext;
+
+    public ParentlessMsInjectionSampleGrid(IViewContext<IPhosphoNetXClientServiceAsync> viewContext)
+    {
+        super(viewContext.getCommonViewContext(), BROWSER_ID, true,
+                PhosphoNetXDisplayTypeIDGenerator.PARENT_LESS_MS_INJECTION_SAMPLE_BROWSER_GRID);
+        specificViewContext = viewContext;
+        removeConfigAndExportButtons();
+        removeFiltersButtons();
+        allowMultipleSelection();
+        showFiltersBar();
+        setBorders(true);
+    }
+    
+    @Override
+    protected void listTableRows(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Sample>> resultSetConfig,
+            AsyncCallback<TypedTableResultSet<Sample>> callback)
+    {
+        specificViewContext.getService().listParentlessMsInjectionSamples(resultSetConfig, callback);
+    }
+
+    @Override
+    protected List<String> getColumnIdsOfFilters()
+    {
+        return Arrays.asList(ParentlessMsInjectionSampleGridColumnIDs.IDENTIFIER,
+                ParentlessMsInjectionSampleGridColumnIDs.REGISTRATION_DATE);
+    }
+
+    @Override
+    protected void prepareExportEntities(
+            TableExportCriteria<TableModelRowWithObject<Sample>> exportCriteria,
+            AbstractAsyncCallback<String> callback)
+    {
+    }
+    
+    public void dispose()
+    {
+        asDisposableWithoutToolbar().dispose();
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/QuestionPage.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/QuestionPage.java
new file mode 100644
index 00000000000..651f2a05755
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/application/wizard/QuestionPage.java
@@ -0,0 +1,67 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.application.wizard;
+
+import com.extjs.gxt.ui.client.util.Margins;
+import com.extjs.gxt.ui.client.widget.Html;
+import com.extjs.gxt.ui.client.widget.form.Radio;
+import com.extjs.gxt.ui.client.widget.form.RadioGroup;
+import com.extjs.gxt.ui.client.widget.layout.RowData;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.wizard.WizardPage;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientServiceAsync;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class QuestionPage extends WizardPage<MsInjectionSampleAnnotationModel>
+{
+
+    private Radio chooseSampleRadioButton;
+    private RadioGroup radioGroup;
+
+    public QuestionPage(IViewContext<IPhosphoNetXClientServiceAsync> viewContext,
+            MsInjectionSampleAnnotationModel model)
+    {
+        super(viewContext, MsInjectionAnnotationWizardState.CHOOSE_OR_CREATE_QUESTION, model);
+        setLeftContentBy(new Html(
+                "Annotating the <tt>MS_INJECTION</tt> samples you have chosen means to link them to a <b>biological sample</b>. "
+                        + "You can choose an existing biological sample or you can create a new one."));
+        radioGroup = new RadioGroup("What do you want to annotate your samples?");
+        radioGroup.setFieldLabel("choose");
+        chooseSampleRadioButton = new Radio();
+        chooseSampleRadioButton.setBoxLabel("I want to choose an existing biological sample.");
+        chooseSampleRadioButton.setValue(true);
+        radioGroup.add(chooseSampleRadioButton);
+        Radio createSampleRadioButton = new Radio();
+        createSampleRadioButton.setBoxLabel("I want to create a new biological sample.");
+        radioGroup.add(createSampleRadioButton);
+        addToRightContent(radioGroup, new RowData(1, -1, new Margins(10)));
+        enableNextButton(true);
+    }
+
+    @Override
+    public void deactivate()
+    {
+        model.setChooseBiologicalSampleFlag(radioGroup.getValue().equals(chooseSampleRadioButton));
+    }
+    
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/dto/BiologicalSampleGridColumnIDs.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/dto/BiologicalSampleGridColumnIDs.java
new file mode 100644
index 00000000000..abe46fe8381
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/dto/BiologicalSampleGridColumnIDs.java
@@ -0,0 +1,30 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.dto;
+
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.wizard.ParentlessMsInjectionSampleGrid;
+
+/**
+ * IDs of columns of {@link ParentlessMsInjectionSampleGrid}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class BiologicalSampleGridColumnIDs
+{
+    public static final String IDENTIFIER = "IDENTIFIER";
+    public static final String REGISTRATION_DATE = "REGISTRATION_DATE";
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/dto/ParentlessMsInjectionSampleGridColumnIDs.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/dto/ParentlessMsInjectionSampleGridColumnIDs.java
new file mode 100644
index 00000000000..5c4effab2f8
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/client/dto/ParentlessMsInjectionSampleGridColumnIDs.java
@@ -0,0 +1,30 @@
+/*
+ * 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.plugin.phosphonetx.client.web.client.dto;
+
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.application.wizard.ParentlessMsInjectionSampleGrid;
+
+/**
+ * IDs of columns of {@link ParentlessMsInjectionSampleGrid}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ParentlessMsInjectionSampleGridColumnIDs
+{
+    public static final String IDENTIFIER = "IDENTIFIER";
+    public static final String REGISTRATION_DATE = "REGISTRATION_DATE";
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/public/phosphonetx-dictionary.js b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/public/phosphonetx-dictionary.js
index b37959b0106..be7e8db6aa9 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/public/phosphonetx-dictionary.js
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/public/phosphonetx-dictionary.js
@@ -38,8 +38,18 @@ var phosphonetx = {
   // SampleAbudndance Browser
   abundance: "Abundance",
   
+  // MS_INJECTION annotation wizard
+  
+  openbis_parentless_ms_injection_sample_main_IDENTIFIER: "MS_INJECTION Sample",
+  openbis_parentless_ms_injection_sample_main_REGISTRATION_DATE: "Registration Date",
+  openbis_biological_sample_main_IDENTIFIER: "Biological Sample",
+  openbis_biological_sample_main_REGISTRATION_DATE: "Registration Date",
+  
+  
   // RawDataSample Browser
   
+  ANNOTATE_MS_INJECTION_SAMPLES_menu_item: "Annotate MS INJECTION Samples",
+  ANNOTATE_MS_INJECTION_SAMPLES_tab_label: "MS INJECTION Samples Annotation Wizard",
   ALL_RAW_DATA_SAMPLES_menu_item: "All MS INJECTION Samples",  
   ALL_RAW_DATA_SAMPLES_tab_label: "MS INJECTION Samples and Related Biological Samples",  
   openbis_raw_data_sample_browser_CODE: "MS INJECTION Sample",
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/PhosphoNetXClientService.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/PhosphoNetXClientService.java
index 516ebbf6b0f..82ab5321db3 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/PhosphoNetXClientService.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/PhosphoNetXClientService.java
@@ -20,6 +20,7 @@ import static ch.systemsx.cisd.common.utilities.SystemTimeProvider.SYSTEM_TIME_P
 
 import java.io.Serializable;
 import java.lang.reflect.Method;
+import java.util.Collections;
 import java.util.List;
 
 import javax.annotation.Resource;
@@ -38,6 +39,7 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.filesystem.IFreeSpaceProvider;
 import ch.systemsx.cisd.common.filesystem.SimpleFreeSpaceProvider;
 import ch.systemsx.cisd.common.servlet.IRequestContextProvider;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ResultSet;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
@@ -45,15 +47,23 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TypedTableResultSe
 import ch.systemsx.cisd.openbis.generic.client.web.server.AbstractClientService;
 import ch.systemsx.cisd.openbis.generic.client.web.server.resultset.DataProviderAdapter;
 import ch.systemsx.cisd.openbis.generic.client.web.server.translator.UserFailureExceptionTranslator;
+import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+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.basic.dto.ServiceVersionHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Vocabulary;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.WebClientConfiguration;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
+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.CacheManager;
 import ch.systemsx.cisd.openbis.generic.shared.util.ICacheManager;
 import ch.systemsx.cisd.openbis.generic.shared.util.Key;
+import ch.systemsx.cisd.openbis.plugin.generic.shared.IGenericServer;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.BuildAndEnvironmentInfo;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.Constants;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.IPhosphoNetXClientService;
@@ -62,7 +72,9 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.ListPro
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.ListProteinSequenceCriteria;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.ListProteinSummaryByExperimentCriteria;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.ListSampleAbundanceByProteinCriteria;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.server.resultset.BiologicalSampleProvider;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.server.resultset.DataSetProteinProvider;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.server.resultset.ParentlessMsInjectionSampleProvider;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.server.resultset.ProteinSequenceProvider;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.server.resultset.ProteinSummaryProvider;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CacheData;
@@ -85,7 +97,13 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.SampleWithPr
 public class PhosphoNetXClientService extends AbstractClientService implements
         IPhosphoNetXClientService, InitializingBean
 {
-    private static final String CACHE_VERSION = "1"; // Sprint S97
+    private static final String CACHE_VERSION = Integer.toString(ServiceVersionHolder.VERSION);
+    
+    @Resource(name = ch.systemsx.cisd.openbis.generic.shared.ResourceNames.COMMON_SERVER)
+    private ICommonServer commonServer;
+    
+    @Resource(name = ch.systemsx.cisd.openbis.plugin.generic.shared.ResourceNames.GENERIC_PLUGIN_SERVER)
+    private IGenericServer genericServer;
 
     @Resource(name = ResourceNames.PHOSPHONETX_PLUGIN_SERVER)
     @Private
@@ -154,6 +172,42 @@ public class PhosphoNetXClientService extends AbstractClientService implements
         return BuildAndEnvironmentInfo.INSTANCE.getFullVersion();
     }
 
+    public TypedTableResultSet<Sample> listParentlessMsInjectionSamples(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Sample>> criteria)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        String sessionToken = getSessionToken();
+        return listEntities(new ParentlessMsInjectionSampleProvider(commonServer, sessionToken),
+                criteria);
+    }
+
+    public TypedTableResultSet<Sample> listBiologicalSamples(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Sample>> criteria)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        String sessionToken = getSessionToken();
+        return listEntities(new BiologicalSampleProvider(commonServer, sessionToken), criteria);
+    }
+    
+    public void linkSamples(Sample parentSample, List<Sample> childSamples)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        String sessionToken = getSessionToken();
+        String[] parents = new String[]
+            { parentSample.getIdentifier() };
+        for (Sample childSample : childSamples)
+        {
+            SampleIdentifier childSampleIdentifier =
+                    SampleIdentifierFactory.parse(childSample.getIdentifier());
+            genericServer.updateSample(
+                    sessionToken,
+                    new SampleUpdatesDTO(new TechId(childSample), Collections
+                            .<IEntityProperty> emptyList(), null, Collections
+                            .<NewAttachment> emptyList(), childSample.getModificationDate(),
+                            childSampleIdentifier, null, parents));
+        }
+    }
+
     public Vocabulary getTreatmentTypeVocabulary()
     {
         final String sessionToken = getSessionToken();
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/BiologicalSampleProvider.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/BiologicalSampleProvider.java
new file mode 100644
index 00000000000..25ceb8c7b81
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/BiologicalSampleProvider.java
@@ -0,0 +1,78 @@
+/*
+ * 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.plugin.phosphonetx.client.web.server.resultset;
+
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.BiologicalSampleGridColumnIDs.IDENTIFIER;
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.BiologicalSampleGridColumnIDs.REGISTRATION_DATE;
+
+import java.util.Arrays;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.client.web.server.resultset.AbstractCommonTableModelProvider;
+import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriterion;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchField;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleAttributeSearchFieldKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SearchCriteriaConnection;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TypedTableModel;
+import ch.systemsx.cisd.openbis.generic.shared.util.TypedTableModelBuilder;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
+
+/**
+ * Provider of biological samples registered by the user. A biological sample is a sample with
+ * sample type code starting with BIO.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public class BiologicalSampleProvider extends AbstractCommonTableModelProvider<Sample>
+{
+    public BiologicalSampleProvider(ICommonServer commonServer, String sessionToken)
+    {
+        super(commonServer, sessionToken);
+    }
+
+    @Override
+    protected TypedTableModel<Sample> createTableModel(int maxSize)
+    {
+        DetailedSearchCriteria criteria = new DetailedSearchCriteria();
+        criteria.setConnection(SearchCriteriaConnection.MATCH_ALL);
+        DetailedSearchCriterion typeCriterion = new DetailedSearchCriterion();
+        typeCriterion.setField(DetailedSearchField
+                .createAttributeField(SampleAttributeSearchFieldKind.SAMPLE_TYPE));
+        typeCriterion.setValue(CommonConstants.BIOLOGICAL_SAMPLE_PREFIX + "*");
+        DetailedSearchCriterion registratorCriterion = new DetailedSearchCriterion();
+        String userName = commonServer.tryGetSession(sessionToken).getUserName();
+        registratorCriterion.setField(DetailedSearchField.createRegistratorField(""));
+        registratorCriterion.setValue(userName);
+        criteria.setCriteria(Arrays.asList(typeCriterion, registratorCriterion));
+        List<Sample> samples = commonServer.searchForSamples(sessionToken, criteria);
+        TypedTableModelBuilder<Sample> builder = new TypedTableModelBuilder<Sample>();
+        builder.addColumn(IDENTIFIER);
+        builder.addColumn(REGISTRATION_DATE);
+        for (Sample sample : samples)
+        {
+            builder.addRow(sample);
+            builder.column(IDENTIFIER).addString(sample.getIdentifier());
+            builder.column(REGISTRATION_DATE).addDate(sample.getRegistrationDate());
+            builder.columnGroup("PROPERTY").addProperties(sample.getProperties());
+        }
+        return builder.getModel();
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ParentlessMsInjectionSampleProvider.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ParentlessMsInjectionSampleProvider.java
new file mode 100644
index 00000000000..f7983672404
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ParentlessMsInjectionSampleProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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.plugin.phosphonetx.client.web.server.resultset;
+
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.ParentlessMsInjectionSampleGridColumnIDs.IDENTIFIER;
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.client.web.client.dto.ParentlessMsInjectionSampleGridColumnIDs.REGISTRATION_DATE;
+
+import java.util.Arrays;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.client.web.server.resultset.AbstractCommonTableModelProvider;
+import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriterion;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchField;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleAttributeSearchFieldKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SearchCriteriaConnection;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TypedTableModel;
+import ch.systemsx.cisd.openbis.generic.shared.util.TypedTableModelBuilder;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
+
+/**
+ * Provider of MS_INJECTION samples registered for the user.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ParentlessMsInjectionSampleProvider extends AbstractCommonTableModelProvider<Sample>
+{
+    public ParentlessMsInjectionSampleProvider(ICommonServer commonServer, String sessionToken)
+    {
+        super(commonServer, sessionToken);
+    }
+
+    @Override
+    protected TypedTableModel<Sample> createTableModel(int maxSize)
+    {
+        DetailedSearchCriteria criteria = new DetailedSearchCriteria();
+        criteria.setConnection(SearchCriteriaConnection.MATCH_ALL);
+        DetailedSearchCriterion typeCriterion = new DetailedSearchCriterion();
+        typeCriterion.setField(DetailedSearchField
+                .createAttributeField(SampleAttributeSearchFieldKind.SAMPLE_TYPE));
+        typeCriterion.setValue(CommonConstants.MS_INJECTION_SAMPLE_TYPE_CODE);
+        DetailedSearchCriterion spaceCriterion = new DetailedSearchCriterion();
+        spaceCriterion.setField(DetailedSearchField
+                .createAttributeField(SampleAttributeSearchFieldKind.GROUP));
+        spaceCriterion.setValue(CommonConstants.MS_DATA_SPACE);
+        DetailedSearchCriterion registratorCriterion = new DetailedSearchCriterion();
+        String userName = commonServer.tryGetSession(sessionToken).getUserName();
+        registratorCriterion.setField(DetailedSearchField.createRegistratorField(""));
+        registratorCriterion.setValue(userName);
+        criteria.setCriteria(Arrays.asList(typeCriterion, spaceCriterion, registratorCriterion));
+        List<Sample> samples = commonServer.searchForSamples(sessionToken, criteria);
+        TypedTableModelBuilder<Sample> builder = new TypedTableModelBuilder<Sample>();
+        builder.addColumn(IDENTIFIER).withDefaultWidth(300);
+        builder.addColumn(REGISTRATION_DATE).withDefaultWidth(300);
+        for (Sample sample : samples)
+        {
+            if (sample.getGeneratedFrom() == null)
+            {
+                builder.addRow(sample);
+                builder.column(IDENTIFIER).addString(sample.getIdentifier());
+                builder.column(REGISTRATION_DATE).addDate(sample.getRegistrationDate());
+            }
+        }
+        return builder.getModel();
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/ProteomicsDataServiceInternal.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/ProteomicsDataServiceInternal.java
index 8ff7a36249b..dcb2734b5c9 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/ProteomicsDataServiceInternal.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/ProteomicsDataServiceInternal.java
@@ -24,7 +24,6 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
@@ -56,6 +55,7 @@ import ch.systemsx.cisd.openbis.generic.shared.translator.ExperimentTranslator;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business.ExperimentLoader;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business.IBusinessObjectFactory;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business.ISampleLoader;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IProteomicsDataServiceInternal;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.authorization.validator.ParentSampleValidator;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.authorization.validator.RawDataSampleValidator;
@@ -67,12 +67,6 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.MsInjectionSample;
 public class ProteomicsDataServiceInternal extends AbstractServer<IProteomicsDataServiceInternal> implements
         IProteomicsDataServiceInternal
 {
-    @Private
-    static final String SPACE_CODE = "MS_DATA";
-
-    @Private
-    static final String RAW_DATA_SAMPLE_TYPE = "MS_INJECTION";
-    
     private static final IValidator<Sample> PARENT_SAMPLE_VALIDATOR = new ParentSampleValidator();
 
     private static final IValidator<MsInjectionSample> RAW_DATA_SAMPLE_VALIDATOR =
@@ -230,7 +224,8 @@ public class ProteomicsDataServiceInternal extends AbstractServer<IProteomicsDat
     {
         ISampleLoader sampleLoader = boFactory.createSampleLoader(session);
         List<Sample> samples =
-                sampleLoader.listSamplesWithParentsByTypeAndSpace(RAW_DATA_SAMPLE_TYPE, SPACE_CODE);
+                sampleLoader.listSamplesWithParentsByTypeAndSpace(
+                        CommonConstants.MS_INJECTION_SAMPLE_TYPE_CODE, CommonConstants.MS_DATA_SPACE);
         PersonPE person = session.tryGetPerson();
         List<Sample> validSamples = new ArrayList<Sample>();
         for (Sample sample : samples)
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/CommonConstants.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/CommonConstants.java
new file mode 100644
index 00000000000..4d73efc2cd8
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/CommonConstants.java
@@ -0,0 +1,31 @@
+/*
+ * 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.plugin.phosphonetx.shared;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class CommonConstants
+{
+
+    public static final String MS_INJECTION_SAMPLE_TYPE_CODE = "MS_INJECTION";
+    public static final String BIOLOGICAL_SAMPLE_PREFIX = "BIO";
+    public static final String MS_DATA_SPACE = "MS_DATA";
+
+}
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandlerTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandlerTest.java
index fb0d3744543..c79d75532b5 100644
--- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandlerTest.java
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandlerTest.java
@@ -41,6 +41,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.GroupIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
 
 /**
  * @author Franz-Josef Elmer
@@ -55,7 +56,7 @@ public class AbundanceHandlerTest extends AssertJUnit
     private static final String EXPERIMENT_CODE = "E1";
 
     private static final GroupIdentifier GROUP_IDENTIFIER = new GroupIdentifier((String) null,
-            Constants.MS_DATA_SPACE);
+            CommonConstants.MS_DATA_SPACE);
 
     private static final String PARAMETER_VALUE = "1234.5";
 
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForMSInjectionTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForMSInjectionTest.java
index 7aed4b784d2..65e69085298 100644
--- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForMSInjectionTest.java
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/DataSetInfoExtractorForMSInjectionTest.java
@@ -25,7 +25,6 @@ import static ch.systemsx.cisd.openbis.etlserver.phosphonetx.DataSetInfoExtracto
 import static ch.systemsx.cisd.openbis.etlserver.phosphonetx.DataSetInfoExtractorForMSInjection.PARENT_TYPE_KEY;
 import static ch.systemsx.cisd.openbis.etlserver.phosphonetx.DataSetInfoExtractorForMSInjection.PROJECT_CODE_KEY;
 import static ch.systemsx.cisd.openbis.etlserver.phosphonetx.DataSetInfoExtractorForMSInjection.SAMPLE_CODE_KEY;
-import static ch.systemsx.cisd.openbis.etlserver.phosphonetx.DataSetInfoExtractorForMSInjection.SAMPLE_TYPE_CODE;
 import static ch.systemsx.cisd.openbis.etlserver.phosphonetx.DataSetInfoExtractorForMSInjection.USER_KEY;
 
 import java.io.File;
@@ -73,6 +72,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
 
 /**
  * @author Franz-Josef Elmer
@@ -86,11 +86,11 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
     private static final String SAMPLE_CODE = "U09-1242";
 
     private static final String SAMPLE_IDENTIFIER =
-            DatabaseInstanceIdentifier.Constants.IDENTIFIER_SEPARATOR + Constants.MS_DATA_SPACE
+            DatabaseInstanceIdentifier.Constants.IDENTIFIER_SEPARATOR + CommonConstants.MS_DATA_SPACE
                     + DatabaseInstanceIdentifier.Constants.IDENTIFIER_SEPARATOR + SAMPLE_CODE;
 
     private static final String EXPERIMENT_IDENTIFIER =
-            DatabaseInstanceIdentifier.Constants.IDENTIFIER_SEPARATOR + Constants.MS_DATA_SPACE
+            DatabaseInstanceIdentifier.Constants.IDENTIFIER_SEPARATOR + CommonConstants.MS_DATA_SPACE
                     + DatabaseInstanceIdentifier.Constants.IDENTIFIER_SEPARATOR + PROJECT_CODE
                     + DatabaseInstanceIdentifier.Constants.IDENTIFIER_SEPARATOR + EXPERIMENT_CODE;
 
@@ -297,7 +297,7 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
 
         DataSetInformation info = extractor.getDataSetInformation(dataSet, service);
 
-        assertEquals(Constants.MS_DATA_SPACE, info.getSpaceCode());
+        assertEquals(CommonConstants.MS_DATA_SPACE, info.getSpaceCode());
         assertEquals(SAMPLE_CODE, info.getSampleCode());
         assertEquals(EXPERIMENT_IDENTIFIER, info.getExperimentIdentifier().toString());
         List<NewProperty> dProps = info.getDataSetProperties();
@@ -332,7 +332,7 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
         
         DataSetInformation info = extractor.getDataSetInformation(dataSet, service);
         
-        assertEquals(Constants.MS_DATA_SPACE, info.getSpaceCode());
+        assertEquals(CommonConstants.MS_DATA_SPACE, info.getSpaceCode());
         assertEquals(SAMPLE_CODE, info.getSampleCode());
         assertEquals(EXPERIMENT_IDENTIFIER, info.getExperimentIdentifier().toString());
         List<NewProperty> dProps = info.getDataSetProperties();
@@ -364,7 +364,7 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
 
         DataSetInformation info = extractor.getDataSetInformation(dataSet, service);
 
-        assertEquals(Constants.MS_DATA_SPACE, info.getSpaceCode());
+        assertEquals(CommonConstants.MS_DATA_SPACE, info.getSpaceCode());
         assertEquals(SAMPLE_CODE, info.getSampleCode());
         assertEquals(EXPERIMENT_IDENTIFIER, info.getExperimentIdentifier().toString());
         List<NewProperty> dProps = info.getDataSetProperties();
@@ -397,7 +397,7 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
         
         DataSetInformation info = extractor.getDataSetInformation(dataSet, service);
         
-        assertEquals(Constants.MS_DATA_SPACE, info.getSpaceCode());
+        assertEquals(CommonConstants.MS_DATA_SPACE, info.getSpaceCode());
         assertEquals(SAMPLE_CODE, info.getSampleCode());
         assertEquals(EXPERIMENT_IDENTIFIER, info.getExperimentIdentifier().toString());
         List<NewProperty> dProps = info.getDataSetProperties();
@@ -436,7 +436,7 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
 
         DataSetInformation info = extractor.getDataSetInformation(dataSet, service);
 
-        assertEquals(Constants.MS_DATA_SPACE, info.getSpaceCode());
+        assertEquals(CommonConstants.MS_DATA_SPACE, info.getSpaceCode());
         assertEquals(null, info.getSampleCode());
         assertEquals(null, info.getSampleIdentifier());
         assertEquals(EXPERIMENT_IDENTIFIER, info.getExperimentIdentifier().toString());
@@ -489,7 +489,7 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
             {
                 {
                     ExperimentIdentifier identifier =
-                            new ExperimentIdentifier(null, Constants.MS_DATA_SPACE, PROJECT_CODE,
+                            new ExperimentIdentifier(null, CommonConstants.MS_DATA_SPACE, PROJECT_CODE,
                                     EXPERIMENT_CODE);
                     one(service).tryToGetExperiment(identifier);
                     Experiment experiment = new Experiment();
@@ -511,9 +511,9 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
         context.checking(new Expectations()
             {
                 {
-                    one(service).getSampleType(DataSetInfoExtractorForMSInjection.SAMPLE_TYPE_CODE);
+                    one(service).getSampleType(CommonConstants.MS_INJECTION_SAMPLE_TYPE_CODE);
                     SampleType sampleType = new SampleType();
-                    sampleType.setCode(DataSetInfoExtractorForMSInjection.SAMPLE_TYPE_CODE);
+                    sampleType.setCode(CommonConstants.MS_INJECTION_SAMPLE_TYPE_CODE);
                     sampleType.setSampleTypePropertyTypes(Arrays.asList(sampleTypePropertyTypes));
                     will(returnValue(sampleType));
                 }
@@ -552,7 +552,7 @@ public class DataSetInfoExtractorForMSInjectionTest extends AbstractFileSystemTe
                                 if (item instanceof NewSample)
                                 {
                                     NewSample sample = (NewSample) item;
-                                    assertEquals(SAMPLE_TYPE_CODE, sample.getSampleType().getCode());
+                                    assertEquals(CommonConstants.MS_INJECTION_SAMPLE_TYPE_CODE, sample.getSampleType().getCode());
                                     assertEquals(SAMPLE_IDENTIFIER, sample.getIdentifier());
                                     assertEquals(EXPERIMENT_IDENTIFIER, sample
                                             .getExperimentIdentifier());
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ResultDataSetUploaderTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ResultDataSetUploaderTest.java
index 71165afb4fc..d31c22ab65d 100644
--- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ResultDataSetUploaderTest.java
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ResultDataSetUploaderTest.java
@@ -64,6 +64,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifi
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.GroupIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
 
 /**
  * @author Franz-Josef Elmer
@@ -242,7 +243,7 @@ public class ResultDataSetUploaderTest extends AssertJUnit
                 {
                     one(service).tryGetSampleWithExperiment(
                             new SampleIdentifier(new SpaceIdentifier(DB_INSTANCE,
-                                    Constants.MS_DATA_SPACE), CELL_LYSATE1));
+                                    CommonConstants.MS_DATA_SPACE), CELL_LYSATE1));
                     ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample =
                             new ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample();
                     sample.setPermId(CELL_LYSATE_PERM_ID1);
@@ -293,7 +294,7 @@ public class ResultDataSetUploaderTest extends AssertJUnit
         p1.setName(PROTEIN_NAME1);
         p1.getParameters().add(createAbundance(CELL_LYSATE1, 2.5));
         p1.getParameters().add(new Parameter());
-        final GroupIdentifier groupIdentifier = new GroupIdentifier(DB_INSTANCE, Constants.MS_DATA_SPACE);
+        final GroupIdentifier groupIdentifier = new GroupIdentifier(DB_INSTANCE, CommonConstants.MS_DATA_SPACE);
         final SampleIdentifier sampleIdentifier =
                 new SampleIdentifier(groupIdentifier, CELL_LYSATE1);
         final ListSamplesByPropertyCriteria criteria =
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/ProteomicsDataServiceInternalTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/ProteomicsDataServiceInternalTest.java
index b8f168f569e..fe247046c59 100644
--- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/ProteomicsDataServiceInternalTest.java
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/ProteomicsDataServiceInternalTest.java
@@ -18,8 +18,6 @@ package ch.systemsx.cisd.openbis.plugin.phosphonetx.server;
 
 import static ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStoreServiceKind.PROCESSING;
 import static ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStoreServiceKind.QUERIES;
-import static ch.systemsx.cisd.openbis.plugin.phosphonetx.server.ProteomicsDataServiceInternal.RAW_DATA_SAMPLE_TYPE;
-import static ch.systemsx.cisd.openbis.plugin.phosphonetx.server.ProteomicsDataServiceInternal.SPACE_CODE;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -55,14 +53,15 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.RoleAssignmentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business.IBusinessObjectFactory;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business.ISampleLoader;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.CommonConstants;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IProteomicsDataServiceInternal;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.MsInjectionSample;
 
@@ -348,7 +347,8 @@ public class ProteomicsDataServiceInternalTest extends AbstractServerTestCase
                     one(boFactory).createSampleLoader(SESSION);
                     will(returnValue(sampleLoader));
                     
-                    one(sampleLoader).listSamplesWithParentsByTypeAndSpace(RAW_DATA_SAMPLE_TYPE, SPACE_CODE);
+                    one(sampleLoader).listSamplesWithParentsByTypeAndSpace(
+                            CommonConstants.MS_INJECTION_SAMPLE_TYPE_CODE, CommonConstants.MS_DATA_SPACE);
                     will(returnValue(samples));
                     
                     one(experimentDAO).listExperimentsWithProperties(experimentIds);
-- 
GitLab