001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.application;
021
022 import org.apache.commons.io.FileUtils;
023 import org.mortbay.jetty.NCSARequestLog;
024 import org.mortbay.jetty.Server;
025 import org.mortbay.jetty.handler.RequestLogHandler;
026 import org.mortbay.jetty.nio.SelectChannelConnector;
027 import org.mortbay.jetty.webapp.WebAppContext;
028 import org.mortbay.thread.QueuedThreadPool;
029 import org.mortbay.xml.XmlConfiguration;
030
031 import java.io.File;
032 import java.io.IOException;
033 import java.net.URISyntaxException;
034 import java.net.URL;
035 import java.util.ArrayList;
036 import java.util.Collection;
037 import java.util.List;
038
039 public class JettyEmbedder {
040
041 private final Server server;
042 private final String host;
043 private final int port;
044 private final String contextPath;
045
046 public JettyEmbedder(String host, int port, String contextPath, URL configurationURL) throws Exception {
047 this.host = host.trim();
048 this.port = port;
049 this.contextPath = contextPath;
050 server = new Server();
051
052 if (configurationURL == null) {
053 configureProgrammatically();
054
055 } else {
056 System.setProperty("jetty.host", this.host);
057 System.setProperty("jetty.port", String.valueOf(port));
058 System.setProperty("jetty.context", contextPath);
059 XmlConfiguration configuration = new XmlConfiguration(configurationURL);
060 configuration.configure(server);
061 }
062 }
063
064 /**
065 * for tests
066 */
067 JettyEmbedder(String host, int port) throws Exception {
068 this(host, port, null, null);
069 }
070
071 public void start() throws Exception {
072 server.start();
073
074 Runtime.getRuntime().addShutdownHook(new Thread() {
075 @Override
076 public void run() {
077 try {
078 server.stop();
079 } catch (Exception e) {
080 System.err.println("Can not stop the Jetty server");
081 e.printStackTrace();
082 }
083 }
084 });
085 }
086
087 private Server configureProgrammatically() throws URISyntaxException, IOException {
088 configureServer();
089 WebAppContext context = new WebAppContext(getPath("/war/sonar-server"), contextPath);
090 server.addHandler(context);
091 return server;
092 }
093
094 public void configureRequestLogs(String filenamePattern) {
095 RequestLogHandler requestLogHandler = new RequestLogHandler();
096 NCSARequestLog requestLog = new NCSARequestLog(filenamePattern);
097 requestLog.setRetainDays(7);
098 requestLog.setAppend(true);
099 requestLog.setExtended(true);
100 requestLog.setLogTimeZone("GMT");
101 requestLogHandler.setRequestLog(requestLog);
102 server.addHandler(requestLogHandler);
103 }
104
105 private void configureServer() throws URISyntaxException {
106 QueuedThreadPool threadPool = new QueuedThreadPool();
107 threadPool.setMinThreads(5);
108 threadPool.setMaxThreads(50);
109 threadPool.setLowThreads(10);
110 server.setThreadPool(threadPool);
111 SelectChannelConnector connector = new SelectChannelConnector();
112 connector.setHost(host);
113 connector.setPort(port);
114 connector.setStatsOn(false);
115 connector.setAcceptors(2);
116 connector.setConfidentialPort(8443);
117 server.addConnector(connector);
118 server.setStopAtShutdown(true);
119 server.setSendServerVersion(false);
120 server.setSendDateHeader(true);
121 server.setGracefulShutdown(1000);
122 }
123
124 final String getPluginsClasspath(String pluginsPathFromClassloader) throws URISyntaxException, IOException {
125 final URL resource = getClass().getResource(pluginsPathFromClassloader);
126 if (resource != null) {
127 File pluginsDir = new File(resource.toURI());
128 List<String> paths = new ArrayList<String>();
129 paths.add(pluginsDir.getCanonicalPath() + System.getProperty("file.separator"));
130
131 Collection<File> files = FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false);
132 if (files != null) {
133 for (File file : files) {
134 paths.add(file.getCanonicalPath());
135 }
136 }
137 return join(paths, ",");
138 }
139 return null;
140 }
141
142 private String join(List<String> paths, String separator) {
143 StringBuilder sb = new StringBuilder();
144 boolean first = true;
145 for (String path : paths) {
146 if (!first) {
147 sb.append(separator);
148 }
149 sb.append(path);
150 first = false;
151 }
152 return sb.toString();
153 }
154
155 private String getPath(String resourcePath) throws URISyntaxException {
156 URL resource = getClass().getResource(resourcePath);
157 if (resource != null) {
158 return resource.toURI().toString();
159 }
160 return null;
161 }
162
163 Server getServer() {
164 return server;
165 }
166
167 @Override
168 public String toString() {
169 return new StringBuilder().append("http://").append(host).append(":").append(port).append(contextPath).toString();
170 }
171 }