Author: [email protected]
Date: Mon Nov  7 17:20:25 2011
New Revision: 1714

Log:


Added:
   
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantConfigUpdateListenerImpl.java
   
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantMutationColumnFamilyProviderImpl.java
   
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantMutationDAO.java
   
sandbox/ivol/tenant-management-gadget/src/main/resources/static/images/remove_disabled.gif
   (contents, props changed)
Modified:
   sandbox/ivol/tenant-management-gadget/pom.xml
   
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/osgi/Activator.java
   
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantBean.java
   
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantRESTServiceImpl.java
   sandbox/ivol/tenant-management-gadget/src/main/resources/jsp/TenantGadget.jsp
   
sandbox/ivol/tenant-management-gadget/src/main/resources/static/css/tenant.css
   sandbox/ivol/tenant-management-gadget/src/main/resources/static/js/tenant.js

Modified: sandbox/ivol/tenant-management-gadget/pom.xml
==============================================================================
--- sandbox/ivol/tenant-management-gadget/pom.xml       (original)
+++ sandbox/ivol/tenant-management-gadget/pom.xml       Mon Nov  7 17:20:25 2011
@@ -29,6 +29,7 @@
 
   <properties>
     <amdatu.opensocial.version>0.2.0</amdatu.opensocial.version>
+    <amdatu.cassandra.version>0.2.1-RC2</amdatu.cassandra.version>
   </properties>
 
   <dependencies>
@@ -92,6 +93,34 @@
       <artifactId>servlet-api</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.amdatu.cassandra</groupId>
+      <artifactId>org.amdatu.cassandra.listener</artifactId>
+      <version>${amdatu.cassandra.version}</version>
+      <scope>provided</scope>
+      <type>bundle</type>
+    </dependency>
+    <dependency>
+      <groupId>org.amdatu.cassandra</groupId>
+      <artifactId>org.amdatu.cassandra.application</artifactId>
+      <version>${amdatu.cassandra.version}</version>
+      <scope>provided</scope>
+      <type>bundle</type>
+    </dependency>
+    <dependency>
+      <groupId>org.amdatu.cassandra</groupId>
+      <artifactId>org.amdatu.cassandra.persistencemanager</artifactId>
+      <version>${amdatu.cassandra.version}</version>
+      <scope>provided</scope>
+      <type>bundle</type>
+    </dependency>
+    <dependency>
+      <groupId>org.amdatu.cassandra</groupId>
+      <artifactId>org.amdatu.cassandra.persistencemanager.hector</artifactId>
+      <version>${amdatu.cassandra.version}</version>
+      <scope>provided</scope>
+      <type>bundle</type>
+    </dependency>
   </dependencies>
 
   <repositories>

Modified: 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/osgi/Activator.java
==============================================================================
--- 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/osgi/Activator.java
 (original)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/osgi/Activator.java
 Mon Nov  7 17:20:25 2011
@@ -13,17 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.amdatu.opensocial.tenant.gadget.osgi;
-
+package org.amdatu.opensocial.tenant.gadget.osgi;
+
 import java.util.Dictionary;
 import java.util.Hashtable;
 
+import org.amdatu.cassandra.listener.ColumnFamilyProvider;
+import 
org.amdatu.cassandra.persistencemanager.hector.HectorCassandraPersistenceManager;
 import org.amdatu.core.tenant.Tenant;
 import org.amdatu.libraries.utilities.osgi.ServiceDependentActivator;
 import org.amdatu.opensocial.gadgetmanagement.GadgetDefinitionProvider;
 import org.amdatu.opensocial.tenant.gadget.service.TenantGadgetDefinition;
 import org.amdatu.opensocial.tenant.gadget.service.TenantGadgetImpl;
 import org.amdatu.opensocial.tenant.gadget.service.TenantRESTServiceImpl;
+import 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl;
 import org.amdatu.web.dispatcher.DispatcherService;
 import org.amdatu.web.httpcontext.ResourceProvider;
 import org.amdatu.web.jsp.JspSupport;
@@ -35,65 +38,72 @@
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.log.LogService;
 import org.osgi.service.useradmin.UserAdmin;
