diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/AbstractCommand.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/AbstractCommand.java
similarity index 91%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/AbstractCommand.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/AbstractCommand.java
index cb6c24fe450ab2c10a4e7b76c3e4b0156c463477..9ad21efd50b63cf54a2ce0558b1a25a05c94bada 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/AbstractCommand.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/AbstractCommand.java
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import java.io.PrintStream;
 
 import ch.systemsx.cisd.args4j.CmdLineParser;
 import ch.systemsx.cisd.args4j.ExampleMode;
-import ch.systemsx.cisd.openbis.dss.api.v1.client.DssComponentFactory;
-import ch.systemsx.cisd.openbis.dss.api.v1.client.IDataSetDss;
-import ch.systemsx.cisd.openbis.dss.api.v1.client.IDssComponent;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.DssComponentFactory;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDssComponent;
 
 /**
  * Superclass for dss command-line client commands.
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandFactory.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandFactory.java
similarity index 97%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandFactory.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandFactory.java
index 1233e5f4235a98d3cbdd64a869d8b0a84c8bfaa1..69a85b4293c31239858628cc7b3aced7114a08fe 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandFactory.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandFactory.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import java.util.Arrays;
 import java.util.List;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandGet.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandGet.java
similarity index 95%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandGet.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandGet.java
index 1f07138eb418015df9c0edf4c3478d1d60358989..c121be4bae4fd44b376cfa0cb5a73972a45ea95b 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandGet.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandGet.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -28,9 +28,9 @@ import ch.systemsx.cisd.args4j.Option;
 import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
-import ch.systemsx.cisd.openbis.dss.api.v1.client.IDataSetDss;
-import ch.systemsx.cisd.openbis.dss.api.v1.client.IDssComponent;
-import ch.systemsx.cisd.openbis.dss.api.v1.shared.FileInfoDssDTO;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDssComponent;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
 
 /**
  * Comand that lists files in the data set.
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandHelp.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandHelp.java
similarity index 97%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandHelp.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandHelp.java
index 9d08c9e4b198d65b0bd1afcf8648aa60a89b91fd..c322746882e4809200ed6c211e8ffec18d541aea 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandHelp.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandHelp.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import java.io.PrintStream;
 import java.util.List;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandLs.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandLs.java
similarity index 93%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandLs.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandLs.java
index 1cb6c01c6446f6ca8db106921a83ba09a5d34a12..0e628533b885ff0c3faa337aa0336e764bb5ae5c 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandLs.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandLs.java
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import ch.systemsx.cisd.args4j.CmdLineParser;
 import ch.systemsx.cisd.args4j.Option;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
-import ch.systemsx.cisd.openbis.dss.api.v1.client.IDataSetDss;
-import ch.systemsx.cisd.openbis.dss.api.v1.client.IDssComponent;
-import ch.systemsx.cisd.openbis.dss.api.v1.shared.FileInfoDssDTO;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDssComponent;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
 
 /**
  * Comand that lists files in the data set.
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/DssClient.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/DssClient.java
similarity index 99%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/DssClient.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/DssClient.java
index 226e493b775be0e9e1ee617dfaf576127ce624ea..ea3cc23dd303728f9505f03df038dede9af92f3b 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/DssClient.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/DssClient.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import java.net.UnknownHostException;
 import java.util.Arrays;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/GlobalArguments.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/GlobalArguments.java
similarity index 98%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/GlobalArguments.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/GlobalArguments.java
index d5ef4679332d0f765a1aabfa355ac1dbf85f6c3e..049957a324ee3c6891ab97ca5038fdc1306c1f9d 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/GlobalArguments.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/GlobalArguments.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/ICommand.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/ICommand.java
similarity index 97%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/ICommand.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/ICommand.java
index 6b9932157df358b957db074d0b9b3e51ec317cfd..f82aec03aac56b28324fc662d5c7a1f89506fb59 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/client/cli/ICommand.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/cli/ICommand.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import java.io.PrintStream;
 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/DssComponentFactory.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/DssComponentFactory.java
similarity index 93%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/DssComponentFactory.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/DssComponentFactory.java
index 3a847ec49a2d19e7b91ad827facde31256551a03..3d0d2526035b902917be3603a8871736d9316e19 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/DssComponentFactory.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/DssComponentFactory.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.v1.client;
+package ch.systemsx.cisd.openbis.dss.client.api.v1;
 
-import ch.systemsx.cisd.openbis.dss.api.v1.client.impl.DssComponent;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.impl.DssComponent;
 
 /**
  * A class that creates DssComponents.
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/IDataSetDss.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDataSetDss.java
similarity index 93%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/IDataSetDss.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDataSetDss.java
index e15176134fee4f85a40ae36d2d8677e504be5375..c53889d9389ff93c864b049d1c327e73d4596e11 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/IDataSetDss.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDataSetDss.java
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.v1.client;
+package ch.systemsx.cisd.openbis.dss.client.api.v1;
 
 import java.io.InputStream;
 
 import ch.systemsx.cisd.common.exceptions.InvalidSessionException;
-import ch.systemsx.cisd.openbis.dss.api.v1.shared.FileInfoDssDTO;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
 
 /**
  * The representation of a Data Set managed by a DSS server. It is safe to use instances in multiple
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/IDssComponent.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDssComponent.java
similarity index 97%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/IDssComponent.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDssComponent.java
index 2c1d2eea9f9f1c6f6b4de1d0026c317c2798a89b..b5e8491c652af4672a0ef59a4ca0c0f5d7920625 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/client/IDssComponent.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/IDssComponent.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.v1.client;
+package ch.systemsx.cisd.openbis.dss.client.api.v1;
 
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.exceptions.InvalidSessionException;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DataSetDss.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DataSetDss.java
new file mode 100644
index 0000000000000000000000000000000000000000..a37ebd94eada96c6a771019cbcefd2169a61de7a
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DataSetDss.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.client.api.v1.impl;
+
+import java.io.InputStream;
+
+import ch.systemsx.cisd.common.exceptions.InvalidSessionException;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.IDssServiceRpcGeneric;
+
+/**
+ * @author Chandrasekhar Ramakrishnan
+ */
+public class DataSetDss implements IDataSetDss
+{
+    private final String code;
+
+    private final IDssServiceRpcGeneric service;
+
+    private final AuthenticatedState parent;
+
+    // private String ownerUrl;
+
+    public DataSetDss(String code, IDssServiceRpcGeneric service, AuthenticatedState parent)
+    {
+        this.code = code;
+        this.service = service;
+        this.parent = parent;
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public InputStream getFile(String path) throws IllegalArgumentException,
+            InvalidSessionException
+    {
+        return parent.getFile(this, path);
+    }
+
+    public FileInfoDssDTO[] listFiles(String startPath, boolean isRecursive)
+            throws IllegalArgumentException, InvalidSessionException
+    {
+        return parent.listFiles(this, startPath, isRecursive);
+    }
+
+    IDssServiceRpcGeneric getService()
+    {
+        return service;
+    }
+
+}
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponent.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponent.java
new file mode 100644
index 0000000000000000000000000000000000000000..735f111aed0cf86e7d0ff192406d1700474532a0
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponent.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.client.api.v1.impl;
+
+import java.io.InputStream;
+import java.util.Collection;
+
+import org.springframework.remoting.RemoteAccessException;
+import org.springframework.remoting.RemoteConnectFailureException;
+
+import ch.systemsx.cisd.common.api.IRpcServiceFactory;
+import ch.systemsx.cisd.common.api.RpcServiceInterfaceDTO;
+import ch.systemsx.cisd.common.api.RpcServiceInterfaceVersionDTO;
+import ch.systemsx.cisd.common.exceptions.AuthorizationFailureException;
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.exceptions.InvalidSessionException;
+import ch.systemsx.cisd.common.spring.HttpInvokerUtils;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDssComponent;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.IDssServiceRpcGeneric;
+import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService;
+import ch.systemsx.cisd.openbis.generic.shared.OpenBisServiceFactory;
+import ch.systemsx.cisd.openbis.generic.shared.OpenBisServiceFactory.ILimsServiceStubFactory;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStore;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
+
+/**
+ * Implementation of the IDssComponent interface. It is a facade for interacting with openBIS and
+ * multiple DSS servers.
+ * <p>
+ * The DssComponent manages a connection to openBIS (IETLLIMSService) as well as connections to data
+ * store servers (IDssServiceRpc) to present a simplified interface to downloading datasets.
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+public class DssComponent implements IDssComponent
+{
+    private static final int SERVER_TIMEOUT_MIN = 5;
+
+    private final IETLLIMSService openBisService;
+
+    private final IRpcServiceFactory dssServiceFactory;
+
+    private AbstractDssComponentState state;
+
+    /**
+     * Public factory method for creating a DssComponent with a username and password.
+     * 
+     * @param user The user name
+     * @param password The user's password
+     * @param openBISUrl The URL to openBIS
+     */
+    public static DssComponent tryCreate(String user, String password, String openBISUrl)
+    {
+        DssComponent component = new DssComponent(openBISUrl, null);
+        try
+        {
+            component.login(user, password);
+        } catch (AuthorizationFailureException e)
+        {
+            // User name / Password is incorrect.
+            return null;
+        }
+        return component;
+    }
+
+    /**
+     * Public factory method for creating a DssComponent for a user that has already been
+     * authenticated.
+     * 
+     * @param sessionToken The session token provided by authentication
+     * @param openBISUrl The URL to openBIS
+     */
+    public static DssComponent tryCreate(String sessionToken, String openBISUrl)
+    {
+        DssComponent component = new DssComponent(openBISUrl, sessionToken);
+        try
+        {
+            component.checkSession();
+        } catch (InvalidSessionException e)
+        {
+            // Session has expired
+            return null;
+        }
+        return component;
+    }
+
+    private static IETLLIMSService createOpenBisService(String openBISURL)
+    {
+        ILimsServiceStubFactory stubFactory = new ILimsServiceStubFactory()
+            {
+                public IETLLIMSService createServiceStub(String serverUrl)
+                {
+                    return HttpInvokerUtils.createServiceStub(IETLLIMSService.class, serverUrl,
+                            SERVER_TIMEOUT_MIN);
+                }
+
+            };
+        return new OpenBisServiceFactory(openBISURL, stubFactory).createService();
+    }
+
+    /**
+     * Create a DSS component that connects to the openBIS instance specified by the URL.
+     * <p>
+     * The DSS component needs to connect to openBIS to find out which DSS manages a given data set.
+     * Once it has a connection to openBIS, it can figure out how to connect to DSS servers itself.
+     * 
+     * @param openBISURL The url to connect to openBIS
+     * @param sessionTokenOrNull A session token; If null is passed in, then login needs to be
+     *            called.
+     */
+    private DssComponent(String openBISURL, String sessionTokenOrNull)
+    {
+        this(createOpenBisService(openBISURL), new DssServiceRpcFactory(), sessionTokenOrNull);
+    }
+
+    /**
+     * Internal constructor, also used for testing.
+     * 
+     * @param service A proxy to the openBIS application server.
+     * @param dssServiceFactory A proxy to the DSS server.
+     * @param sessionTokenOrNull A session token, if the user has already logged in, or null
+     *            otherwise.
+     */
+    protected DssComponent(IETLLIMSService service, IRpcServiceFactory dssServiceFactory,
+            String sessionTokenOrNull)
+    {
+        this.openBisService = service;
+        this.dssServiceFactory = dssServiceFactory;
+        if (sessionTokenOrNull == null)
+        {
+            this.state = new UnauthenticatedState(service);
+        } else
+        {
+            this.state = new AuthenticatedState(service, dssServiceFactory, sessionTokenOrNull);
+        }
+    }
+
+    public String getSessionToken()
+    {
+        return state.getSessionToken();
+    }
+
+    public void checkSession() throws InvalidSessionException
+    {
+        state.checkSession();
+    }
+
+    public IDataSetDss getDataSet(String code) throws EnvironmentFailureException,
+            IllegalStateException
+    {
+        return state.getDataSet(code);
+    }
+
+    public void logout()
+    {
+        // logout and transition to the unauthenticated state
+        state.logout();
+        state = new UnauthenticatedState(openBisService);
+    }
+
+    /**
+     * Authenticates the <code>user</code> with given <code>password</code>.
+     * 
+     * @throws AuthorizationFailureException Thrown if the username / password do not authenticate.
+     * @throws EnvironmentFailureException Thrown in cases where it is not possible to connect to
+     *             the server.
+     */
+    void login(String user, String password) throws AuthorizationFailureException,
+            EnvironmentFailureException
+    {
+        // login and transition to the authenticated state
+        state.login(user, password);
+        state = new AuthenticatedState(openBisService, dssServiceFactory, state.getSessionToken());
+    }
+}
+
+/**
+ * Superclass for component states, which make the state machine of the DSS component explicit.
+ * <p>
+ * By default, all methods just throw an exception. Subclasses should override the methods they
+ * accept.
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+abstract class AbstractDssComponentState implements IDssComponent
+{
+    protected final IETLLIMSService service;
+
+    AbstractDssComponentState(IETLLIMSService service)
+    {
+        this.service = service;
+    }
+
+    public void checkSession() throws IllegalStateException
+    {
+        throw new IllegalStateException("Please log in");
+    }
+
+    public IDataSetDss getDataSet(String code) throws IllegalStateException
+    {
+        throw new IllegalStateException("Please log in");
+    }
+
+    /**
+     * Authenticates the <code>user</code> with given <code>password</code>.
+     * 
+     * @throws AuthorizationFailureException Thrown if the username / password do not authenticate.
+     * @throws EnvironmentFailureException Thrown in cases where it is not possible to connect to
+     *             the server.
+     */
+    abstract void login(final String user, final String password)
+            throws AuthorizationFailureException, EnvironmentFailureException;
+
+    /**
+     * Package visible method used to transfer context information between states.
+     */
+    public abstract String getSessionToken();
+}
+
+/**
+ * An object representing an unauthenticated state. Being in this state implies that the user has
+ * not yet logged in. Only login and logout are allowed in this state.
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+class UnauthenticatedState extends AbstractDssComponentState
+{
+    private SessionContextDTO sessionOrNull;
+
+    UnauthenticatedState(IETLLIMSService service)
+    {
+        super(service);
+    }
+
+    @Override
+    public String getSessionToken()
+    {
+        if (sessionOrNull == null)
+            throw new IllegalStateException("Please log in");
+        return sessionOrNull.getSessionToken();
+    }
+
+    @Override
+    void login(String user, String password) throws AuthorizationFailureException,
+            EnvironmentFailureException
+    {
+        try
+        {
+            sessionOrNull = service.tryToAuthenticate(user, password);
+        } catch (RemoteConnectFailureException e)
+        {
+            throw new EnvironmentFailureException("Could not connect to server", e);
+        }
+        if (sessionOrNull == null)
+            throw new AuthorizationFailureException("Login or Password invalid");
+    }
+
+    public void logout()
+    {
+        return;
+    }
+}
+
+/**
+ * An object representing an authenticated state. Being in this state means that the user has logged
+ * in and all operations are available, except login.
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+class AuthenticatedState extends AbstractDssComponentState
+{
+    private final String sessionToken;
+
+    private final IRpcServiceFactory dssServiceFactory;
+
+    /**
+     * @param service
+     */
+    AuthenticatedState(IETLLIMSService service, IRpcServiceFactory dssServiceFactory,
+            String sessionToken)
+    {
+        super(service);
+        this.dssServiceFactory = dssServiceFactory;
+        this.sessionToken = sessionToken;
+    }
+
+    @Override
+    void login(String user, String password) throws AuthorizationFailureException
+    {
+        throw new IllegalStateException("Already logged in.");
+    }
+
+    @Override
+    public void checkSession()
+    {
+        if (null == service.tryGetSession(getSessionToken()))
+        {
+            throw new InvalidSessionException("Session has expired");
+        }
+    }
+
+    public void logout()
+    {
+        service.logout(getSessionToken());
+    }
+
+    @Override
+    public IDataSetDss getDataSet(String code) throws IllegalArgumentException,
+            EnvironmentFailureException, RemoteAccessException
+    {
+        // Contact openBIS to find out which DSS server manages the data set
+        ExternalData dataSetOpenBis = service.tryGetDataSet(getSessionToken(), code);
+        if (null == dataSetOpenBis)
+        {
+            throw new IllegalArgumentException("Could not retrieve data set with code " + code);
+        }
+        DataStore dataStore = dataSetOpenBis.getDataStore();
+
+        String url = dataStore.getDownloadUrl();
+
+        IDssServiceRpcGeneric dssService = getDssServiceForUrl(url);
+        // Return a proxy to the data set
+        return new DataSetDss(code, dssService, this);
+
+    }
+
+    /**
+     * Package visible method to communicate with the server and get a list of files contained in
+     * this data set.
+     */
+    FileInfoDssDTO[] listFiles(DataSetDss dataSetDss, String startPath, boolean isRecursive)
+            throws InvalidSessionException
+    {
+        return dataSetDss.getService().listFilesForDataSet(getSessionToken(), dataSetDss.getCode(),
+                startPath, isRecursive);
+    }
+
+    /**
+     * Package visible method to communicate with the server and get a list of files contained in
+     * this data set.
+     */
+    InputStream getFile(DataSetDss dataSetDss, String path) throws InvalidSessionException
+    {
+        return dataSetDss.getService().getFileForDataSet(getSessionToken(), dataSetDss.getCode(),
+                path);
+    }
+
+    /**
+     * Create a connection to the DSS server referenced by url
+     */
+    private IDssServiceRpcGeneric getDssServiceForUrl(String url)
+    {
+        // Get an RPC service for the DSS server
+        String serverURL = url;
+        try
+        {
+            IDssServiceRpcGeneric dssService = basicGetDssServiceForUrl(serverURL);
+            return dssService;
+        } catch (RemoteAccessException e)
+        {
+            // if the url begins with https, try http
+            if (serverURL.startsWith("https://"))
+            {
+                // https:// has 8 characters
+                serverURL = "http://" + serverURL.substring(8);
+                IDssServiceRpcGeneric dssService = basicGetDssServiceForUrl(serverURL);
+                return dssService;
+            }
+
+            // Rethrow the exception
+            throw e;
+        }
+    }
+
+    /**
+     * A less sophisticated implementation of getDssServiceForUrl
+     */
+    private IDssServiceRpcGeneric basicGetDssServiceForUrl(String serverURL)
+    {
+        IDssServiceRpcGeneric dssService = null;
+        Collection<RpcServiceInterfaceDTO> ifaces =
+                dssServiceFactory.getSupportedInterfaces(serverURL, false);
+
+        for (RpcServiceInterfaceDTO iface : ifaces)
+        {
+            if (IDssServiceRpcGeneric.DSS_SERVICE_NAME.equals(iface.getInterfaceName()))
+            {
+                for (RpcServiceInterfaceVersionDTO ifaceVersion : iface.getVersions())
+                {
+                    if (1 == ifaceVersion.getMajorVersion())
+                    {
+                        dssService =
+                                dssServiceFactory.getService(ifaceVersion,
+                                        IDssServiceRpcGeneric.class, serverURL, false);
+                        return dssService;
+                    }
+                }
+            }
+        }
+        throw new IllegalArgumentException("Server does not support the "
+                + IDssServiceRpcGeneric.DSS_SERVICE_NAME + " interface.");
+    }
+
+    @Override
+    public String getSessionToken()
+    {
+        return sessionToken;
+    }
+}
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssServiceRpcFactory.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssServiceRpcFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c6f27412b8192d0126fa5e43f34e9b0fce94056
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssServiceRpcFactory.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.client.api.v1.impl;
+
+import java.io.File;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+
+import ch.systemsx.cisd.common.api.IRpcService;
+import ch.systemsx.cisd.common.api.IRpcServiceFactory;
+import ch.systemsx.cisd.common.api.IRpcServiceNameServer;
+import ch.systemsx.cisd.common.api.IncompatibleAPIVersionsException;
+import ch.systemsx.cisd.common.api.RpcServiceInterfaceDTO;
+import ch.systemsx.cisd.common.api.RpcServiceInterfaceVersionDTO;
+import ch.systemsx.cisd.common.spring.HttpInvokerUtils;
+import ch.systemsx.cisd.common.ssl.SslCertificateHelper;
+
+/**
+ * Client-side factory for DssServiceRpc objects.
+ * <p>
+ * Create client-side proxies to server RPC interface objects.
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+// TODO: This code should be refactored and moved into a common location, but it is a bit difficult
+// due to dependencies.
+public class DssServiceRpcFactory implements IRpcServiceFactory
+{
+    private static final int SERVER_TIMEOUT_MIN = 5;
+
+    private static final String NAME_SERVER_SUFFIX = "/rmi-name-server";
+
+    public Collection<RpcServiceInterfaceDTO> getSupportedInterfaces(String serverURL,
+            boolean getServerCertificateFromServer) throws IncompatibleAPIVersionsException
+    {
+        // We assume the location of the name server follows the convention
+        String nameServerURL = serverURL + NAME_SERVER_SUFFIX;
+        Class<IRpcServiceNameServer> clazz = IRpcServiceNameServer.class;
+        if (getServerCertificateFromServer)
+        {
+            new SslCertificateHelper(nameServerURL, getConfigDirectory(), "dss").setUpKeyStore();
+        }
+
+        IRpcServiceNameServer nameServer =
+                new ServiceProxyBuilder<IRpcServiceNameServer>(nameServerURL, clazz,
+                        SERVER_TIMEOUT_MIN, 1).getServiceInterface();
+        return nameServer.getSupportedInterfaces();
+    }
+
+    public <T extends IRpcService> T getService(RpcServiceInterfaceVersionDTO ifaceVersion,
+            Class<T> ifaceClazz, String serverURL, boolean getServerCertificateFromServer)
+            throws IncompatibleAPIVersionsException
+    {
+        String serviceURL = serverURL + ifaceVersion.getUrlSuffix();
+        if (getServerCertificateFromServer)
+        {
+            new SslCertificateHelper(serviceURL, getConfigDirectory(), "dss").setUpKeyStore();
+        }
+
+        return new ServiceProxyBuilder<T>(serviceURL, ifaceClazz, SERVER_TIMEOUT_MIN, 1)
+                .getServiceInterface();
+    }
+
+    private File getConfigDirectory()
+    {
+        String homeDir = System.getProperty("dss.root");
+        File configDir;
+        if (homeDir != null)
+        {
+            configDir = new File(homeDir, "etc");
+        } else
+        {
+            homeDir = System.getProperty("user.home");
+            configDir = new File(homeDir, ".dss");
+        }
+        configDir.mkdirs();
+        return configDir;
+    }
+}
+
+/**
+ * Internal helper class for constructing service proxies;
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+@SuppressWarnings("unchecked")
+class ServiceProxyBuilder<T extends IRpcService>
+{
+    private final String serviceURL;
+
+    private final Class<?> clazz;
+
+    private final int serverTimeoutMin;
+
+    private final int apiClientVersion;
+
+    ServiceProxyBuilder(String serviceURL, Class<?> clazz, int serverTimeoutMin,
+            int apiClientVersion)
+    {
+        this.serviceURL = serviceURL;
+        this.clazz = clazz;
+        this.serverTimeoutMin = serverTimeoutMin;
+        this.apiClientVersion = apiClientVersion;
+    }
+
+    T getServiceInterface() throws IncompatibleAPIVersionsException
+    {
+        T service = getRawServiceProxy();
+        service = wrapProxyInServiceInvocationHandler(service);
+        final int apiServerVersion = service.getMajorVersion();
+        if (apiClientVersion != apiServerVersion)
+        {
+            throw new IncompatibleAPIVersionsException(apiClientVersion, apiServerVersion);
+        }
+
+        return service;
+    }
+
+    private T getRawServiceProxy()
+    {
+        return (T) HttpInvokerUtils.createStreamSupportingServiceStub(clazz, serviceURL,
+                serverTimeoutMin);
+    }
+
+    private T wrapProxyInServiceInvocationHandler(T service)
+    {
+        final ClassLoader classLoader = DssServiceRpcFactory.class.getClassLoader();
+        final ServiceInvocationHandler invocationHandler = new ServiceInvocationHandler(service);
+        final T proxy = (T) Proxy.newProxyInstance(classLoader, new Class[]
+            { clazz }, invocationHandler);
+        return proxy;
+    }
+
+    /**
+     * An invocation handler that unwraps exceptions that occur in methods called via reflection.
+     * 
+     * @author Chandrasekhar Ramakrishnan
+     */
+    private static final class ServiceInvocationHandler implements InvocationHandler
+    {
+        private final IRpcService service;
+
+        private ServiceInvocationHandler(IRpcService service)
+        {
+            this.service = service;
+        }
+
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+        {
+            try
+            {
+                return method.invoke(service, args);
+            } catch (InvocationTargetException ex)
+            {
+                throw ex.getCause();
+            }
+        }
+    }
+}
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServer.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServer.java
index aef7532fca0bbbdfe3a243ea02f80c12068ba551..b7e57457f46bd1230bf2790c748620c65a9190a6 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServer.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServer.java
@@ -53,8 +53,8 @@ import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.logging.LogInitializer;
 import ch.systemsx.cisd.common.utilities.ExtendedProperties;
