Author: ivol37 at gmail.com
Date: Mon Feb 14 15:45:57 2011
New Revision: 782
Log:
[AMDATU-304] Implemented tenant cache as aspect service of tenant management
service.
Added:
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantConfigServiceImpl.java
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementCache.java
Modified:
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/osgi/Activator.java
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementServiceImpl.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/FSTenantStorageProviderServiceTest.java
Modified:
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/osgi/Activator.java
==============================================================================
---
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/osgi/Activator.java
(original)
+++
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/osgi/Activator.java
Mon Feb 14 15:45:57 2011
@@ -19,10 +19,13 @@
import org.amdatu.core.tenant.TenantManagementService;
import org.amdatu.core.tenant.TenantStorageProvider;
+import org.amdatu.core.tenant.service.TenantConfigServiceImpl;
+import org.amdatu.core.tenant.service.TenantManagementCache;
import org.amdatu.core.tenant.service.TenantManagementServiceImpl;
import org.apache.felix.dm.DependencyActivatorBase;
import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
import org.osgi.service.log.LogService;
/**
@@ -39,8 +42,23 @@
.setImplementation(TenantManagementServiceImpl.class)
.setInterface(TenantManagementService.class.getName(), null)
.add(createServiceDependency().setService(TenantStorageProvider.class).setRequired(true))
-
.add(createConfigurationDependency().setPid(TenantManagementService.PID))
.add(createServiceDependency().setService(LogService.class).setRequired(true)));
+
+ // Create and register the Cached Tenant management service
+ String filter = "(" + Constants.OBJECTCLASS + "=" +
TenantManagementService.class.getName() + ")";
+ manager.add(
+ createAspectService(TenantManagementService.class, filter, 10,
null)
+ .setImplementation(TenantManagementCache.class)
+ .setInterface(TenantManagementService.class.getName(), null)
+
.add(createServiceDependency().setService(LogService.class).setRequired(true)));
+
+ // Create and register the Tenant config service
+ manager.add(
+ createComponent()
+ .setImplementation(TenantConfigServiceImpl.class)
+
.add(createServiceDependency().setService(LogService.class).setRequired(true).setInstanceBound(true))
+
.add(createServiceDependency().setService(TenantManagementService.class).setRequired(true))
+
.add(createConfigurationDependency().setPid(TenantManagementService.PID)));
}
@Override
Added:
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantConfigServiceImpl.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantConfigServiceImpl.java
Mon Feb 14 15:45:57 2011
@@ -0,0 +1,136 @@
+/*
+ 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.core.tenant.service;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.amdatu.core.tenant.TenantEntity;
+import org.amdatu.core.tenant.TenantException;
+import org.amdatu.core.tenant.TenantManagementService;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+
+/**
+ * This managed service listens to configuration changes in the tenant config.
It invokes the
+ * tenant management service when new tenants are available, tenants have been
updated or removed.
+ * Note that since the tenant management service is decorated with a cache
aspect, the service actually
+ * invoked will be the cache service, such that the cache will be refreshed
automatically when the
+ * tenant config has been changed.
+ *
+ * @author ivol
+ */
+public class TenantConfigServiceImpl implements ManagedService {
+ // Service dependencies injected by the dependency manager
+ private volatile LogService m_logService;
+ private volatile TenantManagementService m_tenantService;
+
+ // List of provisioned tenants from config admin
+ private List<TenantEntity> m_configTenants;
+
+ @SuppressWarnings("unchecked")
+ public void updated(Dictionary properties) throws ConfigurationException {
+ if (properties != null) {
+ // Build a list of tenants from the configuration file
+ m_configTenants = new ArrayList<TenantEntity>();
+ Enumeration<String> keys = properties.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ if (key.endsWith(".id")) {
+ m_configTenants.add(getTenant(properties, key));
+ }
+ }
+ if (m_logService != null && m_tenantService != null) {
+ update();
+ }
+ }
+ }
+
+ public void start() {
+ update();
+ }
+
+ private void update() {
+ try {
+ update(m_configTenants);
+ }
+ catch (TenantException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not update tenants",
e);
+ }
+ }
+
+ // Invoked when the list of tenants need to be updated
+ private void update(List<TenantEntity> newTenants) throws TenantException {
+ m_logService.log(LogService.LOG_INFO, "Updating tenants after
configuration update.");
+
+ // Build the list of tenants we need to update afterwardds
+ List<TenantEntity> updateTenants = new ArrayList<TenantEntity>();
+ updateTenants.addAll(newTenants);
+
+ // First add new tenants
+ List<TenantEntity> existingTenants = m_tenantService.getTenants();
+ for (TenantEntity newTenant : newTenants) {
+ if (!existingTenants.contains(newTenant)) {
+ // This tenant does not exist yet, add it
+ m_tenantService.createTenant(newTenant.getId(),
newTenant.getName(), newTenant.getProperties());
+
+ // Since the tenant is just added, it doesn't need to be
updated anymore
+ updateTenants.remove(newTenant);
+ }
+ }
+
+ // Now remove tenants that have been removed
+ for (TenantEntity oldTenant : existingTenants) {
+ if (!newTenants.contains(oldTenant)) {
+ // This tenant does not exist anymore, remove it
+ m_tenantService.deleteTenant(oldTenant);
+ }
+ }
+
+ // Now update all tenants
+ for (TenantEntity newTenant : updateTenants) {
+ m_tenantService.updateTenant(newTenant);
+ }
+ }
+
+ // Read a tenant configuration from config admin properties
+ @SuppressWarnings("unchecked")
+ private TenantEntity getTenant(Dictionary dictionary, String idKey) {
+ String nameKey = idKey.substring(0, idKey.lastIndexOf(".id")) +
".name";
+ String propertiesKey = idKey.substring(0, idKey.lastIndexOf(".id")) +
".properties";
+ String id = (String) dictionary.get(idKey);
+ String name = (String) dictionary.get(nameKey);
+ Map<String, String> properties = new HashMap<String, String>();
+ Enumeration<String> keys = dictionary.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ if (key.startsWith(propertiesKey)) {
+ String propName = key.substring(propertiesKey.length() + 1);
+ String propValue = (String) dictionary.get(key);
+ properties.put(propName, propValue);
+ }
+ }
+ return new TenantEntity(id, name, properties);
+ }
+
+
+}
Added:
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementCache.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementCache.java
Mon Feb 14 15:45:57 2011
@@ -0,0 +1,186 @@
+/*
+ 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.core.tenant.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.amdatu.core.tenant.TenantEntity;
+import org.amdatu.core.tenant.TenantException;
+import org.amdatu.core.tenant.TenantManagementService;
+import org.osgi.service.log.LogService;
+
+/**
+ * This class implements a cache for the Tenant management service,
implemented as an aspect of the
+ * original Tenant management service. Note that tenants in Amdatu are
actually read-only; they are
+ * "provisioned" from configuration management.
+ *
+ * @author ivol
+ */
+public class TenantManagementCache implements TenantManagementService {
+ // Service dependencies injected by the dependency manager
+ private volatile TenantManagementService m_tenantService;
+ private volatile LogService m_logService;
+
+ // The tenant cache
+ private List<TenantEntity> m_tenantCache = null;
+
+ // We currently use all-exclusive access.
+ private ReentrantReadWriteLock m_lock = new ReentrantReadWriteLock();
+
+ public void start() throws TenantException {
+ // read the tenants upon startup
+ loadCache();
+
+ m_logService.log(LogService.LOG_INFO, "Tenant management cache
started");
+ }
+
+ public TenantEntity createTenant(String id, String name) throws
TenantException {
+ Lock writelock = m_lock.writeLock();
+ writelock.lock();
+ try {
+ // First clear the cache. This is necessary since while invoking
createTenant
+ // on the tenant management service, getTenantById will be invoked
immediately
+ // after the tenant has been created but before the method returns.
+ clearCache();
+
+ TenantEntity tenant = m_tenantService.createTenant(id, name);
+ return tenant;
+ } finally {
+ writelock.unlock();
+ }
+ }
+
+ public TenantEntity createTenant(String id, String name, Map<String,
String> properties) throws TenantException {
+ Lock writelock = m_lock.writeLock();
+ writelock.lock();
+ try {
+ // First clear the cache. This is necessary since while invoking
createTenant
+ // on the tenant management service, getTenantById will be invoked
immediately
+ // after the tenant has been created but before the method returns.
+ clearCache();
+
+ TenantEntity tenant = m_tenantService.createTenant(id, name,
properties);
+ return tenant;
+ } finally {
+ writelock.unlock();
+ }
+ }
+
+ public void updateTenant(TenantEntity tenant) throws TenantException {
+ Lock writelock = m_lock.writeLock();
+ writelock.lock();
+ try {
+ // First clear the cache. This is necessary since while invoking
createTenant
+ // on the tenant management service, getTenantById will be invoked
immediately
+ // after the tenant has been created but before the method returns.
+ clearCache();
+
+ m_tenantService.updateTenant(tenant);
+ } finally {
+ writelock.unlock();
+ }
+ }
+
+ public void deleteTenant(TenantEntity tenant) throws TenantException {
+ Lock writelock = m_lock.writeLock();
+ writelock.lock();
+ try {
+ // First clear the cache. This is necessary since while invoking
createTenant
+ // on the tenant management service, getTenantById will be invoked
immediately
+ // after the tenant has been created but before the method returns.
+ clearCache();
+
+ m_tenantService.deleteTenant(tenant);
+ } finally {
+ writelock.unlock();
+ }
+ }
+
+ public TenantEntity getTenantById(String id) throws TenantException {
+ if (m_tenantCache == null) {
+ loadCache();
+ }
+
+ Lock readlock = m_lock.readLock();
+ readlock.lock();
+ try {
+ for (TenantEntity tenant : m_tenantCache) {
+ if (tenant.getId().equals(id)) {
+ return tenant;
+ }
+ }
+ } finally {
+ readlock.unlock();
+ }
+ return null;
+ }
+
+ public List<TenantEntity> getTenants() throws TenantException {
+ if (m_tenantCache == null) {
+ loadCache();
+ }
+
+ List<TenantEntity> result = new ArrayList<TenantEntity>();
+ Lock readlock = m_lock.readLock();
+ readlock.lock();
+ try {
+ result.addAll(m_tenantCache);
+ } finally {
+ readlock.unlock();
+ }
+ return result;
+ }
+
+ public List<TenantEntity> getTenants(Map<String, String> properties)
throws TenantException {
+ if (m_tenantCache == null) {
+ loadCache();
+ }
+
+ Lock readlock = m_lock.readLock();
+ readlock.lock();
+ try {
+ List<TenantEntity> matchingTenants = new ArrayList<TenantEntity>();
+ for (TenantEntity tenant : m_tenantCache) {
+ if (tenant.matches(properties)) {
+ matchingTenants.add(tenant);
+ }
+ }
+ return matchingTenants;
+ } finally {
+ readlock.unlock();
+ }
+ }
+
+ private void loadCache() throws TenantException {
+ Lock writelock = m_lock.writeLock();
+ writelock.lock();
+ try {
+ m_tenantCache = new ArrayList<TenantEntity>();
+ m_tenantCache.addAll(m_tenantService.getTenants());
+ } finally {
+ writelock.unlock();
+ }
+ }
+
+ private void clearCache() {
+ m_tenantCache = null;
+ }
+}
Modified:
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementServiceImpl.java
==============================================================================
---
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementServiceImpl.java
(original)
+++
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementServiceImpl.java
Mon Feb 14 15:45:57 2011
@@ -17,8 +17,6 @@
package org.amdatu.core.tenant.service;
import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -34,253 +32,179 @@
import org.amdatu.core.tenant.TenantStorageProvider;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
import org.osgi.service.log.LogService;
/**
* This class implements the Tenant management service. It provides CRUD
operations on tenants and ensures
* that tenants are not only persisted (using the TenantStorageProvider) but
that Tenants are also registered
* as a service such that tenant aware services can become tenant adaptors.
+ * Note that tenants are usually read-only; they are provided by Config Admin.
The tenantConfigService therefore
+ * is a managed service that depends on this config and will invoke this
service when new tenants are available,
+ * tenants have been removed or updated.
*
* @author ivol
*/
-public class TenantManagementServiceImpl implements TenantManagementService,
ManagedService {
- private volatile LogService m_logService;
- private volatile DependencyManager m_manager;
- private volatile TenantStorageProvider m_tenantStorageProvider;
-
- private Map<Tenant, Component> m_tenantComponents = new HashMap<Tenant,
Component>();
-
- // List of tenants provisioned from config admin
- List<TenantEntity> m_tenants = null;
-
- // We currently use all-exclusive access.
- private ReentrantReadWriteLock m_lock = new ReentrantReadWriteLock();
-
- public synchronized void init() throws TenantException {
- // Loop over the tenants provisioned by config admin and add or
update the tenants. We do not
- // remove existing tenants if they are not covered by an entry
in config admin (yet).
- m_logService.log(LogService.LOG_INFO, "Initializing
TenantManagementService with tenants '" + m_tenants + "'.");
- if (m_tenants != null) {
- for (TenantEntity tenant : m_tenants) {
- TenantEntity persTenant =
getTenantById(tenant.getId());
- if (persTenant == null) {
- // Tenant does not yet exist, persist
it, but without registering it as Tenant service yet
- persTenant =
storeTenant(tenant.getId(), tenant.getName());
- }
- persTenant.setName(tenant.getName());
- for (String propKey :
tenant.getProperties().keySet()) {
- String propValue =
tenant.getProperties().get(propKey);
- persTenant.putProperty(propKey,
propValue);
- }
- m_tenantStorageProvider.store(persTenant);
- m_logService.log(LogService.LOG_INFO, "Tenant
'" + tenant.getId() + "' added.");
- }
- }
- }
-
- /**
- * Invoked by the Felix dependency manager.
- */
- public synchronized void start() throws TenantException {
- // TODO if we cannot get our tenants now, should we retry later?
- for (TenantEntity tenant : getTenants()) {
- createTenantService(tenant);
- }
- m_logService.log(LogService.LOG_INFO, "TenantManagementService
started.");
- }
-
- public List<TenantEntity> getTenants() throws TenantException {
- ReadLock lock = m_lock.readLock();
- try {
- lock.lock();
- return m_tenantStorageProvider.getAll();
- } finally {
- lock.unlock();
- }
- }
-
- public TenantEntity getTenantById(String id) throws TenantException {
- ReadLock lock = m_lock.readLock();
- try {
- lock.lock();
- return m_tenantStorageProvider.getById(id);
- } finally {
- lock.unlock();
- }
- }
-
- public List<TenantEntity> getTenants(Map<String, String> properties)
throws TenantException {
- ReadLock lock = m_lock.readLock();
- try {
- lock.lock();
- List<TenantEntity> matchingTenants = new
ArrayList<TenantEntity>();
- for (TenantEntity tenant : getTenants()) {
- if (tenant.matches(properties)) {
- matchingTenants.add(tenant);
- }
- }
- return matchingTenants;
- } finally {
- lock.unlock();
- }
- }
-
- public TenantEntity createTenant(String id, String name) throws
TenantException {
- return createTenant(id, name, null);
- }
-
- public TenantEntity createTenant(String id, String name, Map<String,
String> properties) throws TenantException {
- WriteLock writeLock = m_lock.writeLock();
- writeLock.lock();
- try {
- if (getTenantById(id) != null) {
- throw new TenantException("Tenant with id '" +
id + "' already exists");
- }
- TenantEntity tenant = new TenantEntity(id, name);
- if (properties != null) {
- for (String key : properties.keySet()) {
- tenant.putProperty(key,
properties.get(key));
- }
- }
- m_tenantStorageProvider.store(tenant);
-
- // Downgrade write to read lock
- ReadLock readLock = m_lock.readLock();
- try {
- readLock.lock();
- writeLock.unlock();
- createTenantService(tenant);
- return tenant;
- } finally {
- readLock.unlock();
- }
- } finally {
- if (writeLock.isHeldByCurrentThread()) {
- writeLock.unlock();
- }
- }
- }
-
- // Does the same as createTenant, but without registration of the
stored tenant as Tenant
- // service. Invoked in the init() method since tenant services are
registared in the start() method.
- private synchronized TenantEntity storeTenant(String id, String name)
throws TenantException {
- if (getTenantById(id) != null) {
- throw new TenantException("Tenant with id '" + id + "'
already exists");
- }
- TenantEntity tenant = new TenantEntity(id, name);
- m_tenantStorageProvider.store(tenant);
- return tenant;
- }
-
- public void updateTenant(TenantEntity tenant) throws TenantException {
- WriteLock writeLock = m_lock.writeLock();
- writeLock.lock();
- try {
- m_tenantStorageProvider.store(tenant);
-
- // Downgrade write to read lock
- ReadLock readLock = m_lock.readLock();
- try {
- readLock.lock();
- writeLock.unlock();
- reregisterTenantService(tenant);
- } finally {
- readLock.unlock();
- }
- } finally {
- if (writeLock.isHeldByCurrentThread()) {
- writeLock.unlock();
- }
- }
- }
-
- public void deleteTenant(TenantEntity tenant) throws TenantException {
- WriteLock writeLock = m_lock.writeLock();
- writeLock.lock();
- try {
- if (getTenantById(tenant.getId()) == null) {
- throw new TenantException("Tenant with id '" +
tenant.getId() + "' does not exist, thus cannot be deleted.");
- }
- m_tenantStorageProvider.delete(tenant);
-
- // Downgrade write to read lock
- ReadLock readLock = m_lock.readLock();
- try {
- readLock.lock();
- writeLock.unlock();
- removeTenantService(tenant);
- } finally {
- readLock.unlock();
- }
- } finally {
- if (writeLock.isHeldByCurrentThread()) {
- writeLock.unlock();
- }
- }
- }
-
- 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 reregisterTenantService(TenantEntity tenant) {
- Component component = m_tenantComponents.get(tenant);
- m_manager.remove(component);
- createTenantService(tenant);
- }
-
- private void removeTenantService(TenantEntity tenant) {
- m_manager.remove(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.TENANT_SERVICEPROPERTY +
entry.getKey(), entry.getValue());
- }
- properties.put(Tenant.TENANT_ID_SERVICEPROPERTY,
tenant.getId());
- properties.put(Tenant.TENANT_NAME_SERVICEPROPERTY,
tenant.getName());
- return properties;
- }
-
- @SuppressWarnings("unchecked")
- public void updated(Dictionary properties) throws
ConfigurationException {
- if (properties != null) {
- // Build a list of tenants from the configuration file
- m_tenants = new ArrayList<TenantEntity>();
- Enumeration<String> keys = properties.keys();
- while (keys.hasMoreElements()) {
- String key = keys.nextElement();
- if (key.endsWith(".id")) {
- m_tenants.add(getTenant(properties,
key));
- }
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- private TenantEntity getTenant(Dictionary dictionary, String idKey) {
- String nameKey = idKey.substring(0, idKey.lastIndexOf(".id")) +
".name";
- String propertiesKey = idKey.substring(0,
idKey.lastIndexOf(".id")) + ".properties";
- String id = (String) dictionary.get(idKey);
- String name = (String) dictionary.get(nameKey);
- Map<String, String> properties = new HashMap<String, String>();
- Enumeration<String> keys = dictionary.keys();
- while (keys.hasMoreElements()) {
- String key = keys.nextElement();
- if (key.startsWith(propertiesKey)) {
- String propName =
key.substring(propertiesKey.length() + 1);
- String propValue = (String) dictionary.get(key);
- properties.put(propName, propValue);
- }
- }
- return new TenantEntity(id, name, properties);
- }
+public class TenantManagementServiceImpl implements TenantManagementService {
+ private volatile LogService m_logService;
+ private volatile DependencyManager m_manager;
+ private volatile TenantStorageProvider m_tenantStorageProvider;
+
+ private Map<Tenant, Component> m_tenantComponents = new HashMap<Tenant,
Component>();
+
+ // We currently use all-exclusive access.
+ private ReentrantReadWriteLock m_lock = new ReentrantReadWriteLock();
+
+ public synchronized void start() throws TenantException {
+ m_logService.log(LogService.LOG_INFO, "TenantManagementService
started.");
+ }
+
+ public List<TenantEntity> getTenants() throws TenantException {
+ ReadLock lock = m_lock.readLock();
+ try {
+ lock.lock();
+ return m_tenantStorageProvider.getAll();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public TenantEntity getTenantById(String id) throws TenantException {
+ ReadLock lock = m_lock.readLock();
+ try {
+ lock.lock();
+ return m_tenantStorageProvider.getById(id);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public List<TenantEntity> getTenants(Map<String, String> properties)
throws TenantException {
+ ReadLock lock = m_lock.readLock();
+ try {
+ lock.lock();
+ List<TenantEntity> matchingTenants = new ArrayList<TenantEntity>();
+ for (TenantEntity tenant : getTenants()) {
+ if (tenant.matches(properties)) {
+ matchingTenants.add(tenant);
+ }
+ }
+ return matchingTenants;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public TenantEntity createTenant(String id, String name) throws
TenantException {
+ return createTenant(id, name, null);
+ }
+
+ public TenantEntity createTenant(String id, String name, Map<String,
String> properties) throws TenantException {
+ WriteLock writeLock = m_lock.writeLock();
+ writeLock.lock();
+ try {
+ if (getTenantById(id) != null) {
+ throw new TenantException("Tenant with id '" + id + "' already
exists");
+ }
+ TenantEntity tenant = new TenantEntity(id, name);
+ if (properties != null) {
+ for (String key : properties.keySet()) {
+ tenant.putProperty(key, properties.get(key));
+ }
+ }
+ m_tenantStorageProvider.store(tenant);
+
+ // Downgrade write to read lock
+ ReadLock readLock = m_lock.readLock();
+ try {
+ readLock.lock();
+ writeLock.unlock();
+ createTenantService(tenant);
+ return tenant;
+ } finally {
+ readLock.unlock();
+ }
+ } finally {
+ if (writeLock.isHeldByCurrentThread()) {
+ writeLock.unlock();
+ }
+ }
+ }
+
+ public void updateTenant(TenantEntity tenant) throws TenantException {
+ WriteLock writeLock = m_lock.writeLock();
+ writeLock.lock();
+ try {
+ m_tenantStorageProvider.store(tenant);
+
+ // Downgrade write to read lock
+ ReadLock readLock = m_lock.readLock();
+ try {
+ readLock.lock();
+ writeLock.unlock();
+ reregisterTenantService(tenant);
+ } finally {
+ readLock.unlock();
+ }
+ } finally {
+ if (writeLock.isHeldByCurrentThread()) {
+ writeLock.unlock();
+ }
+ }
+ }
+
+ public void deleteTenant(TenantEntity tenant) throws TenantException {
+ WriteLock writeLock = m_lock.writeLock();
+ writeLock.lock();
+ try {
+ if (getTenantById(tenant.getId()) == null) {
+ throw new TenantException("Tenant with id '" + tenant.getId()
+ "' does not exist, thus cannot be deleted.");
+ }
+ m_tenantStorageProvider.delete(tenant);
+
+ // Downgrade write to read lock
+ ReadLock readLock = m_lock.readLock();
+ try {
+ readLock.lock();
+ writeLock.unlock();
+ removeTenantService(tenant);
+ } finally {
+ readLock.unlock();
+ }
+ } finally {
+ if (writeLock.isHeldByCurrentThread()) {
+ writeLock.unlock();
+ }
+ }
+ }
+
+ 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 reregisterTenantService(TenantEntity tenant) {
+ removeTenantService(tenant);
+ createTenantService(tenant);
+ }
+
+ private void removeTenantService(TenantEntity tenant) {
+ Component component = m_tenantComponents.remove(tenant);
+ if (component != null) {
+ m_manager.remove(component);
+ }
+ }
+
+ 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.TENANT_SERVICEPROPERTY + entry.getKey(),
entry.getValue());
+ }
+ properties.put(Tenant.TENANT_ID_SERVICEPROPERTY, tenant.getId());
+ properties.put(Tenant.TENANT_NAME_SERVICEPROPERTY, tenant.getName());
+ return properties;
+ }
}
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/FSTenantStorageProviderServiceTest.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/FSTenantStorageProviderServiceTest.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/FSTenantStorageProviderServiceTest.java
Mon Feb 14 15:45:57 2011
@@ -97,12 +97,13 @@
m_tenantStorageProvider.delete(teDelete);
}
- TenantEntity te1 = m_tenantManagementService.createTenant("tenant1",
"Tenant1");
+ TenantEntity te1 = new TenantEntity("tenant1", "Tenant1");
+ m_tenantStorageProvider.store(te1);
TenantEntity te2 = m_tenantStorageProvider.getById("tenant1");
Assert.assertNotNull("Tenant was not persisted", te2);
te1.putProperty("favorite.drink", "hot choco");
- m_tenantManagementService.updateTenant(te1);
+ m_tenantStorageProvider.store(te1);
te2 = m_tenantStorageProvider.getById("tenant1");
Assert.assertNotNull("Tenant was not persisted", te2);
@@ -110,6 +111,6 @@
Assert.assertEquals("Tenant property was not set", "hot choco",
te2.getProperties().get("favorite.drink"));
// Remove tenant
- m_tenantManagementService.deleteTenant(te1);
+ m_tenantStorageProvider.delete(te1);
}
}