-
-/**
- * This is the OSGi activator for this gadget bundle.
- *
- * @author ivol
- */
-public class Activator extends ServiceDependentActivator {
-    /**
-     * Context id of the Authorization HTTP Context.
-     */
-    public static final String CONTEXTID = "amdatu-opensocial-tenant";
-
-    /**
-     * URL alias hosting the login gadget.
-     */
-    public static final String ALIAS = "/tenant";
-
-    /**
-     * URL alias hosting the JSPs.
-     */
-    public static final String JSP_ALIAS = ALIAS + "/jsp";
-
-    /**
-     * URL alias hosting the statics.
-     */
+
+/**
+ * This is the OSGi activator for this gadget bundle.
+ * 
+ * @author ivol
+ */
+public class Activator extends ServiceDependentActivator {
+    /**
+     * Context id of the Authorization HTTP Context.
+     */
+    public static final String CONTEXTID = "amdatu-opensocial-tenant";
+
+    /**
+     * URL alias hosting the login gadget.
+     */
+    public static final String ALIAS = "/tenant";
+
+    /**
+     * URL alias hosting the JSPs.
+     */
+    public static final String JSP_ALIAS = ALIAS + "/jsp";
+
+    /**
+     * URL alias hosting the statics.
+     */
     public static final String RES_ALIAS = ALIAS + "/static";
-    
+
     protected Class<?>[] getRequiredServices() {
-        return new Class<?>[] {JaxRsSpi.class};
-    }
-
-    @Override
-    public void initWithDependencies(final BundleContext context, final 
DependencyManager manager) throws Exception {
-
-        Dictionary<String, Object> properties = new Hashtable<String, 
Object>();
-        properties.put(DispatcherService.CONTEXT_ID_KEY, CONTEXTID);
-        properties.put(JspSupport.JSP_ALIAS_KEY, JSP_ALIAS);
-        properties.put(ResourceSupport.RESOURCE_ALIAS_KEY, RES_ALIAS);
-
-        
manager.add(createComponent().setInterface(ResourceProvider.class.getName(), 
properties)
-            .setImplementation(TenantGadgetImpl.class)
-            
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+        return new Class<?>[] { JaxRsSpi.class };
+    }
+
+    @Override
+    public void initWithDependencies(final BundleContext context, final 
DependencyManager manager) throws Exception {
+
+        Dictionary<String, Object> properties = new Hashtable<String, 
Object>();
+        properties.put(DispatcherService.CONTEXT_ID_KEY, CONTEXTID);
+        properties.put(JspSupport.JSP_ALIAS_KEY, JSP_ALIAS);
+        properties.put(ResourceSupport.RESOURCE_ALIAS_KEY, RES_ALIAS);
+
+        
manager.add(createComponent().setInterface(ResourceProvider.class.getName(), 
properties)
+            .setImplementation(TenantGadgetImpl.class)
+            
.add(createServiceDependency().setService(LogService.class).setRequired(true))
             
.add(createServiceDependency().setService(UserAdmin.class).setRequired(true)));
 
         // Register a login gadget definition for each tenant
         manager.add(createAdapterService(Tenant.class, null)
             .setInterface(GadgetDefinitionProvider.class.getName(), null)
             .setImplementation(TenantGadgetDefinition.class));
-        
+
         // Create and register the REST tenant service
         manager.add(
-                createAdapterService(Tenant.class, null)
-                    .setInterface(new String[] {RESTService.class.getName()}, 
null)
-                    .setImplementation(TenantRESTServiceImpl.class)
-                    
.add(createServiceDependency().setService(LogService.class).setRequired(true))
-                    
.add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true)));
-    }
-
-    @Override
-    public void destroy(final BundleContext arg0, final DependencyManager 
arg1) throws Exception {
-    }
-}
+            createAdapterService(Tenant.class, null)
+                .setInterface(new String[] { RESTService.class.getName() }, 
null)
+                .setImplementation(TenantRESTServiceImpl.class)
+                
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+                
.add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
+                
.add(createServiceDependency().setService(HectorCassandraPersistenceManager.class).setRequired(true)));
+
+        // Define a service that provides the ColumnFamily we need
+        manager.add(
+            createComponent()
+                .setInterface(new String[] { 
ColumnFamilyProvider.class.getName() }, null)
+                
.setImplementation(TenantMutationColumnFamilyProviderImpl.class));
+    }
+
+    @Override
+    public void destroy(final BundleContext arg0, final DependencyManager 
arg1) throws Exception {
+    }
+}

