/**
* Copyright 2015 StreamSets Inc.
*
* Licensed under 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 com.streamsets.datacollector.http;
import com.codahale.metrics.JmxReporter;
import com.codahale.metrics.MetricRegistry;
import com.streamsets.datacollector.bundles.SupportBundleManager;
import com.streamsets.datacollector.execution.EventListenerManager;
import com.streamsets.datacollector.execution.Manager;
import com.streamsets.datacollector.main.BuildInfo;
import com.streamsets.datacollector.main.RuntimeInfo;
import com.streamsets.datacollector.main.UserGroupManager;
import com.streamsets.datacollector.publicrestapi.PublicRestAPI;
import com.streamsets.datacollector.restapi.RestAPI;
import com.streamsets.datacollector.restapi.configuration.AclStoreInjector;
import com.streamsets.datacollector.restapi.configuration.BuildInfoInjector;
import com.streamsets.datacollector.restapi.configuration.ConfigurationInjector;
import com.streamsets.datacollector.restapi.configuration.PipelineStoreInjector;
import com.streamsets.datacollector.restapi.configuration.RestAPIResourceConfig;
import com.streamsets.datacollector.restapi.configuration.RuntimeInfoInjector;
import com.streamsets.datacollector.restapi.configuration.StageLibraryInjector;
import com.streamsets.datacollector.restapi.configuration.StandAndClusterManagerInjector;
import com.streamsets.datacollector.restapi.configuration.SupportBundleInjector;
import com.streamsets.datacollector.restapi.configuration.UserGroupManagerInjector;
import com.streamsets.datacollector.stagelibrary.StageLibraryTask;
import com.streamsets.datacollector.store.AclStoreTask;
import com.streamsets.datacollector.store.PipelineStoreTask;
import com.streamsets.datacollector.task.TaskWrapper;
import com.streamsets.datacollector.util.Configuration;
import com.streamsets.datacollector.websockets.SDCWebSocketServlet;
import com.streamsets.lib.security.http.CORSConstants;
import com.streamsets.pipeline.http.MDCFilter;
import dagger.Module;
import dagger.Provides;
import dagger.Provides.Type;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;
import javax.servlet.DispatcherType;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Module(injects = {TaskWrapper.class, Manager.class}, library = true, complete = false)
public class WebServerModule {
private final Manager mgr;
public WebServerModule(Manager pipelineManager) {
mgr = pipelineManager;
}
@Provides
public Manager provideManager() {
return mgr;
}
private final String SWAGGER_PACKAGE = "io.swagger.jaxrs.listing";
@Provides(type = Type.SET_VALUES)
Set<WebAppProvider> provideWebApps() {
return Collections.emptySet();
}
@Provides(type = Type.SET)
ContextConfigurator provideStaticWeb(final RuntimeInfo runtimeInfo) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
ServletHolder servlet = new ServletHolder(new DefaultServlet());
servlet.setInitParameter("dirAllowed", "true");
servlet.setInitParameter("resourceBase", runtimeInfo.getStaticWebDir());
servlet.setInitParameter("cacheControl","max-age=0,public");
context.addServlet(servlet, "/*");
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideMesosDir(final RuntimeInfo runtimeInfo) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
ServletHolder servlet = new ServletHolder(new DefaultServlet());
// can't allow listing of dir as mesos dir will be hosting the jar file
servlet.setInitParameter("dirAllowed", "false");
servlet.setInitParameter("resourceBase", runtimeInfo.getDataDir());
context.addServlet(servlet, "/mesos/*");
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideGzipHandler() {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setGzipHandler(new GzipHandler());
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideMDCFilter() {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
FilterHolder filter = new FilterHolder(new MDCFilter());
context.addFilter(filter, "/*", EnumSet.of(DispatcherType.REQUEST));
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideLocaleDetector() {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
FilterHolder filter = new FilterHolder(new LocaleDetectorFilter());
context.addFilter(filter, "/rest/*", EnumSet.of(DispatcherType.REQUEST));
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideJMX(final MetricRegistry metrics) {
return new ContextConfigurator() {
private JmxReporter reporter;
@Override
public void init(ServletContextHandler context) {
context.setAttribute("com.codahale.metrics.servlets.MetricsServlet.registry", metrics);
ServletHolder servlet = new ServletHolder(new JMXJsonServlet());
context.addServlet(servlet, "/rest/v1/system/jmx");
}
@Override
public void start() {
reporter = JmxReporter.forRegistry(metrics).build();
reporter.start();
}
@Override
public void stop() {
if(reporter != null) {
reporter.stop();
reporter.close();
}
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideLoginServlet() {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
ServletHolder holderEvents = new ServletHolder(new LoginServlet());
context.addServlet(holderEvents, "/login");
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideCrossOriginFilter(final Configuration conf) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
FilterHolder crossOriginFilter = new FilterHolder(CrossOriginFilter.class);
Map<String, String> params = new HashMap<>();
params.put(CrossOriginFilter.ALLOWED_ORIGINS_PARAM,
conf.get(CORSConstants.HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
CORSConstants.HTTP_ACCESS_CONTROL_ALLOW_ORIGIN_DEFAULT));
params.put(CrossOriginFilter.ALLOWED_METHODS_PARAM,
conf.get(CORSConstants.HTTP_ACCESS_CONTROL_ALLOW_METHODS,
CORSConstants.HTTP_ACCESS_CONTROL_ALLOW_METHODS_DEFAULT));
params.put(CrossOriginFilter.ALLOWED_HEADERS_PARAM,
conf.get(CORSConstants.HTTP_ACCESS_CONTROL_ALLOW_HEADERS,
CORSConstants.HTTP_ACCESS_CONTROL_ALLOW_HEADERS_DEFAULT));
crossOriginFilter.setInitParameters(params);
context.addFilter(crossOriginFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideWebSocketServlet(final Configuration configuration, final RuntimeInfo runtimeInfo,
final EventListenerManager eventListenerManager) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
ServletHolder holderEvents = new ServletHolder(new SDCWebSocketServlet(configuration, runtimeInfo,
eventListenerManager));
context.addServlet(holderEvents, "/rest/v1/webSocket");
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideNoAuthenticationRoles(final Configuration configuration, final RuntimeInfo runtimeInfo) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
if (configuration.get(WebServerTask.AUTHENTICATION_KEY, WebServerTask.AUTHENTICATION_DEFAULT).equals("none") &&
!runtimeInfo.isDPMEnabled()) {
FilterHolder filter = new FilterHolder(new AlwaysAllRolesFilter());
context.addFilter(filter, "/*", EnumSet.of(DispatcherType.REQUEST));
}
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideJersey() {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
// REST API that requires authentication
ServletHolder protectedRest = new ServletHolder(new ServletContainer());
protectedRest.setInitParameter(
ServerProperties.PROVIDER_PACKAGES, SWAGGER_PACKAGE + "," +
RestAPI.class.getPackage().getName()
);
protectedRest.setInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, RestAPIResourceConfig.class.getName());
context.addServlet(protectedRest, "/rest/*");
// REST API that it does not require authentication
ServletHolder publicRest = new ServletHolder(new ServletContainer());
publicRest.setInitParameter(ServerProperties.PROVIDER_PACKAGES, PublicRestAPI.class.getPackage().getName());
publicRest.setInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, RestAPIResourceConfig.class.getName());
context.addServlet(publicRest, "/public-rest/*");
}
};
}
@Provides(type = Type.SET)
ContextConfigurator providePipelineStore(final PipelineStoreTask pipelineStore) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(PipelineStoreInjector.PIPELINE_STORE, pipelineStore);
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideAclStore(final AclStoreTask aclStore) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(AclStoreInjector.ACL_STORE, aclStore);
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideSupportBundleManager(final SupportBundleManager supportBundleManager) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(SupportBundleInjector.SUPPORT_BUNDLE_MANAGER, supportBundleManager);
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideStageLibrary(final StageLibraryTask stageLibrary) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(StageLibraryInjector.STAGE_LIBRARY, stageLibrary);
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideConfiguration(final Configuration configuration) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(ConfigurationInjector.CONFIGURATION, configuration);
}
};
}
@Provides(type = Type.SET)
ContextConfigurator providePipelineStateManager(final Manager pipelineManager) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(StandAndClusterManagerInjector.PIPELINE_MANAGER_MGR, pipelineManager);
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideRuntimeInfo(final RuntimeInfo runtimeInfo) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(RuntimeInfoInjector.RUNTIME_INFO, runtimeInfo);
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideBuildInfo(final BuildInfo buildInfo) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(BuildInfoInjector.BUILD_INFO, buildInfo);
}
};
}
@Provides(type = Type.SET)
ContextConfigurator provideUserGroupManager(final UserGroupManager userGroupManager) {
return new ContextConfigurator() {
@Override
public void init(ServletContextHandler context) {
context.setAttribute(UserGroupManagerInjector.USER_GROUP_MANAGER, userGroupManager);
}
};
}
}