| // ======================================================================== |
| // Copyright (c) Webtide LLC |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.apache.org/licenses/LICENSE-2.0.txt |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| |
| package org.eclipse.jetty.deploy.test; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.PrintStream; |
| import java.net.InetAddress; |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.net.UnknownHostException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Properties; |
| |
| import org.eclipse.jetty.deploy.DeploymentManager; |
| import org.eclipse.jetty.http.HttpSchemes; |
| import org.eclipse.jetty.server.Connector; |
| import org.eclipse.jetty.server.Handler; |
| import org.eclipse.jetty.server.Server; |
| import org.eclipse.jetty.server.handler.AbstractHandler; |
| import org.eclipse.jetty.server.handler.HandlerCollection; |
| import org.eclipse.jetty.util.IO; |
| import org.eclipse.jetty.webapp.WebAppContext; |
| import org.eclipse.jetty.xml.XmlConfiguration; |
| import org.junit.Assert; |
| |
| /** |
| * Allows for setting up a Jetty server for testing based on XML configuration files. |
| */ |
| public class XmlConfiguredJetty |
| { |
| private List<URL> xmlConfigurations; |
| private Properties properties = new Properties(); |
| private Server server; |
| private int serverPort; |
| private String scheme = HttpSchemes.HTTP; |
| private File jettyHome; |
| |
| public XmlConfiguredJetty() throws IOException |
| { |
| String testname = new Throwable().getStackTrace()[1].getClassName(); |
| |
| xmlConfigurations = new ArrayList<URL>(); |
| properties = new Properties(); |
| |
| jettyHome = MavenTestingUtils.getTargetTestingDir(testname); |
| deleteContents(jettyHome); // Ensure that we are working with a pristene directory |
| // Prepare Jetty.Home (Test) dir |
| jettyHome.mkdirs(); |
| |
| File logsDir = new File(jettyHome,"logs"); |
| logsDir.mkdirs(); |
| |
| File etcDir = new File(jettyHome,"etc"); |
| etcDir.mkdirs(); |
| IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/realm.properties"),new File(etcDir,"realm.properties")); |
| IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/webdefault.xml"),new File(etcDir,"webdefault.xml")); |
| |
| File contextsDir = new File(jettyHome,"contexts"); |
| if (contextsDir.exists()) |
| { |
| deleteContents(contextsDir); |
| } |
| contextsDir.mkdirs(); |
| File webappsDir = new File(jettyHome,"webapps"); |
| if (webappsDir.exists()) |
| { |
| deleteContents(webappsDir); |
| } |
| webappsDir.mkdirs(); |
| File tmpDir = new File(jettyHome,"tmp"); |
| tmpDir.mkdirs(); |
| |
| // Setup properties |
| System.setProperty("java.io.tmpdir",tmpDir.getAbsolutePath()); |
| properties.setProperty("jetty.home",jettyHome.getAbsolutePath()); |
| System.setProperty("jetty.home",jettyHome.getAbsolutePath()); |
| properties.setProperty("test.basedir",MavenTestingUtils.getBasedir().getAbsolutePath()); |
| properties.setProperty("test.resourcesdir",MavenTestingUtils.getTestResourcesDir().getAbsolutePath()); |
| properties.setProperty("test.webapps",webappsDir.getAbsolutePath()); |
| properties.setProperty("test.targetdir",MavenTestingUtils.getTargetDir().getAbsolutePath()); |
| |
| // Write out configuration for use by ConfigurationManager. |
| File testConfig = MavenTestingUtils.getTargetFile("xml-configured-jetty.properties"); |
| FileOutputStream out = new FileOutputStream(testConfig); |
| properties.store(out,"Generated by " + XmlConfiguredJetty.class.getName()); |
| } |
| |
| public void addConfiguration(File xmlConfigFile) throws MalformedURLException |
| { |
| xmlConfigurations.add(xmlConfigFile.toURI().toURL()); |
| } |
| |
| public void addConfiguration(String testConfigName) throws MalformedURLException |
| { |
| addConfiguration(MavenTestingUtils.getTestResourceFile(testConfigName)); |
| } |
| |
| public void addConfiguration(URL xmlConfig) |
| { |
| xmlConfigurations.add(xmlConfig); |
| } |
| |
| public void assertNoWebAppContexts() |
| { |
| List<WebAppContext> contexts = getWebAppContexts(); |
| if (contexts.size() > 0) |
| { |
| for (WebAppContext context : contexts) |
| { |
| System.out.println("WebAppContext should not exist:\n" + toString(context)); |
| } |
| Assert.assertEquals("Contexts.size",0,contexts.size()); |
| } |
| } |
| |
| public String getResponse(String path) throws IOException |
| { |
| URI destUri = getServerURI().resolve(path); |
| URL url = destUri.toURL(); |
| |
| URLConnection conn = url.openConnection(); |
| |
| InputStream in = null; |
| try |
| { |
| in = conn.getInputStream(); |
| return IO.toString(in); |
| } |
| finally |
| { |
| IO.close(in); |
| } |
| } |
| |
| public void assertResponseContains(String path, String needle) throws IOException |
| { |
| System.out.println("Issuing request to " + path); |
| String content = getResponse(path); |
| Assert.assertTrue("Content should contain <" + needle + ">, instead got <" + content + ">",content.contains(needle)); |
| } |
| |
| public void assertWebAppContextsExists(String... expectedContextPaths) |
| { |
| List<WebAppContext> contexts = getWebAppContexts(); |
| if (expectedContextPaths.length != contexts.size()) |
| { |
| System.out.println("## Expected Contexts"); |
| for (String expected : expectedContextPaths) |
| { |
| System.out.println(expected); |
| } |
| System.out.println("## Actual Contexts"); |
| for (WebAppContext context : contexts) |
| { |
| System.out.printf("%s ## %s%n",context.getContextPath(),context); |
| } |
| Assert.assertEquals("Contexts.size",expectedContextPaths.length,contexts.size()); |
| } |
| |
| for (String expectedPath : expectedContextPaths) |
| { |
| boolean found = false; |
| for (WebAppContext context : contexts) |
| { |
| if (context.getContextPath().equals(expectedPath)) |
| { |
| found = true; |
| break; |
| } |
| } |
| Assert.assertTrue("Did not find Expected Context Path " + expectedPath,found); |
| } |
| } |
| |
| public void copyContext(String srcName, String destName) throws IOException |
| { |
| System.out.printf("Copying Context: %s -> %s%n",srcName,destName); |
| File srcDir = MavenTestingUtils.getTestResourceDir("contexts"); |
| File destDir = new File(jettyHome,"contexts"); |
| |
| File srcFile = new File(srcDir,srcName); |
| File destFile = new File(destDir,destName); |
| |
| copyFile("Context",srcFile,destFile); |
| } |
| |
| private void copyFile(String type, File srcFile, File destFile) throws IOException |
| { |
| PathAssert.assertFileExists(type + " File",srcFile); |
| IO.copyFile(srcFile,destFile); |
| PathAssert.assertFileExists(type + " File",destFile); |
| System.out.printf("Copy %s: %s%n To %s: %s%n",type,srcFile,type,destFile); |
| System.out.printf("Destination Exists: %s - %s%n",destFile.exists(),destFile); |
| } |
| |
| public void copyWebapp(String srcName, String destName) throws IOException |
| { |
| System.out.printf("Copying Webapp: %s -> %s%n",srcName,destName); |
| File srcDir = MavenTestingUtils.getTestResourceDir("webapps"); |
| File destDir = new File(jettyHome,"webapps"); |
| |
| File srcFile = new File(srcDir,srcName); |
| File destFile = new File(destDir,destName); |
| |
| copyFile("Webapp",srcFile,destFile); |
| } |
| |
| private void deleteContents(File dir) |
| { |
| System.out.printf("Delete (dir) %s/%n",dir); |
| for (File file : dir.listFiles()) |
| { |
| // Safety measure. only recursively delete within target directory. |
| if (file.isDirectory() && file.getAbsolutePath().contains("target" + File.separator)) |
| { |
| deleteContents(file); |
| Assert.assertTrue("Delete failed: " + file.getAbsolutePath(),file.delete()); |
| } |
| else |
| { |
| System.out.printf("Delete (file) %s%n",file); |
| Assert.assertTrue("Delete failed: " + file.getAbsolutePath(),file.delete()); |
| } |
| } |
| } |
| |
| public DeploymentManager getActiveDeploymentManager() |
| { |
| List<DeploymentManager> depmans = server.getBeans(DeploymentManager.class); |
| Assert.assertEquals("DeploymentManager bean count",1,depmans.size()); |
| return depmans.get(0); |
| } |
| |
| public File getJettyDir(String name) |
| { |
| return new File(jettyHome,name); |
| } |
| |
| public File getJettyHome() |
| { |
| return jettyHome; |
| } |
| |
| public String getScheme() |
| { |
| return scheme; |
| } |
| |
| public Server getServer() |
| { |
| return server; |
| } |
| |
| public int getServerPort() |
| { |
| return serverPort; |
| } |
| |
| public URI getServerURI() throws UnknownHostException |
| { |
| StringBuffer uri = new StringBuffer(); |
| uri.append(this.scheme).append("://"); |
| uri.append(InetAddress.getLocalHost().getHostAddress()); |
| uri.append(":").append(this.serverPort); |
| return URI.create(uri.toString()); |
| } |
| |
| public List<WebAppContext> getWebAppContexts() |
| { |
| List<WebAppContext> contexts = new ArrayList<WebAppContext>(); |
| HandlerCollection handlers = (HandlerCollection)server.getHandler(); |
| System.out.println(server.dump()); |
| Handler children[] = handlers.getChildHandlers(); |
| |
| for (Handler handler : children) |
| { |
| if (handler instanceof WebAppContext) |
| { |
| WebAppContext context = (WebAppContext)handler; |
| contexts.add(context); |
| } |
| } |
| |
| return contexts; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public void load() throws Exception |
| { |
| XmlConfiguration last = null; |
| Object[] obj = new Object[this.xmlConfigurations.size()]; |
| |
| // Configure everything |
| for (int i = 0; i < this.xmlConfigurations.size(); i++) |
| { |
| URL configURL = this.xmlConfigurations.get(i); |
| XmlConfiguration configuration = new XmlConfiguration(configURL); |
| if (last != null) |
| { |
| configuration.getIdMap().putAll(last.getIdMap()); |
| } |
| configuration.setProperties(properties); |
| obj[i] = configuration.configure(); |
| last = configuration; |
| } |
| |
| // Test for Server Instance. |
| Server foundServer = null; |
| int serverCount = 0; |
| for (int i = 0; i < this.xmlConfigurations.size(); i++) |
| { |
| if (obj[i] instanceof Server) |
| { |
| if (obj[i].equals(foundServer)) |
| { |
| // Identical server instance found |
| break; |
| } |
| foundServer = (Server)obj[i]; |
| serverCount++; |
| } |
| } |
| |
| if (serverCount <= 0) |
| { |
| throw new Exception("Load failed to configure a " + Server.class.getName()); |
| } |
| |
| Assert.assertEquals("Server load count",1,serverCount); |
| |
| this.server = foundServer; |
| this.server.setGracefulShutdown(10); |
| |
| } |
| |
| public void printHandlers(PrintStream out) |
| { |
| Handler handler = server.getHandler(); |
| out.println(toString(handler)); |
| } |
| |
| public void removeContext(String name) |
| { |
| File destDir = new File(jettyHome,"contexts"); |
| File contextFile = new File(destDir,name); |
| if (contextFile.exists()) |
| { |
| Assert.assertTrue("Delete of Context file: " + contextFile.getAbsolutePath(),contextFile.delete()); |
| } |
| } |
| |
| public void setProperty(String key, String value) |
| { |
| properties.setProperty(key,value); |
| } |
| |
| public void setScheme(String scheme) |
| { |
| this.scheme = scheme; |
| } |
| |
| public void start() throws Exception |
| { |
| Assert.assertNotNull("Server should not be null (failed load?)",server); |
| |
| server.start(); |
| |
| // Find the active server port. |
| this.serverPort = (-1); |
| Connector connectors[] = server.getConnectors(); |
| for (int i = 0; i < connectors.length; i++) |
| { |
| Connector connector = connectors[i]; |
| if (connector.getLocalPort() > 0) |
| { |
| this.serverPort = connector.getLocalPort(); |
| break; |
| } |
| } |
| |
| Assert.assertTrue("Server Port is between 1 and 65535. Actually <" + serverPort + ">",(1 <= this.serverPort) && (this.serverPort <= 65535)); |
| |
| // Uncomment to have server start and continue to run (without exiting) |
| // System.out.printf("Listening to port %d%n",this.serverPort); |
| // server.join(); |
| } |
| |
| public void stop() throws Exception |
| { |
| server.stop(); |
| } |
| |
| public String toString(Handler handler) |
| { |
| if (handler instanceof HandlerCollection) |
| { |
| return ((HandlerCollection)handler).dump(); |
| } |
| |
| if (handler instanceof AbstractHandler) |
| { |
| return ((AbstractHandler)handler).dump(); |
| } |
| |
| return handler.toString(); |
| } |
| |
| public void waitForDirectoryScan() |
| { |
| int ms = 2000; |
| System.out.printf("Waiting %d milliseconds for AppProvider to process directory scan ...%n",ms); |
| try |
| { |
| Thread.sleep(ms); |
| } |
| catch (InterruptedException ignore) |
| { |
| /* ignore */ |
| } |
| } |
| } |