Modified: 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantBean.java
==============================================================================
--- 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantBean.java
     (original)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantBean.java
     Mon Nov  7 17:20:25 2011
@@ -5,18 +5,17 @@
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import org.amdatu.libraries.utilities.rest.AtomSyndicationLink;
 
 @XmlRootElement(name = "tenant")
 @XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
-public class TenantBean {
+public class TenantBean implements Comparable<TenantBean>{
     private String m_id;
     private String m_name;
     private String m_hostname;
-    private AtomSyndicationLink m_link;
+    private List<AtomSyndicationLink> m_links;
     
     public TenantBean() {    
     }
@@ -51,11 +50,22 @@
         m_hostname = hostname;
     }
     
-    public AtomSyndicationLink getLink() {
-        return m_link;
+    public List<AtomSyndicationLink> getLinks() {
+        return m_links;
     }
 
-    public void setLink(final AtomSyndicationLink link) {
-        m_link = link;
+    public void setLinks(final List<AtomSyndicationLink> links) {
+        m_links = links;
+    }
+    
+    public void addLink(AtomSyndicationLink link) {
+        if (m_links == null) {
+            m_links = new ArrayList<AtomSyndicationLink>();
+        }
+        m_links.add(link);
+    }
+
+    public int compareTo(TenantBean otherBean) {
+        return 
getName().toLowerCase().compareTo(otherBean.getName().toLowerCase());
     }
 }

Added: 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantConfigUpdateListenerImpl.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantConfigUpdateListenerImpl.java
 Mon Nov  7 17:20:25 2011
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2010, 2011 The Amdatu Foundation
+ *
+ * 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 org.amdatu.opensocial.tenant.gadget.service;
+
+import static 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.CF;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.amdatu.core.tenant.TenantManagementService;
+import 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.MutationType;
+import org.amdatu.opensocial.tenant.gadget.service.TenantMutationDAO.Mutation;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.log.LogService;
+
+public class TenantConfigUpdateListenerImpl {
+    // The thread that inspects the Cassandra database for changes
+    private InspectTenantMutationsThread m_inspectThread;
+
+    // The interval for each individual inspect
+    private static int INSPECT_INTERVAL = 5000;
+
+    private volatile ConfigurationAdmin m_configAdmin;
+    private volatile LogService m_logService;
+    private volatile TenantMutationDAO m_tenantMutationDAO;
+
+    public void start() {
+        // Now start the inspect thread
+        m_inspectThread = new InspectTenantMutationsThread();
+        m_inspectThread.start();
+    }
+
+    public void stop() {
+        // Stop the inspect thread
+        m_inspectThread.interrupt();
+    }
+
+    /**
+     * This Thread inspects available Keyspaces and ColumnFamilies in 
Cassandra and compares these to
+     * the registered CassandraPersistenceManager and ColumnFamilyAvailable 
services. Since other nodes
+     * in the cluster may add, update or drop keyspaces and column families 
and Cassandra does not support
+     * any event mechanism to act upon these events we will continuously 
inspect this ourselves.
+     * 
+     * @author ivol
+     * 
+     */
+    class InspectTenantMutationsThread extends Thread {
+        public void run() {
+            try {
+                while (!isInterrupted()) {
+                    // Inspect the tenant mutation ColumnFamily for new 
mutations
+                    try {
+                        List<String> rowKeys = m_pm.getRowKeys(CF);
+                        if (rowKeys != null && rowKeys.size() > 0) {
+                            applyMutations(rowKeys);
+                        }
+                    }
+                    catch (Exception e) {
+                        m_logService.log(LogService.LOG_ERROR, "An error 
occurred while applying tenant mutation. Cause: " + e.getMessage(), e);
+                    }
+
+                    Thread.sleep(INSPECT_INTERVAL);
+                }
+            }
+            catch (InterruptedException e) {
+                m_logService.log(LogService.LOG_INFO, "Tenant config update 
listener thread interrupted.");
+            }
+        }
+        
+        public void applyMutations(List<String> rowKeys) throws IOException {
+            for (String rowKey : rowKeys) {
+                Mutation mutation = m_tenantMutationDAO.getMutation(rowKey);
+                if (mutation.type == MutationType.UPDATE) {
+                    Configuration config = 
m_configAdmin.getConfiguration(TenantManagementService.PID);
+                    Dictionary properties = config.getProperties();
+                    String tenantKey = findTenantKey(mutation.id);
+                    if (tenantKey == null) {
+                        int newid = findLastTenantKey() + 1;
+                        tenantKey = "tenant" + newid;
+                        properties.put(tenantKey + ".id", mutation.id);
+                    }
+                    properties.put(tenantKey + ".name", mutation.name);
+                    properties.put(tenantKey + ".properties.hostname", 
mutation.hostname);
+                    config.update(properties);
+                }
+            }
+        }
+        
+        private String findTenantKey(String tenantId) throws IOException {
+            Configuration config = 
m_configAdmin.getConfiguration(TenantManagementService.PID);
+            Dictionary properties = config.getProperties();
+            Enumeration keys = properties.keys();
+            while (keys.hasMoreElements()) {
+                String key = keys.nextElement().toString();
+                if (key.endsWith(".id")) {
+                    if (tenantId.equals(properties.get(key))) { 
+                        return key.substring(0, key.indexOf(".id"));
+                    }
+                }
+            }
+            return null;
+        }
+        
+        private int findLastTenantKey() throws IOException {
+            int maxid = 1;
+            Configuration config = 
m_configAdmin.getConfiguration(TenantManagementService.PID);
+            Dictionary properties = config.getProperties();
+            Enumeration keys = properties.keys();
+            while (keys.hasMoreElements()) {
+                String key = keys.nextElement().toString();
+                if (key.endsWith(".id")) {
+                    String id = key.substring("tenant".length(), 
key.indexOf("."));
+                    if (Integer.parseInt(id) > maxid) {
+                        maxid = Integer.parseInt(id);
+                    }
+                }
+            }
+            return maxid;
+        }
+    }
+}

Added: 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantMutationColumnFamilyProviderImpl.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantMutationColumnFamilyProviderImpl.java
 Mon Nov  7 17:20:25 2011
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010, 2011 The Amdatu Foundation
+ *
+ * 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 org.amdatu.opensocial.tenant.gadget.service;
+
+import org.amdatu.cassandra.listener.ColumnFamilyDefinition;
+import org.amdatu.cassandra.listener.ColumnFamilyProvider;
+import org.amdatu.cassandra.listener.ColumnFamilyDefinition.ColumnType;
+import org.amdatu.cassandra.listener.ColumnFamilyDefinition.CompareType;
+
+public class TenantMutationColumnFamilyProviderImpl implements 
ColumnFamilyProvider {
+    final static String KEYSPACE = "Default"; // Hardcoded
+    final static String CF = "TenantMutations"; // Hardcoded
+
+    final static String C_ID = "id";
+    final static String C_NAME = "name";
+    final static String C_HOST = "host";
+    final static String C_TYPE = "type";
+
+    static enum MutationType {
+        UPDATE("update"),
+            DELETE("delete");
+
+        private String m_value;
+
+        MutationType(final String mutationType) {
+            m_value = mutationType;
+        }
+
+        public String getValue() {
+            return m_value;
+        }
+    };
+
+    public ColumnFamilyDefinition[] getColumnFamilies() {
+        return new ColumnFamilyDefinition[] {
+            new ColumnFamilyDefinition(
+                CF,
+                new String[] { KEYSPACE },
+                ColumnType.STANDARD,
+                CompareType.BYTESTYPE,
+                null) };
+    }
+
+}

Added: 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantMutationDAO.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantMutationDAO.java
      Mon Nov  7 17:20:25 2011
@@ -0,0 +1,63 @@
+package org.amdatu.opensocial.tenant.gadget.service;
+
+import static 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.CF;
+import static 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.C_HOST;
+import static 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.C_ID;
+import static 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.C_NAME;
+import static 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.C_TYPE;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import 
org.amdatu.cassandra.persistencemanager.hector.HectorCassandraPersistenceManager;
+import 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.MutationType;
+
+public class TenantMutationDAO {
+    private volatile HectorCassandraPersistenceManager m_pm;
+    private static int m_index = 0;
+
+    public void addUpdateMutation(String id, String name, String hostname) {
+        String rowKey = generateRowKey();
+        m_pm.setValue(CF, rowKey, null, C_ID, id);
+        m_pm.setValue(CF, rowKey, null, C_NAME, name);
+        m_pm.setValue(CF, rowKey, null, C_HOST, hostname);
+        m_pm.setValue(CF, rowKey, null, C_TYPE, MutationType.UPDATE);
+    }
+
+    public void addDeleteMutation(String id) {
+        String rowKey = generateRowKey();
+        m_pm.setValue(CF, rowKey, null, C_ID, id);
+        m_pm.setValue(CF, rowKey, null, C_TYPE, MutationType.DELETE);
+    }
+
+    public List<Mutation> getMutations() {
+        List<String> rowKeys = m_pm.getRowKeys(CF);
+        if (rowKeys != null && rowKeys.size() > 0) {
+            for (String rowKey : rowKeys) {
+            List<Mutation> mutations = new ArrayList<Mutation>();
+            mutations.add(getMutation(rowKey));
+            }
+        }
+    }
+
+    public Mutation getMutation(String rowKey) {
+        Mutation mutation = new Mutation();
+        mutation.id = m_pm.getValue(CF, rowKey, null, C_ID, String.class);
+        mutation.name = m_pm.getValue(CF, rowKey, null, C_NAME, String.class);
+        mutation.hostname = m_pm.getValue(CF, rowKey, null, C_HOST, 
String.class);
+        mutation.type = MutationType.valueOf(m_pm.getValue(CF, rowKey, null, 
C_TYPE, String.class));
+        return mutation;
+    }
+
+    class Mutation {
+        String id;
+        String name;
+        String hostname;
+        MutationType type;
+    }
+
+    private synchronized String generateRowKey() {
+        m_index++;
+        return "row_" + m_index;
+    }
+}

Modified: 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantRESTServiceImpl.java
==============================================================================
--- 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantRESTServiceImpl.java
  (original)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/java/org/amdatu/opensocial/tenant/gadget/service/TenantRESTServiceImpl.java
  Mon Nov  7 17:20:25 2011
@@ -15,8 +15,12 @@
  */
 package org.amdatu.opensocial.tenant.gadget.service;
 
+import static 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.CF;
+import static 
org.amdatu.opensocial.tenant.gadget.service.TenantMutationColumnFamilyProviderImpl.*;
+
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -24,6 +28,7 @@
 import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -37,6 +42,7 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import 
org.amdatu.cassandra.persistencemanager.hector.HectorCassandraPersistenceManager;
 import org.amdatu.core.tenant.Tenant;
 import org.amdatu.core.tenant.TenantManagementService;
 import org.amdatu.libraries.utilities.rest.AtomSyndicationLink;
@@ -55,8 +61,11 @@
         NO_CACHE_CONTROL.setNoCache(true); // No cache
     }
 
-    private ConfigurationAdmin m_configAdmin;
-    private LogService m_logService;
+    private volatile LogService m_logService;
+    private volatile Tenant m_tenant;
+    private volatile TenantMutationDAO m_tenantDAO;
+    
+
 
     public void start() {
         m_logService.log(LogService.LOG_INFO, "Tenant management REST service 
started");
@@ -69,9 +78,11 @@
         try {
             for (TenantBean tenant : getTenants()) {
                 String href = request.getContextPath() + "/rest/tenants/" + 
tenant.getId();
-                tenant.setLink(new 
AtomSyndicationLink().setHref(href).setRel("Alternate")
-                    .setType("application/json"));
-
+                tenant.addLink(new 
AtomSyndicationLink().setHref(href).setRel("edit").setType("application/json"));
+                if (!tenant.getId().equals(m_tenant.getId())) {
+                    // Only provide delete link if the tenant is not the same 
as the current tenant
+                    tenant.addLink(new 
AtomSyndicationLink().setHref(href).setRel("delete").setType("application/json"));
+                }
                 tenantsBean.addTenant(tenant);
             }
         }
@@ -123,6 +134,33 @@
             properties.put(tenantKey + ".name", name);
             properties.put(tenantKey + ".properties.hostname", hostname);
             config.update(properties);
+            
+            m_tenantDAO.addUpdateMutation(id, name, hostname);
+        }
+        catch (Exception e) {
+            throw new WebApplicationException(e, 
Response.Status.INTERNAL_SERVER_ERROR);
+        }
+
+        return Response.ok(tenant, 
MediaType.APPLICATION_JSON_TYPE).cacheControl(NO_CACHE_CONTROL)
+                        .build();
+    }
+
+    @DELETE
+    @Path("/{id}")
+    public Response deleteTenant(@PathParam("id") final String id) {
+        TenantBean tenant = null;
+        try {
+            Configuration config = 
m_configAdmin.getConfiguration(TenantManagementService.PID);
+            Dictionary properties = config.getProperties();
+            String tenantKey = findTenantKey(id);
+            if (tenantKey != null) {
+                properties.remove(tenantKey + ".id");
+                properties.remove(tenantKey + ".name");
+                properties.remove(tenantKey + ".properties.hostname");
+                config.update(properties);
+            }
+            
+            m_tenantDAO.addDeleteMutation(id);
         }
         catch (Exception e) {
             throw new WebApplicationException(e, 
Response.Status.INTERNAL_SERVER_ERROR);
@@ -145,6 +183,8 @@
             key = "tenant" + keyId;
             exists = properties.get(key + ".id") != null;
         }
+        
+        Collections.sort(tenants);
         return tenants;
     }
 
@@ -160,35 +200,7 @@
         return new TenantBean(id, name, hostname);
     }
 
-    private String findTenantKey(String tenantId) throws IOException {
-        Configuration config = 
m_configAdmin.getConfiguration(TenantManagementService.PID);
-        Dictionary properties = config.getProperties();
-        Enumeration keys = properties.keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement().toString();
-            if (key.endsWith(".id")) {
-                if (tenantId.equals(properties.get(key))) { 
-                    return key.substring(0, key.indexOf(".id"));
-                }
-            }
-        }
-        return null;
-    }
+  
     
-    private int findLastTenantKey() throws IOException {
-        int maxid = 1;
-        Configuration config = 
m_configAdmin.getConfiguration(TenantManagementService.PID);
-        Dictionary properties = config.getProperties();
-        Enumeration keys = properties.keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement().toString();
-            if (key.endsWith(".id")) {
-                String id = key.substring("tenant".length(), key.indexOf("."));
-                if (Integer.parseInt(id) > maxid) {
-                    maxid = Integer.parseInt(id);
-                }
-            }
-        }
-        return maxid;
-    }
+
 }

