Repository: metamodel-membrane Updated Branches: refs/heads/METAMODEL-1159-composite-query [created] 45ea4d543
METAMODEL-1159: Added a federated datasource type scoped to the tenant Project: http://git-wip-us.apache.org/repos/asf/metamodel-membrane/repo Commit: http://git-wip-us.apache.org/repos/asf/metamodel-membrane/commit/4185f5e7 Tree: http://git-wip-us.apache.org/repos/asf/metamodel-membrane/tree/4185f5e7 Diff: http://git-wip-us.apache.org/repos/asf/metamodel-membrane/diff/4185f5e7 Branch: refs/heads/METAMODEL-1159-composite-query Commit: 4185f5e75d97642433e1826a5f9dbfab5937e4c9 Parents: 7bb21b7 Author: Kasper Sørensen <i.am.kasper.soren...@gmail.com> Authored: Wed Nov 7 21:53:49 2018 -0800 Committer: Kasper Sørensen <i.am.kasper.soren...@gmail.com> Committed: Wed Nov 7 21:54:48 2018 -0800 ---------------------------------------------------------------------- .../membrane/app/DataContextSupplier.java | 48 ---------- .../federation/FederatedDataContextFactory.java | 92 ++++++++++++++++++++ .../registry/AbstractDataSourceRegistry.java | 45 ++++++++++ .../app/registry/DataContextSupplier.java | 74 ++++++++++++++++ .../file/FileBasedDataSourceRegistry.java | 17 ++-- .../registry/file/FileBasedTenantContext.java | 3 +- .../memory/InMemoryDataSourceRegistry.java | 16 ++-- .../registry/memory/InMemoryTenantContext.java | 2 +- 8 files changed, 227 insertions(+), 70 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/4185f5e7/core/src/main/java/org/apache/metamodel/membrane/app/DataContextSupplier.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/DataContextSupplier.java b/core/src/main/java/org/apache/metamodel/membrane/app/DataContextSupplier.java deleted file mode 100644 index 7ce0cc0..0000000 --- a/core/src/main/java/org/apache/metamodel/membrane/app/DataContextSupplier.java +++ /dev/null @@ -1,48 +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.function.Supplier; - -import org.apache.metamodel.DataContext; -import org.apache.metamodel.factory.DataContextFactoryRegistryImpl; -import org.apache.metamodel.factory.DataContextProperties; - -public class DataContextSupplier implements Supplier<DataContext> { - - private final String dataSourceName; - private final DataContextProperties dataContextProperties; - - public DataContextSupplier(String dataSourceName, DataContextProperties dataContextProperties) { - this.dataSourceName = dataSourceName; - this.dataContextProperties = dataContextProperties; - } - - @Override - public DataContext get() { - final DataContext dataContext = DataContextFactoryRegistryImpl.getDefaultInstance().createDataContext( - dataContextProperties); - return dataContext; - } - - @Override - public String toString() { - return "DataContextSupplier[" + dataSourceName + "]"; - } -} http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/4185f5e7/core/src/main/java/org/apache/metamodel/membrane/app/federation/FederatedDataContextFactory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/federation/FederatedDataContextFactory.java b/core/src/main/java/org/apache/metamodel/membrane/app/federation/FederatedDataContextFactory.java new file mode 100644 index 0000000..db70942 --- /dev/null +++ b/core/src/main/java/org/apache/metamodel/membrane/app/federation/FederatedDataContextFactory.java @@ -0,0 +1,92 @@ +/** + * 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.federation; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.metamodel.CompositeDataContext; +import org.apache.metamodel.ConnectionException; +import org.apache.metamodel.DataContext; +import org.apache.metamodel.factory.DataContextFactory; +import org.apache.metamodel.factory.DataContextProperties; +import org.apache.metamodel.factory.ResourceFactoryRegistry; +import org.apache.metamodel.factory.UnsupportedDataContextPropertiesException; +import org.apache.metamodel.membrane.app.registry.DataSourceRegistry; +import org.apache.metamodel.membrane.app.registry.TenantContext; + +public class FederatedDataContextFactory implements DataContextFactory { + + public static final String DATA_CONTEXT_TYPE = "federated"; + public static final String PROPERTY_DATA_SOURCES = "datasources"; + + private final TenantContext tenant; + + public FederatedDataContextFactory(TenantContext tenant) { + this.tenant = tenant; + } + + @Override + public boolean accepts(DataContextProperties properties, ResourceFactoryRegistry resourceFactoryRegistry) { + return DATA_CONTEXT_TYPE.equals(properties.getDataContextType()); + } + + @Override + public DataContext create(DataContextProperties properties, ResourceFactoryRegistry resourceFactoryRegistry) + throws UnsupportedDataContextPropertiesException, ConnectionException { + + final Object dataSourcesPropertyValue = properties.toMap().get(PROPERTY_DATA_SOURCES); + final Collection<String> dataSourceNames = toDataSourceNames(dataSourcesPropertyValue); + final DataSourceRegistry dataSourceRegistry = tenant.getDataSourceRegistry(); + final List<DataContext> dataContexts = + dataSourceNames.stream().map(dataSourceRegistry::openDataContext).collect(Collectors.toList()); + return new CompositeDataContext(dataContexts); + } + + @SuppressWarnings("unchecked") + private Collection<String> toDataSourceNames(Object dataSourcesPropertyValue) { + if (dataSourcesPropertyValue == null) { + return Collections.emptyList(); + } + if ("*".equals(dataSourcesPropertyValue)) { + return tenant.getDataSourceRegistry().getDataSourceNames(); + } + if (dataSourcesPropertyValue instanceof String) { + final String str = (String) dataSourcesPropertyValue; + return Collections.singleton(str); + } + if (dataSourcesPropertyValue instanceof Collection) { + return new HashSet<>((Collection<String>)dataSourcesPropertyValue); + } + if (dataSourcesPropertyValue.getClass().isArray()) { + final Set<String> result = new HashSet<>(); + final Object[] arr = (Object[]) dataSourcesPropertyValue; + for (Object item : arr) { + result.addAll(toDataSourceNames(item)); + } + return result; + } + throw new IllegalArgumentException("Bad '" + PROPERTY_DATA_SOURCES + "' value: " + dataSourcesPropertyValue); + } + +} http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/4185f5e7/core/src/main/java/org/apache/metamodel/membrane/app/registry/AbstractDataSourceRegistry.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/AbstractDataSourceRegistry.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/AbstractDataSourceRegistry.java new file mode 100644 index 0000000..b83a509 --- /dev/null +++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/AbstractDataSourceRegistry.java @@ -0,0 +1,45 @@ +/** + * 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 org.apache.metamodel.DataContext; +import org.apache.metamodel.factory.DataContextProperties; + +public abstract class AbstractDataSourceRegistry implements DataSourceRegistry { + + private final TenantContext tenantContext; + + public AbstractDataSourceRegistry(TenantContext tenantContext) { + this.tenantContext = tenantContext; + } + + protected DataContextSupplier createDataContextSupplier(String name, DataContextProperties properties) { + final DataContextSupplier supplier = new DataContextSupplier(tenantContext, name, properties); + return supplier; + } + + @Override + public DataContext openDataContext(DataContextProperties properties) { + return createDataContextSupplier(null, properties).get(); + } + + protected TenantContext getTenantContext() { + return tenantContext; + } +} http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/4185f5e7/core/src/main/java/org/apache/metamodel/membrane/app/registry/DataContextSupplier.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/metamodel/membrane/app/registry/DataContextSupplier.java b/core/src/main/java/org/apache/metamodel/membrane/app/registry/DataContextSupplier.java new file mode 100644 index 0000000..2297dca --- /dev/null +++ b/core/src/main/java/org/apache/metamodel/membrane/app/registry/DataContextSupplier.java @@ -0,0 +1,74 @@ +/** + * 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.Collection; +import java.util.function.Supplier; + +import org.apache.metamodel.DataContext; +import org.apache.metamodel.factory.DataContextFactory; +import org.apache.metamodel.factory.DataContextFactoryRegistry; +import org.apache.metamodel.factory.DataContextFactoryRegistryImpl; +import org.apache.metamodel.factory.DataContextProperties; +import org.apache.metamodel.factory.ResourceFactoryRegistry; +import org.apache.metamodel.factory.ResourceFactoryRegistryImpl; +import org.apache.metamodel.membrane.app.federation.FederatedDataContextFactory; + +public class DataContextSupplier implements Supplier<DataContext> { + + private final String dataSourceName; + private final DataContextProperties dataContextProperties; + private final TenantContext tenantContext; + + public DataContextSupplier(TenantContext tenantContext, String dataSourceName, + DataContextProperties dataContextProperties) { + this.tenantContext = tenantContext; + this.dataSourceName = dataSourceName; + this.dataContextProperties = dataContextProperties; + } + + @Override + public DataContext get() { + final DataContextFactoryRegistry registry = getRegistryForTenant(); + final DataContext dataContext = registry.createDataContext(dataContextProperties); + return dataContext; + } + + private DataContextFactoryRegistry getRegistryForTenant() { + final ResourceFactoryRegistry resourceFactoryRegistry = ResourceFactoryRegistryImpl.getDefaultInstance(); + final DataContextFactoryRegistry registry = new DataContextFactoryRegistryImpl(resourceFactoryRegistry); + + // Add default/standard factories. This is pretty cumbersome. New constructor/cloning options in MetaModel + // should make this easier: https://github.com/apache/metamodel/pull/192 + final DataContextFactoryRegistry defaultRegistry = DataContextFactoryRegistryImpl.getDefaultInstance(); + final Collection<DataContextFactory> defaultFactories = defaultRegistry.getFactories(); + for (DataContextFactory factory : defaultFactories) { + registry.addFactory(factory); + } + + // add tenant-specific factories + registry.addFactory(new FederatedDataContextFactory(tenantContext)); + return registry; + } + + @Override + public String toString() { + return "DataContextSupplier[" + dataSourceName + "]"; + } +} http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/4185f5e7/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 60c77ae..b7a2d31 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 @@ -28,17 +28,18 @@ 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.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.app.registry.AbstractDataSourceRegistry; +import org.apache.metamodel.membrane.app.registry.DataContextSupplier; +import org.apache.metamodel.membrane.app.registry.TenantContext; import org.apache.metamodel.membrane.controllers.model.RestDataSourceDefinition; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Strings; -public class FileBasedDataSourceRegistry implements DataSourceRegistry { +public class FileBasedDataSourceRegistry extends AbstractDataSourceRegistry { private static final ObjectMapper OBJECT_MAPPER = JacksonConfig.getObjectMapper(); private static final String DATASOURCE_FILE_SUFFIX = ".json"; @@ -46,7 +47,8 @@ public class FileBasedDataSourceRegistry implements DataSourceRegistry { private final File directory; - public FileBasedDataSourceRegistry(File directory) { + public FileBasedDataSourceRegistry(TenantContext tenantContext, File directory) { + super(tenantContext); this.directory = directory; } @@ -115,7 +117,7 @@ public class FileBasedDataSourceRegistry implements DataSourceRegistry { } final DataContextSupplier supplier = - new DataContextSupplier(dataSourceName, dataSource.toDataContextProperties()); + createDataContextSupplier(dataSourceName, dataSource.toDataContextProperties()); return supplier.get(); } @@ -134,9 +136,4 @@ public class FileBasedDataSourceRegistry implements DataSourceRegistry { throw new UncheckedIOException(new IOException("Unable to delete file: " + file)); } } - - 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/4185f5e7/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 d830125..7e64d3d 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 @@ -31,7 +31,8 @@ class FileBasedTenantContext implements TenantContext { public FileBasedTenantContext(File directory) { this.directory = directory; - this.dataContextRegistry = new CachedDataSourceRegistryWrapper(new FileBasedDataSourceRegistry(directory)); + this.dataContextRegistry = + new CachedDataSourceRegistryWrapper(new FileBasedDataSourceRegistry(this, directory)); } @Override http://git-wip-us.apache.org/repos/asf/metamodel-membrane/blob/4185f5e7/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 index a457ec0..bff3a73 100644 --- 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 @@ -26,16 +26,17 @@ 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; +import org.apache.metamodel.membrane.app.registry.AbstractDataSourceRegistry; +import org.apache.metamodel.membrane.app.registry.TenantContext; -public class InMemoryDataSourceRegistry implements DataSourceRegistry { +public class InMemoryDataSourceRegistry extends AbstractDataSourceRegistry { private final Map<String, Supplier<DataContext>> dataSources; - public InMemoryDataSourceRegistry() { + public InMemoryDataSourceRegistry(final TenantContext tenantContext) { + super(tenantContext); dataSources = new LinkedHashMap<>(); } @@ -46,7 +47,7 @@ public class InMemoryDataSourceRegistry implements DataSourceRegistry { throw new DataSourceAlreadyExistException(name); } - dataSources.put(name, new DataContextSupplier(name, dataContextProperties)); + dataSources.put(name, createDataContextSupplier(name, dataContextProperties)); return name; } @@ -71,9 +72,4 @@ public class InMemoryDataSourceRegistry implements DataSourceRegistry { } 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/4185f5e7/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 index 08b2fa9..330f3b4 100644 --- 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 @@ -29,7 +29,7 @@ public class InMemoryTenantContext implements TenantContext { public InMemoryTenantContext(String tenantIdentifier) { this.tenantIdentifier = tenantIdentifier; - this.dataContextRegistry = new CachedDataSourceRegistryWrapper(new InMemoryDataSourceRegistry()); + this.dataContextRegistry = new CachedDataSourceRegistryWrapper(new InMemoryDataSourceRegistry(this)); } @Override