Repository: brooklyn-server Updated Branches: refs/heads/master bb8980a08 -> 6303d02a0
Inject WebAppContexts into BrooklynWebServer Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/3762d56a Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/3762d56a Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/3762d56a Branch: refs/heads/master Commit: 3762d56ae6540104dacca7fdad07425d32a9182c Parents: 2e58954 Author: Sam Corbett <sam.corb...@cloudsoftcorp.com> Authored: Tue Feb 9 10:31:36 2016 +0000 Committer: Sam Corbett <sam.corb...@cloudsoftcorp.com> Committed: Tue Feb 9 10:31:36 2016 +0000 ---------------------------------------------------------------------- .../brooklyn/launcher/BrooklynLauncher.java | 17 ++- .../brooklyn/launcher/BrooklynWebServer.java | 90 ++++++--------- .../launcher/WebAppContextProvider.java | 115 +++++++++++++++++++ 3 files changed, 164 insertions(+), 58 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3762d56a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java ---------------------------------------------------------------------- diff --git a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java b/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java index 5fa0dec0..e5d4c01 100644 --- a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java +++ b/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java @@ -28,6 +28,7 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; @@ -144,7 +145,7 @@ public class BrooklynLauncher { private Boolean useHttps = null; private InetAddress bindAddress = null; private InetAddress publicAddress = null; - private Map<String,String> webApps = new LinkedHashMap<String,String>(); + private List<WebAppContextProvider> webApps = new LinkedList<>(); private Map<String, ?> webconsoleFlags = Maps.newLinkedHashMap(); private Boolean skipSecurityFilter = null; @@ -397,7 +398,15 @@ public class BrooklynLauncher { * @param warUrl The URL from which the WAR should be loaded, supporting classpath:// protocol in addition to file:// and http(s)://. */ public BrooklynLauncher webapp(String contextPath, String warUrl) { - webApps.put(contextPath, warUrl); + webApps.add(new WebAppContextProvider(contextPath, warUrl)); + return this; + } + + /** + * @see #webapp(String, String) + */ + public BrooklynLauncher webapp(WebAppContextProvider contextProvider) { + webApps.add(contextProvider); return this; } @@ -809,8 +818,8 @@ public class BrooklynLauncher { if (skipSecurityFilter != Boolean.TRUE) { webServer.setSecurityFilter(BrooklynPropertiesSecurityFilter.class); } - for (Map.Entry<String, String> webapp : webApps.entrySet()) { - webServer.addWar(webapp.getKey(), webapp.getValue()); + for (WebAppContextProvider webapp : webApps) { + webServer.addWar(webapp); } webServer.start(); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3762d56a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java ---------------------------------------------------------------------- diff --git a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java b/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java index 37e2e20..0365c14 100644 --- a/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java +++ b/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java @@ -40,7 +40,6 @@ import javax.servlet.DispatcherType; import org.apache.brooklyn.rest.filter.SwaggerFilter; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.SessionManager; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -160,6 +159,9 @@ public class BrooklynWebServer { @SetFromFlag private Map<String, String> wars = new LinkedHashMap<String, String>(); + // would like to remove wars in favour of this but SetFromFlag means we have no idea where it's used. + private Map<String, WebAppContextProvider> contextProviders = new LinkedHashMap<>(); + @SetFromFlag protected boolean ignoreWebappDeploymentFailures = false; @@ -296,7 +298,12 @@ public class BrooklynWebServer { /** specifies a WAR to use at a given context path (only if server not yet started); * cf deploy(path, url) */ public BrooklynWebServer addWar(String path, String warUrl) { - wars.put(path, warUrl); + contextProviders.put(path, new WebAppContextProvider(path, warUrl)); + return this; + } + + public BrooklynWebServer addWar(WebAppContextProvider contextProvider) { + contextProviders.put(contextProvider.getPath(), contextProvider); return this; } @@ -319,6 +326,7 @@ public class BrooklynWebServer { public BrooklynWebServer addAttribute(String field, Object value) { return setAttribute(field, value); } + /** Specifies an attribute passed to deployed webapps * (in addition to {@link BrooklynServiceAttributes#BROOKLYN_MANAGEMENT_CONTEXT} */ public BrooklynWebServer setAttribute(String field, Object value) { @@ -419,17 +427,19 @@ public class BrooklynWebServer { addShutdownHook(); - MutableMap<String, String> allWars = MutableMap.copyOf(wars); - String rootWar = allWars.remove("/"); - if (rootWar==null) rootWar = war; + MutableMap<String, WebAppContextProvider> allWars = MutableMap.copyOf(contextProviders); + for (Map.Entry<String, String> entry : wars.entrySet()) { + allWars.put(entry.getKey(), new WebAppContextProvider(entry.getKey(), entry.getValue())); + } + + WebAppContextProvider rootWar = allWars.remove("/"); + if (rootWar==null) rootWar = new WebAppContextProvider("/", war); - for (Map.Entry<String, String> entry : allWars.entrySet()) { - String pathSpec = entry.getKey(); - String warUrl = entry.getValue(); - WebAppContext webapp = deploy(pathSpec, warUrl); + for (WebAppContextProvider contextProvider : allWars.values()) { + WebAppContext webapp = deploy(contextProvider); webapp.setTempDirectory(Os.mkdirs(new File(webappTempDir, newTimestampedDirName("war", 8)))); } - rootContext = deploy("/", rootWar); + rootContext = deploy(rootWar); rootContext.setTempDirectory(Os.mkdirs(new File(webappTempDir, "war-root"))); rootContext.addFilter(RequestTaggingFilter.class, "/*", EnumSet.allOf(DispatcherType.class)); @@ -589,50 +599,6 @@ public class BrooklynWebServer { log.debug("Stopped Brooklyn web console at "+root); } - /** serve given WAR at the given pathSpec; if not yet started, it is simply remembered until start; - * if server already running, the context for this WAR is started. - * @return the context created and added as a handler - * (and possibly already started if server is started, - * so be careful with any changes you make to it!) */ - public WebAppContext deploy(final String pathSpec, final String warUrl) { - String cleanPathSpec = pathSpec; - while (cleanPathSpec.startsWith("/")) - cleanPathSpec = cleanPathSpec.substring(1); - boolean isRoot = cleanPathSpec.isEmpty(); - - WebAppContext context = new WebAppContext(); - // use a unique session ID to prevent interference with other web apps on same server (esp for localhost); - // it might be better to make this brooklyn-only or base on the management-plane ID; - // but i think it actually *is* per-server instance, since we don't cache sessions server-side, - // so i think this is write. [Alex 2015-09] - context.setInitParameter(SessionManager.__SessionCookieProperty, SessionManager.__DefaultSessionCookie+"_"+"BROOKLYN"+Identifiers.makeRandomId(6)); - context.setAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT, managementContext); - for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) { - context.setAttribute(attributeEntry.getKey(), attributeEntry.getValue()); - } - - try { - File tmpWarFile = Os.writeToTempFile(new CustomResourceLocator(managementContext.getConfig(), ResourceUtils.create(this)).getResourceFromUrl(warUrl), - isRoot ? "ROOT" : ("embedded-" + cleanPathSpec), ".war"); - context.setWar(tmpWarFile.getAbsolutePath()); - } catch (Exception e) { - log.warn("Failed to deploy webapp "+pathSpec+" from "+warUrl - + (ignoreWebappDeploymentFailures ? "; launching run without WAR" : " (rethrowing)") - + ": "+Exceptions.collapseText(e)); - if (!ignoreWebappDeploymentFailures) { - throw new IllegalStateException("Failed to deploy webapp "+pathSpec+" from "+warUrl+": "+Exceptions.collapseText(e), e); - } - log.debug("Detail on failure to deploy webapp: "+e, e); - context.setWar("/dev/null"); - } - - context.setContextPath("/" + cleanPathSpec); - context.setParentLoaderPriority(true); - - deploy(context); - return context; - } - private Thread shutdownHook = null; protected synchronized void addShutdownHook() { @@ -651,6 +617,22 @@ public class BrooklynWebServer { }); } + public WebAppContext deploy(String pathSpec, String war) { + return deploy(new WebAppContextProvider(pathSpec, war)); + } + + /** + * Serve the given WAR at the given pathSpec. If not yet started, it is remembered until start. + * If the server is already running the context for this WAR is started. + * @return the context created and added as a handler (and possibly already started if server is started, + * so be careful with any changes you make to it!) + */ + public WebAppContext deploy(WebAppContextProvider contextProvider) { + WebAppContext context = contextProvider.get(managementContext, attributes, ignoreWebappDeploymentFailures); + deploy(context); + return context; + } + public void deploy(WebAppContext context) { try { handlers.updateHandler(context); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3762d56a/launcher/src/main/java/org/apache/brooklyn/launcher/WebAppContextProvider.java ---------------------------------------------------------------------- diff --git a/launcher/src/main/java/org/apache/brooklyn/launcher/WebAppContextProvider.java b/launcher/src/main/java/org/apache/brooklyn/launcher/WebAppContextProvider.java new file mode 100644 index 0000000..b6f955d --- /dev/null +++ b/launcher/src/main/java/org/apache/brooklyn/launcher/WebAppContextProvider.java @@ -0,0 +1,115 @@ +/* + * 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.brooklyn.launcher; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.File; +import java.io.InputStream; +import java.util.Map; + +import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.core.server.BrooklynServiceAttributes; +import org.apache.brooklyn.launcher.config.CustomResourceLocator; +import org.apache.brooklyn.util.core.ResourceUtils; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.os.Os; +import org.apache.brooklyn.util.text.Identifiers; +import org.eclipse.jetty.server.SessionManager; +import org.eclipse.jetty.webapp.WebAppContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Creates a {@link WebAppContext} for a web app running in the same Jetty container as + * the main Brooklyn app. + */ +public class WebAppContextProvider { + + private static final Logger LOG = LoggerFactory.getLogger(WebAppContextProvider.class); + + protected final String pathSpec; + protected final String warUrl; + + /** + * @param pathSpec The path at which the war should be served. + * @param warUrl The url from which the war should be obtained. + */ + public WebAppContextProvider(String pathSpec, String warUrl) { + this.warUrl = warUrl; + String cleanPathSpec = pathSpec; + while (cleanPathSpec.startsWith("/")) { + cleanPathSpec = cleanPathSpec.substring(1); + } + this.pathSpec = cleanPathSpec; + } + + /** + * Serve given WAR at the given pathSpec; if not yet started, it is simply remembered until start; + * if server already running, the context for this WAR is started. + * @return the context created and added as a handler (and possibly already started if server is + * started, so be careful with any changes you make to it!) + */ + public WebAppContext get(ManagementContext managementContext, Map<String, Object> attributes, boolean ignoreFailures) { + checkNotNull(managementContext, "managementContext"); + checkNotNull(attributes, "attributes"); + boolean isRoot = pathSpec.isEmpty(); + + final WebAppContext context = new WebAppContext(); + // use a unique session ID to prevent interference with other web apps on same server (esp for localhost); + // it might be better to make this brooklyn-only or base on the management-plane ID; + // but i think it actually *is* per-server instance, since we don't cache sessions server-side, + // so i think this is write. [Alex 2015-09] + context.setInitParameter(SessionManager.__SessionCookieProperty, SessionManager.__DefaultSessionCookie + "_" + "BROOKLYN" + Identifiers.makeRandomId(6)); + context.setAttribute(BrooklynServiceAttributes.BROOKLYN_MANAGEMENT_CONTEXT, managementContext); + for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) { + context.setAttribute(attributeEntry.getKey(), attributeEntry.getValue()); + } + + try { + final CustomResourceLocator locator = new CustomResourceLocator(managementContext.getConfig(), ResourceUtils.create(this)); + final InputStream resource = locator.getResourceFromUrl(warUrl); + final String warName = isRoot ? "ROOT" : ("embedded-" + pathSpec); + File tmpWarFile = Os.writeToTempFile(resource, warName, ".war"); + context.setWar(tmpWarFile.getAbsolutePath()); + } catch (Exception e) { + LOG.warn("Failed to deploy webapp " + pathSpec + " from " + warUrl + + (ignoreFailures ? "; launching run without WAR" : " (rethrowing)") + + ": " + Exceptions.collapseText(e)); + if (!ignoreFailures) { + throw new IllegalStateException("Failed to deploy webapp " + pathSpec + " from " + warUrl + ": " + Exceptions.collapseText(e), e); + } + LOG.debug("Detail on failure to deploy webapp: " + e, e); + context.setWar("/dev/null"); + } + + context.setContextPath("/" + pathSpec); + context.setParentLoaderPriority(true); + + return context; + } + + public String getPath() { + return pathSpec; + } + + public String getWarUrl() { + return warUrl; + } +}