Author: angelo.vandersijpt at luminis.eu
Date: Thu Oct 28 13:55:50 2010
New Revision: 214

Log:
AMDATU-121 Refactored the Tenant service to be a little cleaner, and separate 
concerns of storage and interaction better. Also, updated the integration tests 
for this.

Added:
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantEntity.java
      - copied, changed from r213, 
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantStorageProvider.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/dao/TenantColumnFamilyProvider.java
      - copied, changed from r213, 
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/service/TenantColumnFamilyProvider.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/dao/TenantStorageProviderCassandraImpl.java
   
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/InMemoryTenantStorageProvider.java
Removed:
   
trunk/integration-tests/src/test/java/org/amdatu/test/integration/mock/TenantDAOMock.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantAwareService.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantDAO.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/dao/TenantDAOCassandraImpl.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/service/TenantColumnFamilyProvider.java
   
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/InMemoryTenantDAO.java
Modified:
   
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
   
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/TenantManagementServiceTest.java
   
trunk/platform-bundles/profile-service/src/main/java/org/amdatu/platform/profile/PersonService.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/Tenant.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantException.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantManagementService.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/osgi/Activator.java
   
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/service/TenantManagementServiceImpl.java
   
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/TenantManagementServiceTest.java

Modified: 
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
==============================================================================
--- 
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
     (original)
+++ 
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
     Thu Oct 28 13:55:50 2010
@@ -31,8 +31,11 @@
 import org.junit.Before;
 import org.ops4j.pax.exam.Inject;
 import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.container.def.options.VMOption;
 import org.ops4j.pax.exam.options.MavenArtifactProvisionOption;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 
 /**
@@ -66,6 +69,7 @@
             // Setting this system property unfortunately is necessary with 
the current Cassandra implementation
             
systemProperty("org.osgi.framework.system.packages.extra").value("sun.misc,com.sun.management"),
 
+            new VMOption("-Xmx1g"),
             // Enable this line to allow a remote debugger to attach to the VM 
in which Pax Exam runs
             // new 
VMOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"),
 
@@ -96,10 +100,10 @@
                     amdatuCassandraPersistenceManager(),
                     amdatuTenantService(),
                     amdatuUserAdminCassandraStore(),
-                    amdatuWink()
+                    amdatuWink(),
 
                 // And finally deploy ourselves
-//                bundle(integrationTestJarFile().toURI().toString())
+                bundle(integrationTestJarFile().toURI().toString())
                  ));
     }
 
@@ -166,15 +170,23 @@
     };
 
     /**
-     * Helper method to get a given service by class. Will wait for 
SERVICE_TIMEOUT seconds for the service,
+     * Helper method to get a given service by class and filter. Will wait for 
SERVICE_TIMEOUT seconds for the service,
      * and fail if it does not become available.
      */
     @SuppressWarnings("unchecked")
