Author: [email protected]
Date: Mon Dec 12 16:22:51 2011
New Revision: 1832

Log:
AMDATU-468 Added initial adaptor code to tenant module

Added:
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/MultiTenantBundleActivator.java
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/MultiTenantBundleInputStream.java
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantConstants.java
   trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAdapter.java
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAwareBundle.java
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAwareBundleContext.java
   trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/factory/
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/factory/TenantImpl.java
      - copied, changed from r1831, 
/trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantImpl.java
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/factory/TenantServiceFactory.java
      - copied, changed from r1831, 
/trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantServiceFactory.java
Removed:
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantImpl.java
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantServiceFactory.java
Modified:
   
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/osgi/Activator.java
   
trunk/amdatu-core/tenant/src/test/java/org/amdatu/test/unit/TenantEntityTest.java

Added: 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/MultiTenantBundleActivator.java
==============================================================================
--- (empty file)
+++ 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/MultiTenantBundleActivator.java
       Mon Dec 12 16:22:51 2011
@@ -0,0 +1,104 @@
+/*
+ * 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.core.tenant;
+
+import org.amdatu.core.tenant.adaptor.TenantAdapter;
+import org.amdatu.core.tenant.adaptor.TenantAwareBundleContext;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+/**
+ * Generic bundle activator that can be used to convert a normal bundle into a 
multi tenant one.
+ * The process of converting a normal bundle starts with replacing the 
existing bundle activator
+ * with this one. Via a set of extra manifest entries the normal bundle 
activator can be specified.
+ * 
+ * @author <a href="mailto:[email protected]";>Amdatu Project 
Team</a>
+ * @see TenantConstants
+ */
+public class MultiTenantBundleActivator extends DependencyActivatorBase {
+
+    private BundleContext m_context;
+    private String m_bundleActivatorClass;
+    private BundleActivator m_tenantBundleActivator;
+    private TenantAwareBundleContext m_tenantAwareBundleContext;
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws 
Exception {
+        m_context = context;
+
+        // determine scope
+        String scope = (String) 
context.getBundle().getHeaders().get(TenantConstants.MULTITENANT_SCOPE_KEY);
+        if (scope == null || 
(!scope.equals(TenantConstants.MULTITENANT_SCOPE_VALUE_PLATFORM)
+            && !scope.equals(TenantConstants.MULTITENANT_SCOPE_VALUE_BOTH))) {
+            // default to tenants
+            scope = TenantConstants.MULTITENANT_SCOPE_VALUE_TENANTS;
+        }
+
+        // create platform instance
+        if (!scope.equals(TenantConstants.MULTITENANT_SCOPE_VALUE_TENANTS)) {
+            log(LogService.LOG_DEBUG, "[" + 
TenantConstants.MULTITENANT_SCOPE_PLATFORM_TENANTID + "] Starting "
+                + (String) 
m_context.getBundle().getHeaders().get(Constants.BUNDLE_NAME), null);
+            try {
+                m_bundleActivatorClass =
+                    (String) 
context.getBundle().getHeaders().get(TenantConstants.MULTITENANT_BUNDLE_ACTIVATOR_KEY);
+                if (m_bundleActivatorClass == null) {
+                    log(LogService.LOG_ERROR, "Missing manifest header "
+                        + TenantConstants.MULTITENANT_BUNDLE_ACTIVATOR_KEY, 
null);
+                    return;
+                }
+                m_tenantBundleActivator =
+                    (BundleActivator) 
context.getBundle().loadClass(m_bundleActivatorClass).newInstance();
+                m_tenantAwareBundleContext =
+                    new TenantAwareBundleContext(context, 
TenantConstants.MULTITENANT_SCOPE_PLATFORM_TENANTID);
+                m_tenantBundleActivator.start(m_tenantAwareBundleContext);
+            }
+            catch (Exception e) {
+                log(LogService.LOG_ERROR, "Could not start activator for 
platform scope", e);
+            }
+        }
+
+        // create tenant adaptor
+        if (!scope.equals(TenantConstants.MULTITENANT_SCOPE_VALUE_PLATFORM)) {
+            manager.add(createAdapterService(Tenant.class, null)
+                .setImplementation(TenantAdapter.class)
+                .add(createServiceDependency()
+                    .setService(LogService.class)
+                    .setRequired(false)
+                )
+                );
+        }
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) 
throws Exception {
+    }
+
+    private void log(int level, String message, Throwable exception) {
+        final ServiceReference ref = 
m_context.getServiceReference(LogService.class.getName());
+        if (ref != null) {
+            final LogService svc = (LogService) m_context.getService(ref);
+            if (svc != null) {
+                svc.log(level, message, exception);
+                m_context.ungetService(ref);
+            }
+        }
+    }
+}

Added: 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/MultiTenantBundleInputStream.java
==============================================================================
--- (empty file)
+++ 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/MultiTenantBundleInputStream.java
     Mon Dec 12 16:22:51 2011
@@ -0,0 +1,163 @@
+/*
+ * 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.core.tenant;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Attributes;
+import java.util.jar.Attributes.Name;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.osgi.framework.Constants;
+
+/**
+ * Wrapper that modifies an input stream that points to a bundle. The 
resulting input stream represents that
+ * same bundle, but makes it multi tenant aware. It does this by replacing the 
original bundle activator with
+ * one that will create an instance of the original bundle activator for each 
tenant in the system. This
+ * tenant specific instance will receive an adapter to the real bundle context 
when its start() and stop()
+ * life cycle methods are invoked. The adapter in turn does some magic to make 
the bundle work in a
+ * multi tenant environment by:
+ * <ul>
+ * <li>Adding a tenant ID to every service that is registered, to make it 
tenant specific.</li>
+ * <li>Filtering out any service that has a tenant ID property that is 
different from the current
+ * tenant when the bundle queries for services or registers as a listener.</li>
+ * <li>Providing each tenant with a data area that can be exclusively used by 
that tenant.</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:[email protected]";>Amdatu Project 
Team</a>
+ */
+public class MultiTenantBundleInputStream extends InputStream {
+
+    private static final Name MULTITENANT_VERSION_NAME = new 
Attributes.Name(TenantConstants.MULTITENANT_VERSION_KEY);
+    private static final Name BUNDLE_ACTIVATOR_NAME = new 
Attributes.Name(Constants.BUNDLE_ACTIVATOR);
+    private static final String TENANT_IMPORT_PACKAGE = 
MultiTenantBundleActivator.class.getPackage().getName()
+        + ";version=\"[1.0,2)\"";
+
+    private static final int MAX_MANIFEST_SIZE = 65536;
+    private final InputStream m_inputStream;
+
+    public MultiTenantBundleInputStream(InputStream original) {
+        try {
+            original = new BufferedInputStream(original);
+            original.mark(MAX_MANIFEST_SIZE);
+            JarInputStream jis = new JarInputStream(original);
+            Manifest manifest = jis.getManifest();
+            Attributes attributes = manifest.getMainAttributes();
+            // do not process the bundle if it already has a tenant bundle 
activator (somebody already preprocessed it)
+            // or it has no bundle activator at all (there's nothing to make 
tenant aware)
+            if ((attributes.containsKey(MULTITENANT_VERSION_NAME) && 
(attributes.getValue(MULTITENANT_VERSION_NAME)
+                .equals(TenantConstants.MULTITENANT_VERSION_VALUE))) || 
!attributes.containsKey(BUNDLE_ACTIVATOR_NAME)) {
+                original.reset();
+                m_inputStream = original;
+            }
+            else {
+                String originalBundleActivator = 
attributes.getValue(Constants.BUNDLE_ACTIVATOR);
+                attributes.putValue(Constants.BUNDLE_ACTIVATOR, 
MultiTenantBundleActivator.class.getName());
+                
attributes.putValue(TenantConstants.MULTITENANT_BUNDLE_ACTIVATOR_KEY, 
originalBundleActivator);
+                attributes.putValue(TenantConstants.MULTITENANT_VERSION_KEY, 
TenantConstants.MULTITENANT_VERSION_VALUE);
+
+                String originalImportPackage = 
attributes.getValue(Constants.IMPORT_PACKAGE);
+                if (originalImportPackage == null) {
+                    attributes.putValue(Constants.IMPORT_PACKAGE, 
TENANT_IMPORT_PACKAGE);
+                }
+                else {
+                    attributes.putValue(Constants.IMPORT_PACKAGE, 
TENANT_IMPORT_PACKAGE + "," + originalImportPackage);
+                }
+
+                String originalBundleName = 
attributes.getValue(Constants.BUNDLE_NAME);
+                attributes.putValue(Constants.BUNDLE_NAME, originalBundleName 
+ " (MT)");
+
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                JarOutputStream jos = new JarOutputStream(baos, manifest);
+                JarEntry entry = jis.getNextJarEntry();
+                byte[] buffer = new byte[4096];
+                while (entry != null) {
+                    jos.putNextEntry(new JarEntry(entry.getName()));
+                    int bytes = jis.read(buffer);
+                    while (bytes != -1) {
+                        jos.write(buffer, 0, bytes);
+                        bytes = jis.read(buffer);
+                    }
+                    jos.closeEntry();
+                    jis.closeEntry();
+                    entry = jis.getNextJarEntry();
+                }
+                jos.flush();
+                jos.close();
+                baos.close();
+                jis.close();
+                m_inputStream = new ByteArrayInputStream(baos.toByteArray());
+            }
+        }
+        catch (Exception e) {
+            throw new RuntimeException("Could not wrap bundle to preprocess 
it.", e);
+        }
+    }
+
+    public int available() throws IOException {
+        return m_inputStream.available();
+    }
+
+    public void close() throws IOException {
+        m_inputStream.close();
+    }
+
+    public boolean equals(Object other) {
+        return m_inputStream.equals(other);
+    }
+
+    public int hashCode() {
+        return m_inputStream.hashCode();
+    }
+
+    public void mark(int readlimit) {
+        m_inputStream.mark(readlimit);
+    }
+
+    public boolean markSupported() {
+        return m_inputStream.markSupported();
+    }
+
+    public int read() throws IOException {
+        return m_inputStream.read();
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException {
+        return m_inputStream.read(b, off, len);
+    }
+
+    public int read(byte[] b) throws IOException {
+        return m_inputStream.read(b);
+    }
+
+    public void reset() throws IOException {
+        m_inputStream.reset();
+    }
+
+    public long skip(long n) throws IOException {
+        return m_inputStream.skip(n);
+    }
+
+    public String toString() {
+        return m_inputStream.toString();
+    }
+}

Added: 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantConstants.java
==============================================================================
--- (empty file)
+++ 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantConstants.java
  Mon Dec 12 16:22:51 2011
@@ -0,0 +1,34 @@
+/*
+ * 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.core.tenant;
+
+/**
+ * Compile time constants for multi tenancy.
+ * 
+ * @author <a href="mailto:[email protected]";>Amdatu Project 
Team</a>
+ */
+public interface TenantConstants {
+    public static final String MULTITENANT_BUNDLE_ACTIVATOR_KEY = 
"MultiTenant-Bundle-Activator";
+    
+    public static final String MULTITENANT_SCOPE_KEY = "MultiTenant-Scope";
+    public static final String MULTITENANT_SCOPE_VALUE_PLATFORM = "PLATFORM";
+    public static final String MULTITENANT_SCOPE_VALUE_TENANTS = "TENANTS";
+    public static final String MULTITENANT_SCOPE_VALUE_BOTH = "BOTH";
+    public static final String MULTITENANT_SCOPE_PLATFORM_TENANTID = 
"_PLATFORM";
+    
+    public static final String MULTITENANT_VERSION_KEY = "MultiTenant-Version";
+    public static final String MULTITENANT_VERSION_VALUE = "1";
+}

Added: 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAdapter.java
==============================================================================
--- (empty file)
+++ 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAdapter.java
    Mon Dec 12 16:22:51 2011
@@ -0,0 +1,74 @@
+/*
+ * 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.core.tenant.adaptor;
+
+import org.amdatu.core.tenant.Tenant;
+import org.amdatu.core.tenant.TenantConstants;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.log.LogService;
+
+/**
+ * Adapter that instantiates a bundle activator and makes that instance tenant 
specific
+ * by intercepting the bundle context.
+ * 
+ * @author <a href="mailto:[email protected]";>Amdatu Project 
Team</a>
+ */
+public class TenantAdapter {
+    
+    private volatile BundleContext m_context;
+    private volatile Tenant m_tenant;
+    private volatile LogService m_log;
+    private String m_bundleActivatorClass;
+    private BundleActivator m_tenantBundleActivator;
+    private TenantAwareBundleContext m_tenantAwareBundleContext;
+
+    public void start() {
+        m_log.log(LogService.LOG_DEBUG, "[" + m_tenant.getId() + "] Starting "
+            + (String) 
m_context.getBundle().getHeaders().get(Constants.BUNDLE_NAME));
+        try {
+            m_bundleActivatorClass =
+                (String) 
m_context.getBundle().getHeaders().get(TenantConstants.MULTITENANT_BUNDLE_ACTIVATOR_KEY);
+            if (m_bundleActivatorClass == null) {
+                m_log.log(LogService.LOG_ERROR, "Missing manifest header "
+                    + TenantConstants.MULTITENANT_BUNDLE_ACTIVATOR_KEY);
+                return;
+            }
+            m_tenantBundleActivator =
+                (BundleActivator) 
m_context.getBundle().loadClass(m_bundleActivatorClass).newInstance();
+            m_tenantAwareBundleContext = new 
TenantAwareBundleContext(m_context, m_tenant.getId());
+            m_tenantBundleActivator.start(m_tenantAwareBundleContext);
+        }
+        catch (Exception e) {
+            m_log.log(LogService.LOG_ERROR, "Could not start activator for 
tenant " + m_tenant.getId(), e);
+        }
+    }
+
+    public void stop() {
+        m_log.log(LogService.LOG_DEBUG, "[" + m_tenant.getId() + "] Stopping "
+            + (String) 
m_context.getBundle().getHeaders().get(Constants.BUNDLE_NAME));
+        try {
+            if (m_tenantBundleActivator != null) {
+                m_tenantBundleActivator.stop(m_tenantAwareBundleContext);
+                m_tenantAwareBundleContext.unregisterServices();
+            }
+        }
+        catch (Exception e) {
+            m_log.log(LogService.LOG_ERROR, "Could not stop activator for 
tenant " + m_tenant.getId(), e);
+        }
+    }
+}

Added: 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAwareBundle.java
==============================================================================
--- (empty file)
+++ 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAwareBundle.java
        Mon Dec 12 16:22:51 2011
@@ -0,0 +1,152 @@
+/*
+ * 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.core.tenant.adaptor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+
+/**
+ * Wrapper class for the bundle interface to make it tenant aware.
+ * 
+ * @author <a href="mailto:[email protected]";>Amdatu Project 
Team</a>
+ */
+public class TenantAwareBundle implements Bundle {
+       private final Bundle m_bundle;
+       private final String m_tenantId;
+       
+       public TenantAwareBundle(Bundle bundle, String tenantId) {
+               m_bundle = bundle;
+               m_tenantId = tenantId;
+       }
+
+       public int getState() {
+               return m_bundle.getState();
+       }
+
+       public void start(int options) throws BundleException {
+               m_bundle.start(options);
+       }
+
+       public void start() throws BundleException {
+               m_bundle.start();
+       }
+
+       public void stop(int options) throws BundleException {
+               m_bundle.stop(options);
+       }
+
+       public void stop() throws BundleException {
+               m_bundle.stop();
+       }
+
+       public void update(InputStream input) throws BundleException {
+               m_bundle.update(input);
+       }
+
+       public void update() throws BundleException {
+               m_bundle.update();
+       }
+
+       public void uninstall() throws BundleException {
+               m_bundle.uninstall();
+       }
+
+       public Dictionary getHeaders() {
+               return m_bundle.getHeaders();
+       }
+
+       public long getBundleId() {
+               return m_bundle.getBundleId();
+       }
+
+       public String getLocation() {
+               return m_bundle.getLocation();
+       }
+
+       public ServiceReference[] getRegisteredServices() {
+               return m_bundle.getRegisteredServices();
+       }
+
+       public ServiceReference[] getServicesInUse() {
+               return m_bundle.getServicesInUse();
+       }
+
+       public boolean hasPermission(Object permission) {
+               return m_bundle.hasPermission(permission);
+       }
+
+       public URL getResource(String name) {
+               return m_bundle.getResource(name);
+       }
+
+       public Dictionary getHeaders(String locale) {
+               return m_bundle.getHeaders(locale);
+       }
+
+       public String getSymbolicName() {
+               return m_bundle.getSymbolicName();
+       }
+
+       public Class loadClass(String name) throws ClassNotFoundException {
+               return m_bundle.loadClass(name);
+       }
+
+       public Enumeration getResources(String name) throws IOException {
+               return m_bundle.getResources(name);
+       }
+
+       public Enumeration getEntryPaths(String path) {
+               return m_bundle.getEntryPaths(path);
+       }
+
+       public URL getEntry(String path) {
+               return m_bundle.getEntry(path);
+       }
+
+       public long getLastModified() {
+               return m_bundle.getLastModified();
+       }
+
+       public Enumeration findEntries(String path, String filePattern, boolean 
recurse) {
+               return m_bundle.findEntries(path, filePattern, recurse);
+       }
+
+       public BundleContext getBundleContext() {
+               BundleContext bundleContext = m_bundle.getBundleContext();
+               if (bundleContext != null) {
+                       return new TenantAwareBundleContext(bundleContext, 
m_tenantId);
+               }
+               return null;
+       }
+
+       public Map getSignerCertificates(int signersType) {
+               return m_bundle.getSignerCertificates(signersType);
+       }
+
+       public Version getVersion() {
+               return m_bundle.getVersion();
+       }
+}

Added: 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAwareBundleContext.java
==============================================================================
--- (empty file)
+++ 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/adaptor/TenantAwareBundleContext.java
 Mon Dec 12 16:22:51 2011
@@ -0,0 +1,355 @@
+/*
+ * 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.core.tenant.adaptor;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.amdatu.core.tenant.MultiTenantBundleInputStream;
+import org.amdatu.core.tenant.Tenant;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * Wrapper class for the bundle context interface to make it tenant aware.
+ * 
+ * @author <a href="mailto:[email protected]";>Amdatu Project 
Team</a>
+ */
+public class TenantAwareBundleContext implements BundleContext {
+       private static final String TENANT_DATAFILE_PREFIX = "tenant-";
+       private final BundleContext m_bundleContext;
+       private final Bundle m_bundle;
+       private final String m_tenantId;
+       private File m_dataFile;
+       private final ConcurrentHashMap<BundleListener, 
TenantAwareBundleListener> m_bundleListeners = new 
ConcurrentHashMap<BundleListener, TenantAwareBundleListener>();
+       private final ConcurrentHashMap<FrameworkListener, 
TenantAwareFrameworkListener> m_frameworkListeners = new 
ConcurrentHashMap<FrameworkListener, TenantAwareFrameworkListener>();
+       private final ConcurrentHashMap<ServiceRegistrationAdapter, 
ServiceRegistration> m_serviceRegistrations = new 
ConcurrentHashMap<ServiceRegistrationAdapter, ServiceRegistration>();
+
+       public TenantAwareBundleContext(BundleContext bc, String tenantId) {
+               m_bundleContext = bc;
+               m_tenantId = tenantId;
+               m_bundle = new TenantAwareBundle(bc.getBundle(), m_tenantId);
+       }
+
+       public void unregisterServices() {
+               for (ServiceRegistration registration : 
m_serviceRegistrations.values()) {
+                       registration.unregister();
+               }
+               m_serviceRegistrations.clear();
+       }
+
+       public String getProperty(String key) {
+               return m_bundleContext.getProperty(key);
+       }
+
+       public Bundle getBundle() {
+               return m_bundle;
+       }
+
+       public Bundle installBundle(String location, InputStream input)
+                       throws BundleException {
+               return m_bundleContext.installBundle(location,
+                               new MultiTenantBundleInputStream(input));
+       }
+
+       public Bundle installBundle(String location) throws BundleException {
+               try {
+                       return m_bundleContext.installBundle(location,
+                                       new MultiTenantBundleInputStream(
+                                                       
bundleLocationToInputStream(location)));
+               } catch (IOException e) {
+                       throw new BundleException(
+                                       "Could not convert bundle location to 
an input stream, wrapping it failed.",
+                                       e);
+               }
+       }
+
+       private InputStream bundleLocationToInputStream(String location)
+                       throws IOException {
+               return (new URL(location)).openStream();
+       }
+
+       public Bundle getBundle(long id) {
+               Bundle bundle = m_bundleContext.getBundle(id);
+               return new TenantAwareBundle(bundle, m_tenantId);
+       }
+
+       public Bundle[] getBundles() {
+               Bundle[] bundles = m_bundleContext.getBundles();
+               for (int i = 0; i < bundles.length; i++) {
+                       Bundle bundle = bundles[i];
+                       bundles[i] = new TenantAwareBundle(bundle, m_tenantId);
+               }
+               return bundles;
+       }
+
+       public void addServiceListener(ServiceListener listener, String filter)
+                       throws InvalidSyntaxException {
+               m_bundleContext.addServiceListener(listener, 
getCompleteFilter(filter));
+       }
+
+       public void addServiceListener(ServiceListener listener) {
+               try {
+                       m_bundleContext.addServiceListener(listener,
+                                       getCompleteFilter(null));
+               } catch (InvalidSyntaxException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public void removeServiceListener(ServiceListener listener) {
+               m_bundleContext.removeServiceListener(listener);
+       }
+
+       public void addBundleListener(BundleListener listener) {
+               TenantAwareBundleListener tenantAwareBundleListener = new 
TenantAwareBundleListener(
+                               listener);
+               if (m_bundleListeners.putIfAbsent(listener, 
tenantAwareBundleListener) == null) {
+                       
m_bundleContext.addBundleListener(tenantAwareBundleListener);
+               }
+       }
+
+       public void removeBundleListener(BundleListener listener) {
+               TenantAwareBundleListener tenantAwareBundleListener = 
m_bundleListeners
+                               .remove(listener);
+               if (tenantAwareBundleListener != null) {
+                       
m_bundleContext.removeBundleListener(tenantAwareBundleListener);
+               }
+       }
+
+       public void addFrameworkListener(FrameworkListener listener) {
+               TenantAwareFrameworkListener tenantAwareFrameworkListener = new 
TenantAwareFrameworkListener(
+                               listener);
+               if (m_frameworkListeners.putIfAbsent(listener,
+                               tenantAwareFrameworkListener) == null) {
+                       
m_bundleContext.addFrameworkListener(tenantAwareFrameworkListener);
+               }
+       }
+
+       public void removeFrameworkListener(FrameworkListener listener) {
+               TenantAwareFrameworkListener tenantAwareFrameworkListener = 
m_frameworkListeners
+                               .remove(listener);
+               if (tenantAwareFrameworkListener != null) {
+                       m_bundleContext
+                                       
.removeFrameworkListener(tenantAwareFrameworkListener);
+               }
+       }
+
+       public ServiceRegistration registerService(String[] clazzes,
+                       Object service, Dictionary properties) {
+               if (properties == null) {
+                       properties = new Properties();
+               }
+               properties.put(Tenant.TENANT_ID_SERVICEPROPERTY, m_tenantId);
+               ServiceRegistration registration = 
m_bundleContext.registerService(
+                               clazzes, service, properties);
+               ServiceRegistrationAdapter adapter = new 
ServiceRegistrationAdapter(
+                               registration);
+               m_serviceRegistrations.put(adapter, registration);
+               return adapter;
+       }
+
+       public ServiceRegistration registerService(String clazz, Object service,
+                       Dictionary properties) {
+               if (properties == null) {
+                       properties = new Properties();
+               }
+               properties.put(Tenant.TENANT_ID_SERVICEPROPERTY, m_tenantId);
+               ServiceRegistration registration = 
m_bundleContext.registerService(
+                               clazz, service, properties);
+               ServiceRegistrationAdapter adapter = new 
ServiceRegistrationAdapter(
+                               registration);
+               m_serviceRegistrations.put(adapter, registration);
+               return adapter;
+       }
+
+       public ServiceReference[] getServiceReferences(String clazz, String 
filter)
+                       throws InvalidSyntaxException {
+               try {
+                       return m_bundleContext.getServiceReferences(clazz,
+                                       getCompleteFilter(filter));
+               } catch (InvalidSyntaxException e) {
+                       e.printStackTrace();
+               }
+               return null;
+       }
+
+       public String getCompleteFilter(String filter) {
+               String result = (filter == null) ? "(|(" + 
Tenant.TENANT_ID_SERVICEPROPERTY + "="
+                               + m_tenantId + ")(!(" + 
Tenant.TENANT_ID_SERVICEPROPERTY + "=*)))" : "(&(|("
+                               + Tenant.TENANT_ID_SERVICEPROPERTY + "=" + 
m_tenantId + ")(!(" + Tenant.TENANT_ID_SERVICEPROPERTY
+                               + "=*)))" + filter + ")";
+               return result;
+       }
+
+       public ServiceReference[] getAllServiceReferences(String clazz,
+                       String filter) throws InvalidSyntaxException {
+               try {
+                       return m_bundleContext.getAllServiceReferences(clazz,
+                                       getCompleteFilter(filter));
+               } catch (InvalidSyntaxException e) {
+                       e.printStackTrace();
+               }
+               return null;
+       }
+
+       public ServiceReference getServiceReference(String clazz) {
+               try {
+                       ServiceReference[] references = m_bundleContext
+                                       .getServiceReferences(clazz, "(|(" + 
Tenant.TENANT_ID_SERVICEPROPERTY + "="
+                                                       + m_tenantId + ")(!(" + 
Tenant.TENANT_ID_SERVICEPROPERTY + "=*)))");
+                       if (references != null && references.length > 0) {
+                               if (references.length > 1) {
+                                       Arrays.sort(references);
+                               }
+                               return references[0];
+                       }
+               } catch (InvalidSyntaxException e) {
+                       e.printStackTrace();
+               }
+               return null;
+       }
+
+       public Object getService(ServiceReference reference) {
+               return m_bundleContext.getService(reference);
+       }
+
+       public boolean ungetService(ServiceReference reference) {
+               return m_bundleContext.ungetService(reference);
+       }
+
+       public File getDataFile(String filename) {
+               if (m_dataFile == null) {
+                       m_dataFile = 
m_bundleContext.getDataFile(createTenantDataFile());
+                       if (m_dataFile == null) {
+                               return null;
+                       }
+                       m_dataFile.mkdir();
+               }
+               if (filename == null) {
+                       return m_dataFile;
+               } else {
+                       return new File(m_dataFile, filename);
+               }
+       }
+
+       private String createTenantDataFile() {
+               return TENANT_DATAFILE_PREFIX + m_tenantId;
+       }
+
+       public Filter createFilter(String filter) throws InvalidSyntaxException 
{
+               return m_bundleContext.createFilter(filter);
+       }
+
+       private class TenantAwareBundleListener implements BundleListener {
+               private final BundleListener m_listener;
+
+               public TenantAwareBundleListener(BundleListener listener) {
+                       m_listener = listener;
+               }
+
+               public void bundleChanged(BundleEvent event) {
+                       m_listener.bundleChanged(new 
TenantAwareBundleEvent(event));
+               }
+       }
+
+       private class TenantAwareFrameworkListener implements FrameworkListener 
{
+               private final FrameworkListener m_listener;
+
+               public TenantAwareFrameworkListener(FrameworkListener listener) 
{
+                       m_listener = listener;
+
+               }
+
+               public void frameworkEvent(FrameworkEvent event) {
+                       m_listener.frameworkEvent(new 
TenantAwareFrameworkEvent(event));
+               }
+
+       }
+
+       private class TenantAwareBundleEvent extends BundleEvent {
+               private final BundleEvent m_event;
+               private final Bundle m_bundle;
+
+               public TenantAwareBundleEvent(BundleEvent event) {
+                       super(event.getType(), event.getBundle());
+                       m_event = event;
+                       Bundle eventBundle = m_event.getBundle();
+                       BundleContext eventBundleContext = 
eventBundle.getBundleContext();
+                       m_bundle = new TenantAwareBundle(eventBundle, 
m_tenantId);
+               }
+
+               public Bundle getBundle() {
+                       return m_bundle;
+               }
+       }
+
+       private class TenantAwareFrameworkEvent extends FrameworkEvent {
+               private final FrameworkEvent m_event;
+               private final Bundle m_bundle;
+
+               public TenantAwareFrameworkEvent(FrameworkEvent event) {
+                       super(event.getType(), event.getBundle(), 
event.getThrowable());
+                       m_event = event;
+                       Bundle eventBundle = m_event.getBundle();
+                       BundleContext eventBundleContext = 
eventBundle.getBundleContext();
+                       m_bundle = new TenantAwareBundle(eventBundle, 
m_tenantId);
+               }
+
+               public Bundle getBundle() {
+                       return m_bundle;
+               }
+       }
+
+       private class ServiceRegistrationAdapter implements ServiceRegistration 
{
+               private final ServiceRegistration m_registration;
+
+               public ServiceRegistrationAdapter(ServiceRegistration 
registration) {
+                       m_registration = registration;
+
+               }
+
+               public ServiceReference getReference() {
+                       return m_registration.getReference();
+               }
+
+               public void setProperties(Dictionary properties) {
+                       m_registration.setProperties(properties);
+               }
+
+               public void unregister() {
+                       m_serviceRegistrations.remove(this);
+                       m_registration.unregister();
+               }
+       }
+}

Copied: 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/factory/TenantImpl.java
 (from r1831, 
/trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantImpl.java)
==============================================================================
--- 
/trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantImpl.java
      (original)
+++ 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/factory/TenantImpl.java
       Mon Dec 12 16:22:51 2011
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.amdatu.core.tenant.service;
+package org.amdatu.core.tenant.factory;
 
 import java.util.HashMap;
 import java.util.Map;

Copied: 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/factory/TenantServiceFactory.java
 (from r1831, 
/trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantServiceFactory.java)
==============================================================================
--- 
/trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantServiceFactory.java
    (original)
+++ 
trunk/amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/factory/TenantServiceFactory.java
     Mon Dec 12 16:22:51 2011
@@ -1,4 +1,4 @@
-package org.amdatu.core.tenant.service;
+package org.amdatu.core.tenant.factory;
 
 import java.util.Dictionary;
 import java.util.HashMap;

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 Dec 12 16:22:51 2011
@@ -18,7 +18,7 @@
 import java.util.Dictionary;
 import java.util.Hashtable;
 
-import org.amdatu.core.tenant.service.TenantServiceFactory;
+import org.amdatu.core.tenant.factory.TenantServiceFactory;
 import org.apache.felix.dm.DependencyActivatorBase;
 import org.apache.felix.dm.DependencyManager;
 import org.osgi.framework.BundleContext;

Modified: 
trunk/amdatu-core/tenant/src/test/java/org/amdatu/test/unit/TenantEntityTest.java
==============================================================================
--- 
trunk/amdatu-core/tenant/src/test/java/org/amdatu/test/unit/TenantEntityTest.java
   (original)
+++ 
trunk/amdatu-core/tenant/src/test/java/org/amdatu/test/unit/TenantEntityTest.java
   Mon Dec 12 16:22:51 2011
@@ -15,7 +15,7 @@
  */
 package org.amdatu.test.unit;
 
-import org.amdatu.core.tenant.service.TenantImpl;
+import org.amdatu.core.tenant.factory.TenantImpl;
 import org.junit.Assert;
 import org.junit.Test;
 
_______________________________________________
Amdatu-commits mailing list
[email protected]
http://lists.amdatu.org/mailman/listinfo/amdatu-commits

Reply via email to