/* * 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.camp.server.rest; import java.io.File; import java.io.IOException; import java.util.EnumSet; import javax.servlet.DispatcherType; import org.apache.brooklyn.camp.CampPlatform; import org.apache.brooklyn.camp.server.rest.resource.PlatformRestResource; import org.apache.brooklyn.camp.server.rest.util.DtoFactory; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.net.Networking; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.webapp.WebAppContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Charsets; import com.google.common.io.Files; import com.sun.jersey.api.core.DefaultResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.spi.container.servlet.ServletContainer; import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.ServerConnector; public class CampServer { private static final Logger log = LoggerFactory.getLogger(CampServer.class); public static final String CAMP_PLATFORM_ATTRIBUTE = CampPlatform.class.getCanonicalName(); public static final String DTO_FACTORY = DtoFactory.class.getCanonicalName(); private final CampPlatform platform; private final String uriBase; private DtoFactory dtoFactory; WebAppContext webAppContext; Server server; public CampServer(CampPlatform platform, String uriBase) { this.platform = platform; this.uriBase = uriBase; } public CampPlatform getPlatform() { return platform; } public String getUriBase() { return uriBase; } public WebAppContext getWebAppContext() { return webAppContext; } public synchronized DtoFactory getDtoFactory() { if (dtoFactory!=null) return dtoFactory; dtoFactory = createDtoFactory(); return dtoFactory; } protected DtoFactory createDtoFactory() { return new DtoFactory(getPlatform(), getUriBase()); } public synchronized CampServer start() { if (webAppContext!=null) throw new IllegalStateException("Already started"); webAppContext = new WebAppContext(); webAppContext.setContextPath("/"); webAppContext.setAttribute(CAMP_PLATFORM_ATTRIBUTE, getPlatform()); webAppContext.setAttribute(DTO_FACTORY, getDtoFactory()); webAppContext.setWar( // TODO if there is a GUI or other war... //findJsguiWebapp()!=null ? findJsguiWebapp() : CampServerUtils.createTempWebDirWithIndexHtml("CAMP REST API <p> (no gui available - " + "rest endpoint at <a href=\""+PlatformRestResource.CAMP_URI_PATH+"\">"+PlatformRestResource.CAMP_URI_PATH+"</a>)")); CampServerUtils.installAsServletFilter(webAppContext); server = CampServerUtils.startServer(webAppContext, "CAMP server"); return this; } public synchronized void stop() { try { server.stop(); server = null; webAppContext.stop(); webAppContext = null; } catch (Exception e) { throw Exceptions.propagate(e); } } public Integer getPort() { if (server==null) return null; NetworkConnector networkConnector = (NetworkConnector) server.getConnectors()[0]; return networkConnector.getLocalPort(); } public static class CampServerUtils { public static void installAsServletFilter(ServletContextHandler context) { // TODO security // installBrooklynPropertiesSecurityFilter(context); // now set up the REST servlet resources ResourceConfig config = new DefaultResourceConfig(); // load all our REST API modules, JSON, and Swagger for (Object r: CampRestResources.getAllResources()) config.getSingletons().add(r); // configure to match empty path, or any thing which looks like a file path with /assets/ and extension html, css, js, or png // and treat that as static content config.getProperties().put(ServletContainer.PROPERTY_WEB_PAGE_CONTENT_REGEX, "(/?|[^?]*/assets/[^?]+\\.[A-Za-z0-9_]+)"); // and anything which is not matched as a servlet also falls through (but more expensive than a regex check?) config.getFeatures().put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true); // finally create this as a _filter_ which falls through to a web app or something (optionally) FilterHolder filterHolder = new FilterHolder(new ServletContainer(config)); context.addFilter(filterHolder, "/*", EnumSet.allOf(DispatcherType.class)); } public static Server startServer(ContextHandler context, String summary) { // FIXME port hardcoded int port = Networking.nextAvailablePort(8080); // use a nice name in the thread pool (otherwise this is exactly the same as Server defaults) QueuedThreadPool threadPool = new QueuedThreadPool(); threadPool.setName("camp-jetty-server-"+port+"-"+threadPool.getName()); Server server = new Server(threadPool); ServerConnector httpConnector = new ServerConnector(server); httpConnector.setPort(port); server.addConnector(httpConnector); server.setHandler(context); try { server.start(); } catch (Exception e) { throw Exceptions.propagate(e); } log.info("CAMP REST server started ("+summary+") on"); log.info(" http://localhost:"+httpConnector.getLocalPort()+"/"); return server; } /** create a directory with a simple index.html so we have some content being served up */ public static String createTempWebDirWithIndexHtml(String indexHtmlContent) { File dir = Files.createTempDir(); dir.deleteOnExit(); try { Files.write(indexHtmlContent, new File(dir, "index.html"), Charsets.UTF_8); } catch (IOException e) { Exceptions.propagate(e); } return dir.getAbsolutePath(); } } }