-import ch.systemsx.cisd.openbis.dss.api.v1.server.DssServiceRpcGeneric;
 import ch.systemsx.cisd.openbis.dss.generic.server.ConfigParameters.PluginServlet;
+import ch.systemsx.cisd.openbis.dss.generic.server.api.v1.DssServiceRpcGeneric;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.DssPropertyParametersUtil;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/server/DssServiceRpcGeneric.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java
similarity index 93%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/server/DssServiceRpcGeneric.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java
index 00e10eb47e80fa56d99deb79ef8cfd7111915e15..24c07e7ae320d11c5d1b59c541443ab5ebcd1b4a 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/server/DssServiceRpcGeneric.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.v1.server;
+package ch.systemsx.cisd.openbis.dss.generic.server.api.v1;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -23,11 +23,11 @@ import java.io.InputStream;
 import java.util.ArrayList;
 
 import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
-import ch.systemsx.cisd.openbis.dss.api.v1.shared.FileInfoDssBuilder;
-import ch.systemsx.cisd.openbis.dss.api.v1.shared.FileInfoDssDTO;
-import ch.systemsx.cisd.openbis.dss.api.v1.shared.IDssServiceRpcGeneric;
 import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDssServiceRpc;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssBuilder;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.IDssServiceRpcGeneric;
 
 /**
  * Implementation of the generic RPC interface.
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/FileInfoDssBuilder.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssBuilder.java
similarity index 98%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/FileInfoDssBuilder.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssBuilder.java
index 6a40ba3d5c0f8b9cdb986f4f9300a84297118ccd..c8205f8bb1e870829280ec29ccca4bd6c54a83b7 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/FileInfoDssBuilder.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssBuilder.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.v1.shared;
+package ch.systemsx.cisd.openbis.dss.generic.shared.api.v1;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/FileInfoDssDTO.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssDTO.java
similarity index 97%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/FileInfoDssDTO.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssDTO.java
index 41a9c95046173b143caa2c70cdfcf619d0f29b1a..20c10bb6de6825db09b94269408796a78171fac0 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/FileInfoDssDTO.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/FileInfoDssDTO.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.v1.shared;
+package ch.systemsx.cisd.openbis.dss.generic.shared.api.v1;
 
 import java.io.Serializable;
 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/IDssServiceRpcGeneric.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/IDssServiceRpcGeneric.java
similarity index 97%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/IDssServiceRpcGeneric.java
rename to datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/IDssServiceRpcGeneric.java
index 09e5efd1a3ba338b07c3c055554b0e56db1aa30e..51bdc10b2151378336e8d742011078392eb1ec81 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/api/v1/shared/IDssServiceRpcGeneric.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/v1/IDssServiceRpcGeneric.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.v1.shared;
+package ch.systemsx.cisd.openbis.dss.generic.shared.api.v1;
 
 import java.io.InputStream;
 
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandFactoryTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandFactoryTest.java
similarity index 85%
rename from datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandFactoryTest.java
rename to datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandFactoryTest.java
index 7780621e45426a7310ff30bd39a1f0e7c5ccb5d8..f5c57c94b1497c7deebb1a98d9dd84f9661c16ec 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/api/client/cli/CommandFactoryTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/cli/CommandFactoryTest.java
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import org.testng.AssertJUnit;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.openbis.dss.api.client.cli.CommandFactory;
-import ch.systemsx.cisd.openbis.dss.api.client.cli.CommandGet;
-import ch.systemsx.cisd.openbis.dss.api.client.cli.CommandLs;
-import ch.systemsx.cisd.openbis.dss.api.client.cli.ICommand;
+import ch.systemsx.cisd.openbis.dss.client.api.cli.CommandFactory;
+import ch.systemsx.cisd.openbis.dss.client.api.cli.CommandGet;
+import ch.systemsx.cisd.openbis.dss.client.api.cli.CommandLs;
+import ch.systemsx.cisd.openbis.dss.client.api.cli.ICommand;
 
 /**
  * @author Chandrasekhar Ramakrishnan
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/api/client/cli/GlobalArgumentsTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/cli/GlobalArgumentsTest.java
similarity index 96%
rename from datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/api/client/cli/GlobalArgumentsTest.java
rename to datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/cli/GlobalArgumentsTest.java
index c02111f1b6683ecc2dbf8ce895679a41b0c253c9..d201f65e7c5c6959d8df5141b4d321c14fce9385 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/api/client/cli/GlobalArgumentsTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/cli/GlobalArgumentsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.dss.api.client.cli;
+package ch.systemsx.cisd.openbis.dss.client.api.cli;
 
 import org.testng.AssertJUnit;
 import org.testng.annotations.BeforeMethod;
@@ -22,7 +22,7 @@ import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.args4j.CmdLineException;
 import ch.systemsx.cisd.args4j.CmdLineParser;
-import ch.systemsx.cisd.openbis.dss.api.client.cli.GlobalArguments;
+import ch.systemsx.cisd.openbis.dss.client.api.cli.GlobalArguments;
 
 /**
  * @author Chandrasekhar Ramakrishnan
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d241c21e7d08aecb8fb7d54bddfea450c6667435
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTest.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.client.api.v1.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Random;
+
+import org.apache.commons.io.IOUtils;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+import ch.systemsx.cisd.common.api.IRpcServiceFactory;
+import ch.systemsx.cisd.common.api.RpcServiceInterfaceDTO;
+import ch.systemsx.cisd.common.api.RpcServiceInterfaceVersionDTO;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.impl.DssComponent;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssBuilder;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.IDssServiceRpcGeneric;
+import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStore;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
+
+/**
+ * @author Chandrasekhar Ramakrishnan
+ */
+public class DssComponentTest extends AbstractFileSystemTestCase
+{
+    private Mockery context;
+
+    private IETLLIMSService openBisService;
+
+    private IRpcServiceFactory dssServiceFactory;
+
+    private DssComponent dssComponent;
+
+    private File randomDataFile;
+
+    private static final String DUMMY_SESSSION_TOKEN = "DummySessionToken";
+
+    private static final String DUMMY_DSS_URL = "http://localhost/datastore_server";
+
+    public DssComponentTest()
+    {
+
+    }
+
+    @Override
+    @BeforeMethod
+    public void setUp() throws IOException
+    {
+        super.setUp();
+        context = new Mockery();
+        openBisService = context.mock(IETLLIMSService.class);
+        dssServiceFactory = context.mock(IRpcServiceFactory.class);
+        dssComponent = new DssComponent(openBisService, dssServiceFactory, null);
+        randomDataFile = getFileWithRandomData(1);
+    }
+
+    @Test
+    public void testLogin()
+    {
+        final SessionContextDTO session = getDummySession();
+
+        context.checking(new Expectations()
+            {
+                {
+                    one(openBisService).tryToAuthenticate("foo", "bar");
+                    will(returnValue(session));
+                }
+            });
+
+        dssComponent.login("foo", "bar");
+
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testListDataSetFiles() throws IOException
+    {
+        setupExpectations();
+
+        dssComponent.login("foo", "bar");
+        IDataSetDss dataSetProxy = dssComponent.getDataSet("DummyDataSetCode");
+        FileInfoDssDTO[] fileInfos = dataSetProxy.listFiles("/", true);
+        assertEquals(1, fileInfos.length);
+
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testListDataSetFilesNoLogin() throws IOException
+    {
+        dssComponent = new DssComponent(openBisService, dssServiceFactory, DUMMY_SESSSION_TOKEN);
+        setupExpectationsNoLogin();
+        IDataSetDss dataSetProxy = dssComponent.getDataSet("DummyDataSetCode");
+        FileInfoDssDTO[] fileInfos = dataSetProxy.listFiles("/", true);
+        assertEquals(1, fileInfos.length);
+
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testUnsupportedInterface() throws IOException
+    {
+        setupExpectations("Some Server Interface", true);
+
+        dssComponent.login("foo", "bar");
+        try
+        {
+            dssComponent.getDataSet("DummyDataSetCode");
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e)
+        {
+            // correct behavior
+        }
+
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testGetFileContents() throws IOException
+    {
+        setupExpectations();
+
+        dssComponent.login("foo", "bar");
+        IDataSetDss dataSetProxy = dssComponent.getDataSet("DummyDataSetCode");
+        FileInfoDssDTO[] fileInfos = dataSetProxy.listFiles("/", true);
+        FileInfoDssDTO fileFileInfo = null;
+        for (FileInfoDssDTO fid : fileInfos)
+        {
+            if (fid.isDirectory() == false)
+            {
+                fileFileInfo = fid;
+                break;
+            }
+        }
+        if (fileFileInfo == null)
+        {
+            fail("Could not find file info for random file");
+            return;
+        }
+
+        InputStream is = dataSetProxy.getFile(fileFileInfo.getPathInDataSet());
+        int byteCount = 0;
+        while (is.read() >= 0)
+        {
+            ++byteCount;
+        }
+
+        assertEquals(fileFileInfo.getFileSize(), byteCount);
+    }
+
+    private void setupExpectations() throws IOException
+    {
+        setupExpectations(IDssServiceRpcGeneric.DSS_SERVICE_NAME, true);
+    }
+
+    private void setupExpectationsNoLogin() throws IOException
+    {
+        setupExpectations(IDssServiceRpcGeneric.DSS_SERVICE_NAME, false);
+    }
+
+    private void setupExpectations(String serviceName, final boolean needsLogin) throws IOException
+    {
+        final SessionContextDTO session = getDummySession();
+        final ExternalData dataSetExternalData = new ExternalData();
+        DataStore dataStore = new DataStore();
+        dataStore.setDownloadUrl(DUMMY_DSS_URL);
+        dataSetExternalData.setDataStore(dataStore);
+        final IDssServiceRpcGeneric dssService = context.mock(IDssServiceRpcGeneric.class);
+        ArrayList<FileInfoDssDTO> list = new ArrayList<FileInfoDssDTO>();
+        FileInfoDssBuilder builder =
+                new FileInfoDssBuilder(workingDirectory.getCanonicalPath(), workingDirectory
+                        .getCanonicalPath());
+        builder.appendFileInfosForFile(workingDirectory, list, true);
+        final FileInfoDssDTO[] fileInfos = new FileInfoDssDTO[list.size()];
+        list.toArray(fileInfos);
+
+        final ArrayList<RpcServiceInterfaceDTO> ifaces = new ArrayList<RpcServiceInterfaceDTO>(1);
+        final RpcServiceInterfaceDTO iface = new RpcServiceInterfaceDTO(serviceName);
+        final RpcServiceInterfaceVersionDTO ifaceVersion =
+                new RpcServiceInterfaceVersionDTO(serviceName, "/rpc/v1", 1, 0);
+
+        iface.addVersion(ifaceVersion);
+
+        ifaces.add(iface);
+
+        context.checking(new Expectations()
+            {
+                {
+                    final String dataSetCode = "DummyDataSetCode";
+
+                    if (needsLogin)
+                    {
+                        one(openBisService).tryToAuthenticate("foo", "bar");
+                        will(returnValue(session));
+                    }
+                    allowing(openBisService).tryGetDataSet(DUMMY_SESSSION_TOKEN, dataSetCode);
+                    will(returnValue(dataSetExternalData));
+                    allowing(dssServiceFactory).getSupportedInterfaces(DUMMY_DSS_URL, false);
+                    will(returnValue(ifaces));
+                    allowing(dssServiceFactory).getService(ifaceVersion,
+                            IDssServiceRpcGeneric.class, DUMMY_DSS_URL, false);
+                    will(returnValue(dssService));
+                    allowing(dssService).listFilesForDataSet(DUMMY_SESSSION_TOKEN, dataSetCode,
+                            "/", true);
+                    will(returnValue(fileInfos));
+                    allowing(dssService).getFileForDataSet(DUMMY_SESSSION_TOKEN, dataSetCode,
+                            "/random.txt");
+                    will(returnValue(new FileInputStream(randomDataFile)));
+                }
+            });
+    }
+
+    private SessionContextDTO getDummySession()
+    {
+        final SessionContextDTO session = new SessionContextDTO();
+        session.setSessionToken(DUMMY_SESSSION_TOKEN);
+        return session;
+    }
+
+    private File getFileWithRandomData(long sizeInKB) throws IOException
+    {
+        File file = new File(workingDirectory, "random.txt");
+        Random random = new Random();
+        FileOutputStream outputStream = null;
+        try
+        {
+            outputStream = new FileOutputStream(file);
+            byte[] bytes = new byte[1024];
+            for (int i = 0; i < sizeInKB; i++)
+            {
+                random.nextBytes(bytes);
+                outputStream.write(bytes);
+            }
+        } catch (IOException ex)
+        {
+            throw ex;
+        } finally
+        {
+            if (outputStream != null)
+            {
+                IOUtils.closeQuietly(outputStream);
+            }
+        }
+
+        return file;
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTestClient.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTestClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9d571cae3a987b79f1ae2e65502866900637139
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/api/v1/impl/DssComponentTestClient.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.client.api.v1.impl;
+
+import java.util.Properties;
+
+import org.apache.log4j.PropertyConfigurator;
+
+import ch.systemsx.cisd.openbis.dss.client.api.v1.DssComponentFactory;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
+import ch.systemsx.cisd.openbis.dss.client.api.v1.IDssComponent;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
+
+/**
+ * @author Chandrasekhar Ramakrishnan
+ */
+public class DssComponentTestClient
+{
+
+    public static void main(String[] args)
+    {
+        configureLogging();
+        System.out.println("Logging in");
+        IDssComponent component =
+                DssComponentFactory.tryCreate("test", "foobar", "http://localhost:8888");
+        IDataSetDss dataSet = component.getDataSet("20100318094819344-4");
+        FileInfoDssDTO fileInfos[] = dataSet.listFiles("/", true);
+        for (FileInfoDssDTO fileInfo : fileInfos)
+        {
+            System.out.println(fileInfo);
+        }
+        component.logout();
+        System.out.println("Logging out");
+    }
+
+    private static void configureLogging()
+    {
+        Properties props = new Properties();
+        props.put("log4j.appender.STDOUT", "org.apache.log4j.ConsoleAppender");
+        props.put("log4j.appender.STDOUT.layout", "org.apache.log4j.PatternLayout");
+        props.put("log4j.appender.STDOUT.layout.ConversionPattern", "%d %-5p [%t] %c - %m%n");
+        props.put("log4j.rootLogger", "INFO, STDOUT");
+        PropertyConfigurator.configure(props);
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DssServiceRpcV1Test.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DssServiceRpcV1Test.java
index e309591b7a237b8337f82d7cdbbe9bb90f948419..a005b87badb15cdf331c8ab6aaf43b2fdbe515c5 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DssServiceRpcV1Test.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DssServiceRpcV1Test.java
@@ -30,9 +30,9 @@ import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
-import ch.systemsx.cisd.openbis.dss.api.v1.server.DssServiceRpcGeneric;
-import ch.systemsx.cisd.openbis.dss.api.v1.shared.FileInfoDssDTO;
+import ch.systemsx.cisd.openbis.dss.generic.server.api.v1.DssServiceRpcGeneric;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.DatasetLocationUtil;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance;