/** * Copyright 2016 Hortonworks. * * 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.hortonworks.registries.webservice; import com.hortonworks.registries.auth.server.AuthenticationFilter; import com.hortonworks.registries.common.GenericExceptionMapper; import com.hortonworks.registries.common.ServletFilterConfiguration; import io.dropwizard.assets.AssetsBundle; import com.hortonworks.registries.common.FileStorageConfiguration; import com.hortonworks.registries.common.HAConfiguration; import com.hortonworks.registries.common.ModuleConfiguration; import com.hortonworks.registries.common.ModuleRegistration; import com.hortonworks.registries.common.ha.LeadershipAware; import com.hortonworks.registries.common.ha.LeadershipParticipant; import com.hortonworks.registries.common.ha.LocalLeader; import com.hortonworks.registries.common.util.FileStorage; import com.hortonworks.registries.storage.StorageManager; import com.hortonworks.registries.storage.StorageManagerAware; import com.hortonworks.registries.storage.StorageProviderConfiguration; import io.dropwizard.Application; import io.dropwizard.assets.AssetsBundle; import io.dropwizard.lifecycle.ServerLifecycleListener; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import io.federecio.dropwizard.swagger.SwaggerBundle; import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlets.CrossOriginFilter; import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterRegistration; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicReference; /** * */ public class RegistryApplication extends Application<RegistryConfiguration> { private static final Logger LOG = LoggerFactory.getLogger(RegistryApplication.class); protected AtomicReference<LeadershipParticipant> leadershipParticipantRef = new AtomicReference<>(); @Override public void run(RegistryConfiguration registryConfiguration, Environment environment) throws Exception { // handle HA if it is configured registerHA(registryConfiguration.getHaConfig(), environment); registerResources(environment, registryConfiguration); environment.jersey().register(GenericExceptionMapper.class); if (registryConfiguration.isEnableCors()) { enableCORS(environment); } addServletFilters(registryConfiguration, environment); } private void registerHA(HAConfiguration haConfiguration, Environment environment) throws Exception { if(haConfiguration != null) { environment.lifecycle().addServerLifecycleListener(new ServerLifecycleListener() { @Override public void serverStarted(Server server) { String serverUrl = server.getURI().toString(); LOG.info("Received callback as server is started with server URL:[{}]", server); LOG.info("HA configuration: [{}]", haConfiguration); String className = haConfiguration.getClassName(); LeadershipParticipant leadershipParticipant = null; try { leadershipParticipant = (LeadershipParticipant) Class.forName(className).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { throw new RuntimeException(e); } leadershipParticipant.init(haConfiguration.getConfig(), serverUrl); leadershipParticipantRef.set(leadershipParticipant); LOG.info("Registering for leadership with participant [{}]", leadershipParticipant); try { leadershipParticipantRef.get().participateForLeadership(); } catch (Exception e) { LOG.error("Error occurred while participating for leadership with serverUrl [{}]", serverUrl, e); throw new RuntimeException(e); } LOG.info("Registered for leadership with participant [{}]", leadershipParticipant); } }); } else { leadershipParticipantRef.set(LocalLeader.getInstance()); LOG.info("No HA configuration exists, using [{}]", leadershipParticipantRef); } } @Override public String getName() { return "Schema Registry"; } @Override public void initialize(Bootstrap<RegistryConfiguration> bootstrap) { bootstrap.addBundle(new AssetsBundle("/assets", "/", "index.html", "static")); bootstrap.addBundle(new SwaggerBundle<RegistryConfiguration>() { @Override protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(RegistryConfiguration registryConfiguration) { return registryConfiguration.getSwaggerBundleConfiguration(); } }); super.initialize(bootstrap); } private void registerResources(Environment environment, RegistryConfiguration registryConfiguration) throws ClassNotFoundException, IllegalAccessException, InstantiationException { StorageManager storageManager = getStorageManager(registryConfiguration.getStorageProviderConfiguration()); FileStorage fileStorage = getJarStorage(registryConfiguration.getFileStorageConfiguration()); List<ModuleConfiguration> modules = registryConfiguration.getModules(); List<Object> resourcesToRegister = new ArrayList<>(); for (ModuleConfiguration moduleConfiguration : modules) { String moduleName = moduleConfiguration.getName(); String moduleClassName = moduleConfiguration.getClassName(); LOG.info("Registering module [{}] with class [{}]", moduleName, moduleClassName); ModuleRegistration moduleRegistration = (ModuleRegistration) Class.forName(moduleClassName).newInstance(); if (moduleConfiguration.getConfig() == null) { moduleConfiguration.setConfig(new HashMap<String, Object>()); } moduleRegistration.init(moduleConfiguration.getConfig(), fileStorage); if (moduleRegistration instanceof StorageManagerAware) { LOG.info("Module [{}] is StorageManagerAware and setting StorageManager.", moduleName); StorageManagerAware storageManagerAware = (StorageManagerAware) moduleRegistration; storageManagerAware.setStorageManager(storageManager); } if(moduleRegistration instanceof LeadershipAware) { LOG.info("Module [{}] is registered for LeadershipParticipant registration."); LeadershipAware leadershipAware = (LeadershipAware) moduleRegistration; leadershipAware.setLeadershipParticipant(leadershipParticipantRef); } resourcesToRegister.addAll(moduleRegistration.getResources()); } LOG.info("Registering resources to Jersey environment: [{}]", resourcesToRegister); for (Object resource : resourcesToRegister) { environment.jersey().register(resource); } environment.jersey().register(MultiPartFeature.class); } private void enableCORS(Environment environment) { // Enable CORS headers final FilterRegistration.Dynamic cors = environment.servlets().addFilter("CORS", CrossOriginFilter.class); // Configure CORS parameters cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*"); cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Authorization,Content-Type,Accept,Origin"); cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "OPTIONS,GET,PUT,POST,DELETE,HEAD"); // Add URL mapping cors.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*"); } private FileStorage getJarStorage(FileStorageConfiguration fileStorageConfiguration) { FileStorage fileStorage = null; if (fileStorageConfiguration.getClassName() != null) try { fileStorage = (FileStorage) Class.forName(fileStorageConfiguration.getClassName(), true, Thread.currentThread().getContextClassLoader()).newInstance(); fileStorage.init(fileStorageConfiguration.getProperties()); } catch (Exception e) { throw new RuntimeException(e); } return fileStorage; } private StorageManager getStorageManager(StorageProviderConfiguration storageProviderConfiguration) { final String providerClass = storageProviderConfiguration.getProviderClass(); StorageManager storageManager; try { storageManager = (StorageManager) Class.forName(providerClass).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { throw new RuntimeException(e); } storageManager.init(storageProviderConfiguration.getProperties()); return storageManager; } private void addServletFilters(RegistryConfiguration registryConfiguration, Environment environment) { List<ServletFilterConfiguration> servletFilterConfigurations = registryConfiguration.getServletFilters(); if (servletFilterConfigurations != null && !servletFilterConfigurations.isEmpty()) { for (ServletFilterConfiguration servletFilterConfiguration: servletFilterConfigurations) { try { FilterRegistration.Dynamic dynamic = environment.servlets().addFilter(servletFilterConfiguration.getClassName(), (Class<? extends Filter>) Class.forName(servletFilterConfiguration.getClassName())); dynamic.setInitParameters(servletFilterConfiguration.getParams()); dynamic.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*"); } catch (Exception e) { LOG.error("Error registering servlet filter {}", servletFilterConfiguration); throw new RuntimeException(e); } } } } public static void main(String[] args) throws Exception { RegistryApplication registryApplication = new RegistryApplication(); registryApplication.run(args); } }