Modified: 
sandbox/ivol/tenant-management-gadget/src/main/resources/jsp/TenantGadget.jsp
==============================================================================
--- 
sandbox/ivol/tenant-management-gadget/src/main/resources/jsp/TenantGadget.jsp   
    (original)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/resources/jsp/TenantGadget.jsp   
    Mon Nov  7 17:20:25 2011
@@ -46,24 +46,30 @@
     <script type="text/javascript" 
src="${gadgetBaseUrl}/static/js/tenant.js"></script>
     <script type="text/javascript" 
src="${gadgetBaseUrl}/static/js/util.js"></script>
 
-    <fieldset id="tenants">
-      <legend id="tenants_legend">__MSG_tenants__</legend>
-      <div id="tenants"></div>
+    <p>
+      <fieldset id="tenants">
+        <legend id="tenants_legend">__MSG_tenants__</legend>
+        <div id="tenants"></div>
+      </fieldset>
+    </p>
+
+    <p>
+      <input type="button" id="new_tenant_button" value="__MSG_new_tenant__" 
onclick="javascript:showAddTenant();"/>
+    </p>
+
+    <p>
+      <fieldset id="tenant_details" style="display:none;visibility:hidden">
+        <legend id="tenant_details_legend">__MSG_details__</legend>
+          <table width="95%">
+            <tr><td>__MSG_id__</td><td><input type="edit" id="tenant_id" 
disabled="disabled"/></td></tr>
+            <tr><td>__MSG_name__</td><td><input type="edit" id="tenant_name" 
value=""/></td></tr>
+            <tr><td>__MSG_hostname__</td><td><input type="edit" 
id="tenant_hostname" value=""/></td></tr>
+          </table>
+          <input type="submit" id="tenant_save" value="__MSG_save__" 
onclick="javascript:saveTenant();"/>
+          <input type="button" id="cancel" value="__MSG_cancel__" 
onclick="javascript:cancelEdit();"/>
+      </fieldset>
       <div id="infobox"></div>
