/* * 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 com.qubole.presto.kinesis; import com.facebook.presto.connector.ConnectorId; import com.facebook.presto.spi.ConnectorHandleResolver; import com.facebook.presto.spi.NodeManager; import com.facebook.presto.spi.SchemaTableName; import com.facebook.presto.spi.connector.Connector; import com.facebook.presto.spi.connector.ConnectorContext; import com.facebook.presto.spi.connector.ConnectorFactory; import com.facebook.presto.spi.type.TypeManager; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; import io.airlift.bootstrap.Bootstrap; import io.airlift.json.JsonModule; import io.airlift.log.Logger; import java.util.Map; import java.util.Optional; import java.util.function.Supplier; import static java.util.Objects.requireNonNull; /** * * This factory class creates the KinesisConnector during server start and binds all the dependency * by calling create() method. */ public class KinesisConnectorFactory implements ConnectorFactory { public static final String connectorName = "kinesis"; private static final Logger log = Logger.get(KinesisConnectorFactory.class); private final ClassLoader classLoader; private TypeManager typeManager; private NodeManager nodeManager; private Optional<Supplier<Map<SchemaTableName, KinesisStreamDescription>>> tableDescriptionSupplier = Optional.empty(); private Map<String, String> optionalConfig = ImmutableMap.of(); private Optional<Class<? extends KinesisClientProvider>> altProviderClass = Optional.empty(); private KinesisHandleResolver handleResolver; private Injector injector; KinesisConnectorFactory(ClassLoader classLoader, Optional<Supplier<Map<SchemaTableName, KinesisStreamDescription>>> tableDescriptionSupplier, Map<String, String> optionalConfig, Optional<Class<? extends KinesisClientProvider>> altProviderClass) { this.classLoader = classLoader; this.tableDescriptionSupplier = requireNonNull(tableDescriptionSupplier, "tableDescriptionSupplier is null"); this.optionalConfig = requireNonNull(optionalConfig, "optionalConfig is null"); this.altProviderClass = requireNonNull(altProviderClass, "altProviderClass is null"); this.handleResolver = new KinesisHandleResolver(connectorName); // Explanation: AWS uses a newer version of jackson (2.6.6) than airlift (2.4.4). In order to upgrade // to the latest version of the AWS API, we need to turn this feature off. This can be set // in jvm.properties but trying to make this more foolproof. System.setProperty("com.amazonaws.sdk.disableCbor", "true"); } @Override public String getName() { return connectorName; } @Override public ConnectorHandleResolver getHandleResolver() { return new KinesisHandleResolver(connectorName); } @Override public Connector create(String connectorId, Map<String, String> config, ConnectorContext context) { log.info("In connector factory create method. Connector id: " + connectorId); requireNonNull(connectorId, "connectorId is null"); requireNonNull(config, "config is null"); try { Bootstrap app = new Bootstrap( new JsonModule(), new KinesisConnectorModule(), binder -> { binder.bindConstant().annotatedWith(Names.named("connectorId")).to(connectorId); binder.bind(ConnectorId.class).toInstance(new ConnectorId(connectorId)); binder.bind(TypeManager.class).toInstance(context.getTypeManager()); binder.bind(NodeManager.class).toInstance(context.getNodeManager()); // Note: moved creation from KinesisConnectorModule because connector manager accesses it earlier! binder.bind(KinesisHandleResolver.class).toInstance(new KinesisHandleResolver(connectorName)); // Moved creation here from KinesisConnectorModule to make it easier to parameterize if (altProviderClass.isPresent()) { binder.bind(KinesisClientProvider.class).to(altProviderClass.get()).in(Scopes.SINGLETON); } else { binder.bind(KinesisClientProvider.class).to(KinesisClientManager.class).in(Scopes.SINGLETON); } if (tableDescriptionSupplier.isPresent()) { binder.bind(new TypeLiteral<Supplier<Map<SchemaTableName, KinesisStreamDescription>>>() {}).toInstance(tableDescriptionSupplier.get()); } else { binder.bind(new TypeLiteral<Supplier<Map<SchemaTableName, KinesisStreamDescription>>>() {}).to(KinesisTableDescriptionSupplier.class).in(Scopes.SINGLETON); } } ); this.injector = app.strictConfig() .doNotInitializeLogging() .setRequiredConfigurationProperties(config) .setOptionalConfigurationProperties(optionalConfig) .initialize(); KinesisConnector connector = this.injector.getInstance(KinesisConnector.class); // Register objects for shutdown, at the moment only KinesisTableDescriptionSupplier if (!tableDescriptionSupplier.isPresent()) { // This will shutdown related dependent objects as well: KinesisTableDescriptionSupplier supp = getTableDescSupplier(this.injector); connector.registerShutdownObject(supp); } log.info("Done with injector. Returning the connector itself."); return connector; } catch (Exception e) { throw Throwables.propagate(e); } } /** * Convenience method to get the table description supplier. * * @param inj * @return */ protected KinesisTableDescriptionSupplier getTableDescSupplier(Injector inj) { requireNonNull(inj, "Injector is missing in getTableDescSupplier"); Supplier<Map<SchemaTableName, KinesisStreamDescription>> supplier = inj.getInstance(Key.get(new TypeLiteral<Supplier<Map<SchemaTableName, KinesisStreamDescription>>>() {})); requireNonNull(inj, "Injector cannot find any table description supplier"); return (KinesisTableDescriptionSupplier) supplier; } protected Injector getInjector() { return this.injector; } }