-    public <T> T getService(Class<T> serviceClass) {
+    public <T> T getService(Class<T> serviceClass, String filterString) throws 
InvalidSyntaxException {
         T serviceInstance = null;
 
         // First open a service tracker and wait let the service tracker wait 
for the availability of our service
-        ServiceTracker serviceTracker = new ServiceTracker(m_bundleContext, 
serviceClass.getName(), null);
+        ServiceTracker serviceTracker;
+        if (filterString == null) {
+            serviceTracker = new ServiceTracker(m_bundleContext, 
serviceClass.getName(), null);
+        }
+        else {
+            String classFilter = "(" + Constants.OBJECTCLASS + "=" + 
serviceClass.getName() + ")";
+            filterString = "(&" + classFilter + filterString + ")";
+            serviceTracker = new ServiceTracker(m_bundleContext, 
m_bundleContext.createFilter(filterString), null);
+        }
         serviceTracker.open();
         try {
             serviceInstance = (T) 
serviceTracker.waitForService(SERVICE_TIMEOUT * 1000);
@@ -196,6 +208,21 @@
         return serviceInstance;
     }
 
+    /**
+     * Helper method to get a given service by class. Will wait for 
SERVICE_TIMEOUT seconds for the service,
+     * and fail if it does not become available.
+     */
+    public <T> T getService(Class<T> serviceClass) {
+        try {
+            return getService(serviceClass, null);
+        }
+        catch (InvalidSyntaxException e) {
+            return null;
+            // This will not happen
+        }
+    }
+
+
     protected File integrationTestJarFile() {
         FileFilter ff = new FileFilter() {
             public boolean accept(File pathname) {
@@ -207,7 +234,7 @@
     }
 
     ////////////////////////////////////////////////////////////
-    // A load of Pax Exam definitions for easier provisioning
+    // A load of Pax Exam definitions for easier (typo-free) provisioning
 
     protected static MavenArtifactProvisionOption amdatuWink() {
         return 
mavenBundle().groupId("org.amdatu.platform").artifactId("wink-application").versionAsInProject();

Modified: 
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/TenantManagementServiceTest.java
==============================================================================
--- 
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/TenantManagementServiceTest.java
    (original)
+++ 
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/TenantManagementServiceTest.java
    Thu Oct 28 13:55:50 2010
@@ -16,20 +16,17 @@
  */
 package org.amdatu.test.integration.tests;
 
-import static org.ops4j.pax.exam.CoreOptions.*;
-import static org.ops4j.pax.exam.CoreOptions.provision;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
 
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 
 import junit.framework.Assert;
-import org.amdatu.platform.tenant.Tenant;
-import org.amdatu.platform.tenant.TenantDAO;
-import org.amdatu.platform.tenant.TenantException;
-import org.amdatu.platform.tenant.TenantManagementService;
+import org.amdatu.platform.tenant.*;
 import org.amdatu.test.integration.base.IntegrationTestBase;
-import org.amdatu.test.integration.mock.TenantDAOMock;
+import org.amdatu.test.integration.mock.InMemoryTenantStorageProvider;
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyManager;
 import org.junit.Test;
@@ -38,11 +35,15 @@
 import org.ops4j.pax.exam.junit.Configuration;
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
 import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
 
 /**
- * This class provides an integration test for testing the Tenant Management 
Service.
+ * This class provides an integration test for testing the Tenant Management 
Service. We
+ * make sure the right services are registered when they should.
  *
- * @author ivol
+ * TODO When the Cassandra-based storaged is factored out of the main bundle, 
we should
+ * add a test for basic interaction with this storage.
  */
 @RunWith(JUnit4TestRunner.class)
 public class TenantManagementServiceTest extends IntegrationTestBase {
@@ -51,111 +52,92 @@
 
     @Configuration
     public Option[] configure() {
-        return options(
-            mavenConfiguration(),
-
-        // Run test in a Felix container
-            frameworks(felix()),
-
-            // Setting this system property unfortunately is necessary with 
the current Cassandra implementation
-            
systemProperty("org.osgi.framework.system.packages.extra").value("sun.misc,com.sun.management"),
-
-            // Enable this line to allow a remote debugger to attach to the VM 
in which Pax Exam runs
-            // new 
VMOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"),
-
-            // Install bundles we need to execute our test
-            provision(
-                    compendium(),
-                    dependencyManager(),
-                    configAdmin(),
-                    felixLog(),
-
-                // Amdatu platform bundles
-                // TODO: this works fine when running 'mvn install' since the 
artifacts will then be deployed to the maven
-                // repository prior to running this integration test. With 
'mvn integration-test' however, artifacts will
-                // not be deployed and so this will only work when artifacts 
have been deployed to the maven repository
-                // before, possibly using outdated artifacts.
-                    amdatuConfigTemplateManager(),
-                    amdatuCassandraApplication(),
-                    amdatuCassandraListener(),
-                    amdatuCassandraPersistenceManager(),
-                    amdatuTenantService()
-
-                // And finally deploy ourselves
-        //                bundle(integrationTestJarFile().toURI().toString())
-             ));
+        return super.configure();
     }
 
     public Component[] getDependencies(DependencyManager manager) {
-        // TODO update this, so we can get notified of a new tenant service 
becoming available. Yay!
         Component testComponent = manager.createComponent()
             .setImplementation(this)
             .add(manager.createServiceDependency()
-                .setService(TenantManagementService.class));
+                .setService(TenantManagementService.class)
+                .setRequired(true))
+            .add(manager.createServiceDependency()
+                .setService(Tenant.class)
+                .setCallbacks("tenantAdded", "tenantRemoved"));
 
         Properties props = new Properties();
         props.put(Constants.SERVICE_RANKING, 1);
-        Component daoComponent = manager.createComponent()
-            .setInterface(TenantDAO.class.getName(), props)
-            .setImplementation(TenantDAOMock.class);
+        Component storageComponent = manager.createComponent()
+                .setInterface(TenantStorageProvider.class.getName(), props)
+                .setImplementation(InMemoryTenantStorageProvider.class);
+
+        return new Component[] {testComponent, storageComponent};
+    }
+    
+    private final Semaphore m_tenant1Added = new Semaphore(0);
+    private final Semaphore m_tenant1Removed = new Semaphore(0);
+    
+    public void tenantAdded(ServiceReference reference) {
+        if (reference.getProperty(Tenant.SERVICE_PREFIX + 
"id").equals("tenant1")) {
+            m_tenant1Added.release();
+        }
+    }
+
+    public void tenantRemoved(ServiceReference reference) {
+        if (reference.getProperty(Tenant.SERVICE_PREFIX + 
"id").equals("tenant1")) {
+            m_tenant1Removed.release();
+        }
+    }
 
-        return new Component[] {testComponent, daoComponent};
+    private boolean waitForTenantServiceAdded() throws InterruptedException {
+        return m_tenant1Added.tryAcquire(20, TimeUnit.SECONDS);
+    }
+
+    private boolean waitForTenantServiceRemoved() throws InterruptedException {
+        return m_tenant1Removed.tryAcquire(20, TimeUnit.SECONDS);
     }
 
-    // TODO pull this test apart into multiple tests
     @Test
-    public void testTenantManagementService() throws Exception {
+    public void shouldCreateTenantService() throws TenantException, 
InterruptedException {
+        m_tenantManagementService.createTenant("tenant1", "Tenant1");
+        Assert.assertTrue("Tenant service did not become available", 
waitForTenantServiceAdded());
+    }
 
-        Tenant[] allTenants = m_tenantManagementService.getAllTenants();
-        Assert.assertTrue("There are already tenants present in the storage",
-            m_tenantManagementService.getAllTenants().length == 0);
+    @Test
+    public void shouldRemoveTenantService() throws TenantException, 
InterruptedException {
+        TenantEntity tenant = 
m_tenantManagementService.createTenant("tenant1", "Tenant1");
+        waitForTenantServiceAdded();
+        m_tenantManagementService.deleteTenant(tenant);
+        Assert.assertTrue("Tenant service did not disappear", 
waitForTenantServiceRemoved());
+    }
 
-        int tenantCount = allTenants.length;
-        Tenant tenant = 
m_tenantManagementService.createTentant("org.amdatu.test.integration.tests.testtenant",
 "TEST");
+    @Test
+    public void shouldPublishTenantProperties() throws TenantException, 
InterruptedException, InvalidSyntaxException {
+        TenantEntity tenant = 
m_tenantManagementService.createTenant("shouldPublishTenantProperties", 
"shouldPublishTenantProperties");
+        tenant.putProperty("host", "shouldPublishTenantProperties.org");
         m_tenantManagementService.updateTenant(tenant);
 
-        Assert.assertTrue("Added and updated 1 tenant, but the Tenant service 
now holds "
-            + m_tenantManagementService.getAllTenants().length + " tenants, 
expected: " + (tenantCount + 1), m_tenantManagementService
-            .getAllTenants().length == tenantCount + 1);
-
-        // Try to add a tenant with the same id, should throw an exception
-        try {
-            
m_tenantManagementService.createTentant("org.amdatu.test.integration.tests.testtenant",
 "sdfsdfd");
-            Assert.assertTrue("Tenant with the same id could be created 
twice", false);
-        }
-        catch (TenantException e) {}
+        assertNotNull("The service did not become available",
+                getService(Tenant.class, "(" + Tenant.SERVICE_PREFIX + 
"host=shouldPublishTenantProperties.org)"));
+    }
 
-        m_tenantManagementService.deleteTenant(tenant);
+    @Test
+    public void shouldUpdateTenantProperties() throws TenantException, 
InterruptedException, InvalidSyntaxException {
+        TenantEntity tenant = 
m_tenantManagementService.createTenant("shouldUpdateTenantProperties", 
"shouldUpdateTenantProperties");
+        tenant.putProperty("host", "shouldUpdateTenantProperties.org");
+        m_tenantManagementService.updateTenant(tenant);
 
-        Assert.assertTrue(m_tenantManagementService.getAllTenants().length == 
tenantCount);
+        assertNotNull("The service did not become available",
+                getService(Tenant.class, "(" + Tenant.SERVICE_PREFIX + 
"host=shouldPublishTenantProperties.org)"));
 
-        Tenant tenant1 = 
m_tenantManagementService.createTentant("org.amdatu.test.integration.tests.testtenant.1",
 "TEST 1");
-        Tenant tenant2 = 
m_tenantManagementService.createTentant("org.amdatu.test.integration.tests.testtenant.2",
 "TEST 2");
-        Tenant tenant3 = 
m_tenantManagementService.createTentant("org.amdatu.test.integration.tests.testtenant.3",
 "TEST 3");
-        tenant1.getProperties().put("hostname", "localhost");
-        tenant2.getProperties().put("hostname", "localhost");
-        tenant3.getProperties().put("hostname", "amdatu.org");
-        m_tenantManagementService.updateTenant(tenant1);
-        m_tenantManagementService.updateTenant(tenant2);
-        m_tenantManagementService.updateTenant(tenant3);
-
-        Map<String, String> filter = new HashMap<String, String>();
-        filter.put("hostname", "localhost");
-        Assert.assertTrue(m_tenantManagementService.getTenants(filter).length 
== 2);
-
-        filter.put("hostname", "amdatu.org");
-        Assert.assertTrue(m_tenantManagementService.getTenants(filter).length 
== 1);
-
-        m_tenantManagementService.deleteTenant(tenant1);
-        m_tenantManagementService.deleteTenant(tenant2);
-        m_tenantManagementService.deleteTenant(tenant3);
-
-        // What happens if I remove a tenant that was already removed?
-        try {
-            m_tenantManagementService.deleteTenant(tenant);
-            Assert.assertTrue("Tenant with the same id could be deleted 
twice", false);
-        }
-        catch (TenantException e) {}
+        tenant.putProperty("host", "shouldUpdateTenantProperties.com");
+        m_tenantManagementService.updateTenant(tenant);
+
+        assertNotNull("The service did not become available with the new 
properties",
+                getService(Tenant.class, "(" + Tenant.SERVICE_PREFIX + 
"host=shouldPublishTenantProperties.com)"));
 
+        assertNull("The service with the old property still lies around",
+                m_bundleContext.getServiceReference("(" + 
Tenant.SERVICE_PREFIX + "host=shouldPublishTenantProperties.org)"));
     }
+
 }

Modified: 
trunk/platform-bundles/profile-service/src/main/java/org/amdatu/platform/profile/PersonService.java
==============================================================================
--- 
trunk/platform-bundles/profile-service/src/main/java/org/amdatu/platform/profile/PersonService.java
 (original)
+++ 
trunk/platform-bundles/profile-service/src/main/java/org/amdatu/platform/profile/PersonService.java
 Thu Oct 28 13:55:50 2010
@@ -18,7 +18,6 @@
 
 import java.util.List;
 
-import org.amdatu.platform.tenant.TenantAwareService;
 import org.apache.shindig.social.opensocial.model.Person;
 import org.osgi.service.useradmin.User;
 

Modified: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/Tenant.java
==============================================================================
--- 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/Tenant.java
  (original)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/Tenant.java
  Thu Oct 28 13:55:50 2010
@@ -21,60 +21,49 @@
 
 /**
  * This interface represents a tenant. A tenant has an id, name and a map of 
properties that
- * identify the tenant. Tenants can be managed (i.e. persisted) using the 
TenantService.
- * @author ivol
+ * identify the tenant. Tenants can be managed (i.e. persisted) using the 
{@link TenantManagementService}.
+ *
+ * Tenant objects are intended to be stand-alone value objects.
+ *
+ * A tenant is solely identified by its ID, any changes to the name are 
inconsequential.
+ *
+ * For each tenant, an OSGi service is registered. The <code>id</code>, 
<code>name</code> and other properties
+ * will be registered with the service as service properties; the keys will be 
prefixed with {@link #SERVICE_PREFIX}
+ * If the properties contain keys 'name' or 'id', the Tenant's name or id will 
prevail.
  */
 public interface Tenant {
     /**
-     * The property key with which Tenant aware services should register their 
tenant.
-     * So a tenant aware service should add a property named TENANT_AWARE_KEY
-     * with a value that equals the tenant id in its service properties.
-     * For example:
-     * <pre>
-     * {@code
-     *   private volatile org.apache.felix.dm.Component m_component;
-     *   private volatile org.amdatu.platform.tenant.Tenant m_tenant;
-     * 
-     *   public void init() {
-     *     Dictionary<String, String> serviceProperties = new 
Hashtable<String, String>();
-     *     
serviceProperties.put(org.amdatu.platform.tenant.Tenant.TENANT_AWARE_KEY, 
m_tenant.getId());
-     *     m_component.setServiceProperties(serviceProperties);
-     *   }
-     * }
-     * </pre>
+     * All properties from the
      */
-    static final String TENANT_AWARE_KEY = "tenantid";
-    
+    final String SERVICE_PREFIX = "tenant_";
+
     /**
-     * Returns the id of the tenant.
-     * @return the id of the tenant.
+     * The unique ID for this tenant.
      */
     String getId();
     
     /**
-     * Returns the name of the tenant.
-     * @return the name of the tenant.
+     * The name for this tenant; not necessarily unique.
      */
     String getName();
-    
-    /**
-     * Sets the name of the tenant.
-     * @param name Name of the tenant
-     */
-    void setName(String name);
-    
+
     /**
      * Map of properties that identify this tenant. Properties may be a 
hostname or a cookie.
-     * @return List of properties that identify this tenant. If no properties 
are available
-     * then an empty map is returned.
+     * @return A map of properties that identify this tenant. If no properties 
are available
+     * then an empty map is returned. Note that the map is <em>not</em> backed 
by the Tenant
+     * object, and changes made to this map will not result in changes to the 
Tenant.
      */
     Map<String, String> getProperties();
+
+    /**
+     * Sets a property in the tenant; this will be reflected by subsequent 
calls to {@link @getProperties}
+     */
+    void putProperty(String key, String value);
     
     /**
-     * Returns if this tenant matches all specified properties.
-     * @param properties The properties to compare with
-     * @return true if this tenant has all properties of the specified map and 
if all values
-     * are the same (case is not ignored).
+     * Returns whether this tenant matches <em>all</em> specified properties.
+     * @return <code>true</code> if this tenant has all properties of the 
specified map and if all values
+     * are the same, <code>false</code> otherwise.
      */
     boolean matches(Map<String, String> properties);
 }

Copied: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantEntity.java
 (from r213, 
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java)
==============================================================================
--- 
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantImpl.java
     (original)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantEntity.java
    Thu Oct 28 13:55:50 2010
@@ -17,29 +17,29 @@
  */
 package org.amdatu.platform.tenant;
 
+import java.util.HashMap;
 import java.util.Map;
 
+/**
+ * Data-object representing a Tenant.
+ */
+public class TenantEntity implements Tenant {
+    private final String m_id;
+    private final Map<String, String> m_properties;
 
-
-public class TenantImpl implements Tenant {
-    // The id of the tenant
-    private String m_id;
-
-    // The name of the tenant
     private String m_name;
 
-    // The properties of the tenant
-    private Map<String, String> m_properties;
-
-    /**
-     * Constructor.
-     * @param id The id of the tenant
-     * @param name The name of the tenant
-     */
-    public TenantImpl(String id, String name, Map<String, String> properties) {
+    public TenantEntity(String id, String name, Map<String, String> 
properties) {
+        if (id == null) {
+            throw new NullPointerException("id cannot be null");
+        }
         m_id = id;
         m_name = name;
-        m_properties = properties;
+        m_properties = new HashMap<String, String>(properties);
+    }
+
+    public TenantEntity(String id, String name) {
+        this(id, name, new HashMap<String, String>());
     }
 
     public String getId() {
@@ -55,7 +55,11 @@
     }
     
     public Map<String, String> getProperties() {
-        return m_properties;
+        return new HashMap<String, String>(m_properties);
+    }
+
+    public void putProperty(String key, String value) {
+        m_properties.put(key, value);
     }
 
     public String toString() {
@@ -64,11 +68,7 @@
 
     @Override
     public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((m_id == null) ? 0 : m_id.hashCode());
-        result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
-        return result;
+        return m_id.hashCode() * 31;
     }
 
     @Override
@@ -79,18 +79,8 @@
             return false;
         if (getClass() != obj.getClass())
             return false;
-        TenantImpl other = (TenantImpl) obj;
-        if (m_id == null) {
-            if (other.m_id != null)
-                return false;
-        } else if (!m_id.equals(other.m_id))
-            return false;
-        if (m_name == null) {
-            if (other.m_name != null)
-                return false;
-        } else if (!m_name.equals(other.m_name))
-            return false;
-        return true;
+        TenantEntity other = (TenantEntity) obj;
+        return m_id == other.getId();
     }
     
     public boolean matches(Map<String, String> properties) {

Modified: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantException.java
==============================================================================
--- 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantException.java
 (original)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantException.java
 Thu Oct 28 13:55:50 2010
@@ -17,24 +17,16 @@
  */
 package org.amdatu.platform.tenant;
 
+/**
+ * This exception signifies a logical error, e.g. trying to create a tenant 
with an ID that is already in use.
+ */
 public class TenantException extends Exception {
-    /**
-     * The serial version UID of this class. 
-     */
     private static final long serialVersionUID = -4161504676185611010L;
 
-    /**
-     * Constructor for the exception.
-     * @param e the exception
-     */
     public TenantException(Exception e) {
         super(e);
     }
 
-    /**
-     * Constructor for the exception.
-     * @param msg The error message
-     */
     public TenantException(String msg) {
         super(msg);
     }

Modified: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantManagementService.java
==============================================================================
--- 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantManagementService.java
 (original)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantManagementService.java
 Thu Oct 28 13:55:50 2010
@@ -17,6 +17,7 @@
  */
 package org.amdatu.platform.tenant;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -24,52 +25,30 @@
  * are used to create tenant aware services. The tenant service will provide 
tenants
  * and the Felix dependency manager will automatically invoke a service 
instance for 
  * each tenant aware service in which the tenant is injected.
- * @author ivol
  */
 public interface TenantManagementService {
     /**
-     * Returns all available tenants. If no tenants are available an empty 
array is returned.
-     * @return all available tenants.
+     * Gets all tenants, or an empty list if there are none.
      */
-    Tenant[] getAllTenants();
+    List<TenantEntity> getTenants() throws TenantException;
     
     /**
-     * Returns the tenant with the specified id.
-     * @param id The id of the tenant to retrieve
-     * @return the tenant with the specified id.
+     * Gets the tenant with the given ID, or <code>null</code> if this doesn't 
exist.
      */
-    Tenant getTenantById(String id);
+    TenantEntity getTenantById(String id) throws TenantException;
     
     /**
-     * Returns a tenant based on a map of properties that identify one or more 
tenants.
-     * Such an identifier may for example be a hostname that is associated 
with the tenant.
-     * @return Array of all tenants that match the specified properties. Of no 
tenant matches
-     * the properties an empty array is returned
+     * Gets all tenants that match the given properties, or an empty list if 
there are none.
      */
-    Tenant[] getTenants(Map<String, String> properties);
+    List<TenantEntity> getTenants(Map<String, String> properties) throws 
TenantException;
         
     /**
-     * Create a new tenant with the specified id and name. Throws an 
TenantException
-     * if the tenant with that id already exists.
-     * @param id The identifier of the tenant
-     * @param name The name of the tenant
-     * @return the created tenant
-     * @throws TenantException in case a tenant with the specified id already 
exists
-     * or the tenant could not be persisted for any other reason.
+     * Creates a new tenant with the specified id and name.
+     * @throws TenantException in case a tenant with the specified id already 
exists.
      */
-    Tenant createTentant(String id, String name) throws TenantException;
+    TenantEntity createTenant(String id, String name) throws TenantException;
     
-    /**
-     * Updates an existing tenant.
-     * @param tenant The tenant to update
-     * @throws TenantException if the tenant could not be persisted for any 
reason.
-     */
-    void updateTenant(Tenant tenant) throws TenantException;
-    
-    /**
-     * Deletes an existing tenant
-     * @param tenant The tenant to delete
-     * @throws TenantException if the tenant could not be deleted for any 
reason.
-     */
-    void deleteTenant(Tenant tenant) throws TenantException;
+    void updateTenant(TenantEntity tenant) throws TenantException;
+
+    void deleteTenant(TenantEntity tenant) throws TenantException;
 }

Added: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantStorageProvider.java
==============================================================================
--- (empty file)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/TenantStorageProvider.java
   Thu Oct 28 13:55:50 2010
@@ -0,0 +1,48 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.platform.tenant;
+
+import java.util.List;
+
+/**
+ * Interface for the Tenant Storage.
+ *
+ * The {@link TenantStorageProvider} can assume that synchronization will be 
handled externally.
+ *
+ * All methods are allowed to throw a {@link TenantStorageException} when 
storage or retrieval fails.
+ */
+public interface TenantStorageProvider {
+    /**
+     * Stores a tenant. If a tenant with this ID already exists, update it.
+     */
+    void store(TenantEntity tenant) throws TenantStorageException;
+
+    /**
+     * Deletes the specified tenant. The tenant is identified by its ID.
+     */
+    void delete(TenantEntity tenant) throws TenantStorageException;
+
+    /**
+     * Retrieves a tenant with the given ID, or <code>null</code> if none 
exists
+     */
+    TenantEntity getById(String id) throws TenantStorageException;
+
+    /**
+     * Reads all existing Tenants and returns them.
+     */
+    List<TenantEntity> getAll() throws TenantStorageException;
+}

Copied: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/dao/TenantColumnFamilyProvider.java
 (from r213, 
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/service/TenantColumnFamilyProvider.java)
==============================================================================
--- 
/trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/service/TenantColumnFamilyProvider.java
     (original)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/dao/TenantColumnFamilyProvider.java
  Thu Oct 28 13:55:50 2010
@@ -14,7 +14,7 @@
     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-package org.amdatu.platform.tenant.service;
+package org.amdatu.platform.tenant.dao;
 
 import org.amdatu.platform.cassandra.listener.ColumnFamilyAvailable;
 import org.amdatu.platform.cassandra.listener.ColumnFamilyDefinition;

Added: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/dao/TenantStorageProviderCassandraImpl.java
==============================================================================
--- (empty file)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/dao/TenantStorageProviderCassandraImpl.java
  Thu Oct 28 13:55:50 2010
@@ -0,0 +1,96 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.platform.tenant.dao;
+
+import static 
org.amdatu.platform.tenant.dao.TenantColumnFamilyProvider.CF_TENANT;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.amdatu.platform.cassandra.persistencemanager.CassandraException;
+import 
org.amdatu.platform.cassandra.persistencemanager.CassandraPersistenceManager;
+import org.amdatu.platform.tenant.TenantEntity;
+import org.amdatu.platform.tenant.TenantStorageException;
+import org.amdatu.platform.tenant.TenantStorageProvider;
+
+public class TenantStorageProviderCassandraImpl implements 
TenantStorageProvider {
+    // Name of the supercolumns
+    private static final String SC_BASIC = "Basic";
+    private static final String SC_PROPERTIES = "Properties";
+
+    // Name of the columns
+    private static final String C_NAME = "name";
+
+    // Services injected by the Felix dependency manager
+    private volatile CassandraPersistenceManager m_pm;
+
+    public List<TenantEntity> getAll() throws TenantStorageException {
+        try {
+            List<TenantEntity> tenants = new ArrayList<TenantEntity>();
+            List<String> rowKeys = m_pm.getRowKeys(CF_TENANT);
+            if (rowKeys != null) {
+                for (String rowKey : rowKeys) {
+                    TenantEntity tenant = getById(rowKey);
+                    tenants.add(tenant);
+                }
+            }
+            return tenants;
+        }
+        catch (CassandraException e) {
+            throw new TenantStorageException(e);
+        }
+    }
+
+    public TenantEntity getById(String rowKey) throws TenantStorageException {
+        try {
+            if (!m_pm.exists(CF_TENANT, rowKey)) {
+                return null;
+            }
+            Map<String, Map<String, String>> values = 
m_pm.getSuperStringValues(CF_TENANT, rowKey);
+            Map<String, String> basic = values.get(SC_BASIC);
+            Map<String, String> properties = values.get(SC_PROPERTIES);
+            String name = basic.get(C_NAME);
+            return new TenantEntity(rowKey, name, properties);
+        }
+        catch (CassandraException e) {
+            throw new TenantStorageException(e);
+        }
+    }
+
+    public void store(TenantEntity tenant) throws TenantStorageException {
+        try {
+            String id = tenant.getId();
+            m_pm.setStringValue(CF_TENANT, id, SC_BASIC, C_NAME, 
tenant.getName());
+            for (String key : tenant.getProperties().keySet()) {
+                m_pm.setStringValue(CF_TENANT, id, SC_PROPERTIES, key, 
tenant.getProperties().get(key));
+            }
+        }
+        catch (CassandraException e) {
+            throw new TenantStorageException(e);
+        }
+    }
+
+    public void delete(TenantEntity tenant) throws TenantStorageException {
+        try {
+            m_pm.deleteRow(CF_TENANT, tenant.getId());
+        }
+        catch (CassandraException e) {
+            throw new TenantStorageException(e);
+        }
+    }
+}

Modified: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/osgi/Activator.java
==============================================================================
--- 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/osgi/Activator.java
  (original)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/osgi/Activator.java
  Thu Oct 28 13:55:50 2010
@@ -21,10 +21,10 @@
 import org.amdatu.platform.cassandra.listener.ColumnFamilyAvailable;
 import org.amdatu.platform.cassandra.listener.ColumnFamilyProvider;
 import 
org.amdatu.platform.cassandra.persistencemanager.CassandraPersistenceManager;
-import org.amdatu.platform.tenant.TenantDAO;
 import org.amdatu.platform.tenant.TenantManagementService;
-import org.amdatu.platform.tenant.dao.TenantDAOCassandraImpl;
-import org.amdatu.platform.tenant.service.TenantColumnFamilyProvider;
+import org.amdatu.platform.tenant.TenantStorageProvider;
+import org.amdatu.platform.tenant.dao.TenantColumnFamilyProvider;
+import org.amdatu.platform.tenant.dao.TenantStorageProviderCassandraImpl;
 import org.amdatu.platform.tenant.service.TenantManagementServiceImpl;
 import org.apache.felix.dm.DependencyActivatorBase;
 import org.apache.felix.dm.DependencyManager;
@@ -52,20 +52,21 @@
             "(" + CassandraPersistenceManager.KEYSPACE_AWARE_KEY + "="
                     + CassandraPersistenceManager.DEFAULT_KEYSPACE + ")";
 
-        // Create and register the Cassandra Tenant DAO
+        // Create and register the Cassandra Tenant Storage
         manager.add(
                 createComponent()
-                .setImplementation(TenantDAOCassandraImpl.class)
-                .setInterface(TenantDAO.class.getName(), null)
+                .setImplementation(TenantStorageProviderCassandraImpl.class)
+                .setInterface(TenantStorageProvider.class.getName(), null)
                 
.add(createServiceDependency().setService(CassandraPersistenceManager.class, 
keyspaceFilter).setRequired(true))
                 
.add(createServiceDependency().setService(ColumnFamilyAvailable.class, 
tenantFilter).setRequired(true)));
+
         
         // Create and register the Tenant management service
         manager.add(
                 createComponent()
                 .setImplementation(TenantManagementServiceImpl.class)
                 .setInterface(TenantManagementService.class.getName(), null)
-                
.add(createServiceDependency().setService(TenantDAO.class).setRequired(true))
+                
.add(createServiceDependency().setService(TenantStorageProvider.class).setRequired(true))
                 
.add(createServiceDependency().setService(LogService.class).setRequired(true)));
     }
 

Modified: 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/service/TenantManagementServiceImpl.java
==============================================================================
--- 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/service/TenantManagementServiceImpl.java
     (original)
+++ 
trunk/platform-bundles/tenant-service/src/main/java/org/amdatu/platform/tenant/service/TenantManagementServiceImpl.java
     Thu Oct 28 13:55:50 2010
@@ -16,97 +16,112 @@
  */
 package org.amdatu.platform.tenant.service;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.amdatu.platform.tenant.Tenant;
-import org.amdatu.platform.tenant.TenantDAO;
-import org.amdatu.platform.tenant.TenantException;
-import org.amdatu.platform.tenant.TenantManagementService;
+import java.util.*;
+
+import org.amdatu.platform.tenant.*;
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyManager;
-import org.osgi.service.log.LogService;
 
-/**
- * Implementation of the Tenant management service.
- * @author ivol
- */
 public class TenantManagementServiceImpl implements TenantManagementService {
-    // Injected by the Felix dependency manager
     private volatile DependencyManager m_manager;
-    private volatile TenantDAO m_tenantDAO;
-    private volatile LogService m_logService;
+    private volatile TenantStorageProvider m_tenantStorageProvider;
 
-    // Instance variables
-    private List<Tenant> m_tenants = new ArrayList<Tenant>();
     private Map<Tenant, Component> m_tenantComponents = new HashMap<Tenant, 
Component>();
 
+    // We currently use all-exclusive access.
+    private Object m_lock = new Object();
+
     /**
      * Invoked by the Felix dependency manager.
      */
-    public void start() {
-        try {
-            // Upon starting this bundle, we load the available tenants into 
memory
-            m_tenants = m_tenantDAO.readAll();
-
-            // Register all tenants as service
-            for (Tenant tenant : getAllTenants()) {
-                
m_manager.add(m_manager.createComponent().setImplementation(tenant).setInterface(
-                        Tenant.class.getName(), null));
+    public void start() throws TenantException {
+        // TODO if we cannot get our tenants now, should we retry later?
+        synchronized (m_lock) {
+            for (TenantEntity tenant : getTenants()) {
+                createTenantService(tenant);
             }
         }
-        catch (TenantException e) {
-            m_logService.log(LogService.LOG_ERROR, "Could not load tenants", 
e);
+    }
+
+    public List<TenantEntity> getTenants() throws TenantException {
+        synchronized (m_lock) {
+            return m_tenantStorageProvider.getAll();
         }
     }
 
-    public Tenant[] getAllTenants() {
-        return m_tenants.toArray(new Tenant[m_tenants.size()]);
+    public TenantEntity getTenantById(String id) throws TenantException {
+        synchronized (m_lock) {
+            return m_tenantStorageProvider.getById(id);
+        }
     }
 
-    public Tenant getTenantById(String id) {
-        for (Tenant tenant : m_tenants) {
-            if (tenant.getId().equals(id)) {
-                return tenant;
+    public List<TenantEntity> getTenants(Map<String, String> properties) 
throws TenantException {
+        synchronized (m_lock) {
+            List<TenantEntity> matchingTenants = new ArrayList<TenantEntity>();
+            for (TenantEntity tenant : getTenants()) {
+                if (tenant.matches(properties)) {
+                    matchingTenants.add(tenant);
+                }
             }
+            return matchingTenants;
         }
-        return null;
     }
 
-    public Tenant[] getTenants(Map<String, String> properties) {
-        List<Tenant> matchingTenants = new ArrayList<Tenant>();
-        for (Tenant tenant : m_tenants) {
-            if (tenant.matches(properties)) {
-                matchingTenants.add(tenant);
+    public TenantEntity createTenant(String id, String name) throws 
TenantException {
+        synchronized (m_lock) {
+            if (getTenantById(id) != null) {
+                throw new TenantException("Tenant with id '" + id + "' already 
exists");
             }
+            TenantEntity tenant = new TenantEntity(id, name);
+            m_tenantStorageProvider.store(tenant);
+            createTenantService(tenant);
+            return tenant;
         }
-        return matchingTenants.toArray(new Tenant[matchingTenants.size()]);
     }
 
-    public Tenant createTentant(String id, String name) throws TenantException 
{
-        synchronized (this) {
-            Tenant tenant = m_tenantDAO.create(id, name);
-            Component tenantComponent =
-                    
m_manager.createComponent().setImplementation(tenant).setInterface(Tenant.class.getName(),
 null);
-            m_tenantComponents.put(tenant, tenantComponent);
-            m_manager.add(tenantComponent);
-            m_tenants.add(tenant);
-            return tenant;
+    public void updateTenant(TenantEntity tenant) throws TenantException {
+        synchronized (m_lock) {
+            m_tenantStorageProvider.store(tenant);
+            updateTenantService(tenant);
         }
     }
 
-    public void updateTenant(Tenant tenant) throws TenantException {
-        m_tenantDAO.update(tenant);
+    public void deleteTenant(TenantEntity tenant) throws TenantException {
+        synchronized (m_lock) {
+            if (getTenantById(tenant.getId()) == null) {
+                throw new TenantException("Tenant with id '" + tenant.getId() 
+ "' does not exist, thus cannot be deleted.");
+            }
+            m_tenantStorageProvider.delete(tenant);
+            removeTenantService(tenant);
+        }
+    }
+
+    private void createTenantService(TenantEntity tenant) {
+        Component component = m_manager.createComponent()
+                .setImplementation(tenant)
+                .setInterface(Tenant.class.getName(), 
createServiceProperties(tenant));
+        m_manager.add(component);
+        m_tenantComponents.put(tenant, component);
+    }
+
+    private void updateTenantService(TenantEntity tenant) {
+        Component component = m_tenantComponents.get(tenant);
+        component.setServiceProperties(createServiceProperties(tenant));
+    }
+
+    private void removeTenantService(TenantEntity tenant) {
+        m_manager.remove(m_tenantComponents.remove(tenant));
     }
 
-    public void deleteTenant(Tenant tenant) throws TenantException {
-        synchronized (this) {
-            m_tenantDAO.delete(tenant);
-            m_tenants.remove(tenant);
-            m_manager.remove(m_tenantComponents.get(tenant));
-            m_tenantComponents.remove(tenant);
+    private Properties createServiceProperties(TenantEntity tenant) {
+        Properties properties = new Properties();
+        Map<String, String> tenantProperties = tenant.getProperties();
+        for (Map.Entry<String, String> entry : tenantProperties.entrySet()) {
+            properties.put(Tenant.SERVICE_PREFIX + entry.getKey(), 
entry.getValue());
         }
+        properties.put(Tenant.SERVICE_PREFIX + "id", tenant.getId());
+        properties.put(Tenant.SERVICE_PREFIX + "name", tenant.getName());
+        
+        return properties;
     }
 }

Added: 
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/InMemoryTenantStorageProvider.java
==============================================================================
--- (empty file)
+++ 
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/InMemoryTenantStorageProvider.java
 Thu Oct 28 13:55:50 2010
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.test.unit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.amdatu.platform.tenant.TenantEntity;
+import org.amdatu.platform.tenant.TenantStorageProvider;
+
+/**
+ * This service provides an in-memory implementation of the 
TenantStorageProvider, used for unit testing.
+ */
+public class InMemoryTenantStorageProvider implements TenantStorageProvider {
+    private final Map<String, TenantEntity> m_tenants = new HashMap<String, 
TenantEntity>();
+
+    public List<TenantEntity> getAll() {
+        return new ArrayList<TenantEntity>(m_tenants.values());
+    }
+
+    public TenantEntity getById(String id) {
+        return copy(m_tenants.get(id));
+    }
+
+    public void store(TenantEntity tenant) {
+        m_tenants.put(tenant.getId(), copy(tenant));
+    }
+
+    public void delete(TenantEntity tenant) {
+        m_tenants.remove(tenant.getId());
+    }
+
+    private TenantEntity copy(TenantEntity tenant) {
+        if (tenant == null) {
+            return null;
+        }
+        return new TenantEntity(tenant.getId(), tenant.getName(), new 
HashMap<String, String>(tenant.getProperties()));
+    }
+}

Modified: 
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/TenantManagementServiceTest.java
==============================================================================
--- 
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/TenantManagementServiceTest.java
   (original)
+++ 
trunk/platform-bundles/tenant-service/src/test/java/org/amdatu/test/unit/TenantManagementServiceTest.java
   Thu Oct 28 13:55:50 2010
@@ -16,18 +16,21 @@
  */
 package org.amdatu.test.unit;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
 import java.util.HashMap;
 import java.util.Map;
 
-import junit.framework.Assert;
-
 import org.amdatu.libraries.utilities.TestUtil;
-import org.amdatu.platform.tenant.Tenant;
-import org.amdatu.platform.tenant.TenantDAO;
+import org.amdatu.platform.tenant.TenantEntity;
 import org.amdatu.platform.tenant.TenantException;
 import org.amdatu.platform.tenant.TenantManagementService;
+import org.amdatu.platform.tenant.TenantStorageProvider;
 import org.amdatu.platform.tenant.service.TenantManagementServiceImpl;
+import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyManager;
+import org.junit.Before;
 import org.junit.Test;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.log.LogService;
@@ -37,80 +40,100 @@
  * @author ivol
  */
 public class TenantManagementServiceTest {
-    /**
-     * Run the unit test.
-     */
-    @Test
-    public void TenantManagementServiceUnitTest() {
-        // Instantiate the Tenant management service to test
-        TenantDAO tenantDAO = new InMemoryTenantDAO();
-        TenantManagementService tenantService = new 
TenantManagementServiceImpl();
-        TestUtil.configureObject(tenantService, LogService.class, 
TestUtil.createNullObject(LogService.class));
-        TestUtil.configureObject(tenantService, TenantDAO.class, tenantDAO);
-        TestUtil.configureObject(tenantService, DependencyManager.class, new 
DependencyManager(TestUtil.createNullObject(BundleContext.class)));
-        
+    private TenantManagementService m_tenantManagementService;
+
+    @Before
+    public void setUp() {
+        TenantStorageProvider tenantStorageProvider = new 
InMemoryTenantStorageProvider();
+        m_tenantManagementService = new TenantManagementServiceImpl();
+        TestUtil.configureObject(m_tenantManagementService, LogService.class, 
TestUtil.createNullObject(LogService.class));
+        TestUtil.configureObject(m_tenantManagementService, 
TenantStorageProvider.class, tenantStorageProvider);
+        TestUtil.configureObject(m_tenantManagementService, 
DependencyManager.class,
+                new 
DependencyManager(TestUtil.createNullObject(BundleContext.class)) {
+                    public void add(Component c) {
+                    }
+                });
+    }
+
+    @Test
+    public void shouldCreateTenant() throws TenantException {
+        int tenantsBefore = m_tenantManagementService.getTenants().size();
+        TenantEntity tenant = 
m_tenantManagementService.createTenant("shouldCreateTenant", 
"shouldCreateTenant");
+        
assertEquals(m_tenantManagementService.getTenantById("shouldCreateTenant"), 
tenant);
+        assertEquals(m_tenantManagementService.getTenants().size(), 
tenantsBefore + 1);
+    }
+
+    @Test
+    public void shouldNotCreateTenantTwice() throws TenantException {
+        int tenantsBefore = m_tenantManagementService.getTenants().size();
+        m_tenantManagementService.createTenant("shouldNotCreateTenantTwice", 
"shouldNotCreateTenantTwice");
+
+        try {
+            
m_tenantManagementService.createTenant("shouldNotCreateTenantTwice", 
"withsomeothername");
+            fail("We could create a tenant with the same id twice");
+        }
+        catch (TenantException e) {
+            // expected
+        }
+
+        assertEquals(m_tenantManagementService.getTenants().size(), 
tenantsBefore + 1);
+    }
+
+    @Test
+    public void shouldRemoveTenant() throws TenantException {
+        TenantEntity tenant = 
m_tenantManagementService.createTenant("shouldRemoveTenant", 
"shouldRemoveTenant");
+        int tenantsBefore = m_tenantManagementService.getTenants().size();
+        m_tenantManagementService.deleteTenant(tenant);
+        assertEquals(m_tenantManagementService.getTenants().size(), 
tenantsBefore - 1);
+    }
+
+    @Test
+    public void shouldUpdateTenant() throws TenantException {
+        TenantEntity tenant = 
m_tenantManagementService.createTenant("shouldUpdateTenant", 
"shouldUpdateTenant");
+        tenant.setName("updatedName");
+
+        assertEquals("It should not store the tenant before we called 'store'",
+                "shouldUpdateTenant", 
m_tenantManagementService.getTenantById("shouldUpdateTenant").getName());
+
+        m_tenantManagementService.updateTenant(tenant);
+
+        assertEquals("updatedName", 
m_tenantManagementService.getTenantById("shouldUpdateTenant").getName());
+    }
+
+    @Test
+    public void shouldNotRemoveTenantTwice() throws TenantException {
+        TenantEntity tenant = 
m_tenantManagementService.createTenant("shouldNotRemoveTenantTwice", 
"shouldNotRemoveTenantTwice");
+        int tenantsBefore = m_tenantManagementService.getTenants().size();
+        m_tenantManagementService.deleteTenant(tenant);
+        assertEquals(m_tenantManagementService.getTenants().size(), 
tenantsBefore - 1);
         try {
-            // Verify that there are no tenants available right now
-            Tenant[] allTenants = tenantService.getAllTenants();
-            Assert
-            .assertTrue("There are already tenants present in the storage",
-                tenantService.getAllTenants().length == 0);
-
-            // Create and update a tenant and verify that it has been added
-            int tenantCount = allTenants.length;
-            Tenant tenant = 
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant", 
"TEST");
-            tenantService.updateTenant(tenant);
-            Assert.assertTrue("Added and updated 1 tenant, but the Tenant 
service now holds "
-                + tenantService.getAllTenants().length + " tenants, expected: 
" + (tenantCount + 1), tenantService
-                .getAllTenants().length == tenantCount + 1);
-
-            // Try to add a tenant with the same id, this should throw an 
exception
-            try {
-                
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant", 
"sdfsdfd");
-                Assert.assertTrue("Tenant with the same id could be created 
twice", false);
-            }
-            catch (TenantException e) {
-            }
-
-            // Delete the tenant and check if it has been removed
-            tenantService.deleteTenant(tenant);
-            Assert.assertTrue(tenantService.getAllTenants().length == 
tenantCount);
-
-            // Create and update three tenants
-            Tenant tenant1 = 
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant.1", 
"TEST 1");
-            Tenant tenant2 = 
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant.2", 
"TEST 2");
-            Tenant tenant3 = 
tenantService.createTentant("org.amdatu.test.integration.tests.testtenant.3", 
"TEST 3");
-            tenant1.getProperties().put("hostname", "localhost");
-            tenant2.getProperties().put("hostname", "localhost");
-            tenant3.getProperties().put("hostname", "amdatu.org");
-            tenantService.updateTenant(tenant1);
-            tenantService.updateTenant(tenant2);
-            tenantService.updateTenant(tenant3);
-
-            // Check if the filter works correct
-            Map<String, String> filter = new HashMap<String, String>();
-            filter.put("hostname", "localhost");
-            Assert.assertTrue(tenantService.getTenants(filter).length == 2);
-            filter.put("hostname", "amdatu.org");
-            Assert.assertTrue(tenantService.getTenants(filter).length == 1);
-
-            // Delete the tenants, now all tenants should be removed
-            tenantService.deleteTenant(tenant1);
-            tenantService.deleteTenant(tenant2);
-            tenantService.deleteTenant(tenant3);
-            Assert.assertTrue(tenantService.getAllTenants().length == 0);
-            
-            // What happens if I remove a tenant that was already removed? 
This should throw an exception
-            try {
-                tenantService.deleteTenant(tenant);
-                Assert.fail("Tenant with the same id could be deleted twice");
-            }
-            catch (TenantException e) {
-            }
+            m_tenantManagementService.deleteTenant(tenant);
+            fail("we could remove a tenant twice");
         }
         catch (TenantException e) {
-            Assert.fail("An error has occurred: " + e.toString());
-            e.printStackTrace();
+            //expected
+        }
+    }
+
+    @Test
+    public void shouldFilterTenants() throws TenantException {
+        TenantEntity tenant = 
m_tenantManagementService.createTenant("shouldFilterTenants", 
"shouldFilterTenants");
+        assertEquals(0, m_tenantManagementService.getTenants(map("host", 
"amdatu.org")).size());
+        tenant.putProperty("host", "amdatu.org");
+
+        assertEquals("It should not store the tenant before we called 'store'",
+                0, m_tenantManagementService.getTenants(map("host", 
"amdatu.org")).size());
+
+        m_tenantManagementService.updateTenant(tenant);
+        assertEquals(1, m_tenantManagementService.getTenants(map("host", 
"amdatu.org")).size());
+    }
+
+    private static <T> Map<T, T> map(T... elements) {
+        Map<T, T> result = new HashMap<T, T>();
+        for (int i = 0; i < elements.length; i += 2) {
+            result.put(elements[i], elements[i+1]);
         }
-    }   
+        return result;
+    }
+
 }

Reply via email to