-    </fieldset>
-
-    <input type="button" id="new_tenant_button" value="__MSG_new_tenant__" 
onclick="javascript:addTenant();"/>
-
-    <fieldset id="tenant_details" style="display:none;visibility:hidden">
-      <legend id="tenant_details_legend">__MSG_details__</legend>
-        <table width="95%">
-          <tr><td>__MSG_id__</td><td><input type="edit" id="tenant_id" 
disabled="disabled"/></td></tr>
-          <tr><td>__MSG_name__</td><td><input type="edit" id="tenant_name" 
value=""/></td></tr>
-          <tr><td>__MSG_hostname__</td><td><input type="edit" 
id="tenant_hostname" value=""/></td></tr>
-        </table>
-        <input type="submit" id="tenant_save" value="__MSG_save__" 
onclick="javascript:saveTenant();"/>
-        <input type="button" id="cancel" value="__MSG_cancel__" 
onclick="javascript:cancelEdit();"/>
-    </fieldset>
+    </p>
 
     <script type="text/javascript">
       var contextPath = "${contextPath}";

Modified: 
sandbox/ivol/tenant-management-gadget/src/main/resources/static/css/tenant.css
==============================================================================
--- 
sandbox/ivol/tenant-management-gadget/src/main/resources/static/css/tenant.css  
    (original)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/resources/static/css/tenant.css  
    Mon Nov  7 17:20:25 2011
