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