| /* |
| * 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.zeppelin.server; |
| |
| import com.google.gson.Gson; |
| import java.io.File; |
| import java.io.IOException; |
| import java.lang.management.ManagementFactory; |
| import java.nio.file.Files; |
| import java.security.GeneralSecurityException; |
| import java.util.Base64; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.EnumSet; |
| import java.util.Objects; |
| import java.util.stream.Stream; |
| import javax.inject.Inject; |
| import javax.inject.Singleton; |
| import javax.management.remote.JMXServiceURL; |
| import javax.servlet.DispatcherType; |
| import javax.servlet.ServletContextEvent; |
| import javax.servlet.ServletContextListener; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.shiro.web.env.EnvironmentLoaderListener; |
| import org.apache.shiro.web.servlet.ShiroFilter; |
| import org.apache.zeppelin.cluster.ClusterManagerServer; |
| import org.apache.zeppelin.conf.ZeppelinConfiguration; |
| import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; |
| import org.apache.zeppelin.display.AngularObjectRegistryListener; |
| import org.apache.zeppelin.helium.ApplicationEventListener; |
| import org.apache.zeppelin.helium.Helium; |
| import org.apache.zeppelin.helium.HeliumApplicationFactory; |
| import org.apache.zeppelin.helium.HeliumBundleFactory; |
| import org.apache.zeppelin.interpreter.InterpreterFactory; |
| import org.apache.zeppelin.interpreter.InterpreterOutput; |
| import org.apache.zeppelin.interpreter.InterpreterSetting; |
| import org.apache.zeppelin.interpreter.InterpreterSettingManager; |
| import org.apache.zeppelin.interpreter.recovery.RecoveryStorage; |
| import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcessListener; |
| import org.apache.zeppelin.notebook.NoteEventListener; |
| import org.apache.zeppelin.notebook.NoteManager; |
| import org.apache.zeppelin.notebook.Notebook; |
| import org.apache.zeppelin.notebook.AuthorizationService; |
| import org.apache.zeppelin.notebook.Paragraph; |
| import org.apache.zeppelin.notebook.repo.NotebookRepo; |
| import org.apache.zeppelin.notebook.repo.NotebookRepoSync; |
| import org.apache.zeppelin.notebook.scheduler.NoSchedulerService; |
| import org.apache.zeppelin.notebook.scheduler.QuartzSchedulerService; |
| import org.apache.zeppelin.notebook.scheduler.SchedulerService; |
| import org.apache.zeppelin.plugin.PluginManager; |
| import org.apache.zeppelin.rest.exception.WebApplicationExceptionMapper; |
| import org.apache.zeppelin.search.LuceneSearch; |
| import org.apache.zeppelin.search.SearchService; |
| import org.apache.zeppelin.service.*; |
| import org.apache.zeppelin.service.AuthenticationService; |
| import org.apache.zeppelin.socket.ConnectionManager; |
| import org.apache.zeppelin.socket.NotebookServer; |
| import org.apache.zeppelin.user.AuthenticationInfo; |
| import org.apache.zeppelin.user.Credentials; |
| import org.apache.zeppelin.util.ReflectionUtils; |
| import org.apache.zeppelin.utils.PEMImporter; |
| import org.eclipse.jetty.http.HttpVersion; |
| import org.eclipse.jetty.jmx.ConnectorServer; |
| import org.eclipse.jetty.jmx.MBeanContainer; |
| import org.eclipse.jetty.server.ForwardedRequestCustomizer; |
| import org.eclipse.jetty.server.HttpConfiguration; |
| import org.eclipse.jetty.server.HttpConnectionFactory; |
| import org.eclipse.jetty.server.SecureRequestCustomizer; |
| import org.eclipse.jetty.server.Server; |
| import org.eclipse.jetty.server.ServerConnector; |
| import org.eclipse.jetty.server.SslConnectionFactory; |
| import org.eclipse.jetty.server.handler.ContextHandlerCollection; |
| import org.eclipse.jetty.server.session.SessionHandler; |
| import org.eclipse.jetty.servlet.DefaultServlet; |
| import org.eclipse.jetty.servlet.FilterHolder; |
| import org.eclipse.jetty.servlet.ServletHolder; |
| import org.eclipse.jetty.util.ssl.SslContextFactory; |
| import org.eclipse.jetty.util.thread.QueuedThreadPool; |
| import org.eclipse.jetty.util.thread.ThreadPool; |
| import org.eclipse.jetty.webapp.WebAppContext; |
| import org.eclipse.jetty.websocket.servlet.WebSocketServlet; |
| import org.glassfish.hk2.api.Immediate; |
| import org.glassfish.hk2.api.ServiceLocator; |
| import org.glassfish.hk2.api.ServiceLocatorFactory; |
| import org.glassfish.hk2.utilities.ServiceLocatorUtilities; |
| import org.glassfish.hk2.utilities.binding.AbstractBinder; |
| import org.glassfish.jersey.server.ResourceConfig; |
| import org.glassfish.jersey.servlet.ServletProperties; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** Main class of Zeppelin. */ |
| public class ZeppelinServer extends ResourceConfig { |
| private static final Logger LOG = LoggerFactory.getLogger(ZeppelinServer.class); |
| private static final String WEB_APP_CONTEXT_NEXT = "/next"; |
| |
| public static Server jettyWebServer; |
| public static ServiceLocator sharedServiceLocator; |
| |
| private static ZeppelinConfiguration conf; |
| |
| public static void reset() { |
| conf = null; |
| jettyWebServer = null; |
| sharedServiceLocator = null; |
| } |
| |
| @Inject |
| public ZeppelinServer() { |
| InterpreterOutput.limit = conf.getInt(ConfVars.ZEPPELIN_INTERPRETER_OUTPUT_LIMIT); |
| |
| packages("org.apache.zeppelin.rest"); |
| } |
| |
| public static void main(String[] args) throws InterruptedException, IOException { |
| ZeppelinServer.conf = ZeppelinConfiguration.create(); |
| conf.setProperty("args", args); |
| |
| jettyWebServer = setupJettyServer(conf); |
| |
| ContextHandlerCollection contexts = new ContextHandlerCollection(); |
| jettyWebServer.setHandler(contexts); |
| |
| sharedServiceLocator = ServiceLocatorFactory.getInstance().create("shared-locator"); |
| ServiceLocatorUtilities.enableImmediateScope(sharedServiceLocator); |
| ServiceLocatorUtilities.addClasses(sharedServiceLocator, |
| NotebookRepoSync.class, |
| ImmediateErrorHandlerImpl.class); |
| ImmediateErrorHandlerImpl handler = sharedServiceLocator.getService(ImmediateErrorHandlerImpl.class); |
| |
| ServiceLocatorUtilities.bind( |
| sharedServiceLocator, |
| new AbstractBinder() { |
| @Override |
| protected void configure() { |
| Credentials credentials = new Credentials(conf); |
| bindAsContract(InterpreterFactory.class).in(Singleton.class); |
| bindAsContract(NotebookRepoSync.class).to(NotebookRepo.class).in(Immediate.class); |
| bind(LuceneSearch.class).to(SearchService.class).in(Singleton.class); |
| bindAsContract(Helium.class).in(Singleton.class); |
| bind(conf).to(ZeppelinConfiguration.class); |
| bindAsContract(InterpreterSettingManager.class).in(Singleton.class); |
| bindAsContract(InterpreterService.class).in(Singleton.class); |
| bind(credentials).to(Credentials.class); |
| bindAsContract(GsonProvider.class).in(Singleton.class); |
| bindAsContract(WebApplicationExceptionMapper.class).in(Singleton.class); |
| bindAsContract(AdminService.class).in(Singleton.class); |
| bindAsContract(AuthorizationService.class).in(Singleton.class); |
| bindAsContract(ConnectionManager.class).in(Singleton.class); |
| bindAsContract(NoteManager.class).in(Singleton.class); |
| // TODO(jl): Will make it more beautiful |
| if (!StringUtils.isBlank(conf.getShiroPath())) { |
| bind(ShiroAuthenticationService.class).to(AuthenticationService.class).in(Singleton.class); |
| } else { |
| // TODO(jl): Will be added more type |
| bind(NoAuthenticationService.class).to(AuthenticationService.class).in(Singleton.class); |
| } |
| bindAsContract(HeliumBundleFactory.class).in(Singleton.class); |
| bindAsContract(HeliumApplicationFactory.class).in(Singleton.class); |
| bindAsContract(ConfigurationService.class).in(Singleton.class); |
| bindAsContract(NotebookService.class).in(Singleton.class); |
| bindAsContract(JobManagerService.class).in(Singleton.class); |
| bindAsContract(Notebook.class).in(Singleton.class); |
| bindAsContract(NotebookServer.class) |
| .to(AngularObjectRegistryListener.class) |
| .to(RemoteInterpreterProcessListener.class) |
| .to(ApplicationEventListener.class) |
| .to(NoteEventListener.class) |
| .to(WebSocketServlet.class) |
| .in(Singleton.class); |
| if (conf.isZeppelinNotebookCronEnable()) { |
| bind(QuartzSchedulerService.class).to(SchedulerService.class).in(Singleton.class); |
| } else { |
| bind(NoSchedulerService.class).to(SchedulerService.class).in(Singleton.class); |
| } |
| } |
| }); |
| |
| // Multiple Web UI |
| final WebAppContext defaultWebApp = setupWebAppContext(contexts, conf, conf.getString(ConfVars.ZEPPELIN_WAR), conf.getServerContextPath()); |
| final WebAppContext nextWebApp = setupWebAppContext(contexts, conf, conf.getString(ConfVars.ZEPPELIN_ANGULAR_WAR), WEB_APP_CONTEXT_NEXT); |
| |
| initWebApp(defaultWebApp); |
| initWebApp(nextWebApp); |
| // Cluster Manager Server |
| setupClusterManagerServer(sharedServiceLocator); |
| |
| // JMX Enable |
| Stream.of("ZEPPELIN_JMX_ENABLE") |
| .map(System::getenv) |
| .map(Boolean::parseBoolean) |
| .filter(Boolean::booleanValue) |
| .map(jmxEnabled -> "ZEPPELIN_JMX_PORT") |
| .map(System::getenv) |
| .map( |
| portString -> { |
| try { |
| return Integer.parseInt(portString); |
| } catch (Exception e) { |
| return null; |
| } |
| }) |
| .filter(Objects::nonNull) |
| .forEach( |
| port -> { |
| try { |
| MBeanContainer mbeanContainer = |
| new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); |
| jettyWebServer.addEventListener(mbeanContainer); |
| jettyWebServer.addBean(mbeanContainer); |
| |
| JMXServiceURL jmxURL = |
| new JMXServiceURL( |
| String.format( |
| "service:jmx:rmi://0.0.0.0:%d/jndi/rmi://0.0.0.0:%d/jmxrmi", |
| port, port)); |
| ConnectorServer jmxServer = |
| new ConnectorServer(jmxURL, "org.eclipse.jetty.jmx:name=rmiconnectorserver"); |
| jettyWebServer.addBean(jmxServer); |
| |
| // Add JMX Beans |
| // TODO(jl): Need to investigate more about injection and jmx |
| jettyWebServer.addBean( |
| sharedServiceLocator.getService(InterpreterSettingManager.class)); |
| jettyWebServer.addBean(sharedServiceLocator.getService(NotebookServer.class)); |
| |
| LOG.info("JMX Enabled with port: {}", port); |
| } catch (Exception e) { |
| LOG.warn("Error while setting JMX", e); |
| } |
| }); |
| |
| LOG.info("Starting zeppelin server"); |
| try { |
| jettyWebServer.start(); // Instantiates ZeppelinServer |
| List<ErrorData> errorData = handler.waitForAtLeastOneConstructionError(5 * 1000); |
| if(errorData.size() > 0 && errorData.get(0).getThrowable() != null) { |
| throw new Exception(errorData.get(0).getThrowable()); |
| } |
| if (conf.getJettyName() != null) { |
| org.eclipse.jetty.http.HttpGenerator.setJettyVersion(conf.getJettyName()); |
| } |
| } catch (Exception e) { |
| LOG.error("Error while running jettyServer", e); |
| System.exit(-1); |
| } |
| LOG.info("Done, zeppelin server started"); |
| |
| runNoteOnStart(conf); |
| |
| Runtime.getRuntime().addShutdownHook(shutdown(conf)); |
| |
| // Try to get Notebook from ServiceLocator, because Notebook instantiation is lazy, it is |
| // created when user open zeppelin in browser if we don't get it explicitly here. |
| // Lazy loading will cause paragraph recovery and cron job initialization is delayed. |
| Notebook notebook = sharedServiceLocator.getService(Notebook.class); |
| // Try to recover here, don't do it in constructor of Notebook, because it would cause deadlock. |
| notebook.recoveryIfNecessary(); |
| |
| // when zeppelin is started inside of ide (especially for eclipse) |
| // for graceful shutdown, input any key in console window |
| if (System.getenv("ZEPPELIN_IDENT_STRING") == null) { |
| try { |
| System.in.read(); |
| } catch (IOException e) { |
| LOG.error("Exception in ZeppelinServer while main ", e); |
| } |
| System.exit(0); |
| } |
| |
| jettyWebServer.join(); |
| if (!conf.isRecoveryEnabled()) { |
| sharedServiceLocator.getService(InterpreterSettingManager.class).close(); |
| } |
| } |
| |
| private static Thread shutdown(ZeppelinConfiguration conf) { |
| return new Thread( |
| () -> { |
| LOG.info("Shutting down Zeppelin Server ... "); |
| try { |
| if (jettyWebServer != null) { |
| jettyWebServer.stop(); |
| } |
| if (sharedServiceLocator != null) { |
| if (!conf.isRecoveryEnabled()) { |
| sharedServiceLocator.getService(InterpreterSettingManager.class).close(); |
| } |
| sharedServiceLocator.getService(Notebook.class).close(); |
| } |
| Thread.sleep(3000); |
| } catch (Exception e) { |
| LOG.error("Error while stopping servlet container", e); |
| } |
| LOG.info("Bye"); |
| }); |
| } |
| |
| private static Server setupJettyServer(ZeppelinConfiguration conf) { |
| ThreadPool threadPool = |
| new QueuedThreadPool(conf.getInt(ConfVars.ZEPPELIN_SERVER_JETTY_THREAD_POOL_MAX), |
| conf.getInt(ConfVars.ZEPPELIN_SERVER_JETTY_THREAD_POOL_MIN), |
| conf.getInt(ConfVars.ZEPPELIN_SERVER_JETTY_THREAD_POOL_TIMEOUT)); |
| final Server server = new Server(threadPool); |
| initServerConnector(server, conf.getServerPort(), conf.getServerSslPort()); |
| return server; |
| } |
| private static void initServerConnector(Server server, int port, int sslPort) { |
| |
| ServerConnector connector; |
| HttpConfiguration httpConfig = new HttpConfiguration(); |
| httpConfig.addCustomizer(new ForwardedRequestCustomizer()); |
| httpConfig.setSendServerVersion(conf.sendJettyName()); |
| httpConfig.setRequestHeaderSize(conf.getJettyRequestHeaderSize()); |
| if (conf.useSsl()) { |
| LOG.debug("Enabling SSL for Zeppelin Server on port {}", sslPort); |
| httpConfig.setSecureScheme("https"); |
| httpConfig.setSecurePort(sslPort); |
| |
| HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig); |
| httpsConfig.addCustomizer(new SecureRequestCustomizer()); |
| |
| connector = |
| new ServerConnector( |
| server, |
| new SslConnectionFactory(getSslContextFactory(conf), HttpVersion.HTTP_1_1.asString()), |
| new HttpConnectionFactory(httpsConfig)); |
| connector.setPort(sslPort); |
| } else { |
| connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig)); |
| connector.setPort(port); |
| } |
| // Set some timeout options to make debugging easier. |
| int timeout = 1000 * 30; |
| connector.setIdleTimeout(timeout); |
| connector.setHost(conf.getServerAddress()); |
| server.addConnector(connector); |
| } |
| |
| private static void runNoteOnStart(ZeppelinConfiguration conf) throws IOException, InterruptedException { |
| String noteIdToRun = conf.getNotebookRunId(); |
| if (!StringUtils.isEmpty(noteIdToRun)) { |
| LOG.info("Running note {} on start", noteIdToRun); |
| NotebookService notebookService = (NotebookService) ServiceLocatorUtilities.getService( |
| sharedServiceLocator, NotebookService.class.getName()); |
| |
| ServiceContext serviceContext; |
| String base64EncodedJsonSerializedServiceContext = conf.getNotebookRunServiceContext(); |
| if (StringUtils.isEmpty(base64EncodedJsonSerializedServiceContext)) { |
| LOG.info("No service context provided. use ANONYMOUS"); |
| serviceContext = new ServiceContext(AuthenticationInfo.ANONYMOUS, new HashSet<String>() {}); |
| } else { |
| serviceContext = new Gson().fromJson( |
| new String(Base64.getDecoder().decode(base64EncodedJsonSerializedServiceContext)), |
| ServiceContext.class); |
| } |
| |
| boolean success = notebookService.runAllParagraphs(noteIdToRun, null, serviceContext, new ServiceCallback<Paragraph>() { |
| @Override |
| public void onStart(String message, ServiceContext context) throws IOException { |
| } |
| |
| @Override |
| public void onSuccess(Paragraph result, ServiceContext context) throws IOException { |
| } |
| |
| @Override |
| public void onFailure(Exception ex, ServiceContext context) throws IOException { |
| } |
| }); |
| |
| if (conf.getNotebookRunAutoShutdown()) { |
| Thread t = shutdown(conf); |
| t.start(); |
| t.join(); |
| System.exit(success ? 0 : 1); |
| } |
| } |
| } |
| |
| private static void setupNotebookServer( |
| WebAppContext webapp, ZeppelinConfiguration conf, ServiceLocator serviceLocator) { |
| String maxTextMessageSize = conf.getWebsocketMaxTextMessageSize(); |
| final ServletHolder servletHolder = |
| new ServletHolder(serviceLocator.getService(NotebookServer.class)); |
| servletHolder.setInitParameter("maxTextMessageSize", maxTextMessageSize); |
| |
| webapp.addServlet(servletHolder, "/ws/*"); |
| } |
| |
| private static void setupClusterManagerServer(ServiceLocator serviceLocator) { |
| if (conf.isClusterMode()) { |
| LOG.info("Cluster mode is enabled, starting ClusterManagerServer"); |
| ClusterManagerServer clusterManagerServer = ClusterManagerServer.getInstance(conf); |
| |
| NotebookServer notebookServer = serviceLocator.getService(NotebookServer.class); |
| clusterManagerServer.addClusterEventListeners(ClusterManagerServer.CLUSTER_NOTE_EVENT_TOPIC, notebookServer); |
| |
| AuthorizationService authorizationService = serviceLocator.getService(AuthorizationService.class); |
| clusterManagerServer.addClusterEventListeners(ClusterManagerServer.CLUSTER_AUTH_EVENT_TOPIC, authorizationService); |
| |
| InterpreterSettingManager interpreterSettingManager = serviceLocator.getService(InterpreterSettingManager.class); |
| clusterManagerServer.addClusterEventListeners(ClusterManagerServer.CLUSTER_INTP_SETTING_EVENT_TOPIC, interpreterSettingManager); |
| |
| // Since the ClusterInterpreterLauncher is lazy, dynamically generated, So in cluster mode, |
| // when the zeppelin service starts, Create a ClusterInterpreterLauncher object, |
| // This allows the ClusterInterpreterLauncher to listen for cluster events. |
| try { |
| InterpreterSettingManager intpSettingManager = sharedServiceLocator.getService(InterpreterSettingManager.class); |
| RecoveryStorage recoveryStorage = ReflectionUtils.createClazzInstance( |
| conf.getRecoveryStorageClass(), |
| new Class[] {ZeppelinConfiguration.class, InterpreterSettingManager.class}, |
| new Object[] {conf, intpSettingManager}); |
| recoveryStorage.init(); |
| PluginManager.get().loadInterpreterLauncher(InterpreterSetting.CLUSTER_INTERPRETER_LAUNCHER_NAME, recoveryStorage); |
| } catch (IOException e) { |
| LOG.error(e.getMessage(), e); |
| } |
| |
| clusterManagerServer.start(); |
| } else { |
| LOG.info("Cluster mode is disabled"); |
| } |
| } |
| |
| private static SslContextFactory getSslContextFactory(ZeppelinConfiguration conf) { |
| SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); |
| |
| // initialize KeyStore |
| // Check for PEM files |
| if (StringUtils.isNoneBlank(conf.getPemKeyFile(), conf.getPemCertFile())) { |
| setupKeystoreWithPemFiles(sslContextFactory, conf); |
| } else { |
| // Set keystore |
| sslContextFactory.setKeyStorePath(conf.getKeyStorePath()); |
| sslContextFactory.setKeyStoreType(conf.getKeyStoreType()); |
| sslContextFactory.setKeyStorePassword(conf.getKeyStorePassword()); |
| sslContextFactory.setKeyManagerPassword(conf.getKeyManagerPassword()); |
| } |
| |
| // initialize TrustStore |
| if (conf.useClientAuth()) { |
| if (StringUtils.isNotBlank(conf.getPemCAFile())) { |
| setupTruststoreWithPemFiles(sslContextFactory, conf); |
| } else { |
| sslContextFactory.setNeedClientAuth(conf.useClientAuth()); |
| // Set truststore |
| sslContextFactory.setTrustStorePath(conf.getTrustStorePath()); |
| sslContextFactory.setTrustStoreType(conf.getTrustStoreType()); |
| sslContextFactory.setTrustStorePassword(conf.getTrustStorePassword()); |
| } |
| } |
| |
| return sslContextFactory; |
| } |
| |
| private static void setupKeystoreWithPemFiles(SslContextFactory.Server sslContextFactory, ZeppelinConfiguration conf) { |
| File pemKey = new File(conf.getPemKeyFile()); |
| File pemCert = new File(conf.getPemCertFile()); |
| boolean isPemKeyFileReadable = Files.isReadable(pemKey.toPath()); |
| boolean isPemCertFileReadable = Files.isReadable(pemCert.toPath()); |
| if (!isPemKeyFileReadable) { |
| LOG.warn("PEM key file {} is not readable", pemKey); |
| } |
| if (!isPemCertFileReadable) { |
| LOG.warn("PEM cert file {} is not readable", pemCert); |
| } |
| if (isPemKeyFileReadable && isPemCertFileReadable) { |
| try { |
| String password = conf.getPemKeyPassword(); |
| sslContextFactory.setKeyStore(PEMImporter.loadKeyStore(pemCert, pemKey, password)); |
| sslContextFactory.setKeyStoreType("JKS"); |
| sslContextFactory.setKeyStorePassword(password); |
| } catch (IOException | GeneralSecurityException e) { |
| LOG.error("Failed to initialize KeyStore from PEM files", e); |
| } |
| } else { |
| LOG.error("Failed to read PEM files"); |
| } |
| } |
| |
| private static void setupTruststoreWithPemFiles(SslContextFactory.Server sslContextFactory, ZeppelinConfiguration conf) { |
| File pemCa = new File(conf.getPemCAFile()); |
| if (Files.isReadable(pemCa.toPath())) { |
| try { |
| sslContextFactory.setTrustStore(PEMImporter.loadTrustStore(pemCa)); |
| sslContextFactory.setTrustStoreType("JKS"); |
| sslContextFactory.setTrustStorePassword(""); |
| sslContextFactory.setNeedClientAuth(conf.useClientAuth()); |
| } catch (IOException | GeneralSecurityException e) { |
| LOG.error("Failed to initialize TrustStore from PEM CA file", e); |
| } |
| } else { |
| LOG.error("PEM CA file {} is not readable", pemCa); |
| } |
| } |
| |
| private static void setupRestApiContextHandler(WebAppContext webapp, ZeppelinConfiguration conf) { |
| final ServletHolder servletHolder = |
| new ServletHolder(new org.glassfish.jersey.servlet.ServletContainer()); |
| |
| servletHolder.setInitParameter("javax.ws.rs.Application", ZeppelinServer.class.getName()); |
| servletHolder.setName("rest"); |
| servletHolder.setForcedPath("rest"); |
| webapp.setSessionHandler(new SessionHandler()); |
| webapp.addServlet(servletHolder, "/api/*"); |
| |
| String shiroIniPath = conf.getShiroPath(); |
| if (!StringUtils.isBlank(shiroIniPath)) { |
| webapp.setInitParameter("shiroConfigLocations", new File(shiroIniPath).toURI().toString()); |
| webapp |
| .addFilter(ShiroFilter.class, "/api/*", EnumSet.allOf(DispatcherType.class)) |
| .setInitParameter("staticSecurityManagerEnabled", "true"); |
| webapp.addEventListener(new EnvironmentLoaderListener()); |
| } |
| } |
| |
| private static WebAppContext setupWebAppContext( |
| ContextHandlerCollection contexts, ZeppelinConfiguration conf, String warPath, String contextPath) { |
| WebAppContext webApp = new WebAppContext(); |
| webApp.setContextPath(contextPath); |
| LOG.info("warPath is: {}", warPath); |
| File warFile = new File(warPath); |
| if (warFile.isDirectory()) { |
| // Development mode, read from FS |
| // webApp.setDescriptor(warPath+"/WEB-INF/web.xml"); |
| webApp.setResourceBase(warFile.getPath()); |
| webApp.setParentLoaderPriority(true); |
| } else { |
| // use packaged WAR |
| webApp.setWar(warFile.getAbsolutePath()); |
| webApp.setExtractWAR(false); |
| File warTempDirectory = new File(conf.getRelativeDir(ConfVars.ZEPPELIN_WAR_TEMPDIR) + contextPath); |
| warTempDirectory.mkdir(); |
| LOG.info("ZeppelinServer Webapp path: {}", warTempDirectory.getPath()); |
| webApp.setTempDirectory(warTempDirectory); |
| } |
| // Explicit bind to root |
| webApp.addServlet(new ServletHolder(new DefaultServlet()), "/*"); |
| contexts.addHandler(webApp); |
| |
| webApp.addFilter(new FilterHolder(CorsFilter.class), "/*", EnumSet.allOf(DispatcherType.class)); |
| |
| webApp.setInitParameter( |
| "org.eclipse.jetty.servlet.Default.dirAllowed", |
| Boolean.toString(conf.getBoolean(ConfVars.ZEPPELIN_SERVER_DEFAULT_DIR_ALLOWED))); |
| return webApp; |
| } |
| |
| private static void initWebApp(WebAppContext webApp) { |
| webApp.addEventListener( |
| new ServletContextListener() { |
| @Override |
| public void contextInitialized(ServletContextEvent servletContextEvent) { |
| servletContextEvent |
| .getServletContext() |
| .setAttribute(ServletProperties.SERVICE_LOCATOR, sharedServiceLocator); |
| } |
| |
| @Override |
| public void contextDestroyed(ServletContextEvent servletContextEvent) {} |
| }); |
| |
| // Create `ZeppelinServer` using reflection and setup REST Api |
| setupRestApiContextHandler(webApp, conf); |
| |
| // Notebook server |
| setupNotebookServer(webApp, conf, sharedServiceLocator); |
| } |
| } |