@@ -20,7 +20,6 @@
 }
 
 table td {
-
    max-width: 280px;
    _width: 280px;               /* IE */
    white-space: pre;            /* CSS 2.0 */

Added: 
sandbox/ivol/tenant-management-gadget/src/main/resources/static/images/remove_disabled.gif
==============================================================================
Binary file. No diff available.

Modified: 
sandbox/ivol/tenant-management-gadget/src/main/resources/static/js/tenant.js
==============================================================================
--- 
sandbox/ivol/tenant-management-gadget/src/main/resources/static/js/tenant.js    
    (original)
+++ 
sandbox/ivol/tenant-management-gadget/src/main/resources/static/js/tenant.js    
    Mon Nov  7 17:20:25 2011
@@ -30,6 +30,14 @@
   gadgets.io.makeRequest(url, callback, params);
 }
 
+function doDeleteTenant(url, callback) {
+  var params = {};
+  params[gadgets.io.RequestParameters.CONTENT_TYPE] = 
gadgets.io.ContentType.JSON;
+  params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.DELETE;
+  url = getBaseUrl() + addNoCache(unescape(url));
+  gadgets.io.makeRequest(url, callback, params);
+}
+
 function onTenantsLoaded(response) {
   if (response.rc == 200) {
      var html = "<p><center><table class='stripeMe'>";
@@ -42,13 +50,21 @@
       var id = tenants[i]["id"];
       var name = tenants[i]["name"];
       var hostname = tenants[i]["hostname"];
-      var link = tenants[i]["link"].href;
-
-      var editTenant = " onclick=\"javascript:editTenant('" + escape(link) + 
"');\"";
-      var deleteTentant = " onclick=\"javascript:confirmDeleteTenant('" + 
escape(link) + "', '" + escape(name) + "');\"";
 
+      // Create the edit link
+      var editLink = getLink(ensureArray(tenants[i]["links"]), "edit");
+      var editTenant = " onclick=\"javascript:showEditTenant('" + 
escape(editLink) + "');\"";
       html += "<tr><td><a href='#'" + editTenant + ">" + name + " (" + 
hostname + ")</a></td>";
-      html += "<td align='center'><a href='#'><img src='" + contextPath + 
"/tenant/static/images/remove.gif'" + deleteTenant + "/></a></td></tr>";
+
+      // Create the delete link
+      var deleteLink = getLink(ensureArray(tenants[i]["links"]), "delete");
+      if (deleteLink) {
+        var deleteTenant = " onclick=\"javascript:showDeleteTenant('" + 
escape(deleteLink) + "', '" + escape(name) + "');\"";
+        html += "<td align='center'><a href='#'><img src='" + contextPath + 
"/tenant/static/images/remove.gif'" + deleteTenant + "/></a></td></tr>";
+      } else {
+        html += "<td align='center'><a class='tooltip' title='The current 
Tenant you are working on cannot be removed.'>";
+        html += "<img src='" + contextPath + 
"/tenant/static/images/remove_disabled.gif'/></a></td></tr>";
+      }
     }
     html += "</table></center></p>";
 
@@ -63,6 +79,14 @@
   gadgets.window.adjustHeight();
 }
 
