You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metamodel.apache.org by ka...@apache.org on 2017/10/04 16:32:08 UTC
metamodel-membrane git commit: METAMODEL-1166: Fixed caching of
tenant and data source context
Repository: metamodel-membrane
Updated Branches:
refs/heads/master 6f929c29c -> 013c8dcbe
METAMODEL-1166: Fixed caching of tenant and data source context
Closes #12
Project: http://git-wip-us.apache.org/repos/asf/metamodel-membrane/repo
Commit: http://git-wip-us.apache.org/repos/asf/metamodel-membrane/commit/013c8dcb
Tree: http://git-wip-us.apache.org/repos/asf/metamodel-membrane/tree/013c8dcb
Diff: http://git-wip-us.apache.org/repos/asf/metamodel-membrane/diff/013c8dcb
Branch: refs/heads/master
Commit: 013c8dcbedd18745c200549271f6d69e096414a9
Parents: 6f929c2
Author: Kasper Sørensen <i....@gmail.com>
Authored: Wed Oct 4 09:31:26 2017 -0700
Committer: Kasper Sørensen <i....@gmail.com>
Committed: Wed Oct 4 09:31:38 2017 -0700
----------------------------------------------------------------------
CHANGES.md | 1 +
.../app/CachedDataSourceRegistryWrapper.java | 119 ------------------
.../membrane/app/DataSourceRegistry.java | 82 -------------
.../app/InMemoryDataSourceRegistry.java | 77 ------------
.../membrane/app/InMemoryTenantContext.java | 45 -------
.../membrane/app/InMemoryTenantRegistry.java | 79 ------------
.../metamodel/membrane/app/TenantContext.java | 31 -----
.../metamodel/membrane/app/TenantRegistry.java | 39 ------
.../app/registry/DataSourceRegistry.java | 82 +++++++++++++
.../membrane/app/registry/TenantContext.java | 31 +++++
.../membrane/app/registry/TenantRegistry.java | 39 ++++++
.../cache/CachedDataSourceRegistryWrapper.java | 120 +++++++++++++++++++
.../cache/CachedTenantRegistryWrapper.java | 113 +++++++++++++++++
.../file/FileBasedDataSourceRegistry.java | 2 +-
.../registry/file/FileBasedTenantContext.java | 6 +-
.../registry/file/FileBasedTenantRegistry.java | 4 +-
.../memory/InMemoryDataSourceRegistry.java | 79 ++++++++++++
.../registry/memory/InMemoryTenantContext.java | 49 ++++++++
.../registry/memory/InMemoryTenantRegistry.java | 81 +++++++++++++
.../membrane/controllers/ColumnController.java | 4 +-
.../controllers/DataSourceController.java | 6 +-
.../membrane/controllers/QueryController.java | 4 +-
.../membrane/controllers/SchemaController.java | 4 +-
.../membrane/controllers/TableController.java | 4 +-
.../controllers/TableDataController.java | 4 +-
.../membrane/controllers/TenantController.java | 4 +-
.../resources/context/application-context.xml | 10 +-
.../controllers/DataSourceControllerTest.java | 4 +-
.../TenantInteractionScenarioTest.java | 4 +-
postman-tests/Membrane.postman_collection.json | 24 +++-
30 files changed, 646 insertions(+), 505 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/CHANGES.md
----------------------------------------------------------------------
diff --git a/CHANGES.md b/CHANGES.md
index 78c1e34..0d5c6c6 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -3,5 +3,6 @@
* [METAMODEL-1153] - Added endpoints for deleting data sources.
* [METAMODEL-1147] - Implemented Swagger codegen to build model classes from swagger file.
* [METAMODEL-1149] - File based registry for tenant and data source information.
+* [METAMODEL-1166] - Caching of tenant and data source context information
* [METAMODEL-1154] - Added update and delete capabilities in POST call to table data endpoint.
* Established project source control, structure and build.
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/CachedDataSourceRegistryWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/CachedDataSourceRegistryWrapper.java b/core/src/main/java/org/apache/metamodel/membrane/app/CachedDataSourceRegistryWrapper.java
deleted file mode 100644
index b7b5b1e..0000000
--- a/core/src/main/java/org/apache/metamodel/membrane/app/CachedDataSourceRegistryWrapper.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.metamodel.membrane.app;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.metamodel.DataContext;
-import org.apache.metamodel.MetaModelException;
-import org.apache.metamodel.factory.DataContextProperties;
-import org.apache.metamodel.membrane.app.exceptions.DataSourceAlreadyExistException;
-import org.apache.metamodel.membrane.app.exceptions.NoSuchDataSourceException;
-import org.apache.metamodel.util.FileHelper;
-
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.cache.RemovalListener;
-import com.google.common.cache.RemovalNotification;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
-/**
- * A wrapper that adds a cache around a {@link DataSourceRegistry} in order to prevent re-connecting all the time to the
- * same data source.
- */
-public class CachedDataSourceRegistryWrapper implements DataSourceRegistry {
-
- /**
- * The default timeout (in seconds) before the cache evicts and closes the created {@link DataContext}s.
- */
- public static final int DEFAULT_TIMEOUT_SECONDS = 60;
-
- private final DataSourceRegistry delegate;
- private final LoadingCache<String, DataContext> loadingCache;
-
- public CachedDataSourceRegistryWrapper(final DataSourceRegistry delegate) {
- this(delegate, DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- }
-
- public CachedDataSourceRegistryWrapper(final DataSourceRegistry delegate, final long cacheTimeout,
- final TimeUnit cacheTimeoutUnit) {
- this.delegate = delegate;
- this.loadingCache = CacheBuilder.newBuilder().expireAfterAccess(cacheTimeout, cacheTimeoutUnit)
- .removalListener(createRemovalListener()).build(createCacheLoader());
- }
-
- private RemovalListener<String, DataContext> createRemovalListener() {
- return new RemovalListener<String, DataContext>() {
- @Override
- public void onRemoval(final RemovalNotification<String, DataContext> notification) {
- final DataContext dataContext = notification.getValue();
- // some DataContexts are closeable - attempt closing it here
- FileHelper.safeClose(dataContext);
- }
- };
- }
-
- private CacheLoader<String, DataContext> createCacheLoader() {
- return new CacheLoader<String, DataContext>() {
- @Override
- public DataContext load(final String key) throws Exception {
- return delegate.openDataContext(key);
- }
- };
- }
-
- @Override
- public List<String> getDataSourceNames() {
- return delegate.getDataSourceNames();
- }
-
- @Override
- public String registerDataSource(final String dataSourceName, final DataContextProperties dataContextProperties)
- throws DataSourceAlreadyExistException {
- loadingCache.invalidate(dataSourceName);
- return delegate.registerDataSource(dataSourceName, dataContextProperties);
- }
-
- @Override
- public DataContext openDataContext(final String dataSourceName) throws NoSuchDataSourceException {
- try {
- return loadingCache.getUnchecked(dataSourceName);
- } catch (UncheckedExecutionException e) {
- final Throwable cause = e.getCause();
- if (cause instanceof RuntimeException) {
- throw (RuntimeException) cause;
- }
- throw new MetaModelException(
- "Unexpected error happened while getting DataContext '" + dataSourceName + "' from cache", e);
- }
- }
-
- @Override
- public void removeDataSource(String dataSourceName) throws NoSuchDataSourceException {
- delegate.removeDataSource(dataSourceName);
- loadingCache.invalidate(dataSourceName);
- }
-
- @Override
- public DataContext openDataContext(DataContextProperties properties) {
- return delegate.openDataContext(properties);
- }
-}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/DataSourceRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/DataSourceRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/DataSourceRegistry.java
deleted file mode 100644
index 1c5db17..0000000
--- a/core/src/main/java/org/apache/metamodel/membrane/app/DataSourceRegistry.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.metamodel.membrane.app;
-
-import java.util.List;
-
-import org.apache.metamodel.DataContext;
-import org.apache.metamodel.UpdateableDataContext;
-import org.apache.metamodel.factory.DataContextProperties;
-import org.apache.metamodel.membrane.app.exceptions.DataSourceAlreadyExistException;
-import org.apache.metamodel.membrane.app.exceptions.DataSourceNotUpdateableException;
-import org.apache.metamodel.membrane.app.exceptions.NoSuchDataSourceException;
-
-/**
- * Represents a user's/tenant's registry of {@link DataContext}s.
- */
-public interface DataSourceRegistry {
-
- public List<String> getDataSourceNames();
-
- /**
- *
- * @param dataSourceName
- * @param dataContextProperties
- * @return the identifier/name for the data source.
- * @throws DataSourceAlreadyExistException
- */
- public String registerDataSource(String dataSourceName, DataContextProperties dataContextProperties)
- throws DataSourceAlreadyExistException;
-
- public void removeDataSource(String dataSourceName) throws NoSuchDataSourceException;
-
- /**
- * Opens a {@link DataContext} that exists in the registry.
- *
- * @param dataSourceName
- * @return
- * @throws NoSuchDataSourceException
- */
- public DataContext openDataContext(String dataSourceName) throws NoSuchDataSourceException;
-
- /**
- * Opens a {@link DataContext} based on a set of {@link DataContextProperties}. This allows you to instantiate a
- * data source without necesarily having registered it (yet).
- *
- * @param properties
- * @return
- */
- public DataContext openDataContext(DataContextProperties properties);
-
- /**
- * Opens a {@link UpdateableDataContext} that exists in the registry.
- *
- * @param dataSourceName
- * @return
- * @throws DataSourceNotUpdateableException
- */
- public default UpdateableDataContext openDataContextForUpdate(String dataSourceName)
- throws DataSourceNotUpdateableException {
- final DataContext dataContext = openDataContext(dataSourceName);
- if (dataContext instanceof UpdateableDataContext) {
- return (UpdateableDataContext) dataContext;
- }
- throw new DataSourceNotUpdateableException(dataSourceName);
- }
-}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryDataSourceRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryDataSourceRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryDataSourceRegistry.java
deleted file mode 100644
index 338ed86..0000000
--- a/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryDataSourceRegistry.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.metamodel.membrane.app;
-
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import org.apache.metamodel.DataContext;
-import org.apache.metamodel.factory.DataContextProperties;
-import org.apache.metamodel.membrane.app.exceptions.DataSourceAlreadyExistException;
-import org.apache.metamodel.membrane.app.exceptions.NoSuchDataSourceException;
-
-public class InMemoryDataSourceRegistry implements DataSourceRegistry {
-
- private final Map<String, Supplier<DataContext>> dataSources;
-
- public InMemoryDataSourceRegistry() {
- dataSources = new LinkedHashMap<>();
- }
-
- @Override
- public String registerDataSource(final String name, final DataContextProperties dataContextProperties)
- throws DataSourceAlreadyExistException {
- if (dataSources.containsKey(name)) {
- throw new DataSourceAlreadyExistException(name);
- }
-
- dataSources.put(name, new DataContextSupplier(name, dataContextProperties));
- return name;
- }
-
- @Override
- public List<String> getDataSourceNames() {
- return dataSources.keySet().stream().collect(Collectors.toList());
- }
-
- @Override
- public DataContext openDataContext(String name) {
- final Supplier<DataContext> supplier = dataSources.get(name);
- if (supplier == null) {
- throw new NoSuchDataSourceException(name);
- }
- return supplier.get();
- }
-
- @Override
- public void removeDataSource(String dataSourceName) throws NoSuchDataSourceException {
- if (!dataSources.containsKey(dataSourceName)) {
- throw new NoSuchDataSourceException(dataSourceName);
- }
- dataSources.remove(dataSourceName);
- }
-
- public DataContext openDataContext(DataContextProperties properties) {
- final DataContextSupplier supplier = new DataContextSupplier(null, properties);
- return supplier.get();
- }
-}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryTenantContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryTenantContext.java b/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryTenantContext.java
deleted file mode 100644
index 3ecb7fe..0000000
--- a/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryTenantContext.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.metamodel.membrane.app;
-
-public class InMemoryTenantContext implements TenantContext {
-
- private final String tenantIdentifier;
- private final DataSourceRegistry dataContextRegistry;
-
- public InMemoryTenantContext(String tenantIdentifier) {
- this.tenantIdentifier = tenantIdentifier;
- this.dataContextRegistry = new CachedDataSourceRegistryWrapper(new InMemoryDataSourceRegistry());
- }
-
- @Override
- public String getTenantName() {
- return tenantIdentifier;
- }
-
- @Override
- public DataSourceRegistry getDataSourceRegistry() {
- return dataContextRegistry;
- }
-
- @Override
- public String toString() {
- return "InMemoryTenantContext[" + tenantIdentifier + "]";
- }
-}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryTenantRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryTenantRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryTenantRegistry.java
deleted file mode 100644
index 8665819..0000000
--- a/core/src/main/java/org/apache/metamodel/membrane/app/InMemoryTenantRegistry.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.metamodel.membrane.app;
-
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import org.apache.metamodel.membrane.app.exceptions.NoSuchTenantException;
-import org.apache.metamodel.membrane.app.exceptions.TenantAlreadyExistException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * In-memory {@link TenantRegistry}. This is not particularly
- * production-friendly as it is non-persistent, but it is useful for demo
- * purposes.
- */
-public class InMemoryTenantRegistry implements TenantRegistry {
-
- private static final Logger logger = LoggerFactory.getLogger(InMemoryTenantRegistry.class);
- private final Map<String, TenantContext> tenants;
-
- public InMemoryTenantRegistry() {
- tenants = new LinkedHashMap<>();
- logger.info("Initialized!");
- }
-
- @Override
- public List<String> getTenantIdentifiers() {
- return tenants.keySet().stream().collect(Collectors.toList());
- }
-
- @Override
- public TenantContext getTenantContext(String tenantIdentifier) {
- final TenantContext tenant = tenants.get(tenantIdentifier);
- if (tenant == null) {
- throw new NoSuchTenantException(tenantIdentifier);
- }
- return tenant;
- }
-
- @Override
- public TenantContext createTenantContext(String tenantIdentifier) {
- if (tenants.containsKey(tenantIdentifier)) {
- throw new TenantAlreadyExistException(tenantIdentifier);
- }
- final InMemoryTenantContext tenantContext = new InMemoryTenantContext(tenantIdentifier);
- tenants.put(tenantIdentifier, tenantContext);
- logger.info("Created new tenant: {}", tenantContext);
- return tenantContext;
- }
-
- @Override
- public void deleteTenantContext(String tenantIdentifier) {
- final TenantContext removedTenant = tenants.remove(tenantIdentifier);
- if (removedTenant == null) {
- throw new NoSuchTenantException(tenantIdentifier);
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/TenantContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/TenantContext.java b/core/src/main/java/org/apache/metamodel/membrane/app/TenantContext.java
deleted file mode 100644
index 491859f..0000000
--- a/core/src/main/java/org/apache/metamodel/membrane/app/TenantContext.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.metamodel.membrane.app;
-
-/**
- * Represents a context-object containing all the information and services
- * related to a particular tenant.
- */
-public interface TenantContext {
-
- public String getTenantName();
-
- public DataSourceRegistry getDataSourceRegistry();
-
-}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/TenantRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/TenantRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/TenantRegistry.java
deleted file mode 100644
index 6a32800..0000000
--- a/core/src/main/java/org/apache/metamodel/membrane/app/TenantRegistry.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.metamodel.membrane.app;
-
-import java.util.List;
-
-import org.apache.metamodel.membrane.app.exceptions.NoSuchTenantException;
-import org.apache.metamodel.membrane.app.exceptions.TenantAlreadyExistException;
-
-/**
- * Represents the application's central registry of tenants
- */
-public interface TenantRegistry {
-
- public List<String> getTenantIdentifiers();
-
- public TenantContext getTenantContext(String tenantIdentifier) throws NoSuchTenantException;
-
- public TenantContext createTenantContext(String tenantIdentifier) throws IllegalArgumentException,
- TenantAlreadyExistException;
-
- public void deleteTenantContext(String tenantIdentifier) throws NoSuchTenantException;
-}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/DataSourceRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/DataSourceRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/DataSourceRegistry.java
new file mode 100644
index 0000000..00ec8e0
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/DataSourceRegistry.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.metamodel.membrane.app.registry;
+
+import java.util.List;
+
+import org.apache.metamodel.DataContext;
+import org.apache.metamodel.UpdateableDataContext;
+import org.apache.metamodel.factory.DataContextProperties;
+import org.apache.metamodel.membrane.app.exceptions.DataSourceAlreadyExistException;
+import org.apache.metamodel.membrane.app.exceptions.DataSourceNotUpdateableException;
+import org.apache.metamodel.membrane.app.exceptions.NoSuchDataSourceException;
+
+/**
+ * Represents a user's/tenant's registry of {@link DataContext}s.
+ */
+public interface DataSourceRegistry {
+
+ public List<String> getDataSourceNames();
+
+ /**
+ *
+ * @param dataSourceName
+ * @param dataContextProperties
+ * @return the identifier/name for the data source.
+ * @throws DataSourceAlreadyExistException
+ */
+ public String registerDataSource(String dataSourceName, DataContextProperties dataContextProperties)
+ throws DataSourceAlreadyExistException;
+
+ public void removeDataSource(String dataSourceName) throws NoSuchDataSourceException;
+
+ /**
+ * Opens a {@link DataContext} that exists in the registry.
+ *
+ * @param dataSourceName
+ * @return
+ * @throws NoSuchDataSourceException
+ */
+ public DataContext openDataContext(String dataSourceName) throws NoSuchDataSourceException;
+
+ /**
+ * Opens a {@link DataContext} based on a set of {@link DataContextProperties}. This allows you to instantiate a
+ * data source without necesarily having registered it (yet).
+ *
+ * @param properties
+ * @return
+ */
+ public DataContext openDataContext(DataContextProperties properties);
+
+ /**
+ * Opens a {@link UpdateableDataContext} that exists in the registry.
+ *
+ * @param dataSourceName
+ * @return
+ * @throws DataSourceNotUpdateableException
+ */
+ public default UpdateableDataContext openDataContextForUpdate(String dataSourceName)
+ throws DataSourceNotUpdateableException {
+ final DataContext dataContext = openDataContext(dataSourceName);
+ if (dataContext instanceof UpdateableDataContext) {
+ return (UpdateableDataContext) dataContext;
+ }
+ throw new DataSourceNotUpdateableException(dataSourceName);
+ }
+}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/TenantContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/TenantContext.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/TenantContext.java
new file mode 100644
index 0000000..4d7b470
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/TenantContext.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.metamodel.membrane.app.registry;
+
+/**
+ * Represents a context-object containing all the information and services
+ * related to a particular tenant.
+ */
+public interface TenantContext {
+
+ public String getTenantName();
+
+ public DataSourceRegistry getDataSourceRegistry();
+
+}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/TenantRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/TenantRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/TenantRegistry.java
new file mode 100644
index 0000000..764fbc0
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/TenantRegistry.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.metamodel.membrane.app.registry;
+
+import java.util.List;
+
+import org.apache.metamodel.membrane.app.exceptions.NoSuchTenantException;
+import org.apache.metamodel.membrane.app.exceptions.TenantAlreadyExistException;
+
+/**
+ * Represents the application's central registry of tenants
+ */
+public interface TenantRegistry {
+
+ public List<String> getTenantIdentifiers();
+
+ public TenantContext getTenantContext(String tenantIdentifier) throws NoSuchTenantException;
+
+ public TenantContext createTenantContext(String tenantIdentifier) throws IllegalArgumentException,
+ TenantAlreadyExistException;
+
+ public void deleteTenantContext(String tenantIdentifier) throws NoSuchTenantException;
+}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/cache/CachedDataSourceRegistryWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/cache/CachedDataSourceRegistryWrapper.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/cache/CachedDataSourceRegistryWrapper.java
new file mode 100644
index 0000000..3a3a478
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/cache/CachedDataSourceRegistryWrapper.java
@@ -0,0 +1,120 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.metamodel.membrane.app.registry.cache;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.metamodel.DataContext;
+import org.apache.metamodel.MetaModelException;
+import org.apache.metamodel.factory.DataContextProperties;
+import org.apache.metamodel.membrane.app.exceptions.DataSourceAlreadyExistException;
+import org.apache.metamodel.membrane.app.exceptions.NoSuchDataSourceException;
+import org.apache.metamodel.membrane.app.registry.DataSourceRegistry;
+import org.apache.metamodel.util.FileHelper;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.cache.RemovalListener;
+import com.google.common.cache.RemovalNotification;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+/**
+ * A wrapper that adds a cache around a {@link DataSourceRegistry} in order to prevent re-connecting all the time to the
+ * same data source.
+ */
+public class CachedDataSourceRegistryWrapper implements DataSourceRegistry {
+
+ /**
+ * The default timeout (in seconds) before the cache evicts and closes the created {@link DataContext}s.
+ */
+ public static final int DEFAULT_TIMEOUT_SECONDS = 60;
+
+ private final DataSourceRegistry delegate;
+ private final LoadingCache<String, DataContext> loadingCache;
+
+ public CachedDataSourceRegistryWrapper(final DataSourceRegistry delegate) {
+ this(delegate, DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ public CachedDataSourceRegistryWrapper(final DataSourceRegistry delegate, final long cacheTimeout,
+ final TimeUnit cacheTimeoutUnit) {
+ this.delegate = delegate;
+ this.loadingCache = CacheBuilder.newBuilder().expireAfterAccess(cacheTimeout, cacheTimeoutUnit)
+ .removalListener(createRemovalListener()).build(createCacheLoader());
+ }
+
+ private RemovalListener<String, DataContext> createRemovalListener() {
+ return new RemovalListener<String, DataContext>() {
+ @Override
+ public void onRemoval(final RemovalNotification<String, DataContext> notification) {
+ final DataContext dataContext = notification.getValue();
+ // some DataContexts are closeable - attempt closing it here
+ FileHelper.safeClose(dataContext);
+ }
+ };
+ }
+
+ private CacheLoader<String, DataContext> createCacheLoader() {
+ return new CacheLoader<String, DataContext>() {
+ @Override
+ public DataContext load(final String key) throws Exception {
+ return delegate.openDataContext(key);
+ }
+ };
+ }
+
+ @Override
+ public List<String> getDataSourceNames() {
+ return delegate.getDataSourceNames();
+ }
+
+ @Override
+ public String registerDataSource(final String dataSourceName, final DataContextProperties dataContextProperties)
+ throws DataSourceAlreadyExistException {
+ loadingCache.invalidate(dataSourceName);
+ return delegate.registerDataSource(dataSourceName, dataContextProperties);
+ }
+
+ @Override
+ public DataContext openDataContext(final String dataSourceName) throws NoSuchDataSourceException {
+ try {
+ return loadingCache.getUnchecked(dataSourceName);
+ } catch (UncheckedExecutionException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ }
+ throw new MetaModelException(
+ "Unexpected error happened while getting DataContext '" + dataSourceName + "' from cache", e);
+ }
+ }
+
+ @Override
+ public void removeDataSource(String dataSourceName) throws NoSuchDataSourceException {
+ delegate.removeDataSource(dataSourceName);
+ loadingCache.invalidate(dataSourceName);
+ }
+
+ @Override
+ public DataContext openDataContext(DataContextProperties properties) {
+ return delegate.openDataContext(properties);
+ }
+}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/cache/CachedTenantRegistryWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/cache/CachedTenantRegistryWrapper.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/cache/CachedTenantRegistryWrapper.java
new file mode 100644
index 0000000..6ba500f
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/cache/CachedTenantRegistryWrapper.java
@@ -0,0 +1,113 @@
+package org.apache.metamodel.membrane.app.registry.cache;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.metamodel.MetaModelException;
+import org.apache.metamodel.membrane.app.exceptions.NoSuchTenantException;
+import org.apache.metamodel.membrane.app.exceptions.TenantAlreadyExistException;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
+import org.apache.metamodel.util.FileHelper;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.cache.RemovalListener;
+import com.google.common.cache.RemovalNotification;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+public class CachedTenantRegistryWrapper implements TenantRegistry {
+
+ /**
+ * The default timeout (in seconds) before the cache evicts and closes the
+ * created {@link TenantContext}s.
+ */
+ public static final int DEFAULT_TIMEOUT_SECONDS = 10 * 60;
+
+ private final TenantRegistry delegate;
+ private final LoadingCache<String, TenantContext> loadingCache;
+
+ public CachedTenantRegistryWrapper(TenantRegistry delegate) {
+ this(delegate, DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ public CachedTenantRegistryWrapper(TenantRegistry delegate, final long cacheTimeout,
+ final TimeUnit cacheTimeoutUnit) {
+ this.delegate = delegate;
+ this.loadingCache = CacheBuilder.newBuilder().expireAfterAccess(cacheTimeout, cacheTimeoutUnit).removalListener(
+ createRemovalListener()).build(createCacheLoader());
+ }
+
+ private RemovalListener<String, TenantContext> createRemovalListener() {
+ return new RemovalListener<String, TenantContext>() {
+ @Override
+ public void onRemoval(final RemovalNotification<String, TenantContext> notification) {
+ final TenantContext tenantContext = notification.getValue();
+ // TenantContexts could be closeable - attempt closing it here
+ FileHelper.safeClose(tenantContext);
+ }
+ };
+ }
+
+ private CacheLoader<String, TenantContext> createCacheLoader() {
+ return new CacheLoader<String, TenantContext>() {
+ @Override
+ public TenantContext load(final String key) throws Exception {
+ return delegate.getTenantContext(key);
+ }
+ };
+ }
+
+ @Override
+ public List<String> getTenantIdentifiers() {
+ return delegate.getTenantIdentifiers();
+ }
+
+ @Override
+ public TenantContext getTenantContext(String tenantIdentifier) throws NoSuchTenantException {
+ try {
+ return loadingCache.getUnchecked(tenantIdentifier);
+ } catch (UncheckedExecutionException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ }
+ throw new MetaModelException("Unexpected error happened while getting TenantContext '" + tenantIdentifier
+ + "' from cache", e);
+ }
+ }
+
+ @Override
+ public TenantContext createTenantContext(String tenantIdentifier) throws IllegalArgumentException,
+ TenantAlreadyExistException {
+ final TenantContext tenantContext = delegate.createTenantContext(tenantIdentifier);
+ loadingCache.put(tenantContext.getTenantName(), tenantContext);
+ return tenantContext;
+ }
+
+ @Override
+ public void deleteTenantContext(String tenantIdentifier) throws NoSuchTenantException {
+ delegate.deleteTenantContext(tenantIdentifier);
+ loadingCache.invalidate(tenantIdentifier);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedDataSourceRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedDataSourceRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedDataSourceRegistry.java
index 1a7759d..60c77ae 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedDataSourceRegistry.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedDataSourceRegistry.java
@@ -29,10 +29,10 @@ import java.util.stream.Collectors;
import org.apache.metamodel.DataContext;
import org.apache.metamodel.factory.DataContextProperties;
import org.apache.metamodel.membrane.app.DataContextSupplier;
-import org.apache.metamodel.membrane.app.DataSourceRegistry;
import org.apache.metamodel.membrane.app.config.JacksonConfig;
import org.apache.metamodel.membrane.app.exceptions.DataSourceAlreadyExistException;
import org.apache.metamodel.membrane.app.exceptions.NoSuchDataSourceException;
+import org.apache.metamodel.membrane.app.registry.DataSourceRegistry;
import org.apache.metamodel.membrane.controllers.model.RestDataSourceDefinition;
import com.fasterxml.jackson.databind.ObjectMapper;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantContext.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantContext.java
index b1bc48c..d830125 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantContext.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantContext.java
@@ -20,9 +20,9 @@ package org.apache.metamodel.membrane.app.registry.file;
import java.io.File;
-import org.apache.metamodel.membrane.app.CachedDataSourceRegistryWrapper;
-import org.apache.metamodel.membrane.app.DataSourceRegistry;
-import org.apache.metamodel.membrane.app.TenantContext;
+import org.apache.metamodel.membrane.app.registry.DataSourceRegistry;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.cache.CachedDataSourceRegistryWrapper;
class FileBasedTenantContext implements TenantContext {
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantRegistry.java
index 6242038..94acdcd 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantRegistry.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/file/FileBasedTenantRegistry.java
@@ -30,10 +30,10 @@ import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
-import org.apache.metamodel.membrane.app.TenantContext;
-import org.apache.metamodel.membrane.app.TenantRegistry;
import org.apache.metamodel.membrane.app.exceptions.NoSuchTenantException;
import org.apache.metamodel.membrane.app.exceptions.TenantAlreadyExistException;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
import com.google.common.base.Strings;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryDataSourceRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryDataSourceRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryDataSourceRegistry.java
new file mode 100644
index 0000000..a457ec0
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryDataSourceRegistry.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.metamodel.membrane.app.registry.memory;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.apache.metamodel.DataContext;
+import org.apache.metamodel.factory.DataContextProperties;
+import org.apache.metamodel.membrane.app.DataContextSupplier;
+import org.apache.metamodel.membrane.app.exceptions.DataSourceAlreadyExistException;
+import org.apache.metamodel.membrane.app.exceptions.NoSuchDataSourceException;
+import org.apache.metamodel.membrane.app.registry.DataSourceRegistry;
+
+public class InMemoryDataSourceRegistry implements DataSourceRegistry {
+
+ private final Map<String, Supplier<DataContext>> dataSources;
+
+ public InMemoryDataSourceRegistry() {
+ dataSources = new LinkedHashMap<>();
+ }
+
+ @Override
+ public String registerDataSource(final String name, final DataContextProperties dataContextProperties)
+ throws DataSourceAlreadyExistException {
+ if (dataSources.containsKey(name)) {
+ throw new DataSourceAlreadyExistException(name);
+ }
+
+ dataSources.put(name, new DataContextSupplier(name, dataContextProperties));
+ return name;
+ }
+
+ @Override
+ public List<String> getDataSourceNames() {
+ return dataSources.keySet().stream().collect(Collectors.toList());
+ }
+
+ @Override
+ public DataContext openDataContext(String name) {
+ final Supplier<DataContext> supplier = dataSources.get(name);
+ if (supplier == null) {
+ throw new NoSuchDataSourceException(name);
+ }
+ return supplier.get();
+ }
+
+ @Override
+ public void removeDataSource(String dataSourceName) throws NoSuchDataSourceException {
+ if (!dataSources.containsKey(dataSourceName)) {
+ throw new NoSuchDataSourceException(dataSourceName);
+ }
+ dataSources.remove(dataSourceName);
+ }
+
+ public DataContext openDataContext(DataContextProperties properties) {
+ final DataContextSupplier supplier = new DataContextSupplier(null, properties);
+ return supplier.get();
+ }
+}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryTenantContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryTenantContext.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryTenantContext.java
new file mode 100644
index 0000000..08b2fa9
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryTenantContext.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.metamodel.membrane.app.registry.memory;
+
+import org.apache.metamodel.membrane.app.registry.DataSourceRegistry;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.cache.CachedDataSourceRegistryWrapper;
+
+public class InMemoryTenantContext implements TenantContext {
+
+ private final String tenantIdentifier;
+ private final DataSourceRegistry dataContextRegistry;
+
+ public InMemoryTenantContext(String tenantIdentifier) {
+ this.tenantIdentifier = tenantIdentifier;
+ this.dataContextRegistry = new CachedDataSourceRegistryWrapper(new InMemoryDataSourceRegistry());
+ }
+
+ @Override
+ public String getTenantName() {
+ return tenantIdentifier;
+ }
+
+ @Override
+ public DataSourceRegistry getDataSourceRegistry() {
+ return dataContextRegistry;
+ }
+
+ @Override
+ public String toString() {
+ return "InMemoryTenantContext[" + tenantIdentifier + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryTenantRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryTenantRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryTenantRegistry.java
new file mode 100644
index 0000000..37586b1
--- /dev/null
+++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/memory/InMemoryTenantRegistry.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.metamodel.membrane.app.registry.memory;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.metamodel.membrane.app.exceptions.NoSuchTenantException;
+import org.apache.metamodel.membrane.app.exceptions.TenantAlreadyExistException;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * In-memory {@link TenantRegistry}. This is not particularly
+ * production-friendly as it is non-persistent, but it is useful for demo
+ * purposes.
+ */
+public class InMemoryTenantRegistry implements TenantRegistry {
+
+ private static final Logger logger = LoggerFactory.getLogger(InMemoryTenantRegistry.class);
+ private final Map<String, TenantContext> tenants;
+
+ public InMemoryTenantRegistry() {
+ tenants = new LinkedHashMap<>();
+ logger.info("Initialized!");
+ }
+
+ @Override
+ public List<String> getTenantIdentifiers() {
+ return tenants.keySet().stream().collect(Collectors.toList());
+ }
+
+ @Override
+ public TenantContext getTenantContext(String tenantIdentifier) {
+ final TenantContext tenant = tenants.get(tenantIdentifier);
+ if (tenant == null) {
+ throw new NoSuchTenantException(tenantIdentifier);
+ }
+ return tenant;
+ }
+
+ @Override
+ public TenantContext createTenantContext(String tenantIdentifier) {
+ if (tenants.containsKey(tenantIdentifier)) {
+ throw new TenantAlreadyExistException(tenantIdentifier);
+ }
+ final InMemoryTenantContext tenantContext = new InMemoryTenantContext(tenantIdentifier);
+ tenants.put(tenantIdentifier, tenantContext);
+ logger.info("Created new tenant: {}", tenantContext);
+ return tenantContext;
+ }
+
+ @Override
+ public void deleteTenantContext(String tenantIdentifier) {
+ final TenantContext removedTenant = tenants.remove(tenantIdentifier);
+ if (removedTenant == null) {
+ throw new NoSuchTenantException(tenantIdentifier);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/controllers/ColumnController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/controllers/ColumnController.java b/core/src/main/java/org/apache/metamodel/membrane/controllers/ColumnController.java
index 5e51a39..a0efb7b 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/controllers/ColumnController.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/controllers/ColumnController.java
@@ -20,8 +20,8 @@ package org.apache.metamodel.membrane.controllers;
import org.apache.metamodel.DataContext;
import org.apache.metamodel.membrane.app.DataContextTraverser;
-import org.apache.metamodel.membrane.app.TenantContext;
-import org.apache.metamodel.membrane.app.TenantRegistry;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
import org.apache.metamodel.membrane.swagger.model.GetColumnResponse;
import org.apache.metamodel.membrane.swagger.model.GetColumnResponseMetadata;
import org.apache.metamodel.schema.Column;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/controllers/DataSourceController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/controllers/DataSourceController.java b/core/src/main/java/org/apache/metamodel/membrane/controllers/DataSourceController.java
index 0dea52e..21fe39f 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/controllers/DataSourceController.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/controllers/DataSourceController.java
@@ -30,10 +30,10 @@ import org.apache.metamodel.DataContext;
import org.apache.metamodel.UpdateableDataContext;
import org.apache.metamodel.factory.DataContextProperties;
import org.apache.metamodel.factory.DataContextPropertiesImpl;
-import org.apache.metamodel.membrane.app.DataSourceRegistry;
-import org.apache.metamodel.membrane.app.TenantContext;
-import org.apache.metamodel.membrane.app.TenantRegistry;
import org.apache.metamodel.membrane.app.exceptions.InvalidDataSourceException;
+import org.apache.metamodel.membrane.app.registry.DataSourceRegistry;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
import org.apache.metamodel.membrane.controllers.model.RestDataSourceDefinition;
import org.apache.metamodel.membrane.swagger.model.DeleteDatasourceResponse;
import org.apache.metamodel.membrane.swagger.model.GetDatasourceResponse;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/controllers/QueryController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/controllers/QueryController.java b/core/src/main/java/org/apache/metamodel/membrane/controllers/QueryController.java
index 33a0567..7c8a90c 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/controllers/QueryController.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/controllers/QueryController.java
@@ -25,8 +25,8 @@ import java.util.stream.Collectors;
import org.apache.metamodel.DataContext;
import org.apache.metamodel.data.DataSet;
-import org.apache.metamodel.membrane.app.TenantContext;
-import org.apache.metamodel.membrane.app.TenantRegistry;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
import org.apache.metamodel.membrane.swagger.model.QueryResponse;
import org.apache.metamodel.query.Query;
import org.slf4j.Logger;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/controllers/SchemaController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/controllers/SchemaController.java b/core/src/main/java/org/apache/metamodel/membrane/controllers/SchemaController.java
index 04d55e1..7be34b9 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/controllers/SchemaController.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/controllers/SchemaController.java
@@ -25,8 +25,8 @@ import javax.ws.rs.core.UriBuilder;
import org.apache.metamodel.DataContext;
import org.apache.metamodel.membrane.app.DataContextTraverser;
-import org.apache.metamodel.membrane.app.TenantContext;
-import org.apache.metamodel.membrane.app.TenantRegistry;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
import org.apache.metamodel.membrane.swagger.model.GetSchemaResponse;
import org.apache.metamodel.membrane.swagger.model.GetSchemaResponseTables;
import org.apache.metamodel.schema.Schema;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/controllers/TableController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/controllers/TableController.java b/core/src/main/java/org/apache/metamodel/membrane/controllers/TableController.java
index af7decf..5da8bb0 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/controllers/TableController.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/controllers/TableController.java
@@ -25,8 +25,8 @@ import javax.ws.rs.core.UriBuilder;
import org.apache.metamodel.DataContext;
import org.apache.metamodel.membrane.app.DataContextTraverser;
-import org.apache.metamodel.membrane.app.TenantContext;
-import org.apache.metamodel.membrane.app.TenantRegistry;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
import org.apache.metamodel.membrane.swagger.model.GetTableResponse;
import org.apache.metamodel.membrane.swagger.model.GetTableResponseColumns;
import org.apache.metamodel.schema.Table;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/controllers/TableDataController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/controllers/TableDataController.java b/core/src/main/java/org/apache/metamodel/membrane/controllers/TableDataController.java
index f31f690..42ed7ab 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/controllers/TableDataController.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/controllers/TableDataController.java
@@ -34,9 +34,9 @@ import org.apache.metamodel.data.WhereClauseBuilder;
import org.apache.metamodel.delete.RowDeletionBuilder;
import org.apache.metamodel.insert.RowInsertionBuilder;
import org.apache.metamodel.membrane.app.DataContextTraverser;
-import org.apache.metamodel.membrane.app.TenantContext;
-import org.apache.metamodel.membrane.app.TenantRegistry;
import org.apache.metamodel.membrane.app.config.JacksonConfig;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
import org.apache.metamodel.membrane.swagger.model.Operator;
import org.apache.metamodel.membrane.swagger.model.PostDataRequest;
import org.apache.metamodel.membrane.swagger.model.PostDataRequestDelete;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/java/org/apache/metamodel/membrane/controllers/TenantController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/metamodel/membrane/controllers/TenantController.java b/core/src/main/java/org/apache/metamodel/membrane/controllers/TenantController.java
index e94983b..d4c72e5 100644
--- a/core/src/main/java/org/apache/metamodel/membrane/controllers/TenantController.java
+++ b/core/src/main/java/org/apache/metamodel/membrane/controllers/TenantController.java
@@ -24,8 +24,8 @@ import java.util.stream.Collectors;
import javax.ws.rs.core.UriBuilder;
-import org.apache.metamodel.membrane.app.TenantContext;
-import org.apache.metamodel.membrane.app.TenantRegistry;
+import org.apache.metamodel.membrane.app.registry.TenantContext;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
import org.apache.metamodel.membrane.swagger.model.DeleteTenantResponse;
import org.apache.metamodel.membrane.swagger.model.GetTenantResponse;
import org.apache.metamodel.membrane.swagger.model.GetTenantResponseDatasources;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/main/resources/context/application-context.xml
----------------------------------------------------------------------
diff --git a/core/src/main/resources/context/application-context.xml b/core/src/main/resources/context/application-context.xml
index b5219ce..542d44d 100644
--- a/core/src/main/resources/context/application-context.xml
+++ b/core/src/main/resources/context/application-context.xml
@@ -33,8 +33,14 @@ under the License.
<context:component-scan base-package="org.apache.metamodel.membrane.app" />
<bean id="tenantRegistry"
- class="org.apache.metamodel.membrane.app.registry.file.FileBasedTenantRegistry">
- <constructor-arg name="directory" value="${DATA_DIRECTORY}" />
+ class="org.apache.metamodel.membrane.app.registry.cache.CachedTenantRegistryWrapper">
+ <constructor-arg name="delegate">
+ <bean
+ class="org.apache.metamodel.membrane.app.registry.file.FileBasedTenantRegistry">
+ <constructor-arg name="directory" value="${DATA_DIRECTORY}" />
+ </bean>
+ </constructor-arg>
</bean>
+
</beans>
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/test/java/org/apache/metamodel/membrane/controllers/DataSourceControllerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/membrane/controllers/DataSourceControllerTest.java b/core/src/test/java/org/apache/metamodel/membrane/controllers/DataSourceControllerTest.java
index 2a7e240..99a16f8 100644
--- a/core/src/test/java/org/apache/metamodel/membrane/controllers/DataSourceControllerTest.java
+++ b/core/src/test/java/org/apache/metamodel/membrane/controllers/DataSourceControllerTest.java
@@ -20,9 +20,9 @@ package org.apache.metamodel.membrane.controllers;
import static org.junit.Assert.assertEquals;
-import org.apache.metamodel.membrane.app.InMemoryTenantRegistry;
-import org.apache.metamodel.membrane.app.TenantRegistry;
import org.apache.metamodel.membrane.app.exceptions.InvalidDataSourceException;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
+import org.apache.metamodel.membrane.app.registry.memory.InMemoryTenantRegistry;
import org.apache.metamodel.membrane.controllers.model.RestDataSourceDefinition;
import org.apache.metamodel.membrane.swagger.model.GetDatasourceResponse;
import org.junit.Assert;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/core/src/test/java/org/apache/metamodel/membrane/controllers/TenantInteractionScenarioTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/metamodel/membrane/controllers/TenantInteractionScenarioTest.java b/core/src/test/java/org/apache/metamodel/membrane/controllers/TenantInteractionScenarioTest.java
index 3e0575d..7071548 100644
--- a/core/src/test/java/org/apache/metamodel/membrane/controllers/TenantInteractionScenarioTest.java
+++ b/core/src/test/java/org/apache/metamodel/membrane/controllers/TenantInteractionScenarioTest.java
@@ -22,9 +22,9 @@ import static org.junit.Assert.assertEquals;
import java.util.Map;
-import org.apache.metamodel.membrane.app.InMemoryTenantRegistry;
-import org.apache.metamodel.membrane.app.TenantRegistry;
import org.apache.metamodel.membrane.app.config.JacksonConfig;
+import org.apache.metamodel.membrane.app.registry.TenantRegistry;
+import org.apache.metamodel.membrane.app.registry.memory.InMemoryTenantRegistry;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/013c8dcb/postman-tests/Membrane.postman_collection.json
----------------------------------------------------------------------
diff --git a/postman-tests/Membrane.postman_collection.json b/postman-tests/Membrane.postman_collection.json
index 62e816f..e249ead 100644
--- a/postman-tests/Membrane.postman_collection.json
+++ b/postman-tests/Membrane.postman_collection.json
@@ -2,7 +2,7 @@
"variables": [],
"info": {
"name": "Membrane",
- "_postman_id": "1265d16a-b1fd-26a4-7ea5-d2e4015df97e",
+ "_postman_id": "fc875392-a36c-6ff7-46fb-53eab9cd3c3e",
"description": "",
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
},
@@ -27,7 +27,10 @@
"url": "{{baseUrl}}/swagger.json",
"method": "GET",
"header": [],
- "body": {},
+ "body": {
+ "mode": "raw",
+ "raw": ""
+ },
"description": ""
},
"response": []
@@ -43,9 +46,12 @@
"tests[\"Status code is 200\"] = responseCode.code === 200;",
"",
"var jsonData = JSON.parse(responseBody);",
- "tests[\"type is tenant\"] = jsonData.type === \"tenant\";",
+ "var isTenant = jsonData.type === \"tenant\";",
+ "tests[\"type is tenant\"] = isTenant;",
"",
- "postman.setGlobalVariable(\"membrane_tenant\", jsonData.name);",
+ "if (isTenant) {",
+ " postman.setGlobalVariable(\"membrane_tenant\", jsonData.name);",
+ "}",
""
]
}
@@ -89,7 +95,10 @@
"url": "{{baseUrl}}/{{membrane_tenant}}",
"method": "GET",
"header": [],
- "body": {},
+ "body": {
+ "mode": "raw",
+ "raw": ""
+ },
"description": ""
},
"response": []
@@ -521,7 +530,10 @@
"url": "{{baseUrl}}/{{membrane_tenant}}/{{membrane_data_source}}",
"method": "DELETE",
"header": [],
- "body": {},
+ "body": {
+ "mode": "raw",
+ "raw": ""
+ },
"description": ""
},
"response": []