+function getLink(tenants, linkType) {
+  for (j=0; j<tenants.length; j++) {
+    if(tenants[j].rel == linkType) {
+      return tenants[j].href;
+    }
+  }
+}
+
 function onTenantLoaded(response) {
   if (response.rc == 200) {
       var tenant = response.data["tenant"];
@@ -79,15 +103,16 @@
   }
 }
 
-function editTenant(link) {
-  loadTenant(escape(unescape(link)), onTenantLoaded);
-  hide('new_tenant_button');
-  document.getElementById('tenant_details_legend').innerHTML = 
updateTenantLabel;
-  show('tenant_details');
-}
 
-function deleteTenant() {
 
+function showDeleteTenant(link, name) {
+  if (confirm('Are you sure you want to delete the Tenant "' + name + '"?')) {
+    deleteTenant(link);
+  }
+}
+
+function deleteTenant(link) {
+  doDeleteTenant(escape(link), onTenantDeleted);
 }
 
 function saveTenant() {
@@ -96,23 +121,51 @@
 }
 
 function onTenantSaved() {
-  document.getElementById('infobox').innerHTML = "Tenant updated 
successfully.";
+  hide('tenant_details');
+  loadTenants();
+  showInfo("Tenant saved successfully.");
+}
+
+function onTenantDeleted() {
+  hide('tenant_details');
+  loadTenants();
+  showInfo("Tenant deleted successfully.");
+}
+
+function showInfo(message) {
+  document.getElementById('infobox').innerHTML = "<p><font color='#267F00'>" + 
message + "</p>";
+  show('infobox');
+  gadgets.window.adjustHeight();
 }
 
-function confirmDeleteTenant(tenant) {
-  alert('confirm');
+function showError(message) {
+  document.getElementById('infobox').innerHTML = "<p><font color='#FF0000'>" + 
message + "</p>";
+  show('infobox');
+  gadgets.window.adjustHeight();
+}
+
+function showEditTenant(link) {
+  loadTenant(escape(unescape(link)), onTenantLoaded);
+  hide('new_tenant_button');
+  hide('infobox');
+  document.getElementById('tenant_details_legend').innerHTML = 
updateTenantLabel;
+  show('tenant_details');
 }
 
 function cancelEdit() {
   hide('tenant_details');
   show('new_tenant_button');
+  hide('infobox');
   gadgets.window.adjustHeight();
 }
 
-function addTenant() {
+function showAddTenant() {
   hide('new_tenant_button');
   document.getElementById('tenant_details_legend').innerHTML = newTenantLabel;
   document.getElementById('tenant_id').disabled = "";
+  document.getElementById('tenant_id').value = "";
+  document.getElementById('tenant_name').value = "";
+  document.getElementById('tenant_hostname').value = "";
   show('tenant_details');
   gadgets.window.adjustHeight();
 }
\ No newline at end of file
_______________________________________________
Amdatu-commits mailing list
[email protected]
http://lists.amdatu.org/mailman/listinfo/amdatu-commits

Reply via email to