diff options
593 files changed, 25325 insertions, 17035 deletions
diff --git a/README.txt b/README.txt index 640c7e9b43..118cf1a413 100644 --- a/README.txt +++ b/README.txt @@ -1,62 +1,17 @@ -JETTY -===== +This is a source checkout of the Jetty webserver. -The Jetty project is a 100% Java HTTP Server, HTTP Client -and Servlet Container. - - -The Jetty @ eclipse project is based on the Jetty project at codehaus - - http://jetty.codehaus.org - -Ongoing development is now at the eclipse foundation - - http://www.eclipse.org/jetty/ - - -Jetty @ eclipse is open source and is dual licensed using the apache 2.0 and -eclipse public license 1.0. You may choose either license when distributing -jetty. - - - -BUILDING JETTY -============== - -Jetty uses maven 2 as its build system. Maven will fetch -the dependancies, build the server and assemble a runnable -version: +To build, use: mvn install +The jetty distribution will be built in + jetty-distribution/target/distribution -RUNNING JETTY -============= - -The run directory is either the top-level of a binary release -or jetty-distribution/target/assembly-prep directory when built from -source. - -To run with the default options: - - java -jar start.jar - -To run with specific configuration file(s) - - java -jar start.jar etc/jetty.xml - -To see the available options - - java -jar start.jar --help - -To run with JSP support - - java -jar start.jar OPTIONS=Server,jsp - -To run with JMX support - - java -jar start.jar OPTIONS=Server,jmx etc/jetty-jmx.xml etc/jetty.xml - +The first build may take a long time as maven downloads all the +dependencies. +The tests do a lot of stress testing, and on some machines it is +neccessary to set the file descriptor limit to greater than 2048 +for the tests to all pass successfully. diff --git a/VERSION.txt b/VERSION.txt index 919f1812ea..a40c39d7f8 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,18 +1,159 @@ -jetty-8.0.0.M1 8 April 2010 +jetty-8.0.0.M1 12 July 2010 + 306350 Ensure jars excluded by ordering are not scanned for annotations + + JETTY-1224 Change jetty-8 merge rules for fragment descriptors and annotations + Ensure <absolute-ordering> in web.xml overrides relative <ordering> in fragments + Ensure empty <absolute-ordering> implies exclusion of all fragments + Ensure servlet-api jar class inheritance hierarchy is scanned + +jetty-7.1.5.v20100705 + + Update ecj to 3.6 Helios release drop + + 288194 Add blacklist/whitelist to ProxyServlet and ProxyHandler + + 296570 EOFException for HttpExchange when HttpClient.stop called. + + 311550 The WebAppProvider should allow setTempDirectory + + 316449 Websocket disconnect fix + + 316584 Exception on startup if temp path has spaces and extractWAR=false + + 316597 Removed null check and fixed name in Resource#hrefEncodeURI + + 316970 jetty.sh fails to find JETTY_HOME in standard directories + + 316973 jetty.sh claims java installation is invalid + + 316976 removed quotes of JAVA_OPTIONS in jetty.sh + + 317019 Date HTTP header not sent for HTTP/1.0 requests + + 317759 Allow roles and constraints to be added after init + + 317906 OPTIONS correctly handles TRACE + + 318308 Correct quoting of unicode control characters + + 318470 unboxing NPE protection in HttpConnection + + 318551 Optional uncheck Printwriter + + JETTY-1237 Save local/remote address to be available after close + +jetty-7.1.4.v20100610 + + 298551 SslSocketConnector does not need keystore stream + + 295715 AbstractSessionManager decoupled from Context + + 292326 Stop continuations if server is stopped. + + 292814 Make QoSFilter and DoSFilter JMX manageable + + 293222 Improve request log to handle/show asynchronous latency + + 294212 Can not customize session cookie path + + 301608 Deregister shutdown hooks + + 302350 org.eclipse.jetty.server.NCSARequestLog is missing JavaDoc + + 303661 jetty.sh failes if JETTY_HOME is not writeable + + 304100 Better document JMX setup in jetty-jmx.xml + + 305300 AsyncContext.start dispatches runnable + + 314299 Create test harness for JDBCLoginService + + 314581 Implement the Sec-Websocket handshake + + 315190 CrossOriginFilter avoid headers not understood by WebSocket + + 315687 included init script fails to test for JETTY_HOME as empty + + 315715 Improved Cookie version handling. Server.setMaxCookieVersion + + 315744 Fixed STOP.PORT and STOP.KEY in start.jar + + 315748 Removed --fromDaemon from start.jar (replaced with --daemon) + + 315925 Improved context xml configuration handling + + 315995 Incorrect package name in system classes list + + 316119 Fixed maxIdleTime for SocketEndPoint + + 316254 Implement @DeclareRoles + + 316334 Breaking change on org.eclipse.jetty.client.HttpExchange + + 316399 Debug output in MultiPartFilter + + 316413 Restarting webapp for packed war fails + + 316557 OSGi HttpService failure due to undeployed context handlers + + JETTY-547 Delay close after shutdown until request read + + JETTY-1231 Support context request log handler + +jetty-7.1.3.v20100526 + + 296567 HttpClient RedirectListener handles new HttpDestination + + 297598 JDBCLoginService uses hardcoded credential class + + 305898 Websocket handles query string in URI + + 307457 Exchanges are left unhandled when connection is lost + + 313205 Unable to run test-jdbc-sessions tests + + 314177 JSTL support is broken + + 314009 jetty.xml configuration file on command line + + 314459 support maven3 for builds + +jetty-7.1.2.v20100523 + + 308866 Update test suite to JUnit4 - Module jetty-util + + 312948 Recycle SSL crypto buffers + + 313196 randomly allocate ports for session test. + + 313278 Implement octet ranges in IPAccessHandler + + 313336 secure websockets + + 314009 updated README.txt + + Update links to jetty website and wiki on test webapp + +jetty-7.1.1.v20100517 + + 302344 Make the list of available contexts if root context is not configured optional + + 304803 Remove TypeUtil Integer and Long caches + + 306226 HttpClient should allow changing the keystore and truststore type + + 308857 Update test suite to JUnit4 - Module jetty-jndi + + 308856 Update test suite to JUnit4 - Module jetty-jmx + + 308860 Update test suite to JUnit4 - Module jetty-rewrite + + 308850 Update test suite to JUnit4 - Module jetty-annotations + + 308853 Update test suite to JUnit4 - Module jetty-deploy + + 308854 Update test suite to JUnit4 - Module jetty-http + + 308859 Update test suite to JUnit4 - Module jetty-policy + + 308858 Update test suite to JUnit4 - Module jetty-plus + + 308863 Update test suite to JUnit4 - Module jetty-servlet + + 308855 Update test suite to JUnit4 - Module jetty-io + + 308862 Update test suite to JUnit4 - Module jetty-server + + 308867 Update test suite to JUnit4 - Module jetty-webapp + + 310918 Fixed write blocking for client HttpConnection + + 312526 Protect shutdown thread initialization during shutdown + +jetty-7.1.0 5 May 2010 + + 306353 fixed cross context dispatch to root context. + + 311154 Added deprecated StringBuffer API for backwards compatibility + + 311554 Protect shutdown thread from Server#doStop + + 312243 Optimized timeout handling + +jetty-7.1.0.RC1 5 May 2010 + + 286889 Allow System and Server classes to be set on Server instance and when applied to all webapps + + 291448 SessionManager has isCheckingRemoteSessionIdEncoding + + 296650 JETTY-1198 reset idle timeout on request body chunks + + 297104 HTTP CONNECT does not work correct with SSL destinations + + 306782 Close connection when expected 100 continues is not sent + + 308848 Update test suite to JUnit4 - Module jetty-ajp + + 308861 Update test suite to JUnit4 - Module jetty-security + + 308864 Update test suite to JUnit4 - Module jetty-servlets + + 308865 Update test suite to JUnit4 - Module jetty-start + + 308868 Update test suite to JUnit4 - Module jetty-websocket + + 308869 Update test suite to JUnit4 - Module jetty-xml + + 309153 Hide extracted WEB-INF/lib when running a non-extracted war + + 309369 Added WebSocketLoadTest + + 309686 Fixed response buffers usage + + 310094 Improved start.jar options handling and configs + + 310382 NPE protection when WAR is not a file + + 310562 SslSocketConnector fails to start if excludeCipherSuites is set + + 310634 Get the localport when opening a server socket. + + 310703 Update test suite to JUnit4 - Module tests/test-integration + + 310918 Synchronize content exchange + + 311154 Use Appendable in preference to StringBuilder/StringBuffer in APIs + + 311362 Optional org.eclipse.jetty.util.log.stderr.SOURCE + + JETTY-1030 - Improve jetty.sh script + + JETTY-1142 Replace Set-Cookies with same name + +jetty-7.1.0.RC0 27 April 2010 + + 294563 Websocket client connection + + 297104 Improve handling of CONNECT method + 306349 ProxyServlet does not work unless deployed at / + + 307294 Add AbstractLifeCycle.AbstractLifeCycleListener implementation + 307847 Fixed combining mime type parameters + 307898 Handle large/async websocket messages + + 308009 ObjectMBean incorrectly casts getTargetException() to Exception + + 308420 convert jetty-plus.xml to use DeploymentManager + + 308925 Protect the test webapp from remote access + + 309466 Removed synchronization from StdErrLog + + 309765 Added JSP module + + 310051 _configurationClasses now defaults to null in WebAppContext + + 310094 Improved start.jar usage and config files + + 310431 Default ErrorHandler as server Bean + + 310467 Allow SocketConnector to create generic Connection objects + + 310603 Make Logger interface consistent + + 310605 Make a clean room implementation of the JSP logger bridge + + Add AnnotationConfiguration to jetty-plus.xml + + Fix jetty-plus.xml reference to addLifeCycle + + JETTY-1200 SSL NIO Endpoint wraps non NIO buffers + JETTY-1202 Use platform default algorithm for SecureRandom + Merged 7.0.2.v20100331 + Add NPE protection to ContainerInitializerConfiguration + Temporarily remove jetty-osgi module to clarify jsp version compatibility + + JETTY-1212 handle long content lengths + + JETTY-1214 avoid ISE when scavenging invalid session + + JETTY-903 Stop both caches - -jetty-7.0.2.v20100331 +jetty-7.0.2.v20100331 31 March 2010 + 297552 Don't call Continuation timeouts from acceptor tick + 298236 Additional unit tests for jetty-client + 306783 NPE in StdErrLog when Throwable is null @@ -25,6 +166,17 @@ jetty-7.0.2.v20100331 + Ensure webapps with no WEB-INF don't scan WEB-INF/lib + Allow Configuration array to be set on Server instance for all web apps +jetty-6.1.24 21 April 2010 + + JETTY-903 Stop both caches + + JETTY-1198 reset idle timeout on request body chunks + + JETTY-1200 SSL NIO Endpoint wraps non NIO buffers + + JETTY-1211 SetUID loadlibrary name and debug + + 308925 Protect the test webapp from remote access + + COMETD-99 ClientImpl logs exceptions in listeners with "debug" level + + COMETD-100 ClientImpl logs "null" as clientId + + COMETD-107 Reloading the application with reload extension does not fire /meta/connect handlers until long poll timeout expires + + Upgraded to cometd 1.1.1 client + jetty-6.1.23 2 April 2010 + JSON parses NaN as null + Updated JSP to 2.1.v20091210 diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/FileServerXml.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/FileServerXml.java index d9bf0a3446..6cf59bad31 100644 --- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/FileServerXml.java +++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/FileServerXml.java @@ -10,7 +10,8 @@ import org.eclipse.jetty.xml.XmlConfiguration; * This server is identical to {@link FileServer}, except that it * is configured via an {@link XmlConfiguration} config file that * does the identical work. - * @see http://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk/example-jetty-embedded/src/main/resources/fileserver.xml + * <p> + * See <a href="http://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk/example-jetty-embedded/src/main/resources/fileserver.xml">fileserver.xml</a> */ public class FileServerXml { diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java index 12a4fa6018..27f9d30bac 100644 --- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java +++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java @@ -73,6 +73,16 @@ public class LikeJettyXml ssl_connector.setTruststore(jetty_home + "/etc/keystore"); ssl_connector.setTrustPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); ssl_connector.setStatsOn(true); + ssl_connector.setExcludeCipherSuites( + new String[] { + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" + }); server.addConnector(ssl_connector); HandlerCollection handlers = new HandlerCollection(); diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java index 45e512f8b6..59608de10c 100644 --- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java +++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java @@ -50,7 +50,7 @@ import org.eclipse.jetty.util.ajax.JSON; * <li>{@link HandlerWrapper} which will nest one handler inside another. In * this example, the HelloHandler is nested inside a HandlerWrapper that sets * the greeting as a request attribute. - * <li>{@link ListHandler} which will call a collection of handlers until the + * <li>{@link HandlerList} which will call a collection of handlers until the * request is marked as handled. In this example, a list is used to combine the * param handler (which only handles the request if there are parameters) and * the wrapper handler. Frequently handler lists are terminated with the diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ProxyServer.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ProxyServer.java index d8862c0c4b..a7fbfd6735 100644 --- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ProxyServer.java +++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ProxyServer.java @@ -13,10 +13,12 @@ package org.eclipse.jetty.embedded; -import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.bio.SocketConnector; -import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.server.handler.ProxyHandler; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlets.ProxyServlet; public class ProxyServer @@ -24,18 +26,25 @@ public class ProxyServer public static void main(String[] args) throws Exception { Server server = new Server(); - Connector connector = new SocketConnector(); + SelectChannelConnector connector = new SelectChannelConnector(); connector.setPort(8080); - server.setConnectors(new Connector[] - { connector }); + server.addConnector(connector); - ServletHandler handler = new ServletHandler(); - server.setHandler(handler); + HandlerCollection handlers = new HandlerCollection(); + server.setHandler(handlers); - handler.addServletWithMapping(ProxyServlet.class,"/"); + ServletContextHandler context = new ServletContextHandler(handlers, "/", ServletContextHandler.SESSIONS); + ServletHolder proxyServlet = new ServletHolder(ProxyServlet.class); + proxyServlet.setInitParameter("whiteList", "google.com, www.eclipse.org"); + proxyServlet.setInitParameter("blackList", "google.com/calendar/*, www.eclipse.org/committers/"); + context.addServlet(proxyServlet, "/*"); + + ProxyHandler proxy = new ProxyHandler(); + proxy.setWhite(new String[]{"mail.google.com"}); + proxy.addWhite("www.google.com"); + handlers.addHandler(proxy); server.start(); - server.join(); } } diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java index 73579c25c3..7224824cb3 100644 --- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java +++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.embedded; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -49,7 +50,7 @@ public class SecuredHelloHandler knownRoles.add("user"); knownRoles.add("admin"); - security.setConstraintMappings(new ConstraintMapping[] {mapping}, knownRoles); + security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); security.setAuthenticator(new BasicAuthenticator()); security.setLoginService(loginService); security.setStrict(false); diff --git a/jetty-aggregate/jetty-all-server/pom.xml b/jetty-aggregate/jetty-all-server/pom.xml index 0ddae93427..0bcb8a40ac 100644 --- a/jetty-aggregate/jetty-all-server/pom.xml +++ b/jetty-aggregate/jetty-all-server/pom.xml @@ -10,6 +10,7 @@ <name>Jetty :: Aggregate :: All Server</name> <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -28,6 +29,22 @@ <overWriteSnapshots>true</overWriteSnapshots> </configuration> </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> </executions> </plugin> <plugin> diff --git a/jetty-aggregate/jetty-all/pom.xml b/jetty-aggregate/jetty-all/pom.xml index aacac05879..747e7244c9 100644 --- a/jetty-aggregate/jetty-all/pom.xml +++ b/jetty-aggregate/jetty-all/pom.xml @@ -10,6 +10,7 @@ <name>Jetty :: Aggregate :: All core Jetty</name> <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -28,6 +29,22 @@ <overWriteSnapshots>true</overWriteSnapshots> </configuration> </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> </executions> </plugin> <plugin> diff --git a/jetty-aggregate/jetty-client/pom.xml b/jetty-aggregate/jetty-client/pom.xml index 14c5b85450..d7dc050ade 100644 --- a/jetty-aggregate/jetty-client/pom.xml +++ b/jetty-aggregate/jetty-client/pom.xml @@ -10,6 +10,7 @@ <name>Jetty :: Aggregate :: HTTP Client</name> <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -28,11 +29,26 @@ <overWriteSnapshots>true</overWriteSnapshots> </configuration> </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> </executions> </plugin> <plugin> - <groupId>org.apache.maven.plugins - </groupId> + <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> diff --git a/jetty-aggregate/jetty-plus/pom.xml b/jetty-aggregate/jetty-plus/pom.xml index 1781a798ec..228a8579f5 100644 --- a/jetty-aggregate/jetty-plus/pom.xml +++ b/jetty-aggregate/jetty-plus/pom.xml @@ -10,6 +10,7 @@ <name>Jetty :: Aggregate :: Plus Server</name> <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -28,6 +29,22 @@ <overWriteSnapshots>true</overWriteSnapshots> </configuration> </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> </executions> </plugin> <plugin> diff --git a/jetty-aggregate/jetty-server/pom.xml b/jetty-aggregate/jetty-server/pom.xml index 333f8a0ce0..a7ccc33e04 100644 --- a/jetty-aggregate/jetty-server/pom.xml +++ b/jetty-aggregate/jetty-server/pom.xml @@ -10,6 +10,7 @@ <name>Jetty :: Aggregate :: HTTP Server</name> <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -28,6 +29,22 @@ <overWriteSnapshots>true</overWriteSnapshots> </configuration> </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> </executions> </plugin> <plugin> diff --git a/jetty-aggregate/jetty-servlet/pom.xml b/jetty-aggregate/jetty-servlet/pom.xml index 3d9ff026b3..d7e4930f28 100644 --- a/jetty-aggregate/jetty-servlet/pom.xml +++ b/jetty-aggregate/jetty-servlet/pom.xml @@ -10,6 +10,7 @@ <name>Jetty :: Aggregate :: Servlet Server</name> <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -28,6 +29,22 @@ <overWriteSnapshots>true</overWriteSnapshots> </configuration> </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> </executions> </plugin> <plugin> diff --git a/jetty-aggregate/jetty-webapp/pom.xml b/jetty-aggregate/jetty-webapp/pom.xml index 781383a458..d713f165f1 100644 --- a/jetty-aggregate/jetty-webapp/pom.xml +++ b/jetty-aggregate/jetty-webapp/pom.xml @@ -10,6 +10,7 @@ <name>Jetty :: Aggregate :: WebApp Server</name> <build> + <sourceDirectory>${project.build.directory}/sources</sourceDirectory> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -21,13 +22,29 @@ <goal>unpack-dependencies</goal> </goals> <configuration> - <includes>**</includes> + <includes>META-INF/**,org/eclipse/**</includes> <excludes>**/MANIFEST.MF,javax/**</excludes> <outputDirectory>${project.build.directory}/classes</outputDirectory> <overWriteReleases>false</overWriteReleases> <overWriteSnapshots>true</overWriteSnapshots> </configuration> </execution> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> </executions> </plugin> <plugin> diff --git a/jetty-aggregate/pom.xml b/jetty-aggregate/pom.xml index d8b1f2c762..e93bd41d46 100644 --- a/jetty-aggregate/pom.xml +++ b/jetty-aggregate/pom.xml @@ -11,6 +11,24 @@ <name>Jetty :: Aggregate Project</name> <packaging>pom</packaging> <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <configuration> + <!-- No Point running PMD on aggregate projects --> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <!-- No Point running Findbugs on aggregate projects --> + <skip>true</skip> + </configuration> + </plugin> + </plugins> </build> <modules> <module>jetty-server</module> diff --git a/jetty-ajp/pom.xml b/jetty-ajp/pom.xml index 1a7f4dce06..1fe20ca944 100644 --- a/jetty-ajp/pom.xml +++ b/jetty-ajp/pom.xml @@ -54,14 +54,13 @@ </execution> </executions> </plugin> - - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.ajp.*</onlyAnalyze> + </configuration> </plugin> - </plugins> </build> <dependencies> @@ -73,6 +72,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13Connection.java b/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13Connection.java index 8f81643f98..807cc6fd98 100644 --- a/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13Connection.java +++ b/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13Connection.java @@ -34,8 +34,6 @@ import org.eclipse.jetty.server.Server; * Connection implementation of the Ajp13 protocol. <p/> XXX Refactor to remove * duplication of HttpConnection * - * - * */ public class Ajp13Connection extends HttpConnection { diff --git a/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13Generator.java b/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13Generator.java index 10f0b4e25a..ce2efa1bc8 100644 --- a/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13Generator.java +++ b/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13Generator.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.ajp; @@ -28,13 +28,12 @@ import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; /** - * - * - */ + * + * + */ public class Ajp13Generator extends AbstractGenerator { private static HashMap __headerHash = new HashMap(); @@ -117,6 +116,19 @@ public class Ajp13Generator extends AbstractGenerator /* ------------------------------------------------------------ */ @Override + public boolean isRequest() + { + return false; + } + + /* ------------------------------------------------------------ */ + @Override + public boolean isResponse() + { + return true; + } + /* ------------------------------------------------------------ */ + @Override public void reset(boolean returnBuffers) { super.reset(returnBuffers); @@ -142,10 +154,9 @@ public class Ajp13Generator extends AbstractGenerator _last = false; _head = false; _noContent = false; - _close = false; + _persistent = true; - _header = null; // Buffer for HTTP header (and maybe small _content) _buffer = null; // Buffer for copy of passed _content @@ -157,7 +168,7 @@ public class Ajp13Generator extends AbstractGenerator /* ------------------------------------------------------------ */ /** * Add content. - * + * * @param content * @param last * @throws IllegalArgumentException @@ -239,7 +250,7 @@ public class Ajp13Generator extends AbstractGenerator /* ------------------------------------------------------------ */ /** * Add content. - * + * * @param b * byte * @return true if the buffers are full @@ -289,7 +300,7 @@ public class Ajp13Generator extends AbstractGenerator /** * Prepare buffer for unchecked writes. Prepare the generator buffer to * receive unchecked writes - * + * * @return the available space in the buffer. * @throws IOException */ @@ -342,8 +353,8 @@ public class Ajp13Generator extends AbstractGenerator _last = _last | allContentAdded; boolean has_server = false; - if (_version == HttpVersions.HTTP_1_0_ORDINAL) - _close = true; + if (_persistent==null) + _persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL); // get a header buffer if (_header == null) @@ -363,7 +374,7 @@ public class Ajp13Generator extends AbstractGenerator if (_reason == null) _reason=HttpGenerator.getReasonBuffer(_status); if (_reason == null) - _reason = new ByteArrayBuffer(TypeUtil.toString(_status)); + _reason = new ByteArrayBuffer(Integer.toString(_status)); addBuffer(_reason); if (_status == 100 || _status == 204 || _status == 304) @@ -380,7 +391,7 @@ public class Ajp13Generator extends AbstractGenerator int num_fields = 0; if (fields != null) - { + { // Add headers int s=fields.size(); for (int f=0;f<s;f++) @@ -389,7 +400,7 @@ public class Ajp13Generator extends AbstractGenerator if (field==null) continue; num_fields++; - + byte[] codes = (byte[]) __headerHash.get(field.getName()); if (codes != null) { @@ -440,7 +451,7 @@ public class Ajp13Generator extends AbstractGenerator /* ------------------------------------------------------------ */ /** * Complete the message. - * + * * @throws IOException */ @Override @@ -494,7 +505,7 @@ public class Ajp13Generator extends AbstractGenerator { int len = -1; int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0); - + switch (to_flush) { @@ -591,8 +602,6 @@ public class Ajp13Generator extends AbstractGenerator total += len; } - - return total; } catch (IOException e) diff --git a/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13SocketConnector.java b/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13SocketConnector.java index 9e94bdad38..0aabac5611 100644 --- a/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13SocketConnector.java +++ b/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13SocketConnector.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.ajp; @@ -16,16 +16,16 @@ package org.eclipse.jetty.ajp; import java.io.IOException; import org.eclipse.jetty.http.HttpSchemes; +import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.bio.SocketConnector; import org.eclipse.jetty.util.log.Log; /** - * - * - * + * + * + * */ public class Ajp13SocketConnector extends SocketConnector { @@ -33,12 +33,13 @@ public class Ajp13SocketConnector extends SocketConnector static boolean __allowShutdown = false; public Ajp13SocketConnector() { - super.setHeaderBufferSize(Ajp13Packet.MAX_DATA_SIZE); + super.setRequestHeaderSize(Ajp13Packet.MAX_DATA_SIZE); + super.setResponseHeaderSize(Ajp13Packet.MAX_DATA_SIZE); super.setRequestBufferSize(Ajp13Packet.MAX_DATA_SIZE); super.setResponseBufferSize(Ajp13Packet.MAX_DATA_SIZE); // IN AJP protocol the socket stay open, so - // by default the time out is set to 900 seconds - super.setMaxIdleTime(900000); + // by default the time out is set to 0 seconds + super.setMaxIdleTime(0); } @Override @@ -47,8 +48,8 @@ public class Ajp13SocketConnector extends SocketConnector super.doStart(); Log.info("AJP13 is not a secure protocol. Please protect port {}",Integer.toString(getLocalPort())); } - - + + /* ------------------------------------------------------------ */ /* (non-Javadoc) @@ -60,11 +61,14 @@ public class Ajp13SocketConnector extends SocketConnector super.customize(endpoint,request); if (request.isSecure()) request.setScheme(HttpSchemes.HTTPS); + + System.err.println("Customize "+endpoint+" "+request); + } /* ------------------------------------------------------------ */ @Override - protected HttpConnection newHttpConnection(EndPoint endpoint) + protected Connection newConnection(EndPoint endpoint) { return new Ajp13Connection(this,endpoint,getServer()); } diff --git a/jetty-ajp/src/test/java/org/eclipse/jetty/ajp/Ajp13ConnectionTest.java b/jetty-ajp/src/test/java/org/eclipse/jetty/ajp/Ajp13ConnectionTest.java index be12b4cc46..1bf169ac8f 100644 --- a/jetty-ajp/src/test/java/org/eclipse/jetty/ajp/Ajp13ConnectionTest.java +++ b/jetty-ajp/src/test/java/org/eclipse/jetty/ajp/Ajp13ConnectionTest.java @@ -4,61 +4,81 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.ajp; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; +import java.net.SocketTimeoutException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.log.Log; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; -public class Ajp13ConnectionTest extends TestCase +public class Ajp13ConnectionTest { - private Server _server; - private Ajp13SocketConnector _connector; + private static Server _server; + private static Ajp13SocketConnector _connector; private Socket _client; - protected void setUp() throws Exception + @BeforeClass + public static void startServer() throws Exception { _server=new Server(); _connector=new Ajp13SocketConnector(); _connector.setPort(0); - _connector.setMaxIdleTime(100); _server.setConnectors(new Connector[] { _connector }); _server.setHandler(new Handler()); _server.start(); + } - _client=new Socket("localhost",_connector.getLocalPort()); + @AfterClass + public static void stopServer() throws Exception + { + _connector.close(); + _server.stop(); + } + @Before + public void openSocket() throws Exception + { + _client=new Socket("localhost",_connector.getLocalPort()); + _client.setSoTimeout(500); } - protected void tearDown() throws Exception + @After + public void closeSocket() throws Exception { _client.close(); - _connector.close(); - _server.stop(); } + @Test public void testPacket1() throws Exception { OutputStream os=_client.getOutputStream(); @@ -71,6 +91,7 @@ public class Ajp13ConnectionTest extends TestCase assertTrue(true); } + @Test public void testPacket2() throws Exception { OutputStream os=_client.getOutputStream(); @@ -83,6 +104,7 @@ public class Ajp13ConnectionTest extends TestCase assertTrue(true); } + @Test public void testPacket3() throws Exception { OutputStream os=_client.getOutputStream(); @@ -95,6 +117,7 @@ public class Ajp13ConnectionTest extends TestCase assertTrue(true); } + @Test public void testSSLPacketWithIntegerKeySize() throws Exception { OutputStream os=_client.getOutputStream(); @@ -107,6 +130,7 @@ public class Ajp13ConnectionTest extends TestCase assertTrue(true); } + @Test public void testSSLPacketWithStringKeySize() throws Exception { OutputStream os=_client.getOutputStream(); @@ -119,19 +143,21 @@ public class Ajp13ConnectionTest extends TestCase assertTrue(true); } + @Test public void testPacketWithBody() throws Exception { OutputStream os=_client.getOutputStream(); - os.write(TypeUtil.fromHexString(getTestHeader())); + os.write(TypeUtil.fromHexString(getTestHeader())); os.write(TypeUtil.fromHexString(getTestShortBody())); os.write(TypeUtil.fromHexString(getTestTinyBody())); - + readResponse(_client); assertTrue(true); } + @Test public void testPacketWithChunkedBody() throws Exception { OutputStream os=_client.getOutputStream(); @@ -261,41 +287,29 @@ public class Ajp13ConnectionTest extends TestCase private String getTestTinyBody() { StringBuffer body = new StringBuffer(""); - + body.append("123400042d2d0d0a"); - + return body.toString(); - + } - + // TODO: char array instead of string? private String readResponse(Socket _client) throws IOException { - BufferedReader br=null; + ByteArrayOutputStream bout = new ByteArrayOutputStream(); try { - br=new BufferedReader(new InputStreamReader(_client.getInputStream())); - - StringBuffer sb=new StringBuffer(); - String line; - while ((line=br.readLine()) != null) - { - sb.append(line); - sb.append('\n'); - } - - return sb.toString(); + IO.copy(_client.getInputStream(),bout); } - finally + catch(SocketTimeoutException e) { - if (br != null) - { - br.close(); - } + Log.ignore(e); } + return bout.toString("utf-8"); } - + public static class Handler extends AbstractHandler { public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException diff --git a/jetty-ajp/src/test/java/org/eclipse/jetty/ajp/TestAjpParser.java b/jetty-ajp/src/test/java/org/eclipse/jetty/ajp/TestAjpParser.java index 710b4264cc..b89d2b3381 100644 --- a/jetty-ajp/src/test/java/org/eclipse/jetty/ajp/TestAjpParser.java +++ b/jetty-ajp/src/test/java/org/eclipse/jetty/ajp/TestAjpParser.java @@ -4,48 +4,51 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.ajp; import java.io.IOException; -import junit.framework.TestCase; - import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.util.TypeUtil; +import org.junit.Test; -public class TestAjpParser extends TestCase -{ +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +public class TestAjpParser +{ + @Test public void testPacket1() throws Exception { String packet = "123401070202000f77696474683d20485454502f312e300000122f636f6e74726f6c2f70726f647563742f2200000e3230382e32372e3230332e31323800ffff000c7777772e756c74612e636f6d000050000005a006000a6b6565702d616c69766500a00b000c7777772e756c74612e636f6d00a00e002b4d6f7a696c6c612f342e302028636f6d70617469626c653b20426f726465724d616e6167657220332e302900a0010043696d6167652f6769662c20696d6167652f782d786269746d61702c20696d6167652f6a7065672c20696d6167652f706a7065672c20696d6167652f706d672c202a2f2a00a008000130000600067570726f64310008000a4145533235362d53484100ff"; byte[] src = TypeUtil.fromHexString(packet); - + ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE); SimpleBuffers buffers=new SimpleBuffers(buffer,null); - + EndPoint endp = new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE); - + Ajp13Parser parser = new Ajp13Parser(buffers,endp); parser.setEventHandler(new EH()); parser.setGenerator(new Ajp13Generator(buffers,endp)); - + parser.parseAvailable(); - + assertTrue(true); - } - + } + + @Test public void testPacket2() throws Exception { String packet="1234020102020008485454502f312e3100000f2f6363632d7777777777772f61616100000c38382e3838382e38382e383830ffff00116363632e6363636363636363632e636f6d0001bb010009a00b00116363632e6363636363636363632e636f6d00a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004039324643303544413043444141443232303137413743443141453939353132413330443938363838423843433041454643364231363035323543433232353341000b0100ff"; @@ -58,8 +61,9 @@ public class TestAjpParser extends TestCase parser.setGenerator(new Ajp13Generator(buffers,endp)); parser.parse(); assertTrue(true); - } - + } + + @Test public void testPacket3() throws Exception { String packet="1234028f02020008485454502f312e3100000d2f666f726d746573742e6a737000000d3139322e3136382e342e31383000ffff00107777772e777265636b6167652e6f726700005000000aa0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a00200075554462d382c2a00a003000c677a69702c6465666c61746500a004000e656e2d67622c656e3b713d302e3500a006000a6b6565702d616c69766500a00900f95048505345535349443d37626361383232616638333466316465373663633630336366636435313938633b20667041757468436f6f6b69653d433035383430394537393344364245434633324230353234344242303039343230383344443645443533304230454637464137414544413745453231313538333745363033454435364332364446353531383635333335423433374531423637414641343533364345304546323342333642323133374243423932333943363631433131443330393842333938414546334546334146454344423746353842443b204a53455353494f4e49443d7365366331623864663432762e6a657474793300a00b00107777772e777265636b6167652e6f726700000a6b6565702d616c69766500000333303000a00e00654d6f7a696c6c612f352e3020285831313b20553b204c696e7578207838365f36343b20656e2d55533b2072763a312e382e302e3929204765636b6f2f3230303631323035202844656269616e2d312e382e302e392d3129204570697068616e792f322e313400a008000130000600066a657474793300ff"; @@ -73,79 +77,80 @@ public class TestAjpParser extends TestCase parser.parse(); assertTrue(true); } - - + + @Test public void testSSLPacketWithIntegerKeySize() throws Exception { String packet = "1234025002020008485454502f312e3100000f2f746573742f64756d702f696e666f00000e3139322e3136382e3130302e343000ffff000c776562746964652d746573740001bb01000ca00b000c776562746964652d7465737400a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500a00d001a68747470733a2f2f776562746964652d746573742f746573742f00a00900174a53455353494f4e49443d69326c6e307539773573387300000d43616368652d436f6e74726f6c0000096d61782d6167653d3000000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004032413037364245323330433238393130383941414132303631344139384441443131314230323132343030374130363642454531363742303941464337383942000b0100ff"; byte[] src = TypeUtil.fromHexString(packet); - + ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE); SimpleBuffers buffers=new SimpleBuffers(buffer,null); - + EndPoint endp = new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE); - + Ajp13Parser parser = new Ajp13Parser(buffers,endp); parser.setEventHandler(new EH()); parser.setGenerator(new Ajp13Generator(buffers,endp)); - + parser.parseAvailable(); - + assertTrue(true); } + @Test public void testSSLPacketWithStringKeySize() throws Exception { String packet = "1234025002020008485454502f312e3100000f2f746573742f64756d702f696e666f00000e3139322e3136382e3130302e343000ffff000c776562746964652d746573740001bb01000ca00b000c776562746964652d7465737400a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500a00d001a68747470733a2f2f776562746964652d746573742f746573742f00a00900174a53455353494f4e49443d69326c6e307539773573387300000d43616368652d436f6e74726f6c0000096d61782d6167653d3000000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004032413037364245323330433238393130383941414132303631344139384441443131314230323132343030374130363642454531363742303941464337383942000b000332353600ff"; byte[] src = TypeUtil.fromHexString(packet); - + ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE); SimpleBuffers buffers=new SimpleBuffers(buffer,null); - + EndPoint endp = new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE); - + Ajp13Parser parser = new Ajp13Parser(buffers,endp); parser.setEventHandler(new EH()); parser.setGenerator(new Ajp13Generator(buffers,endp)); - + parser.parseAvailable(); - + assertTrue(true); } + @Test public void testSSLPacketFragment() throws Exception { String packet = "1234025002020008485454502f312e3100000f2f746573742f64756d702f696e666f00000e3139322e3136382e3130302e343000ffff000c776562746964652d746573740001bb01000ca00b000c776562746964652d7465737400a00e005a4d6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420352e313b20656e2d55533b2072763a312e382e312e3129204765636b6f2f32303036313230342046697265666f782f322e302e302e3100a0010063746578742f786d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d302e382c696d6167652f706e672c2a2f2a3b713d302e3500a004000e656e2d75732c656e3b713d302e3500a003000c677a69702c6465666c61746500a002001e49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e3700000a4b6565702d416c69766500000333303000a006000a6b6565702d616c69766500a00d001a68747470733a2f2f776562746964652d746573742f746573742f00a00900174a53455353494f4e49443d69326c6e307539773573387300000d43616368652d436f6e74726f6c0000096d61782d6167653d3000000c4d61782d466f7277617264730000023130000800124448452d5253412d4145533235362d5348410009004032413037364245323330433238393130383941414132303631344139384441443131314230323132343030374130363642454531363742303941464337383942000b0100ff"; byte[] src = TypeUtil.fromHexString(packet); - + for (int f=1;f<src.length;f++) { byte[] frag0=new byte[src.length-f]; byte[] frag1=new byte[f]; - + System.arraycopy(src,0,frag0,0,src.length-f); System.arraycopy(src,src.length-f,frag1,0,f); - + ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE); SimpleBuffers buffers=new SimpleBuffers(buffer,null); - + ByteArrayEndPoint endp = new ByteArrayEndPoint(frag0,Ajp13Packet.MAX_PACKET_SIZE); endp.setNonBlocking(true); - + Ajp13Parser parser = new Ajp13Parser(buffers,endp); parser.setEventHandler(new EH()); parser.setGenerator(new Ajp13Generator(buffers,endp)); parser.parseNext(); - + endp.setIn(new ByteArrayBuffer(frag1)); parser.parseAvailable(); } - + assertTrue(true); } - - - + + @Test public void testPacketWithBody() throws Exception { String packet=getTestHeader(); @@ -154,7 +159,7 @@ public class TestAjpParser extends TestCase SimpleBuffers buffers=new SimpleBuffers(buffer,null); ByteArrayEndPoint endp=new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE); endp.setNonBlocking(true); - + final int count[]={0}; Ajp13Generator gen = new Ajp13Generator(buffers,endp) { @@ -167,29 +172,28 @@ public class TestAjpParser extends TestCase Ajp13Parser parser = new Ajp13Parser(buffers,endp); parser.setEventHandler(new EH()); parser.setGenerator(gen); - + parser.parseNext(); assertEquals(1,parser.getState()); assertEquals(0,count[0]); - + endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString(getTestShortBody()))); parser.parseNext(); assertEquals(1,parser.getState()); assertEquals(1,count[0]); - + endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString(getTestTinyBody()))); parser.parseNext(); parser.parseNext(); assertEquals(0,parser.getState()); assertEquals(1,count[0]); - + assertTrue(true); } - - + @Test public void testPacketWithChunkedBody() throws Exception { String packet="123400ff02040008485454502f312e3100000f2f746573742f64756d702f696e666f0000093132372e302e302e3100ffff00096c6f63616c686f7374000050000007a00e000d4a6176612f312e352e305f313100a00b00096c6f63616c686f737400a0010034746578742f68746d6c2c20696d6167652f6769662c20696d6167652f6a7065672c202a3b20713d2e322c202a2f2a3b20713d2e3200a006000a6b6565702d616c69766500a00700216170706c69636174696f6e2f782d7777772d666f726d2d75726c656e636f6465640000115472616e736665722d456e636f64696e670000076368756e6b656400000c4d61782d466f727761726473000002313000ff"; @@ -198,7 +202,7 @@ public class TestAjpParser extends TestCase SimpleBuffers buffers=new SimpleBuffers(buffer,null); ByteArrayEndPoint endp=new ByteArrayEndPoint(src,Ajp13Packet.MAX_PACKET_SIZE); endp.setNonBlocking(true); - + final int count[]={0}; Ajp13Generator gen = new Ajp13Generator(buffers,endp) { @@ -211,105 +215,100 @@ public class TestAjpParser extends TestCase Ajp13Parser parser = new Ajp13Parser(buffers,endp); parser.setEventHandler(new EH()); parser.setGenerator(gen); - + parser.parseNext(); assertEquals(1,parser.getState()); assertEquals(1,count[0]); - + endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString("1234007e007c7468656e616d653d746865253230717569636b25323062726f776e253230666f782532306a756d70732532306f766572253230746f2532307468652532306c617a79253230646f67253230544845253230515549434b25323042524f574e253230464f582532304a554d50532532304f564552253230544f25323054"))); while (parser.parseNext()>0); assertEquals(1,parser.getState()); assertEquals(2,count[0]); - + endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString("12340042004048452532304c415a59253230444f472532302676616c75656f66323d6162636465666768696a6b6c6d6e6f707172737475767778797a31323334353637383930"))); while (parser.parseNext()>0); assertEquals(1,parser.getState()); assertEquals(3,count[0]); - + endp.setIn(new ByteArrayBuffer(TypeUtil.fromHexString("123400020000"))); while (parser.getState()!=0 && parser.parseNext()>0); assertEquals(0,parser.getState()); assertEquals(3,count[0]); - + assertTrue(true); } - - - + @Test public void testPacketFragment() throws Exception { String packet = "123401070202000f77696474683d20485454502f312e300000122f636f6e74726f6c2f70726f647563742f2200000e3230382e32372e3230332e31323800ffff000c7777772e756c74612e636f6d000050000005a006000a6b6565702d616c69766500a00b000c7777772e756c74612e636f6d00a00e002b4d6f7a696c6c612f342e302028636f6d70617469626c653b20426f726465724d616e6167657220332e302900a0010043696d6167652f6769662c20696d6167652f782d786269746d61702c20696d6167652f6a7065672c20696d6167652f706a7065672c20696d6167652f706d672c202a2f2a00a008000130000600067570726f64310008000a4145533235362d53484100ff"; byte[] src = TypeUtil.fromHexString(packet); - + for (int f=1;f<src.length;f++) { byte[] frag0=new byte[src.length-f]; byte[] frag1=new byte[f]; - + System.arraycopy(src,0,frag0,0,src.length-f); System.arraycopy(src,src.length-f,frag1,0,f); - + ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE); SimpleBuffers buffers=new SimpleBuffers(buffer,null); - + ByteArrayEndPoint endp = new ByteArrayEndPoint(frag0,Ajp13Packet.MAX_PACKET_SIZE); endp.setNonBlocking(true); - + Ajp13Parser parser = new Ajp13Parser(buffers,endp); parser.setEventHandler(new EH()); parser.setGenerator(new Ajp13Generator(buffers,endp)); parser.parseNext(); - + endp.setIn(new ByteArrayBuffer(frag1)); parser.parseAvailable(); } - + assertTrue(true); } - - - + + @Test public void testPacketFragmentWithBody() throws Exception { String packet = getTestHeader()+getTestBody(); byte[] src = TypeUtil.fromHexString(packet); - + for (int f=1;f<src.length;f++) { byte[] frag0=new byte[src.length-f]; byte[] frag1=new byte[f]; - + System.arraycopy(src,0,frag0,0,src.length-f); System.arraycopy(src,src.length-f,frag1,0,f); - + ByteArrayBuffer buffer= new ByteArrayBuffer(Ajp13Packet.MAX_PACKET_SIZE); SimpleBuffers buffers=new SimpleBuffers(buffer,null); - + ByteArrayEndPoint endp = new ByteArrayEndPoint(frag0,Ajp13Packet.MAX_PACKET_SIZE); endp.setNonBlocking(true); - + Ajp13Parser parser = new Ajp13Parser(buffers,endp); parser.setEventHandler(new EH()); parser.setGenerator(new Ajp13Generator(buffers,endp)); parser.parseNext(); - + endp.setIn(new ByteArrayBuffer(frag1)); parser.parseAvailable(); } - + assertTrue(true); } - - + private String getTestHeader() { StringBuffer header = new StringBuffer(""); - - + header.append("1234026902040008485454502f31"); header.append("2e310000162f61646d696e2f496d6167"); header.append("6555706c6f61642e68746d00000a3130"); @@ -350,17 +349,13 @@ public class TestAjpParser extends TestCase header.append("3130000500176964303d4974656d2669"); header.append("64313d32266964323d696d673200ff"); - return header.toString(); - } private String getTestBody() { StringBuffer body = new StringBuffer(""); - - - + body.append("123402f902f72d2d2d2d2d2d2d2d"); body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d"); body.append("2d2d2d2d2d3934333833323534323630"); @@ -409,17 +404,15 @@ public class TestAjpParser extends TestCase body.append("0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d"); body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d3934"); body.append("33383332353432363038372d2d0d0a"); - - + return body.toString(); - } - - + + private String getTestShortBody() { StringBuffer body = new StringBuffer(""); - + body.append("123402f702f52d2d2d2d2d2d2d2d"); body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d"); body.append("2d2d2d2d2d3934333833323534323630"); @@ -468,25 +461,20 @@ public class TestAjpParser extends TestCase body.append("0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d"); body.append("2d2d2d2d2d2d2d2d2d2d2d2d2d2d3934"); body.append("33383332353432363038372d2d"); - - + return body.toString(); - } private String getTestTinyBody() { StringBuffer body = new StringBuffer(""); - + body.append("123400042d2d0d0a"); - + return body.toString(); - } - - + private static class EH implements Ajp13Parser.EventHandler { - public void content(Buffer ref) throws IOException { // System.err.println(ref); @@ -515,7 +503,7 @@ public class TestAjpParser extends TestCase public void parsedProtocol(Buffer protocol) throws IOException { // System.err.println(protocol); - + } public void parsedQueryString(Buffer value) throws IOException @@ -526,13 +514,13 @@ public class TestAjpParser extends TestCase public void parsedRemoteAddr(Buffer addr) throws IOException { // System.err.println("addr="+addr); - + } public void parsedRemoteHost(Buffer host) throws IOException { // System.err.println("host="+host); - + } public void parsedRequestAttribute(String key, Buffer value) throws IOException @@ -542,7 +530,7 @@ public class TestAjpParser extends TestCase public void parsedServerName(Buffer name) throws IOException { - // System.err.println("Server:: "+name); + // System.err.println("Server:: "+name); } public void parsedServerPort(int port) throws IOException @@ -552,7 +540,7 @@ public class TestAjpParser extends TestCase public void parsedSslSecure(boolean secure) throws IOException { - // System.err.println("Secure:: "+secure); + // System.err.println("Secure:: "+secure); } public void parsedUri(Buffer uri) throws IOException @@ -604,13 +592,10 @@ public class TestAjpParser extends TestCase { // System.err.println(key+":: "+value); } - + public void parsedRequestAttribute(String key, int value) throws IOException { // System.err.println(key+":: "+value); } - } - - } diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index 01e1b1b27b..e619f7747c 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -33,25 +33,25 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.annotations.*</onlyAnalyze> + </configuration> </plugin> - </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractConfiguration.java index 3b2e8ce837..f245642b9d 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractConfiguration.java @@ -17,17 +17,15 @@ import java.net.URI; import java.util.ArrayList; import java.util.List; -import javax.servlet.ServletContext; - -import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.Configuration; +import org.eclipse.jetty.webapp.Descriptor; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.FragmentDescriptor; +import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebInfConfiguration; -import org.eclipse.jetty.webapp.WebXmlProcessor; -import org.eclipse.jetty.webapp.Descriptor; -import org.eclipse.jetty.webapp.Fragment; import org.eclipse.jetty.webapp.Descriptor.MetaDataComplete; @@ -35,15 +33,20 @@ public abstract class AbstractConfiguration implements Configuration { public static final String CONTAINER_JAR_RESOURCES = WebInfConfiguration.CONTAINER_JAR_RESOURCES; public static final String WEB_INF_JAR_RESOURCES = WebInfConfiguration.WEB_INF_JAR_RESOURCES; - public static final String METADATA_COMPLETE = WebXmlProcessor.METADATA_COMPLETE; - public static final String WEBXML_CLASSNAMES = WebXmlProcessor.WEBXML_CLASSNAMES; - + public static final String WEB_INF_ORDERED_JAR_RESOURCES = WebInfConfiguration.WEB_INF_ORDERED_JAR_RESOURCES; + public static final String METADATA_COMPLETE = MetaData.METADATA_COMPLETE; + public static final String WEBXML_CLASSNAMES = MetaData.WEBXML_CLASSNAMES; + public static final String DISCOVERED_ANNOTATIONS = "org.eclipse.jetty.discoveredAnnotations"; + public void parseContainerPath (final WebAppContext context, final AnnotationParser parser) throws Exception { //if no pattern for the container path is defined, then by default scan NOTHING Log.debug("Scanning container jars"); - + List<DiscoveredAnnotation> discoveredAnnotations = new ArrayList<DiscoveredAnnotation>(); + context.setAttribute(DISCOVERED_ANNOTATIONS, discoveredAnnotations); + + //Convert from Resource to URI ArrayList<URI> containerUris = new ArrayList<URI>(); List<Resource> jarResources = (List<Resource>)context.getAttribute(CONTAINER_JAR_RESOURCES); @@ -71,59 +74,71 @@ public abstract class AbstractConfiguration implements Configuration return false; } }); + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException ("No metadata"); + + metaData.addDiscoveredAnnotations((List<DiscoveredAnnotation>)context.getAttribute(DISCOVERED_ANNOTATIONS)); + context.removeAttribute(DISCOVERED_ANNOTATIONS); } public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser) throws Exception { - WebXmlProcessor webXmlProcessor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (webXmlProcessor == null) - throw new IllegalStateException ("No processor for web xml"); - - List<Fragment> frags = webXmlProcessor.getFragments(); + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException ("No metadata"); - // + get all WEB-INF/lib jars - // + those that are not in ORDERED_LIBS are ignored (they are excluded by ordering) - // + those that have web-fragment.xml and metadata-complete are ignored + List<FragmentDescriptor> frags = metaData.getFragments(); + //email from Rajiv Mordani jsrs 315 7 April 2010 + //jars that do not have a web-fragment.xml are still considered fragments + //they have to participate in the ordering ArrayList<URI> webInfUris = new ArrayList<URI>(); - List<Resource> jarResources = (List<Resource>)context.getAttribute(WEB_INF_JAR_RESOURCES); - List<String> orderedJars = (List<String>)context.getAttribute(ServletContext.ORDERED_LIBS); - for (Resource r : jarResources) + + List<Resource> jars = (List<Resource>)context.getAttribute(WEB_INF_ORDERED_JAR_RESOURCES); + + //No ordering just use the jars in any order + if (jars == null || jars.isEmpty()) + jars = (List<Resource>)context.getAttribute(WEB_INF_JAR_RESOURCES); + + List<DiscoveredAnnotation> discoveredAnnotations = new ArrayList<DiscoveredAnnotation>(); + context.setAttribute(DISCOVERED_ANNOTATIONS, discoveredAnnotations); + + for (Resource r : jars) { + discoveredAnnotations.clear(); //start fresh for each jar URI uri = r.getURI(); - Fragment f = getFragmentFromJar(r, frags); + FragmentDescriptor f = getFragmentFromJar(r, frags); - //check if the jar has a web-fragment.xml - if (f == null) //no web-fragment.xml, so scan it - webInfUris.add(uri); - else + //if a jar has no web-fragment.xml we scan it (because it is not exluded by the ordering) + //or if it has a fragment we scan it if it is not metadata complete + if (f == null || !isMetaDataComplete(f)) { - //check if web-fragment is metadata-complete and if it has been excluded from ordering - if (!isMetaDataComplete(f) && !isExcluded(r, orderedJars)) - webInfUris.add(uri); + parser.parse(uri, + new ClassNameResolver() + { + public boolean isExcluded (String name) + { + if (context.isSystemClass(name)) return true; + if (context.isServerClass(name)) return false; + return false; + } + + public boolean shouldOverride (String name) + { + //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp? + if (context.isParentLoaderPriority()) + return false; + return true; + } + }); + + metaData.addDiscoveredAnnotations(r, discoveredAnnotations); } } - - parser.parse(webInfUris.toArray(new URI[webInfUris.size()]), - new ClassNameResolver() - { - public boolean isExcluded (String name) - { - if (context.isSystemClass(name)) return true; - if (context.isServerClass(name)) return false; - return false; - } - - public boolean shouldOverride (String name) - { - //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp? - if (context.isParentLoaderPriority()) - return false; - return true; - } - }); + context.removeAttribute(DISCOVERED_ANNOTATIONS); } public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser) @@ -135,6 +150,13 @@ public abstract class AbstractConfiguration implements Configuration Resource classesDir = context.getWebInf().addPath("classes/"); if (classesDir.exists()) { + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException ("No metadata"); + + List<DiscoveredAnnotation> discoveredAnnotations = new ArrayList<DiscoveredAnnotation>(); + context.setAttribute(DISCOVERED_ANNOTATIONS, discoveredAnnotations); + parser.parse(classesDir, new ClassNameResolver() { @@ -153,46 +175,22 @@ public abstract class AbstractConfiguration implements Configuration return true; } }); + + //TODO - where to set the annotations discovered from WEB-INF/classes? + metaData.addDiscoveredAnnotations (discoveredAnnotations); + context.removeAttribute(DISCOVERED_ANNOTATIONS); } } } - public void parse25Classes (final WebAppContext context, final AnnotationParser parser) - throws Exception - { - //only parse servlets, filters and listeners from web.xml - if (Log.isDebugEnabled()) Log.debug("Scanning only classes from web.xml"); - ArrayList<String> classNames = (ArrayList<String>)context.getAttribute(WEBXML_CLASSNAMES); - for (String s : classNames) - { - Class clazz = Loader.loadClass(null, s); - parser.parse(clazz, new ClassNameResolver() - { - public boolean isExcluded (String name) - { - if (context.isSystemClass(name)) return true; - if (context.isServerClass(name)) return false; - return false; - } - - public boolean shouldOverride (String name) - { - //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp? - if (context.isParentLoaderPriority()) - return false; - return true; - } - }, true); - } - - } + - public Fragment getFragmentFromJar (Resource jar, List<Fragment> frags) + public FragmentDescriptor getFragmentFromJar (Resource jar, List<FragmentDescriptor> frags) throws Exception { //check if the jar has a web-fragment.xml - Fragment d = null; - for (Fragment frag: frags) + FragmentDescriptor d = null; + for (FragmentDescriptor frag: frags) { Resource fragResource = frag.getResource(); //eg jar:file:///a/b/c/foo.jar!/META-INF/web-fragment.xml if (Resource.isContainedIn(fragResource,jar)) @@ -209,28 +207,4 @@ public abstract class AbstractConfiguration implements Configuration { return (d!=null && d.getMetaDataComplete() == MetaDataComplete.True); } - - public boolean isExcluded (Resource jar, List<String> orderedJars) - { - if (jar == null) - return false; - - //no ordering, jar cannot be excluded - if (orderedJars == null) - return false; - - //ordering that excludes all jars - if (orderedJars.isEmpty()) - return true; - - //ordering applied, check jar is in it - String fullname = jar.getName(); - int i = fullname.indexOf(".jar"); - int j = fullname.lastIndexOf("/", i); - String name = fullname.substring(j+1,i+4); - if (orderedJars.contains(name)) - return false; - - return true; - } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 75b089fd0c..bb03499d8e 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -24,6 +24,7 @@ import javax.servlet.annotation.HandlesTypes; import org.eclipse.jetty.plus.annotation.ContainerInitializer; import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppContext; /** @@ -34,6 +35,8 @@ import org.eclipse.jetty.webapp.WebAppContext; public class AnnotationConfiguration extends AbstractConfiguration { public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap"; + + public void preConfigure(final WebAppContext context) throws Exception { @@ -59,13 +62,12 @@ public class AnnotationConfiguration extends AbstractConfiguration //Only scan jars and classes if metadata is not complete and the web app is version 3.0, or //a 2.5 version webapp that has specifically asked to discover annotations if (Log.isDebugEnabled()) Log.debug("parsing annotations"); - + AnnotationParser parser = new AnnotationParser(); //Discoverable annotations - those that you have to look for without loading a class parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context)); parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context)); parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context)); - ClassInheritanceHandler classHandler = new ClassInheritanceHandler(); parser.registerClassHandler(classHandler); registerServletContainerInitializerAnnotationHandlers(context, parser); @@ -74,17 +76,30 @@ public class AnnotationConfiguration extends AbstractConfiguration { if (Log.isDebugEnabled()) Log.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered()); parseContainerPath(context, parser); - parseWebInfLib (context, parser); + //email from Rajiv Mordani jsrs 315 7 April 2010 + // If there is a <others/> then the ordering should be + // WEB-INF/classes the order of the declared elements + others. + // In case there is no others then it is + // WEB-INF/classes + order of the elements. parseWebInfClasses(context, parser); + parseWebInfLib (context, parser); } - else - { - if (Log.isDebugEnabled()) Log.debug("Scanning only classes in web.xml for annotations"); - parse25Classes(context, parser); - } //save the type inheritance map created by the parser for later reference context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap()); + + /* + * processing is now done in metadata.resolve() + * + //TODO change the time at which the discovered annotations are applied. According to the + //servlet spec p.81, the annotations associated with a fragment have to be applied directly + //after those of the fragment's descriptor. For now, to make progress, we just process them + //as we have been doing, ie after all the descriptors have been processed. + for (ClassAnnotation annotation:discoveredAnnotations) + { + annotation.apply(); + } + */ } } @@ -105,6 +120,7 @@ public class AnnotationConfiguration extends AbstractConfiguration public void registerServletContainerInitializerAnnotationHandlers (WebAppContext context, AnnotationParser parser) + throws Exception { //TODO verify my interpretation of the spec. That is, that metadata-complete has nothing //to do with finding the ServletContainerInitializers, classes designated to be of interest to them, @@ -125,7 +141,7 @@ public class AnnotationConfiguration extends AbstractConfiguration { for (ServletContainerInitializer service : loadedInitializers) { - if (!isFromExcludedJar(context, orderedJars, service)) + if (!isFromExcludedJar(context, service)) { HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class); ContainerInitializer initializer = new ContainerInitializer(); @@ -147,10 +163,10 @@ public class AnnotationConfiguration extends AbstractConfiguration } } else - Log.info("No classes in HandlesTypes on initializer "+service.getClass()); + if (Log.isDebugEnabled()) Log.debug("No classes in HandlesTypes on initializer "+service.getClass()); } else - Log.info("No annotation on initializer "+service.getClass()); + if (Log.isDebugEnabled()) Log.debug("No annotation on initializer "+service.getClass()); } } } @@ -163,26 +179,29 @@ public class AnnotationConfiguration extends AbstractConfiguration * @param service * @return */ - public boolean isFromExcludedJar (WebAppContext context, List<String> orderedJars, ServletContainerInitializer service) + public boolean isFromExcludedJar (WebAppContext context, ServletContainerInitializer service) + throws Exception { - boolean isExcluded = false; - - try - { - String loadingJarName = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class").toString(); - - int i = loadingJarName.indexOf(".jar"); - int j = loadingJarName.lastIndexOf("/", i); - loadingJarName = loadingJarName.substring(j+1,i+4); - - if (orderedJars != null) - isExcluded = orderedJars.contains(loadingJarName); - } - catch (Exception e) - { - Log.warn("Problem determining jar containing ServletContaininerInitializer "+service, e); - } + List<String> orderedLibs = (List<String>)context.getAttribute(ServletContext.ORDERED_LIBS); + + //If no ordering, nothing is excluded + if (orderedLibs == null) + return false; + + //ordering that does not include any jars, everything excluded + if (orderedLibs.isEmpty()) + return true; + + + String loadingJarName = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class").toString(); + + int i = loadingJarName.indexOf(".jar"); + if (i < 0) + return false; //not from a jar therefore not from WEB-INF so not excludable + + int j = loadingJarName.lastIndexOf("/", i); + loadingJarName = loadingJarName.substring(j+1,i+4); - return isExcluded; + return (!orderedLibs.contains(loadingJarName)); } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index 56577ef0de..85b0d039cf 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -43,7 +43,7 @@ import org.objectweb.asm.commons.EmptyVisitor; public class AnnotationParser { protected List<String> _parsedClassNames = new ArrayList<String>(); - protected Map<String, DiscoverableAnnotationHandler> _annotationHandlers = new HashMap<String, DiscoverableAnnotationHandler>(); + protected Map<String, List<DiscoverableAnnotationHandler>> _annotationHandlers = new HashMap<String, List<DiscoverableAnnotationHandler>>(); protected List<ClassHandler> _classHandlers = new ArrayList<ClassHandler>(); protected List<MethodHandler> _methodHandlers = new ArrayList<MethodHandler>(); protected List<FieldHandler> _fieldHandlers = new ArrayList<FieldHandler>(); @@ -310,12 +310,15 @@ public class AnnotationParser public void visitEnd() { super.visitEnd(); - + //call all AnnotationHandlers with classname, annotation name + values - DiscoverableAnnotationHandler handler = AnnotationParser.this._annotationHandlers.get(_annotationName); - if (handler != null) + List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName); + if (handlers != null) { - handler.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues); + for (DiscoverableAnnotationHandler h:handlers) + { + h.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues); + } } } }; @@ -340,10 +343,13 @@ public class AnnotationParser { super.visitEnd(); //call all AnnotationHandlers with classname, method, annotation name + values - DiscoverableAnnotationHandler handler = AnnotationParser.this._annotationHandlers.get(_annotationName); - if (handler != null) + List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName); + if (handlers != null) { - handler.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues); + for (DiscoverableAnnotationHandler h:handlers) + { + h.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues); + } } } }; @@ -369,10 +375,13 @@ public class AnnotationParser public void visitEnd() { super.visitEnd(); - DiscoverableAnnotationHandler handler = AnnotationParser.this._annotationHandlers.get(_annotationName); - if (handler != null) + List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName); + if (handlers != null) { - handler.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues); + for (DiscoverableAnnotationHandler h:handlers) + { + h.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues); + } } } }; @@ -383,9 +392,22 @@ public class AnnotationParser } + /** + * Register a handler that will be called back when the named annotation is + * encountered on a class. + * + * @param annotationName + * @param handler + */ public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler) { - _annotationHandlers.put(annotationName, handler); + List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName); + if (handlers == null) + { + handlers = new ArrayList<DiscoverableAnnotationHandler>(); + _annotationHandlers.put(annotationName, handlers); + } + handlers.add(handler); } public void registerClassHandler (ClassHandler handler) @@ -499,7 +521,6 @@ public class AnnotationParser * Only class files in jar files will be scanned. * @param loader * @param visitParents - * @param jarNamePattern * @param nullInclusive * @param resolver * @throws Exception @@ -588,6 +609,14 @@ public class AnnotationParser scanner.scan(null, uris, true); } + public void parse (URI uri, final ClassNameResolver resolver) + throws Exception + { + if (uri == null) + return; + URI[] uris = {uri}; + parse(uris, resolver); + } private void scanClass (InputStream is) throws IOException diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java index a76544306d..9aa6f3ea07 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java @@ -21,7 +21,7 @@ public interface ClassNameResolver * Based on the execution context, should the class represented * by "name" be excluded from consideration? * @param name - * @return + * @return true if classname is excluded */ public boolean isExcluded (String name); @@ -31,7 +31,7 @@ public interface ClassNameResolver * represented by "name" is detected, should the existing * one be overridden or not? * @param name - * @return + * @return true if name should be overridden */ public boolean shouldOverride (String name); } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java index 051b8074fd..e224855d69 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java @@ -32,7 +32,7 @@ import org.eclipse.jetty.webapp.WebAppContext; public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotationHandler { - protected WebAppContext _wac; + protected WebAppContext _context; /** * @param introspectAncestors @@ -40,7 +40,7 @@ public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotat public DeclareRolesAnnotationHandler(WebAppContext context) { super(false); - _wac = context; + _context = context; } @@ -57,15 +57,11 @@ public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotat return; String[] roles = declareRoles.value(); - + if (roles != null && roles.length > 0) { - HashSet<String> union = new HashSet<String>(); - Set<String> existing = ((ConstraintSecurityHandler)_wac.getSecurityHandler()).getRoles(); - if (existing != null) - union.addAll(existing); - union.addAll(Arrays.asList(roles)); - ((ConstraintSecurityHandler)_wac.getSecurityHandler()).setRoles(union); + for (String r:roles) + ((ConstraintSecurityHandler)_context.getSecurityHandler()).addRole(r); } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java index 24e28104fb..24a21c5dd0 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java @@ -19,6 +19,8 @@ import javax.servlet.annotation.MultipartConfig; import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.webapp.Descriptor; +import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; /** @@ -28,13 +30,13 @@ import org.eclipse.jetty.webapp.WebAppContext; */ public class MultiPartConfigAnnotationHandler extends AbstractIntrospectableAnnotationHandler { - protected WebAppContext _wac; + protected WebAppContext _context; public MultiPartConfigAnnotationHandler(WebAppContext context) { //TODO verify that MultipartConfig is not inheritable super(false); - _wac = context; + _context = context; } /** * @see org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler#doHandle(java.lang.Class) @@ -48,24 +50,41 @@ public class MultiPartConfigAnnotationHandler extends AbstractIntrospectableAnno if (multi == null) return; - + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + //TODO: The MultipartConfigElement needs to be set on the ServletHolder's Registration. //How to identify the correct Servlet? If the Servlet has no WebServlet annotation on it, does it mean that this MultipartConfig //annotation applies to all declared instances in web.xml/programmatically? //Assuming TRUE for now. - - ServletHolder[] holders = _wac.getServletHandler().getServlets(); + ServletHolder holder = getServletHolderForClass(clazz); + if (holder != null) + { + Descriptor d = metaData.getOriginDescriptor(holder.getName()+".servlet.multipart-config"); + //if a descriptor has already set the value for multipart config, do not + //let the annotation override it + if (d == null) + { + metaData.setOrigin(holder.getName()+".servlet.multipart-config"); + holder.getRegistration().setMultipartConfig(new MultipartConfigElement(multi)); + } + } + } + + private ServletHolder getServletHolderForClass (Class clazz) + { + ServletHolder holder = null; + ServletHolder[] holders = _context.getServletHandler().getServlets(); if (holders != null) { for (ServletHolder h : holders) { if (h.getClassName().equals(clazz.getName())) { - h.getRegistration().setMultipartConfig(new MultipartConfigElement(multi)); + holder = h; } } } + return holder; } - } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java index 1cae8bc7b3..357cd4e39f 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java @@ -21,18 +21,19 @@ import javax.annotation.PostConstruct; import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler; import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; import org.eclipse.jetty.plus.annotation.PostConstructCallback; +import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; public class PostConstructAnnotationHandler extends AbstractIntrospectableAnnotationHandler { - protected WebAppContext _wac; + protected WebAppContext _context; protected LifeCycleCallbackCollection _callbacks; public PostConstructAnnotationHandler (WebAppContext wac) { super(true); - _wac = wac; - _callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); + _context = wac; + _callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); } @@ -55,7 +56,17 @@ public class PostConstructAnnotationHandler extends AbstractIntrospectableAnnota throw new IllegalStateException(m+" throws checked exceptions"); if (Modifier.isStatic(m.getModifiers())) throw new IllegalStateException(m+" is static"); - + + //ServletSpec 3.0 p80 If web.xml declares even one post-construct then all post-constructs + //in fragments must be ignored. Otherwise, they are additive. + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + MetaData.Origin origin = metaData.getOrigin("post-construct"); + if (origin != null && + (origin == MetaData.Origin.WebXml || + origin == MetaData.Origin.WebDefaults || + origin == MetaData.Origin.WebOverride)) + return; + PostConstructCallback callback = new PostConstructCallback(); callback.setTarget(clazz.getName(), m.getName()); _callbacks.add(callback); diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PreDestroyAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PreDestroyAnnotationHandler.java index 5e551e1422..3b593f5ca7 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PreDestroyAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PreDestroyAnnotationHandler.java @@ -21,23 +21,23 @@ import javax.annotation.PreDestroy; import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler; import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; import org.eclipse.jetty.plus.annotation.PreDestroyCallback; +import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; public class PreDestroyAnnotationHandler extends AbstractIntrospectableAnnotationHandler { - WebAppContext _wac; + WebAppContext _context; LifeCycleCallbackCollection _callbacks; public PreDestroyAnnotationHandler (WebAppContext wac) { super(true); - _wac = wac; - _callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); + _context = wac; + _callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); } public void doHandle(Class clazz) - { - + { //Check that the PreDestroy is on a class that we're interested in if (Util.isServletType(clazz)) { @@ -55,7 +55,17 @@ public class PreDestroyAnnotationHandler extends AbstractIntrospectableAnnotatio throw new IllegalStateException(m+" throws checked exceptions"); if (Modifier.isStatic(m.getModifiers())) throw new IllegalStateException(m+" is static"); - + + //ServletSpec 3.0 p80 If web.xml declares even one predestroy then all predestroys + //in fragments must be ignored. Otherwise, they are additive. + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + MetaData.Origin origin = metaData.getOrigin("pre-destroy"); + if (origin != null && + (origin == MetaData.Origin.WebXml || + origin == MetaData.Origin.WebDefaults || + origin == MetaData.Origin.WebOverride)) + return; + PreDestroyCallback callback = new PreDestroyCallback(); callback.setTarget(clazz.getName(), m.getName()); _callbacks.add(callback); diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java index eb2a249e6f..c3e5548146 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java @@ -26,18 +26,20 @@ import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectab import org.eclipse.jetty.plus.annotation.Injection; import org.eclipse.jetty.plus.annotation.InjectionCollection; import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.MetaData.Origin; public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationHandler { - protected WebAppContext _wac; + protected WebAppContext _context; protected InjectionCollection _injections; public ResourceAnnotationHandler (WebAppContext wac) { super(true); - _wac = wac; - _injections = (InjectionCollection)_wac.getAttribute(InjectionCollection.INJECTION_COLLECTION); + _context = wac; + _injections = (InjectionCollection)_context.getAttribute(InjectionCollection.INJECTION_COLLECTION); } @@ -78,8 +80,8 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH try { - if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name,mappedName)) - if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name,mappedName)) + if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name,mappedName)) + if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name,mappedName)) throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName)); } catch (NamingException e) @@ -109,29 +111,41 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH } //work out default name - String name = clazz.getCanonicalName()+"/"+field.getName(); - + String name = clazz.getCanonicalName()+"/"+field.getName(); //allow @Resource name= to override the field name name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name); String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null); //get the type of the Field Class type = field.getType(); - - //check if an injection has already been setup for this target by web.xml - Injection webXmlInjection = _injections.getInjection(name, clazz, field); - if (webXmlInjection == null) + + //Servlet Spec 3.0 p. 76 + //If a descriptor has specified at least 1 injection target for this + //resource, then it overrides this annotation + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + if (metaData.getOriginDescriptor("resource-ref."+name+".injection") != null) + { + //at least 1 injection was specified for this resource by a descriptor, so + //it overrides this annotation + return; + } + + //No injections for this resource in any descriptors, so we can add it + //Does the injection already exist? + Injection injection = _injections.getInjection(name, clazz, field); + if (injection == null) { + //No injection has been specified, add it try { - boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName); + boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name, mappedName); if (!bound) - bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName); + bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName); if (!bound) bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(null, name, mappedName); if (!bound) { - //see if there is an env-entry value been bound from web.xml + //see if there is an env-entry value been bound try { InitialContext ic = new InitialContext(); @@ -149,11 +163,14 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH { Log.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name); // Make the Injection for it if the binding succeeded - Injection injection = new Injection(); + injection = new Injection(); injection.setTarget(clazz, field, type); injection.setJndiName(name); injection.setMappingName(mappedName); _injections.add(injection); + + //TODO - an @Resource is equivalent to a resource-ref, resource-env-ref, message-destination + metaData.setOrigin("resource-ref."+name+".injection"); } else if (!Util.isEnvEntryType(type)) { @@ -182,7 +199,6 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH * * This will generate a JNDI entry, and an Injection to be * processed when an instance of the class is created. - * @param injections */ public void handleMethod(Class clazz, Method method) { @@ -245,19 +261,31 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH Class paramType = method.getParameterTypes()[0]; Class resourceType = resource.type(); + + //Servlet Spec 3.0 p. 76 + //If a descriptor has specified at least 1 injection target for this + //resource, then it overrides this annotation + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + if (metaData.getOriginDescriptor("resource-ref."+name+".injection") != null) + { + //at least 1 injection was specified for this resource by a descriptor, so + //it overrides this annotation + return; + } + //check if an injection has already been setup for this target by web.xml - Injection webXmlInjection = _injections.getInjection(name, clazz, method, paramType); - if (webXmlInjection == null) + Injection injection = _injections.getInjection(name, clazz, method, paramType); + if (injection == null) { try { //try binding name to environment //try the webapp's environment first - boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName); + boolean bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name, mappedName); //try the server's environment if (!bound) - bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName); + bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName); //try the jvm's environment if (!bound) @@ -284,11 +312,13 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH { Log.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name); // Make the Injection for it - Injection injection = new Injection(); + injection = new Injection(); injection.setTarget(clazz, method,paramType,resourceType); injection.setJndiName(name); injection.setMappingName(mappedName); _injections.add(injection); + //TODO - an @Resource is equivalent to a resource-ref, resource-env-ref, message-destination + metaData.setOrigin("resource-ref."+name+".injection"); } else if (!Util.isEnvEntryType(paramType)) { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java index 1c17208770..cf849771d7 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java @@ -20,24 +20,27 @@ import javax.servlet.Servlet; import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; import org.eclipse.jetty.plus.annotation.RunAsCollection; +import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.Descriptor; +import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; public class RunAsAnnotationHandler extends AbstractIntrospectableAnnotationHandler { - protected WebAppContext _wac; + protected WebAppContext _context; public RunAsAnnotationHandler (WebAppContext wac) { //Introspect only the given class for a RunAs annotation, as it is a class level annotation, //and according to Common Annotation Spec p2-6 a class-level annotation is not inheritable. super(false); - _wac = wac; + _context = wac; } public void doHandle (Class clazz) { - RunAsCollection runAsCollection = (RunAsCollection)_wac.getAttribute(RunAsCollection.RUNAS_COLLECTION); + RunAsCollection runAsCollection = (RunAsCollection)_context.getAttribute(RunAsCollection.RUNAS_COLLECTION); if (!Servlet.class.isAssignableFrom(clazz)) return; @@ -48,10 +51,22 @@ public class RunAsAnnotationHandler extends AbstractIntrospectableAnnotationHand String role = runAs.value(); if (role != null) { - org.eclipse.jetty.plus.annotation.RunAs ra = new org.eclipse.jetty.plus.annotation.RunAs(); - ra.setTargetClassName(clazz.getCanonicalName()); - ra.setRoleName(role); - runAsCollection.add(ra); + ServletHolder holder = getServletHolderForClass(clazz); + if (holder != null) + { + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + Descriptor d = metaData.getOriginDescriptor(holder.getName()+".servlet.run-as"); + //if a descriptor has already set the value for run-as, do not + //let the annotation override it + if (d == null) + { + metaData.setOrigin(holder.getName()+".servlet.run-as"); + org.eclipse.jetty.plus.annotation.RunAs ra = new org.eclipse.jetty.plus.annotation.RunAs(); + ra.setTargetClassName(clazz.getCanonicalName()); + ra.setRoleName(role); + runAsCollection.add(ra); + } + } } else Log.warn("Bad value for @RunAs annotation on class "+clazz.getName()); @@ -71,4 +86,20 @@ public class RunAsAnnotationHandler extends AbstractIntrospectableAnnotationHand Log.warn("@RunAs annotation ignored on method: "+className+"."+methodName+" "+signature); } + private ServletHolder getServletHolderForClass (Class clazz) + { + ServletHolder holder = null; + ServletHolder[] holders = _context.getServletHandler().getServlets(); + if (holders != null) + { + for (ServletHolder h : holders) + { + if (h.getClassName().equals(clazz.getName())) + { + holder = h; + } + } + } + return holder; + } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java index b6556a7ace..aac9748b61 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java @@ -52,12 +52,12 @@ import org.eclipse.jetty.webapp.WebAppContext; public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnnotationHandler { - private WebAppContext _wac; + private WebAppContext _context; public ServletSecurityAnnotationHandler(WebAppContext wac) { super(false); - _wac = wac; + _context = wac; } /** @@ -65,7 +65,7 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno */ public void doHandle(Class clazz) { - if (!(_wac.getSecurityHandler() instanceof ConstraintAware)) + if (!(_context.getSecurityHandler() instanceof ConstraintAware)) { Log.warn("SecurityHandler not ConstraintAware, skipping security annotation processing"); return; @@ -79,7 +79,7 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno //of the url patterns defined for this servlet, then skip the security annotation. List<ServletMapping> servletMappings = getServletMappings(clazz.getCanonicalName()); - List<ConstraintMapping> constraintMappings = LazyList.array2List(((ConstraintAware)_wac.getSecurityHandler()).getConstraintMappings()); + List<ConstraintMapping> constraintMappings = ((ConstraintAware)_context.getSecurityHandler()).getConstraintMappings(); if (constraintsExist(servletMappings, constraintMappings)) { @@ -87,6 +87,9 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno return; } + //Make a fresh list + constraintMappings = new ArrayList<ConstraintMapping>(); + //Get the values that form the constraints that will apply unless there are HttpMethodConstraints to augment them HttpConstraint defaults = servletSecurity.value(); @@ -102,9 +105,10 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno servletSecurity.httpMethodConstraints())); //set up the security constraints produced by the annotation - ConstraintAware securityHandler = (ConstraintAware)_wac.getSecurityHandler(); - - securityHandler.setConstraintMappings((ConstraintMapping[]) LazyList.toArray(constraintMappings,ConstraintMapping.class),securityHandler.getRoles()); + ConstraintAware securityHandler = (ConstraintAware)_context.getSecurityHandler(); + + for (ConstraintMapping m:constraintMappings) + securityHandler.addConstraintMapping(m); } @@ -234,11 +238,11 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno protected List<ServletMapping> getServletMappings(String className) { List<ServletMapping> results = new ArrayList<ServletMapping>(); - ServletMapping[] mappings = _wac.getServletHandler().getServletMappings(); + ServletMapping[] mappings = _context.getServletHandler().getServletMappings(); for (ServletMapping mapping : mappings) { //Check the name of the servlet that this mapping applies to, and then find the ServletHolder for it to find it's class - ServletHolder holder = _wac.getServletHandler().getServlet(mapping.getServletName()); + ServletHolder holder = _context.getServletHandler().getServlet(mapping.getServletName()); if (holder.getClassName().equals(className)) results.add(mapping); } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java index b920ab711e..5b394efeb6 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java @@ -21,8 +21,6 @@ import org.objectweb.asm.Type; /** * Util - * - * */ public class Util { @@ -37,8 +35,16 @@ public class Util /** * Check if the presented method belongs to a class that is one * of the classes with which a servlet container should be concerned. - * @param m - * @return + * @param c + * @return true if class is a type of one of the following: + * ({@link javax.servlet.Servlet}, + * {@link javax.servlet.Filter}, + * {@link javax.servlet.ServletContextListener}, + * {@link javax.servlet.ServletContextAttributeListener}, + * {@link javax.servlet.ServletRequestListener}, + * {@link javax.servlet.ServletRequestAttributeListener}, + * {@link javax.servlet.http.HttpSessionListener}, + * {@link javax.servlet.http.HttpSessionAttributeListener}) */ public static boolean isServletType (Class c) { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java new file mode 100644 index 0000000000..5a101f60cf --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java @@ -0,0 +1,210 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import java.util.ArrayList; +import java.util.EnumSet; + +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.annotation.WebFilter; +import javax.servlet.annotation.WebInitParam; + +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; +import org.eclipse.jetty.servlet.Holder; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.MetaData.Origin; + +/** + * WebFilterAnnotation + * + * + */ +public class WebFilterAnnotation extends DiscoveredAnnotation +{ + + /** + * @param context + * @param className + */ + public WebFilterAnnotation(WebAppContext context, String className) + { + super(context, className); + } + + /** + * @see org.eclipse.jetty.annotations.ClassAnnotation#apply() + */ + public void apply() + { + // TODO verify against rules for annotation v descriptor + + Class clazz = getTargetClass(); + if (clazz == null) + { + Log.warn(_className+" cannot be loaded"); + return; + } + + + //Servlet Spec 8.1.2 + if (!Filter.class.isAssignableFrom(clazz)) + { + Log.warn(clazz.getName()+" is not assignable from javax.servlet.Filter"); + return; + } + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + + WebFilter filterAnnotation = (WebFilter)clazz.getAnnotation(WebFilter.class); + + if (filterAnnotation.value().length > 0 && filterAnnotation.urlPatterns().length > 0) + { + Log.warn(clazz.getName()+" defines both @WebFilter.value and @WebFilter.urlPatterns"); + return; + } + + String name = (filterAnnotation.filterName().equals("")?clazz.getName():filterAnnotation.filterName()); + String[] urlPatterns = filterAnnotation.value(); + if (urlPatterns.length == 0) + urlPatterns = filterAnnotation.urlPatterns(); + + FilterHolder holder = _context.getServletHandler().getFilter(name); + if (holder == null) + { + //Filter with this name does not already exist, so add it + holder = _context.getServletHandler().newFilterHolder(Holder.Source.ANNOTATION); + holder.setName(name); + + holder.setHeldClass(clazz); + metaData.setOrigin(name+".filter.filter-class"); + + holder.setDisplayName(filterAnnotation.displayName()); + metaData.setOrigin(name+".filter.display-name"); + + for (WebInitParam ip: filterAnnotation.initParams()) + { + holder.setInitParameter(ip.name(), ip.value()); + metaData.setOrigin(name+".filter.init-param."+ip.name()); + } + + FilterMapping mapping = new FilterMapping(); + mapping.setFilterName(holder.getName()); + + if (urlPatterns.length > 0) + { + ArrayList paths = new ArrayList(); + for (String s:urlPatterns) + { + paths.add(Util.normalizePattern(s)); + } + mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()])); + } + + if (filterAnnotation.servletNames().length > 0) + { + ArrayList<String> names = new ArrayList<String>(); + for (String s : filterAnnotation.servletNames()) + { + names.add(s); + } + mapping.setServletNames((String[])names.toArray(new String[names.size()])); + } + + EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class); + for (DispatcherType d : filterAnnotation.dispatcherTypes()) + { + dispatcherSet.add(d); + } + mapping.setDispatcherTypes(dispatcherSet); + metaData.setOrigin(name+".filter.mappings"); + + holder.setAsyncSupported(filterAnnotation.asyncSupported()); + metaData.setOrigin(name+".filter.async-supported"); + + _context.getServletHandler().addFilter(holder); + _context.getServletHandler().addFilterMapping(mapping); + } + else + { + //A Filter definition for the same name already exists from web.xml + //ServletSpec 3.0 p81 if the Filter is already defined and has mappings, + //they override the annotation. If it already has DispatcherType set, that + //also overrides the annotation. Init-params are additive, but web.xml overrides + //init-params of the same name. + for (WebInitParam ip: filterAnnotation.initParams()) + { + //if (holder.getInitParameter(ip.name()) == null) + if (metaData.getOrigin(name+".filter.init-param."+ip.name())==Origin.NotSet) + { + holder.setInitParameter(ip.name(), ip.value()); + metaData.setOrigin(name+".filter.init-param."+ip.name()); + } + } + + FilterMapping[] mappings = _context.getServletHandler().getFilterMappings(); + boolean mappingExists = false; + if (mappings != null) + { + for (FilterMapping m:mappings) + { + if (m.getFilterName().equals(name)) + { + mappingExists = true; + break; + } + } + } + //if a descriptor didn't specify at least one mapping, use the mappings from the annotation and the DispatcherTypes + //from the annotation + if (!mappingExists) + { + FilterMapping mapping = new FilterMapping(); + mapping.setFilterName(holder.getName()); + + if (urlPatterns.length > 0) + { + ArrayList paths = new ArrayList(); + for (String s:urlPatterns) + { + paths.add(Util.normalizePattern(s)); + } + mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()])); + } + if (filterAnnotation.servletNames().length > 0) + { + ArrayList<String> names = new ArrayList<String>(); + for (String s : filterAnnotation.servletNames()) + { + names.add(s); + } + mapping.setServletNames((String[])names.toArray(new String[names.size()])); + } + + EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class); + for (DispatcherType d : filterAnnotation.dispatcherTypes()) + { + dispatcherSet.add(d); + } + mapping.setDispatcherTypes(dispatcherSet); + _context.getServletHandler().addFilterMapping(mapping); + metaData.setOrigin(name+".filter.mappings"); + } + } + } + +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java index b252dafb7c..5ee2d729fb 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 2009-2010 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -13,178 +13,33 @@ package org.eclipse.jetty.annotations; -import java.util.ArrayList; -import java.util.EnumSet; import java.util.List; -import javax.servlet.DispatcherType; -import javax.servlet.Filter; -import javax.servlet.annotation.WebFilter; -import javax.servlet.annotation.WebInitParam; - import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.servlet.FilterMapping; -import org.eclipse.jetty.servlet.Holder; -import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; import org.eclipse.jetty.webapp.WebAppContext; +/** + * WebFilterAnnotationHandler + * + * + */ public class WebFilterAnnotationHandler implements DiscoverableAnnotationHandler { - protected WebAppContext _wac; - + protected WebAppContext _context; + public WebFilterAnnotationHandler (WebAppContext wac) { - _wac = wac; + _context = wac; } - + public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, List<Value> values) { - Class clazz = null; - try - { - clazz = Loader.loadClass(null, className); - } - catch (Exception e) - { - Log.warn(e); - return; - } - - //Servlet Spec 8.1.2 - if (!Filter.class.isAssignableFrom(clazz)) - { - Log.warn(clazz.getName()+" is not assignable from javax.servlet.Filter"); - return; - } - - WebFilter filterAnnotation = (WebFilter)clazz.getAnnotation(WebFilter.class); - - if (filterAnnotation.value().length > 0 && filterAnnotation.urlPatterns().length > 0) - { - Log.warn(clazz.getName()+" defines both @WebFilter.value and @WebFilter.urlPatterns"); - return; - } - - String name = (filterAnnotation.filterName().equals("")?clazz.getName():filterAnnotation.filterName()); - String[] urlPatterns = filterAnnotation.value(); - if (urlPatterns.length == 0) - urlPatterns = filterAnnotation.urlPatterns(); - - FilterHolder holder = _wac.getServletHandler().getFilter(name); - if (holder == null) - { - //Filter with this name does not already exist, so add it - holder = _wac.getServletHandler().newFilterHolder(Holder.Source.ANNOTATION); - holder.setHeldClass(clazz); - holder.setName(name); - holder.setDisplayName(filterAnnotation.displayName()); - - for (WebInitParam ip: filterAnnotation.initParams()) - { - holder.setInitParameter(ip.name(), ip.value()); - } - - FilterMapping mapping = new FilterMapping(); - mapping.setFilterName(holder.getName()); - - if (urlPatterns.length > 0) - { - ArrayList paths = new ArrayList(); - for (String s:urlPatterns) - { - paths.add(Util.normalizePattern(s)); - } - mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()])); - } - - if (filterAnnotation.servletNames().length > 0) - { - ArrayList<String> names = new ArrayList<String>(); - for (String s : filterAnnotation.servletNames()) - { - names.add(s); - } - mapping.setServletNames((String[])names.toArray(new String[names.size()])); - } - - EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class); - for (DispatcherType d : filterAnnotation.dispatcherTypes()) - { - dispatcherSet.add(d); - } - mapping.setDispatcherTypes(dispatcherSet); - - holder.setAsyncSupported(filterAnnotation.asyncSupported()); - - _wac.getServletHandler().addFilter(holder); - _wac.getServletHandler().addFilterMapping(mapping); - } - else - { - //A Filter definition for the same name already exists from web.xml - //ServletSpec 3.0 p81 if the Filter is already defined and has mappings, - //they override the annotation. If it already has DispatcherType set, that - //also overrides the annotation. Init-params are additive, but web.xml overrides - //init-params of the same name. - for (WebInitParam ip: filterAnnotation.initParams()) - { - if (holder.getInitParameter(ip.name()) == null) - holder.setInitParameter(ip.name(), ip.value()); - } - - FilterMapping[] mappings = _wac.getServletHandler().getFilterMappings(); - boolean mappingExists = false; - if (mappings != null) - { - for (FilterMapping m:mappings) - { - if (m.getFilterName().equals(name)) - { - mappingExists = true; - break; - } - } - } - //if the web.xml didn't specify at least one mapping, use the mappings from the annotation and the DispatcherTypes - //from the annotation - if (!mappingExists) - { - FilterMapping mapping = new FilterMapping(); - mapping.setFilterName(holder.getName()); - - if (urlPatterns.length > 0) - { - ArrayList paths = new ArrayList(); - for (String s:urlPatterns) - { - paths.add(Util.normalizePattern(s)); - } - mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()])); - } - if (filterAnnotation.servletNames().length > 0) - { - ArrayList<String> names = new ArrayList<String>(); - for (String s : filterAnnotation.servletNames()) - { - names.add(s); - } - mapping.setServletNames((String[])names.toArray(new String[names.size()])); - } - - EnumSet<DispatcherType> dispatcherSet = EnumSet.noneOf(DispatcherType.class); - for (DispatcherType d : filterAnnotation.dispatcherTypes()) - { - dispatcherSet.add(d); - } - mapping.setDispatcherTypes(dispatcherSet); - - _wac.getServletHandler().addFilterMapping(mapping); - } - } + WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, className); + ((List<DiscoveredAnnotation>)_context.getAttribute(AnnotationConfiguration.DISCOVERED_ANNOTATIONS)).add(wfAnnotation); } public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, @@ -198,5 +53,5 @@ public class WebFilterAnnotationHandler implements DiscoverableAnnotationHandler { Log.warn ("@WebFilter not applicable for methods: "+className+"."+methodName+" "+signature); } - + } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java new file mode 100644 index 0000000000..a92a27c9c5 --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java @@ -0,0 +1,83 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import javax.servlet.ServletContextAttributeListener; +import javax.servlet.ServletContextListener; +import javax.servlet.ServletRequestAttributeListener; +import javax.servlet.ServletRequestListener; +import javax.servlet.http.HttpSessionAttributeListener; +import javax.servlet.http.HttpSessionListener; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.MetaData.Origin; + +/** + * WebListenerAnnotation + * + * + */ +public class WebListenerAnnotation extends DiscoveredAnnotation +{ + + /** + * @param context + * @param className + */ + public WebListenerAnnotation(WebAppContext context, String className) + { + super(context, className); + } + + /** + * @see org.eclipse.jetty.annotations.ClassAnnotation#apply() + */ + public void apply() + { + // TODO check algorithm against ordering rules for descriptors v annotations + + Class clazz = getTargetClass(); + + if (clazz == null) + { + Log.warn(_className+" cannot be loaded"); + return; + } + + try + { + if (ServletContextListener.class.isAssignableFrom(clazz) || + ServletContextAttributeListener.class.isAssignableFrom(clazz) || + ServletRequestListener.class.isAssignableFrom(clazz) || + ServletRequestAttributeListener.class.isAssignableFrom(clazz) || + HttpSessionListener.class.isAssignableFrom(clazz) || + HttpSessionAttributeListener.class.isAssignableFrom(clazz)) + { + java.util.EventListener listener = (java.util.EventListener)clazz.newInstance(); + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + if (metaData.getOrigin(clazz.getName()+".listener") == Origin.NotSet) + _context.addEventListener(listener); + } + else + Log.warn(clazz.getName()+" does not implement one of the servlet listener interfaces"); + } + catch (Exception e) + { + Log.warn(e); + } + } +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java index e3ff3e50e9..262973862c 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 2009-2010 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -14,55 +14,27 @@ package org.eclipse.jetty.annotations; import java.util.List; -import javax.servlet.ServletContextAttributeListener; -import javax.servlet.ServletContextListener; -import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.ServletRequestListener; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionListener; - import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; -import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; import org.eclipse.jetty.webapp.WebAppContext; public class WebListenerAnnotationHandler implements DiscoverableAnnotationHandler { - protected WebAppContext _wac; + protected WebAppContext _context; public WebListenerAnnotationHandler (WebAppContext wac) { - _wac = wac; + _context = wac; } public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, List<Value> values) { - Class clazz = null; - try - { - clazz = Loader.loadClass(null, className); - - if (ServletContextListener.class.isAssignableFrom(clazz) || - ServletContextAttributeListener.class.isAssignableFrom(clazz) || - ServletRequestListener.class.isAssignableFrom(clazz) || - ServletRequestAttributeListener.class.isAssignableFrom(clazz) || - HttpSessionListener.class.isAssignableFrom(clazz) || - HttpSessionAttributeListener.class.isAssignableFrom(clazz)) - { - java.util.EventListener listener = (java.util.EventListener)clazz.newInstance(); - _wac.addEventListener(listener); - } - else - Log.warn(clazz.getName()+" does not implement one of the servlet listener interfaces"); - } - catch (Exception e) - { - Log.warn(e); - return; - } + WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, className); + ((List<DiscoveredAnnotation>)_context.getAttribute(AnnotationConfiguration.DISCOVERED_ANNOTATIONS)).add(wlAnnotation); } public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java new file mode 100644 index 0000000000..ee78f38030 --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java @@ -0,0 +1,169 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import java.util.ArrayList; + +import javax.servlet.annotation.WebInitParam; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; + +import org.eclipse.jetty.servlet.Holder; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; +import org.eclipse.jetty.util.LazyList; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.MetaData.Origin; + +/** + * WebServletAnnotation + * + * + */ +public class WebServletAnnotation extends DiscoveredAnnotation +{ + + public WebServletAnnotation (WebAppContext context, String className) + { + super(context, className); + } + + /** + * @see org.eclipse.jetty.annotations.ClassAnnotation#apply() + */ + public void apply() + { + //TODO check this algorithm with new rules for applying descriptors and annotations in order + Class clazz = getTargetClass(); + + if (clazz == null) + { + Log.warn(_className+" cannot be loaded"); + return; + } + + //Servlet Spec 8.1.1 + if (!HttpServlet.class.isAssignableFrom(clazz)) + { + Log.warn(clazz.getName()+" is not assignable from javax.servlet.http.HttpServlet"); + return; + } + + WebServlet annotation = (WebServlet)clazz.getAnnotation(WebServlet.class); + + if (annotation.urlPatterns().length > 0 && annotation.value().length > 0) + { + Log.warn(clazz.getName()+ " defines both @WebServlet.value and @WebServlet.urlPatterns"); + return; + } + + String[] urlPatterns = annotation.value(); + if (urlPatterns.length == 0) + urlPatterns = annotation.urlPatterns(); + + if (urlPatterns.length == 0) + { + Log.warn(clazz.getName()+ " defines neither @WebServlet.value nor @WebServlet.urlPatterns"); + return; + } + + //canonicalize the patterns + ArrayList<String> urlPatternList = new ArrayList<String>(); + for (String p : urlPatterns) + urlPatternList.add(Util.normalizePattern(p)); + + String servletName = (annotation.name().equals("")?clazz.getName():annotation.name()); + + MetaData metaData = ((MetaData)_context.getAttribute(MetaData.METADATA)); + + //Find out if a <servlet> of this type already exists with this name + ServletHolder[] holders = _context.getServletHandler().getServlets(); + boolean isNew = true; + ServletHolder holder = null; + if (holders != null) + { + for (ServletHolder h : holders) + { + if (h.getClassName().equals(clazz.getName()) && h.getName().equals(servletName)) + { + holder = h; + isNew = false; + break; + } + } + } + + if (isNew) + { + //No servlet of this name has already been defined, either by a descriptor + //or another annotation (which would be impossible). + holder = _context.getServletHandler().newServletHolder(Holder.Source.ANNOTATION); + holder.setHeldClass(clazz); + metaData.setOrigin(servletName+".servlet.servlet-class"); + + holder.setName(servletName); + holder.setDisplayName(annotation.displayName()); + metaData.setOrigin(servletName+".servlet.display-name"); + + holder.setInitOrder(annotation.loadOnStartup()); + metaData.setOrigin(servletName+".servlet.load-on-startup"); + + holder.setAsyncSupported(annotation.asyncSupported()); + metaData.setOrigin(servletName+".servlet.async-supported"); + + for (WebInitParam ip:annotation.initParams()) + { + holder.setInitParameter(ip.name(), ip.value()); + metaData.setOrigin(servletName+".servlet.init-param."+ip.name()); + } + + _context.getServletHandler().addServlet(holder); + ServletMapping mapping = new ServletMapping(); + mapping.setServletName(holder.getName()); + mapping.setPathSpecs( LazyList.toStringArray(urlPatternList)); + _context.getServletHandler().addServletMapping(mapping); + metaData.setOrigin(servletName+".servlet.mappings"); + } + else + { + //check if the existing servlet has each init-param from the annotation + //if not, add it + for (WebInitParam ip:annotation.initParams()) + { + //if (holder.getInitParameter(ip.name()) == null) + if (metaData.getOrigin(servletName+".servlet.init-param"+ip.name())==Origin.NotSet) + { + holder.setInitParameter(ip.name(), ip.value()); + metaData.setOrigin(servletName+".servlet.init-param."+ip.name()); + } + } + + //check the url-patterns, if there annotation has a new one, add it + ServletMapping[] mappings = _context.getServletHandler().getServletMappings(); + + //ServletSpec 3.0 p81 If a servlet already has url mappings from a + //descriptor the annotation is ignored + if (mappings == null && metaData.getOriginDescriptor(servletName+".servlet.mappings") != null) + { + ServletMapping mapping = new ServletMapping(); + mapping.setServletName(servletName); + mapping.setPathSpecs(LazyList.toStringArray(urlPatternList)); + _context.getServletHandler().addServletMapping(mapping); + } + } + } +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java index 10b9ce2ea5..d869b98be0 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java @@ -13,25 +13,12 @@ package org.eclipse.jetty.annotations; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.ListIterator; - -import javax.servlet.annotation.MultipartConfig; -import javax.servlet.annotation.WebInitParam; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.servlet.Holder; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.servlet.ServletMapping; -import org.eclipse.jetty.util.LazyList; -import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; import org.eclipse.jetty.webapp.WebAppContext; /** @@ -42,29 +29,18 @@ import org.eclipse.jetty.webapp.WebAppContext; */ public class WebServletAnnotationHandler implements DiscoverableAnnotationHandler { - protected WebAppContext _wac; + protected WebAppContext _context; public WebServletAnnotationHandler (WebAppContext wac) { - _wac = wac; + _context = wac; } /** - * Handle a WebServlet annotation. - * - * If web.xml does not define a servlet of the same name, then this is an entirely - * new servlet definition. + * Handle discovering a WebServlet annotation. * - * Otherwise, the values from web.xml override the values from the annotation except for: - * - * <ul> - * <li>init-params: if the annotation contains a different init-param name, then it is added to the - * effective init-params for the servlet<li> - * <li>url-patterns: if the annotation contains a different url-pattern, then it is added to the - * effective url-patterns for the servlet</li> - * </ul> * * @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List) */ @@ -74,110 +50,8 @@ public class WebServletAnnotationHandler implements DiscoverableAnnotationHandle if (!"javax.servlet.annotation.WebServlet".equals(annotationName)) return; - //TODO Do we want to load the class now and look at the annotation values - //with reflection, or do we want to use the raw annotation values from - //asm parsing? - Class clazz; - try - { - clazz = Loader.loadClass(null, className); - } - catch (Exception e) - { - Log.warn(e); - return; - } - - //Servlet Spec 8.1.1 - if (!HttpServlet.class.isAssignableFrom(clazz)) - { - Log.warn(clazz.getName()+" is not assignable from javax.servlet.http.HttpServlet"); - return; - } - - WebServlet annotation = (WebServlet)clazz.getAnnotation(WebServlet.class); - - if (annotation.urlPatterns().length > 0 && annotation.value().length > 0) - { - Log.warn(clazz.getName()+ " defines both @WebServlet.value and @WebServlet.urlPatterns"); - return; - } - - String[] urlPatterns = annotation.value(); - if (urlPatterns.length == 0) - urlPatterns = annotation.urlPatterns(); - - if (urlPatterns.length == 0) - { - Log.warn(clazz.getName()+ " defines neither @WebServlet.value nor @WebServlet.urlPatterns"); - return; - } - //canonicalize the patterns - ArrayList<String> urlPatternList = new ArrayList<String>(); - for (String p : urlPatterns) - urlPatternList.add(Util.normalizePattern(p)); - - String servletName = (annotation.name().equals("")?clazz.getName():annotation.name()); - - //Find out if a <servlet> from web.xml of this type already exists with this name - ServletHolder[] holders = _wac.getServletHandler().getServlets(); - boolean isNew = true; - ServletHolder holder = null; - if (holders != null) - { - for (ServletHolder h : holders) - { - if (h.getClassName().equals(clazz.getName()) && h.getName().equals(servletName)) - { - holder = h; - isNew = false; - break; - } - } - } - - if (isNew) - { - holder = _wac.getServletHandler().newServletHolder(Holder.Source.ANNOTATION); - holder.setHeldClass(clazz); - holder.setName(servletName); - holder.setDisplayName(annotation.displayName()); - holder.setInitOrder(annotation.loadOnStartup()); - holder.setAsyncSupported(annotation.asyncSupported()); - for (WebInitParam ip:annotation.initParams()) - { - holder.setInitParameter(ip.name(), ip.value()); - } - - _wac.getServletHandler().addServlet(holder); - ServletMapping mapping = new ServletMapping(); - mapping.setServletName(holder.getName()); - mapping.setPathSpecs( LazyList.toStringArray(urlPatternList)); - _wac.getServletHandler().addServletMapping(mapping); - } - else - { - //check if the existing servlet has each init-param from the annotation - //if not, add it - for (WebInitParam ip:annotation.initParams()) - { - if (holder.getInitParameter(ip.name()) == null) - holder.setInitParameter(ip.name(), ip.value()); - } - - //check the url-patterns, if there annotation has a new one, add it - ServletMapping[] mappings = _wac.getServletHandler().getServletMappings(); - - //ServletSpec 3.0 p81 If a servlet already has url mappings from a - //descriptor the annotation is ignored - if (mappings == null) - { - ServletMapping mapping = new ServletMapping(); - mapping.setServletName(servletName); - mapping.setPathSpecs(LazyList.toStringArray(urlPatternList)); - _wac.getServletHandler().addServletMapping(mapping); - } - } + WebServletAnnotation annotation = new WebServletAnnotation (_context, className); + ((List<DiscoveredAnnotation>)_context.getAttribute(AnnotationConfiguration.DISCOVERED_ANNOTATIONS)).add(annotation); } public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java index af1ec022c6..764aaddaf0 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java @@ -14,18 +14,16 @@ package org.eclipse.jetty.annotations; import java.io.File; -import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.List; -import java.util.List; + +import junit.framework.TestCase; import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.webapp.Fragment; +import org.eclipse.jetty.webapp.FragmentDescriptor; import org.eclipse.jetty.webapp.WebAppContext; -import junit.framework.TestCase; - /** * TestAnnotationConfiguration * @@ -34,31 +32,7 @@ import junit.framework.TestCase; public class TestAnnotationConfiguration extends TestCase { - /** - * Test method for {@link org.eclipse.jetty.annotations.AbstractConfiguration#parseWebInfLib(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.annotations.AnnotationParser)}. - */ - public void testExclusions() - throws Exception - { - AnnotationConfiguration config = new AnnotationConfiguration(); - WebAppContext wac = new WebAppContext(); - - Resource r = Resource.newResource("file:///home/janb/file.jar"); - List<String> orderedJars = new ArrayList<String>(); - - //empty ordering excludes all jars - assertTrue(config.isExcluded(r, orderedJars)); - - //an ordering with name included - orderedJars.add("file.jar"); - orderedJars.add("abc.jar"); - orderedJars.add("xyz.jar"); - assertFalse(config.isExcluded(r, orderedJars)); - - //an ordering with name excluded - orderedJars.remove("file.jar"); - assertTrue(config.isExcluded(r, orderedJars)); - } + public void testGetFragmentFromJar () @@ -74,9 +48,9 @@ public class TestAnnotationConfiguration extends TestCase AnnotationConfiguration config = new AnnotationConfiguration(); WebAppContext wac = new WebAppContext(); - List<Fragment> frags = new ArrayList<Fragment>(); - frags.add(new Fragment(Resource.newResource("jar:"+url+"file.jar!/fooa.props"), null)); - frags.add(new Fragment(Resource.newResource("jar:"+url+"file2.jar!/foob.props"), null)); + List<FragmentDescriptor> frags = new ArrayList<FragmentDescriptor>(); + frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file.jar!/fooa.props"), null)); + frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file2.jar!/foob.props"), null)); assertNotNull(config.getFragmentFromJar(jar1, frags)); } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java index e89133ef84..7cfc0aafe4 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.annotations; @@ -16,22 +16,24 @@ package org.eclipse.jetty.annotations; import java.util.ArrayList; import java.util.List; import java.util.Map; - import javax.naming.Context; import javax.naming.InitialContext; -import junit.framework.TestCase; - import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; import org.eclipse.jetty.util.MultiMap; +import org.junit.After; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** - * TestAnnotationInheritance - * * */ -public class TestAnnotationInheritance extends TestCase +public class TestAnnotationInheritance { List<String> classNames = new ArrayList<String>(); @@ -41,7 +43,7 @@ public class TestAnnotationInheritance extends TestCase public final List<String> annotatedClassNames = new ArrayList<String>(); public final List<String> annotatedMethods = new ArrayList<String>(); public final List<String> annotatedFields = new ArrayList<String>(); - + public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, List<Value> values) { @@ -50,7 +52,7 @@ public class TestAnnotationInheritance extends TestCase public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, List<Value> values) - { + { annotatedFields.add(className+"."+fieldName); } @@ -58,29 +60,28 @@ public class TestAnnotationInheritance extends TestCase List<Value> values) { annotatedMethods.add(className+"."+methodName); - } + } } - - - public void tearDown () throws Exception + + @After + public void destroy() throws Exception { classNames.clear(); InitialContext ic = new InitialContext(); Context comp = (Context)ic.lookup("java:comp"); comp.destroySubcontext("env"); } - - - public void testParseClassNames () - throws Exception - { + + @Test + public void testParseClassNames() throws Exception + { classNames.add(ClassA.class.getName()); classNames.add(ClassB.class.getName()); - - SampleHandler handler = new SampleHandler(); + + SampleHandler handler = new SampleHandler(); AnnotationParser parser = new AnnotationParser(); parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", handler); - parser.parse(classNames, new ClassNameResolver () + parser.parse(classNames, new ClassNameResolver () { public boolean isExcluded(String name) { @@ -90,12 +91,12 @@ public class TestAnnotationInheritance extends TestCase public boolean shouldOverride(String name) { return false; - } - }); - + } + }); + //check we got 2 class annotations assertEquals(2, handler.annotatedClassNames.size()); - + //check we got all annotated methods on each class assertEquals (7, handler.annotatedMethods.size()); assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.a")); @@ -105,22 +106,19 @@ public class TestAnnotationInheritance extends TestCase assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.l")); assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.a")); assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.c")); - + //check we got all annotated fields on each class assertEquals(1, handler.annotatedFields.size()); - assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0)); + assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0)); } - - - - - public void testParseClass () - throws Exception + + @Test + public void testParseClass() throws Exception { SampleHandler handler = new SampleHandler(); AnnotationParser parser = new AnnotationParser(); parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", handler); - parser.parse(ClassB.class, new ClassNameResolver () + parser.parse(ClassB.class, new ClassNameResolver () { public boolean isExcluded(String name) { @@ -130,12 +128,12 @@ public class TestAnnotationInheritance extends TestCase public boolean shouldOverride(String name) { return false; - } - }, true); - + } + }, true); + //check we got 2 class annotations assertEquals(2, handler.annotatedClassNames.size()); - + //check we got all annotated methods on each class assertEquals (7, handler.annotatedMethods.size()); assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.a")); @@ -145,15 +143,14 @@ public class TestAnnotationInheritance extends TestCase assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.l")); assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.a")); assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.c")); - + //check we got all annotated fields on each class assertEquals(1, handler.annotatedFields.size()); - assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0)); + assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0)); } - - - public void testExclusions() - throws Exception + + @Test + public void testExclusions() throws Exception { AnnotationParser parser = new AnnotationParser(); SampleHandler handler = new SampleHandler(); @@ -168,7 +165,7 @@ public class TestAnnotationInheritance extends TestCase public boolean shouldOverride(String name) { return false; - } + } }); assertEquals (0, handler.annotatedClassNames.size()); assertEquals (0, handler.annotatedFields.size()); @@ -188,32 +185,30 @@ public class TestAnnotationInheritance extends TestCase public boolean shouldOverride(String name) { return false; - } + } }); assertEquals (1, handler.annotatedClassNames.size()); } - - public void testTypeInheritanceHandling () - throws Exception + + @Test + public void testTypeInheritanceHandling() throws Exception { AnnotationParser parser = new AnnotationParser(); ClassInheritanceHandler handler = new ClassInheritanceHandler(); parser.registerClassHandler(handler); - + class Foo implements InterfaceD { - } - + classNames.clear(); classNames.add(ClassA.class.getName()); classNames.add(ClassB.class.getName()); classNames.add(InterfaceD.class.getName()); classNames.add(Foo.class.getName()); - - + parser.parse(classNames, null); - + MultiMap map = handler.getMap(); assertNotNull(map); assertFalse(map.isEmpty()); @@ -230,5 +225,4 @@ public class TestAnnotationInheritance extends TestCase assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]); assertEquals(Foo.class.getName(), classes[1]); } - } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java index b4586feb4b..bef8867a7b 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java @@ -4,41 +4,36 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.annotations; + import java.util.Arrays; import java.util.List; -import junit.framework.TestCase; - import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; - - -public class TestAnnotationParser extends TestCase +public class TestAnnotationParser { - - public void testSampleAnnotation () - throws Exception - { - - + @Test + public void testSampleAnnotation() throws Exception + { String[] classNames = new String[]{"org.eclipse.jetty.annotations.ClassA"}; AnnotationParser parser = new AnnotationParser(); - - + class SampleAnnotationHandler implements DiscoverableAnnotationHandler { - List<String> methods = Arrays.asList("a", "b", "c", "d", "l"); - - + private List<String> methods = Arrays.asList("a", "b", "c", "d", "l"); public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, List<Value> values) @@ -62,7 +57,7 @@ public class TestAnnotationParser extends TestCase List<Value> values) { System.err.println("Sample annotated method : classname="+className+" methodName="+methodName+" access="+access+" desc="+desc+" signature="+signature); - + org.objectweb.asm.Type retType = org.objectweb.asm.Type.getReturnType(desc); System.err.println("REturn type = "+retType); org.objectweb.asm.Type[] params = org.objectweb.asm.Type.getArgumentTypes(desc); @@ -70,23 +65,22 @@ public class TestAnnotationParser extends TestCase System.err.println("No params"); else System.err.println(params.length+" params"); - + if (exceptions == null) System.err.println("No exceptions"); else System.err.println(exceptions.length+" exceptions"); - + assertEquals("org.eclipse.jetty.annotations.ClassA", className); - assertTrue(methods.contains(methodName)); - assertEquals("org.eclipse.jetty.annotations.Sample", annotation); + assertTrue(methods.contains(methodName)); + assertEquals("org.eclipse.jetty.annotations.Sample", annotation); } - } - + parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", new SampleAnnotationHandler()); - + long start = System.currentTimeMillis(); - parser.parse(classNames, new ClassNameResolver () + parser.parse(classNames, new ClassNameResolver () { public boolean isExcluded(String name) { @@ -97,28 +91,26 @@ public class TestAnnotationParser extends TestCase { return false; } - + }); long end = System.currentTimeMillis(); System.err.println("Time to parse class: "+((end-start))); - } + } - - public void testMultiAnnotation () - throws Exception + @Test + public void testMultiAnnotation() throws Exception { String[] classNames = new String[]{"org.eclipse.jetty.annotations.ClassB"}; AnnotationParser parser = new AnnotationParser(); - - + class MultiAnnotationHandler implements DiscoverableAnnotationHandler { public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, List<Value> values) { assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className)); - + for (Value anv: values) { System.err.println(anv.toString()); @@ -134,7 +126,7 @@ public class TestAnnotationParser extends TestCase public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, List<Value> values) - { + { assertTrue("org.eclipse.jetty.annotations.ClassB".equals(className)); assertTrue("a".equals(methodName)); for (Value anv: values) @@ -143,7 +135,7 @@ public class TestAnnotationParser extends TestCase } } } - + parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Multi", new MultiAnnotationHandler()); parser.parse(classNames, null); } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java index e236f5ee11..beb2c4aacc 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java @@ -257,14 +257,14 @@ public class TestSecurityAnnotationConversions extends TestCase compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); } - private void compareResults (ConstraintMapping[] expectedMappings, ConstraintMapping[] actualMappings) + private void compareResults (ConstraintMapping[] expectedMappings, List<ConstraintMapping> actualMappings) { assertNotNull(actualMappings); - assertEquals(expectedMappings.length, actualMappings.length); + assertEquals(expectedMappings.length, actualMappings.size()); - for (int k=0; k < actualMappings.length; k++) + for (int k=0; k < actualMappings.size(); k++) { - ConstraintMapping am = actualMappings[k]; + ConstraintMapping am = actualMappings.get(k); boolean matched = false; for (int i=0; i< expectedMappings.length && !matched; i++) diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java index 67a1aa6c7c..f7f6c7ffdc 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java @@ -4,58 +4,60 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.annotations; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.util.ArrayList; -import java.util.List; import java.util.Arrays; import java.util.HashSet; +import java.util.List; -import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; -import org.eclipse.jetty.annotations.AnnotationParser.Value; -import org.eclipse.jetty.annotations.AnnotationParser.ListValue; -import org.eclipse.jetty.annotations.AnnotationParser.SimpleValue; import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; import org.eclipse.jetty.plus.annotation.RunAsCollection; import org.eclipse.jetty.security.ConstraintSecurityHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletMapping; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; - - -import junit.framework.TestCase; +import org.junit.Test; /** * TestServletAnnotations * * */ -public class TestServletAnnotations extends TestCase +public class TestServletAnnotations { - - - public void testServletAnnotation() - throws Exception + @Test + public void testServletAnnotation() throws Exception { List<String> classes = new ArrayList<String>(); classes.add("org.eclipse.jetty.annotations.ServletC"); AnnotationParser parser = new AnnotationParser(); WebAppContext wac = new WebAppContext(); + wac.setAttribute(MetaData.METADATA, new MetaData(wac)); LifeCycleCallbackCollection collection = new LifeCycleCallbackCollection(); wac.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION, collection); RunAsCollection runAsCollection = new RunAsCollection(); wac.setAttribute(RunAsCollection.RUNAS_COLLECTION, runAsCollection); + List<DiscoveredAnnotation> discoveredAnnotations = new ArrayList<DiscoveredAnnotation>(); + wac.setAttribute(AnnotationConfiguration.DISCOVERED_ANNOTATIONS, discoveredAnnotations); parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(wac)); - parser.parse(classes, new ClassNameResolver () + parser.parse(classes, new ClassNameResolver () { public boolean isExcluded(String name) { @@ -66,8 +68,12 @@ public class TestServletAnnotations extends TestCase { return false; } - }); + + assertEquals(1, discoveredAnnotations.size()); + assertTrue(discoveredAnnotations.get(0) instanceof WebServletAnnotation); + + discoveredAnnotations.get(0).apply(); ServletHolder[] holders = wac.getServletHandler().getServlets(); assertNotNull(holders); @@ -88,6 +94,7 @@ public class TestServletAnnotations extends TestCase throws Exception { WebAppContext wac = new WebAppContext(); + wac.setAttribute(MetaData.METADATA, new MetaData(wac)); ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); wac.setSecurityHandler(sh); sh.setRoles(new HashSet<String>(Arrays.asList(new String[]{"humpty", "dumpty"}))); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java index 50cc21c608..6fdef5830c 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java @@ -2,14 +2,10 @@ package org.eclipse.jetty.annotations.resources; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; - import javax.naming.Context; import javax.naming.InitialContext; -import junit.framework.TestCase; - import org.eclipse.jetty.annotations.AnnotationIntrospector; import org.eclipse.jetty.annotations.AnnotationParser; import org.eclipse.jetty.annotations.ClassNameResolver; @@ -19,11 +15,17 @@ import org.eclipse.jetty.plus.annotation.Injection; import org.eclipse.jetty.plus.annotation.InjectionCollection; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.MetaData; import org.eclipse.jetty.webapp.WebAppContext; +import org.junit.Test; -public class TestResourceAnnotations extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class TestResourceAnnotations { + @Test public void testResourceAnnotations () throws Exception { @@ -32,6 +34,7 @@ public class TestResourceAnnotations extends TestCase wac.setServer(server); InjectionCollection injections = new InjectionCollection(); wac.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections); + wac.setAttribute(MetaData.METADATA, new MetaData(wac)); InitialContext ic = new InitialContext(); Context comp = (Context)ic.lookup("java:comp"); Context env = comp.createSubcontext("env"); @@ -39,13 +42,12 @@ public class TestResourceAnnotations extends TestCase org.eclipse.jetty.plus.jndi.EnvEntry resourceA = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", new Integer(1000), false); org.eclipse.jetty.plus.jndi.EnvEntry resourceB = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", new Integer(2000), false); - AnnotationIntrospector parser = new AnnotationIntrospector(); ResourceAnnotationHandler handler = new ResourceAnnotationHandler(wac); parser.registerHandler(handler); parser.introspect(ResourceA.class); parser.introspect(ResourceB.class); - + //processing classA should give us these jndi name bindings: // java:comp/env/myf // java:comp/env/org.eclipse.jetty.annotations.resources.ResourceA/g @@ -54,73 +56,71 @@ public class TestResourceAnnotations extends TestCase // java:comp/env/resA // java:comp/env/org.eclipse.jetty.annotations.resources.ResourceB/f // java:comp/env/org.eclipse.jetty.annotations.resources.ResourceA/n - // + // assertEquals(resourceB.getObjectToBind(), env.lookup("myf")); assertEquals(resourceA.getObjectToBind(), env.lookup("mye")); assertEquals(resourceA.getObjectToBind(), env.lookup("resA")); - assertEquals(resourceA.getObjectToBind(), env.lookup("org.eclipse.jetty.annotations.resources.ResourceA/g")); + assertEquals(resourceA.getObjectToBind(), env.lookup("org.eclipse.jetty.annotations.resources.ResourceA/g")); assertEquals(resourceA.getObjectToBind(), env.lookup("org.eclipse.jetty.annotations.resources.ResourceA/h")); assertEquals(resourceB.getObjectToBind(), env.lookup("org.eclipse.jetty.annotations.resources.ResourceB/f")); assertEquals(resourceB.getObjectToBind(), env.lookup("org.eclipse.jetty.annotations.resources.ResourceA/n")); - + //we should have Injections assertNotNull(injections); - + List<Injection> resBInjections = injections.getInjections(ResourceB.class.getCanonicalName()); assertNotNull(resBInjections); - + //only 1 field injection because the other has no Resource mapping assertEquals(1, resBInjections.size()); Injection fi = resBInjections.get(0); assertEquals ("f", fi.getTarget().getName()); - + //3 method injections on class ResourceA, 4 field injections List<Injection> resAInjections = injections.getInjections(ResourceA.class.getCanonicalName()); assertNotNull(resAInjections); assertEquals(7, resAInjections.size()); int fieldCount = 0; int methodCount = 0; - Iterator<Injection> itor = resAInjections.iterator(); - while (itor.hasNext()) + for (Injection x : resAInjections) { - Injection x = itor.next(); if (x.isField()) fieldCount++; - else + else methodCount++; } assertEquals(4, fieldCount); assertEquals(3, methodCount); - - + //test injection ResourceB binst = new ResourceB(); injections.inject(binst); - + //check injected values Field f = ResourceB.class.getDeclaredField ("f"); f.setAccessible(true); assertEquals(resourceB.getObjectToBind() , f.get(binst)); - + //@Resource(mappedName="resA") //test the default naming scheme but using a mapped name from the environment - f = ResourceA.class.getDeclaredField("g"); + f = ResourceA.class.getDeclaredField("g"); f.setAccessible(true); assertEquals(resourceA.getObjectToBind(), f.get(binst)); - + //@Resource(name="resA") //test using the given name as the name from the environment f = ResourceA.class.getDeclaredField("j"); f.setAccessible(true); assertEquals(resourceA.getObjectToBind(), f.get(binst)); - + //@Resource(mappedName="resB") //test using the default name on an inherited field - f = ResourceA.class.getDeclaredField("n"); + f = ResourceA.class.getDeclaredField("n"); f.setAccessible(true); assertEquals(resourceB.getObjectToBind(), f.get(binst)); - + comp.destroySubcontext("env"); } + @Test public void testResourcesAnnotation () throws Exception { diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index 66528ca613..cc725dd86b 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -23,6 +23,11 @@ <goals> <goal>manifest</goal> </goals> + <configuration> + <instructions> + <Import-Package>javax.net.*,*</Import-Package> + </instructions> + </configuration> </execution> </executions> </plugin> @@ -33,18 +38,18 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.client.*</onlyAnalyze> + </configuration> </plugin> - </plugins> </build> <dependencies> @@ -58,16 +63,17 @@ <artifactId>jetty-server</artifactId> <version>${project.version}</version> <scope>test</scope> - </dependency> + </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> <version>${project.version}</version> <scope>test</scope> - </dependency> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> @@ -85,5 +91,11 @@ <scope>test</scope> </dependency> --> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-websocket</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/CachedExchange.java b/jetty-client/src/main/java/org/eclipse/jetty/client/CachedExchange.java index de1e9933dd..c36cb6834d 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/CachedExchange.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/CachedExchange.java @@ -35,14 +35,14 @@ public class CachedExchange extends HttpExchange _responseFields = cacheHeaders ? new HttpFields() : null; } - public int getResponseStatus() + public synchronized int getResponseStatus() { if (getStatus() < HttpExchange.STATUS_PARSING_HEADERS) throw new IllegalStateException("Response not received yet"); return _responseStatus; } - public HttpFields getResponseFields() + public synchronized HttpFields getResponseFields() { if (getStatus() < HttpExchange.STATUS_PARSING_CONTENT) throw new IllegalStateException("Headers not completely received yet"); @@ -50,14 +50,14 @@ public class CachedExchange extends HttpExchange } @Override - protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException + protected synchronized void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException { _responseStatus = status; super.onResponseStatus(version, status, reason); } @Override - protected void onResponseHeader(Buffer name, Buffer value) throws IOException + protected synchronized void onResponseHeader(Buffer name, Buffer value) throws IOException { if (_responseFields != null) _responseFields.add(name, value); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ContentExchange.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ContentExchange.java index 2e0b3411f4..5673cef584 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ContentExchange.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ContentExchange.java @@ -45,14 +45,14 @@ public class ContentExchange extends CachedExchange super(cacheFields); } - public String getResponseContent() throws UnsupportedEncodingException + public synchronized String getResponseContent() throws UnsupportedEncodingException { if (_responseContent != null) return _responseContent.toString(_encoding); return null; } - public byte[] getResponseContentBytes() + public synchronized byte[] getResponseContentBytes() { if (_responseContent != null) return _responseContent.toByteArray(); @@ -60,7 +60,7 @@ public class ContentExchange extends CachedExchange } @Override - protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException + protected synchronized void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException { if (_responseContent!=null) _responseContent.reset(); @@ -68,7 +68,7 @@ public class ContentExchange extends CachedExchange } @Override - protected void onResponseHeader(Buffer name, Buffer value) throws IOException + protected synchronized void onResponseHeader(Buffer name, Buffer value) throws IOException { super.onResponseHeader(name, value); int header = HttpHeaders.CACHE.getOrdinal(name); @@ -92,7 +92,7 @@ public class ContentExchange extends CachedExchange } @Override - protected void onResponseContent(Buffer content) throws IOException + protected synchronized void onResponseContent(Buffer content) throws IOException { super.onResponseContent(content); if (_responseContent == null) @@ -101,7 +101,7 @@ public class ContentExchange extends CachedExchange } @Override - protected void onRetry() throws IOException + protected synchronized void onRetry() throws IOException { if (_fileForUpload != null) { @@ -112,17 +112,17 @@ public class ContentExchange extends CachedExchange super.onRetry(); } - private InputStream getInputStream() throws IOException + private synchronized InputStream getInputStream() throws IOException { return new FileInputStream(_fileForUpload); } - public File getFileForUpload() + public synchronized File getFileForUpload() { return _fileForUpload; } - public void setFileForUpload(File fileForUpload) throws IOException + public synchronized void setFileForUpload(File fileForUpload) throws IOException { this._fileForUpload = fileForUpload; setRequestContentSource(getInputStream()); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index 0ee716cf16..be20cc49c6 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -75,11 +75,8 @@ import org.eclipse.jetty.util.thread.Timeout; * be allocated from a destination, so that multiple request sources are not multiplexed * over the same connection. * - * - * - * - * @see {@link HttpExchange} - * @see {@link HttpDestination} + * @see HttpExchange + * @see HttpDestination */ public class HttpClient extends HttpBuffers implements Attributes { @@ -212,10 +209,6 @@ public class HttpClient extends HttpBuffers implements Attributes } /* ------------------------------------------------------------ */ - /** - * @param name - * @return - */ public void clearAttributes() { _attributes.clearAttributes(); @@ -287,7 +280,7 @@ public class HttpClient extends HttpBuffers implements Attributes /** * returns the SecurityRealmResolver reg_realmResolveristered with the HttpClient or null * - * @return + * @return the SecurityRealmResolver reg_realmResolveristered with the HttpClient or null */ public RealmResolver getRealmResolver() { @@ -303,7 +296,7 @@ public class HttpClient extends HttpBuffers implements Attributes /** * Registers a listener that can listen to the stream of execution between the client and the - * server and influence events. Sequential calls to the method wrapper sequentially wrap the preceeding + * server and influence events. Sequential calls to the method wrapper sequentially wrap the preceding * listener in a delegation model. * <p/> * NOTE: the SecurityListener is a special listener which doesn't need to be added via this @@ -320,7 +313,8 @@ public class HttpClient extends HttpBuffers implements Attributes } _registeredListeners.add(listenerClass); } - + + /* ------------------------------------------------------------ */ public LinkedList<String> getRegisteredListeners() { return _registeredListeners; @@ -528,7 +522,7 @@ public class HttpClient extends HttpBuffers implements Attributes * if a keystore location has been provided then client will attempt to use it as the keystore, * otherwise we simply ignore certificates and run with a loose ssl context. * - * @return + * @return the SSL context * @throws IOException */ protected SSLContext getSSLContext() throws IOException @@ -807,12 +801,36 @@ public class HttpClient extends HttpBuffers implements Attributes /* ------------------------------------------------------------ */ public void setKeyManagerPassword(String keyManagerPassword) { - this._keyManagerPassword = new Password(keyManagerPassword).toString();; + this._keyManagerPassword = new Password(keyManagerPassword).toString(); } /* ------------------------------------------------------------ */ public void setTrustStorePassword(String trustStorePassword) { - this._trustStorePassword = new Password(trustStorePassword).toString();; + this._trustStorePassword = new Password(trustStorePassword).toString(); + } + + /* ------------------------------------------------------------ */ + public String getKeyStoreType() + { + return this._keyStoreType; + } + + /* ------------------------------------------------------------ */ + public void setKeyStoreType(String keyStoreType) + { + this._keyStoreType = keyStoreType; + } + + /* ------------------------------------------------------------ */ + public String getTrustStoreType() + { + return this._trustStoreType; + } + + /* ------------------------------------------------------------ */ + public void setTrustStoreType(String trustStoreType) + { + this._trustStoreType = trustStoreType; } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java index 9633c7e9ec..9244314355 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.client; +import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; @@ -28,7 +29,6 @@ import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersions; -import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint; import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; @@ -37,6 +37,7 @@ import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.View; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.Timeout; @@ -214,23 +215,28 @@ public class HttpConnection implements Connection if (!_generator.isComplete()) { - InputStream in = _exchange.getRequestContentSource(); - if (in != null) + if (_exchange!=null) { - if (_requestContentChunk == null || _requestContentChunk.length() == 0) + InputStream in = _exchange.getRequestContentSource(); + if (in != null) { - _requestContentChunk = _exchange.getRequestContentChunk(); - _destination.getHttpClient().schedule(_timeout); + if (_requestContentChunk == null || _requestContentChunk.length() == 0) + { + _requestContentChunk = _exchange.getRequestContentChunk(); + _destination.getHttpClient().schedule(_timeout); - if (_requestContentChunk != null) - _generator.addContent(_requestContentChunk,false); - else - _generator.complete(); + if (_requestContentChunk != null) + _generator.addContent(_requestContentChunk,false); + else + _generator.complete(); - flushed = _generator.flushBuffer(); - io += flushed; + flushed = _generator.flushBuffer(); + io += flushed; + } } - } + else + _generator.complete(); + } else _generator.complete(); } @@ -333,16 +339,17 @@ public class HttpConnection implements Connection no_progress = 0; if (_exchange != null) { + HttpExchange exchange=_exchange; _exchange.disassociate(); _exchange = null; if (_status==HttpStatus.SWITCHING_PROTOCOLS_101) { - HttpConnection switched=_exchange.onSwitchProtocol(_endp); + Connection switched=exchange.onSwitchProtocol(_endp); if (switched!=null) { // switched protocol! - HttpExchange exchange = _pipeline; + exchange = _pipeline; _pipeline = null; if (exchange!=null) _destination.send(exchange); @@ -351,7 +358,6 @@ public class HttpConnection implements Connection } } - if (_pipeline == null) { if (!isReserved()) @@ -364,13 +370,13 @@ public class HttpConnection implements Connection if (!isReserved()) _destination.returnConnection(this,close); - HttpExchange exchange = _pipeline; + exchange = _pipeline; _pipeline = null; _destination.send(exchange); } else { - HttpExchange exchange = _pipeline; + exchange = _pipeline; _pipeline = null; send(exchange); } @@ -388,6 +394,11 @@ public class HttpConnection implements Connection { _exchange.disassociate(); } + + if (!_generator.isComplete() && _generator.getBytesBuffered()>0 && _endp instanceof AsyncEndPoint) + { + ((AsyncEndPoint)_endp).setWritable(false); + } } return this; @@ -544,6 +555,8 @@ public class HttpConnection implements Connection @Override public void headerComplete() throws IOException { + if (_endp instanceof AsyncEndPoint) + ((AsyncEndPoint)_endp).scheduleIdle(); HttpExchange exchange = _exchange; if (exchange!=null) exchange.setStatus(HttpExchange.STATUS_PARSING_CONTENT); @@ -552,6 +565,8 @@ public class HttpConnection implements Connection @Override public void content(Buffer ref) throws IOException { + if (_endp instanceof AsyncEndPoint) + ((AsyncEndPoint)_endp).scheduleIdle(); HttpExchange exchange = _exchange; if (exchange!=null) exchange.getEventListener().onResponseContent(ref); @@ -579,6 +594,25 @@ public class HttpConnection implements Connection public void close() throws IOException { + //if there is a live, unfinished exchange, set its status to be + //excepted and wake up anyone waiting on waitForDone() + + if (_exchange != null && !_exchange.isDone()) + { + switch (_exchange.getStatus()) + { + case HttpExchange.STATUS_CANCELLED: + case HttpExchange.STATUS_CANCELLING: + case HttpExchange.STATUS_COMPLETED: + case HttpExchange.STATUS_EXCEPTED: + case HttpExchange.STATUS_EXPIRED: + break; + default: + _exchange.setStatus(HttpExchange.STATUS_EXCEPTED); + _exchange.getEventListener().onException(new EOFException("local close")); + } + } + _endp.close(); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index 09ab59e94d..b885828022 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -219,7 +219,7 @@ public class HttpDestination if (connection!=null) { _connections.remove(connection); - connection.getEndPoint().close(); + connection.close(); connection=null; } if (_idle.size() > 0) @@ -229,9 +229,10 @@ public class HttpDestination if (connection==null) return null; - if (connection.cancelIdleTimeout() ) + // Check if the connection was idle, + // but it expired just a moment ago + if (connection.cancelIdleTimeout()) return connection; - } } @@ -271,6 +272,11 @@ public class HttpDestination HttpExchange ex = _queue.removeFirst(); ex.setStatus(HttpExchange.STATUS_EXCEPTED); ex.getEventListener().onConnectionFailed(throwable); + + // Since an existing connection had failed, we need to create a + // connection if the queue is not empty and client is running. + if (!_queue.isEmpty() && _client.isStarted()) + startNewConnection(); } } @@ -323,7 +329,7 @@ public class HttpDestination else { HttpExchange ex = _queue.removeFirst(); - connection.send(ex); + send(connection, ex); } } @@ -372,7 +378,7 @@ public class HttpDestination else { HttpExchange ex = _queue.removeFirst(); - connection.send(ex); + send(connection, ex); } this.notifyAll(); } @@ -388,7 +394,7 @@ public class HttpDestination } } - public void returnIdleConnection(HttpConnection connection) throws IOException + public void returnIdleConnection(HttpConnection connection) { try { @@ -403,10 +409,10 @@ public class HttpDestination { _idle.remove(connection); _connections.remove(connection); + if (!_queue.isEmpty() && _client.isStarted()) startNewConnection(); } - } public void send(HttpExchange ex) throws IOException @@ -483,11 +489,9 @@ public class HttpDestination HttpConnection connection = getIdleConnection(); if (connection != null) { - boolean sent = connection.send(ex); - if (!sent) connection = null; + send(connection, ex); } - - if (connection == null) + else { synchronized (this) { @@ -500,6 +504,20 @@ public class HttpDestination } } + protected void send(HttpConnection connection, HttpExchange exchange) throws IOException + { + synchronized (this) + { + // If server closes the connection, put the exchange back + // to the exchange queue and recycle the connection + if(!connection.send(exchange)) + { + _queue.addFirst(exchange); + returnIdleConnection(connection); + } + } + } + @Override public synchronized String toString() { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java index eae8542cdc..cfe9b81051 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java @@ -25,6 +25,7 @@ import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersions; import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.io.ByteArrayBuffer; @@ -53,8 +54,8 @@ import org.eclipse.jetty.util.log.Log; * see {@link org.eclipse.jetty.client.ContentExchange} and {@link org.eclipse.jetty.client.CachedExchange}.</p> * * <p>Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in - * turn selects a {@link HttpDestination} and calls its {@link HttpDestination#send(HttpExchange), which - * then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange). + * turn selects a {@link HttpDestination} and calls its {@link HttpDestination#send(HttpExchange)}, which + * then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange)}. * A developer may wish to directly call send on the destination or connection if they wish to bypass * some handling provided (eg Cookie handling in the HttpDestination).</p> * @@ -129,7 +130,7 @@ public class HttpExchange * || onExpire * || onRequestComplete && onResponseComplete * </pre> - * @return + * @return the done status * @throws InterruptedException */ public int waitForDone () throws InterruptedException @@ -172,6 +173,7 @@ public class HttpExchange case STATUS_WAITING_FOR_CONNECTION: case STATUS_WAITING_FOR_COMMIT: case STATUS_CANCELLING: + case STATUS_EXCEPTED: set=_status.compareAndSet(oldStatus,newStatus); break; } @@ -282,6 +284,7 @@ public class HttpExchange case STATUS_CANCELLING: switch (newStatus) { + case STATUS_EXCEPTED: case STATUS_CANCELLED: if (set=_status.compareAndSet(oldStatus,newStatus)) done(); @@ -300,6 +303,9 @@ public class HttpExchange case STATUS_START: set=_status.compareAndSet(oldStatus,newStatus); break; + default: + set=true; + break; } break; default: @@ -324,6 +330,15 @@ public class HttpExchange } } + /** + * @deprecated + */ + @Deprecated + public boolean isDone (int status) + { + return isDone(); + } + public HttpEventListener getEventListener() { return _listener; @@ -659,7 +674,7 @@ public class HttpExchange /** */ - protected HttpConnection onSwitchProtocol(EndPoint enpd) throws IOException + protected Connection onSwitchProtocol(EndPoint endp) throws IOException { return null; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java index 6e0d47d0a2..d3de1e680a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java @@ -16,6 +16,7 @@ package org.eclipse.jetty.client; import java.io.IOException; import org.eclipse.jetty.http.HttpHeaders; +import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.io.Buffer; @@ -26,8 +27,8 @@ import org.eclipse.jetty.io.Buffer; */ public class RedirectListener extends HttpEventListenerWrapper { + private final HttpExchange _exchange; private HttpDestination _destination; - private HttpExchange _exchange; private String _location; private int _attempts; private boolean _requestComplete; @@ -44,6 +45,7 @@ public class RedirectListener extends HttpEventListenerWrapper _exchange = ex; } + @Override public void onResponseStatus( Buffer version, int status, Buffer reason ) throws IOException { @@ -61,6 +63,7 @@ public class RedirectListener extends HttpEventListenerWrapper } + @Override public void onResponseHeader( Buffer name, Buffer value ) throws IOException { @@ -77,6 +80,7 @@ public class RedirectListener extends HttpEventListenerWrapper super.onResponseHeader(name,value); } + @Override public void onRequestComplete() throws IOException { _requestComplete = true; @@ -87,6 +91,7 @@ public class RedirectListener extends HttpEventListenerWrapper } } + @Override public void onResponseComplete() throws IOException { _responseComplete = true; @@ -109,7 +114,23 @@ public class RedirectListener extends HttpEventListenerWrapper else _exchange.setURI(_location); - _destination.resend(_exchange); + // destination may have changed + HttpDestination destination=_destination.getHttpClient().getDestination(_exchange.getAddress(),HttpSchemes.HTTPS.equals(String.valueOf(_exchange.getScheme()))); + + if (_destination==destination) + _destination.resend(_exchange); + else + { + // unwrap to find ultimate listener. + HttpEventListener listener=this; + while(listener instanceof HttpEventListenerWrapper) + listener=((HttpEventListenerWrapper)listener).getEventListener(); + //reset the listener + _exchange.getEventListener().onRetry(); + _exchange.reset(); + _exchange.setEventListener(listener); + destination.send(_exchange); + } return false; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java index aba10d0615..730a53a01a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java @@ -25,7 +25,6 @@ import javax.net.ssl.SSLSession; import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.http.HttpVersions; -import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.ConnectedEndPoint; @@ -35,6 +34,7 @@ import org.eclipse.jetty.io.nio.DirectNIOBuffer; import org.eclipse.jetty.io.nio.IndirectNIOBuffer; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; import org.eclipse.jetty.io.nio.SelectorManager; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.Timeout; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/security/SecurityListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/security/SecurityListener.java index 87d37b9a7a..20902d4312 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/security/SecurityListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/security/SecurityListener.java @@ -58,7 +58,7 @@ public class SecurityListener extends HttpEventListenerWrapper * scrapes an authentication type from the authString * * @param authString - * @return + * @return the authentication type */ protected String scrapeAuthenticationType( String authString ) { @@ -80,7 +80,7 @@ public class SecurityListener extends HttpEventListenerWrapper * scrapes a set of authentication details from the authString * * @param authString - * @return + * @return the authentication details */ protected Map<String, String> scrapeAuthenticationDetails( String authString ) { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java index bc6c075e64..fff68bb5e5 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpExchangeCancelTest.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.client; import java.io.IOException; +import java.net.SocketTimeoutException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; @@ -281,10 +282,10 @@ public abstract class AbstractHttpExchangeCancelTest extends TestCase getHttpClient().send(exchange); int status = exchange.waitForDone(); - assertEquals(HttpExchange.STATUS_COMPLETED, status); assertTrue(exchange.isResponseCompleted()); assertFalse(exchange.isFailed()); assertFalse(exchange.isAssociated()); + assertEquals(HttpExchange.STATUS_COMPLETED, status); } public void testHttpExchangeOnServerException() throws Exception @@ -322,7 +323,8 @@ public abstract class AbstractHttpExchangeCancelTest extends TestCase httpClient.send(exchange); int status = exchange.waitForDone(); - assertEquals(HttpExchange.STATUS_EXPIRED, status); + + assertTrue(HttpExchange.STATUS_EXPIRED==status||HttpExchange.STATUS_EXCEPTED==status); assertFalse(exchange.isResponseCompleted()); assertFalse(exchange.isFailed()); assertTrue(exchange.isExpired()); @@ -395,8 +397,11 @@ public abstract class AbstractHttpExchangeCancelTest extends TestCase @Override protected void onException(Throwable ex) { - // ex.printStackTrace(); - this.failed = true; + if (ex instanceof SocketTimeoutException || + ex.getCause() instanceof SocketTimeoutException) + expired=true; + else + failed = true; } public boolean isFailed() diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java index 7ed394dac0..48030d4cbd 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java @@ -21,6 +21,9 @@ public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest _scheme="https://"; startServer(); _httpClient=new HttpClient(); + _httpClient.setIdleTimeout(2000); + _httpClient.setTimeout(2500); + _httpClient.setConnectTimeout(1000); _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); _httpClient.setMaxConnectionsPerAddress(2); _httpClient.start(); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/BlockingHttpExchangeCancelTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/BlockingHttpExchangeCancelTest.java index d05b39ea7a..549144a9b1 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/BlockingHttpExchangeCancelTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/BlockingHttpExchangeCancelTest.java @@ -14,6 +14,8 @@ package org.eclipse.jetty.client; +import org.eclipse.jetty.util.log.Log; + /** * @version $Revision$ $Date$ */ @@ -42,4 +44,5 @@ public class BlockingHttpExchangeCancelTest extends AbstractHttpExchangeCancelTe { return httpClient; } + } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionTest.java index f282b82285..beed5f51b4 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionTest.java @@ -14,49 +14,161 @@ package org.eclipse.jetty.client; +import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * @version $Revision$ $Date$ */ -public class ConnectionTest extends TestCase +public class ConnectionTest { + @Test + public void testServerClosedConnection() throws Exception + { + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(null); + int port=serverSocket.getLocalPort(); + + HttpClient httpClient = new HttpClient(); + httpClient.setMaxConnectionsPerAddress(1); + httpClient.start(); + try + { + CountDownLatch latch = new CountDownLatch(1); + HttpExchange exchange = new ConnectionExchange(latch); + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); + httpClient.send(exchange); + + Socket remote = serverSocket.accept(); + OutputStream output = remote.getOutputStream(); + output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8")); + output.write("Content-Length: 0\r\n".getBytes("UTF-8")); + output.write("\r\n".getBytes("UTF-8")); + output.flush(); + + assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); + + remote.close(); + + // Need to wait a bit to allow the client to detect + // that the server has closed the connection + Thread.sleep(500); + + // The server has closed the connection and another attempt to send + // with the same connection would fail because the connection has been + // closed by the client as well. + // The client must open a new connection in this case, and we check + // that the new request completes correctly + exchange.reset(); + httpClient.send(exchange); + + remote = serverSocket.accept(); + output = remote.getOutputStream(); + output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8")); + output.write("Content-Length: 0\r\n".getBytes("UTF-8")); + output.write("\r\n".getBytes("UTF-8")); + output.flush(); + + assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); + } + finally + { + httpClient.stop(); + } + } + + @Test public void testConnectionFailed() throws Exception { - ServerSocket socket = new ServerSocket(); - socket.bind(null); - int port=socket.getLocalPort(); - socket.close(); + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(null); + int port=serverSocket.getLocalPort(); + serverSocket.close(); HttpClient httpClient = new HttpClient(); httpClient.start(); + try + { + CountDownLatch latch = new CountDownLatch(1); + HttpExchange exchange = new ConnectionExchange(latch); + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); + httpClient.send(exchange); - CountDownLatch latch = new CountDownLatch(1); - HttpExchange exchange = new ConnectionExchange(latch); - exchange.setAddress(new Address("localhost", port)); - exchange.setURI("/"); - httpClient.send(exchange); + boolean passed = latch.await(4000, TimeUnit.MILLISECONDS); + assertTrue(passed); - boolean passed = latch.await(4000, TimeUnit.MILLISECONDS); - assertTrue(passed); + long wait = 100; + long maxWait = 10 * wait; + long curWait = wait; + while (curWait < maxWait && !exchange.isDone()) + { + Thread.sleep(wait); + curWait += wait; + } - long wait = 100; - long maxWait = 10 * wait; - long curWait = wait; - while (curWait < maxWait && !exchange.isDone()) + assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.getStatus()); + } + finally { - Thread.sleep(wait); - curWait += wait; + httpClient.stop(); } + } + + @Test + public void testMultipleConnectionsFailed() throws Exception + { + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(null); + int port=serverSocket.getLocalPort(); + serverSocket.close(); - assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.getStatus()); + HttpClient httpClient = new HttpClient(); + httpClient.setMaxConnectionsPerAddress(1); + httpClient.start(); + try + { + HttpExchange[] exchanges = new HttpExchange[20]; + final CountDownLatch latch = new CountDownLatch(exchanges.length); + for (int i = 0; i < exchanges.length; ++i) + { + HttpExchange exchange = new HttpExchange() + { + @Override + protected void onConnectionFailed(Throwable x) + { + latch.countDown(); + } + }; + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); + exchanges[i] = exchange; + } + + for (HttpExchange exchange : exchanges) + httpClient.send(exchange); + + for (HttpExchange exchange : exchanges) + assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone()); + + assertTrue(latch.await(1000, TimeUnit.MILLISECONDS)); + } + finally + { + httpClient.stop(); + } } + @Test public void testConnectionTimeoutWithSocketConnector() throws Exception { HttpClient httpClient = new HttpClient(); @@ -64,7 +176,6 @@ public class ConnectionTest extends TestCase int connectTimeout = 5000; httpClient.setConnectTimeout(connectTimeout); httpClient.start(); - try { CountDownLatch latch = new CountDownLatch(1); @@ -86,6 +197,7 @@ public class ConnectionTest extends TestCase } } + @Test public void testConnectionTimeoutWithSelectConnector() throws Exception { HttpClient httpClient = new HttpClient(); @@ -93,7 +205,6 @@ public class ConnectionTest extends TestCase int connectTimeout = 5000; httpClient.setConnectTimeout(connectTimeout); httpClient.start(); - try { CountDownLatch latch = new CountDownLatch(1); @@ -115,56 +226,62 @@ public class ConnectionTest extends TestCase } } + @Test public void testIdleConnection() throws Exception { - ServerSocket socket = new ServerSocket(); - socket.bind(null); - int port=socket.getLocalPort(); + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(null); + int port=serverSocket.getLocalPort(); HttpClient httpClient = new HttpClient(); httpClient.setIdleTimeout(700); httpClient.start(); + try + { + HttpExchange exchange = new ConnectionExchange(); + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); + HttpDestination dest = httpClient.getDestination(new Address("localhost", port),false); - HttpExchange exchange = new ConnectionExchange(); - exchange.setAddress(new Address("localhost", port)); - exchange.setURI("/"); - HttpDestination dest = httpClient.getDestination(new Address("localhost", port),false); - - httpClient.send(exchange); - Socket s = socket.accept(); - byte[] buf = new byte[4096]; - s.getInputStream().read(buf); - assertEquals(1,dest.getConnections()); - assertEquals(0,dest.getIdleConnections()); - - s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes()); + httpClient.send(exchange); + Socket s = serverSocket.accept(); + byte[] buf = new byte[4096]; + s.getInputStream().read(buf); + assertEquals(1,dest.getConnections()); + assertEquals(0,dest.getIdleConnections()); - Thread.sleep(300); - assertEquals(1,dest.getConnections()); - assertEquals(1,dest.getIdleConnections()); + s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes()); - exchange = new ConnectionExchange(); - exchange.setAddress(new Address("localhost", port)); - exchange.setURI("/"); + Thread.sleep(300); + assertEquals(1,dest.getConnections()); + assertEquals(1,dest.getIdleConnections()); - httpClient.send(exchange); - s.getInputStream().read(buf); - assertEquals(1,dest.getConnections()); - assertEquals(0,dest.getIdleConnections()); - s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes()); + exchange = new ConnectionExchange(); + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); - Thread.sleep(500); + httpClient.send(exchange); + s.getInputStream().read(buf); + assertEquals(1,dest.getConnections()); + assertEquals(0,dest.getIdleConnections()); + s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes()); - assertEquals(1,dest.getConnections()); - assertEquals(1,dest.getIdleConnections()); + Thread.sleep(500); - Thread.sleep(500); + assertEquals(1,dest.getConnections()); + assertEquals(1,dest.getIdleConnections()); - assertEquals(0,dest.getConnections()); - assertEquals(0,dest.getIdleConnections()); + Thread.sleep(500); - socket.close(); + assertEquals(0,dest.getConnections()); + assertEquals(0,dest.getIdleConnections()); + serverSocket.close(); + } + finally + { + httpClient.stop(); + } } private class ConnectionExchange extends HttpExchange @@ -187,7 +304,7 @@ public class ConnectionTest extends TestCase if (latch!=null) latch.countDown(); } - + @Override protected void onException(Throwable x) { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java index 71692727d8..e2daf2b485 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java @@ -6,157 +6,108 @@ package org.eclipse.jetty.client; // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== import java.io.IOException; -import java.util.concurrent.atomic.AtomicInteger; - +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - -import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.util.log.Log; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; -/* Test expiring connections - * +/** * Test contributed by: Michiel Thuys for JETTY-806 */ -public class ExpireTest extends TestCase +public class ExpireTest { - HttpClient client; - - Server server; - - AtomicInteger expireCount = new AtomicInteger(); + private Server server; + private HttpClient client; + private int port; - final String host = "localhost"; - - int _port; - - @Override - protected void setUp() throws Exception + @Before + public void init() throws Exception { - client = new HttpClient(); - client.setConnectorType( HttpClient.CONNECTOR_SELECT_CHANNEL ); - client.setTimeout( 200 ); - client.setMaxRetries( 0 ); - client.setMaxConnectionsPerAddress(100); - try - { - client.start(); - } - catch ( Exception e ) - { - throw new Error( "Cannot start HTTP client: " + e ); - } - - // Create server server = new Server(); SelectChannelConnector connector = new SelectChannelConnector(); - connector.setHost( host ); - connector.setPort( 0 ); - server.setConnectors( new Connector[] { connector } ); - server.setHandler( new AbstractHandler() + connector.setHost("localhost"); + connector.setPort(0); + server.addConnector(connector); + server.setHandler(new AbstractHandler() { - public void handle( String target, Request baseRequest, HttpServletRequest servletRequest, HttpServletResponse response ) throws IOException, - ServletException + public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) + throws IOException, ServletException { - Request request = (Request) servletRequest; + request.setHandled(true); try { - Thread.sleep( 2000 ); + Thread.sleep(2000); } - catch ( InterruptedException e ) + catch (InterruptedException x) { - // TODO Auto-generated catch block - e.printStackTrace(); + throw new ServletException(x); } - request.setHandled( true ); } - } ); - try - { - server.start(); - _port = connector.getLocalPort(); - } - catch ( Exception e ) - { - Log.warn( "Cannot create server: " + e ); - } + }); + server.start(); + port = connector.getLocalPort(); + + client = new HttpClient(); + client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + client.setTimeout(200); + client.setMaxRetries(0); + client.setMaxConnectionsPerAddress(100); + client.start(); } - @Override - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { client.stop(); server.stop(); + server.join(); } - public void testExpire() throws IOException + @Test + public void testExpire() throws Exception { - String baseUrl = "http://" + host + ":" + _port + "/"; + String baseUrl = "http://" + "localhost" + ":" + port + "/"; int count = 200; - expireCount.set( 0 ); - Log.info( "Starting test on " + baseUrl ); + final CountDownLatch expires = new CountDownLatch(count); for (int i=0;i<count;i++) { - if (i%10==0) - System.err.print('.'); - expireCount.incrementAndGet(); - final ContentExchange ex = new ContentExchange() + final ContentExchange exchange = new ContentExchange() { @Override protected void onExpire() { - expireCount.decrementAndGet(); + expires.countDown(); } }; - ex.setMethod( "GET" ); - ex.setURL( baseUrl ); + exchange.setMethod("GET"); + exchange.setURL(baseUrl); - client.send( ex ); - try - { - Thread.sleep( 50 ); - } - catch ( InterruptedException e ) - { - break; - } + client.send(exchange); + Thread.sleep(50); } - // Log.info("Test done"); - // Wait to be sure that all exchanges have expired - try - { - Thread.sleep( 2000 ); - int loops = 0; - while ( expireCount.get()>0 && loops < 10 ) // max out at 30 seconds - { - Log.info( "waiting for test to complete: "+expireCount.get()+" of "+count ); - ++loops; - Thread.sleep( 2000 ); - } - Thread.sleep( 2000 ); - } - catch ( InterruptedException e ) - { - } - System.err.println('!'); - assertEquals( 0, expireCount.get() ); + // Wait to be sure that all exchanges have expired + assertTrue(expires.await(5, TimeUnit.SECONDS)); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java index a0dc69d08f..3ec2d764cb 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpExchangeTest.java @@ -13,12 +13,15 @@ package org.eclipse.jetty.client; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -30,11 +33,14 @@ import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.io.nio.DirectNIOBuffer; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; /** * Functional testing for HttpExchange. @@ -55,9 +61,9 @@ public class HttpExchangeTest extends TestCase { startServer(); _httpClient=new HttpClient(); - _httpClient.setIdleTimeout(2000); - _httpClient.setTimeout(2500); - _httpClient.setConnectTimeout(1000); + _httpClient.setIdleTimeout(3000); + _httpClient.setTimeout(3500); + _httpClient.setConnectTimeout(2000); _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); _httpClient.setMaxConnectionsPerAddress(_maxConnectionsPerAddress); _httpClient.start(); @@ -94,8 +100,6 @@ public class HttpExchangeTest extends TestCase sender(1,true); sender(10,false); sender(10,true); - sender(20,false); - sender(20,true); } } @@ -123,7 +127,6 @@ public class HttpExchangeTest extends TestCase protected void onRequestCommitted() { result="committed"; - // System.err.println(n+" Request committed: "+close); } @Override @@ -136,13 +139,11 @@ public class HttpExchangeTest extends TestCase protected void onResponseStatus(Buffer version, int status, Buffer reason) { result="status"; - // System.err.println(n+" Response Status: " + version+" "+status+" "+reason); } @Override protected void onResponseHeader(Buffer name, Buffer value) { - // System.err.println(n+" Response header: " + name + " = " + value); } @Override @@ -156,14 +157,12 @@ public class HttpExchangeTest extends TestCase protected void onResponseContent(Buffer content) { len+=content.length(); - // System.err.println(n+" Response content:" + content.length()); } @Override protected void onResponseComplete() { result="complete"; - // System.err.println(n+" Response completed "+len); if (len==2009) latch.countDown(); else @@ -216,16 +215,19 @@ public class HttpExchangeTest extends TestCase assertTrue(complete.await(45,TimeUnit.SECONDS)); long elapsed=System.currentTimeMillis()-start; + // make windows-friendly ... System.currentTimeMillis() on windows is dope! + /* if(elapsed>0) System.err.println(nb+"/"+_count+" c="+close+" rate="+(nb*1000/elapsed)); + */ assertEquals("nb="+nb+" close="+close,0,latch.getCount()); } public void testPostWithContentExchange() throws Exception { - for (int i=0;i<200;i++) + for (int i=0;i<20;i++) { ContentExchange httpExchange=new ContentExchange(); //httpExchange.setURL(_scheme+"localhost:"+_port+"/"); @@ -243,7 +245,7 @@ public class HttpExchangeTest extends TestCase public void testGetWithContentExchange() throws Exception { - for (int i=0;i<200;i++) + for (int i=0;i<10;i++) { ContentExchange httpExchange=new ContentExchange(); httpExchange.setURL(_scheme+"localhost:"+_port+"/?i="+i); @@ -259,6 +261,84 @@ public class HttpExchangeTest extends TestCase } } + public void testShutdownWithExchange() throws Exception + { + final AtomicReference<Throwable> throwable=new AtomicReference<Throwable>(); + + HttpExchange httpExchange=new HttpExchange() + { + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.client.HttpExchange#onException(java.lang.Throwable) + */ + @Override + protected void onException(Throwable x) + { + throwable.set(x); + } + + }; + httpExchange.setURL(_scheme+"localhost:"+_port+"/"); + httpExchange.setMethod("SLEEP"); + _httpClient.send(httpExchange); + new Thread() + { + @Override + public void run() + { + try { + Thread.sleep(250); + _httpClient.stop(); + } catch(Exception e) {e.printStackTrace();} + } + }.start(); + int status = httpExchange.waitForDone(); + + assertTrue(throwable.get().toString().indexOf("local close")>=0); + assertEquals(HttpExchange.STATUS_EXCEPTED, status); + } + + public void testBigPostWithContentExchange() throws Exception + { + int size =32; + ContentExchange httpExchange=new ContentExchange(); + + Buffer babuf = new ByteArrayBuffer(size*36*1024); + Buffer niobuf = new DirectNIOBuffer(size*36*1024); + + byte[] bytes="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes(); + + for (int i=0;i<size*1024;i++) + { + babuf.put(bytes); + niobuf.put(bytes); + } + + httpExchange.setURL(_scheme+"localhost:"+_port+"/"); + httpExchange.setMethod(HttpMethods.POST); + httpExchange.setRequestContentType("application/data"); + httpExchange.setRequestContent(babuf); + + _httpClient.send(httpExchange); + int status = httpExchange.waitForDone(); + + assertEquals(HttpExchange.STATUS_COMPLETED,status); + String result=httpExchange.getResponseContent(); + assertEquals(babuf.length(),result.length()); + + httpExchange.reset(); + httpExchange.setURL(_scheme+"localhost:"+_port+"/"); + httpExchange.setMethod(HttpMethods.POST); + httpExchange.setRequestContentType("application/data"); + httpExchange.setRequestContent(niobuf); + _httpClient.send(httpExchange); + status = httpExchange.waitForDone(); + result=httpExchange.getResponseContent(); + assertEquals(niobuf.length(),result.length()); + assertEquals(HttpExchange.STATUS_COMPLETED, status); + } + public void testSlowPost() throws Exception { ContentExchange httpExchange=new ContentExchange() @@ -289,7 +369,6 @@ public class HttpExchangeTest extends TestCase if (_index>=data.length()) return -1; - //System.err.println("sleep "+_index); try { Thread.sleep(250); @@ -377,7 +456,7 @@ public class HttpExchangeTest extends TestCase } - public static void copyStream(InputStream in, OutputStream out) + public static void copyStrxeam(InputStream in, OutputStream out) { try { @@ -403,6 +482,8 @@ public class HttpExchangeTest extends TestCase _server=new Server(); _server.setGracefulShutdown(500); _connector=new SelectChannelConnector(); + + _connector.setMaxIdleTime(3000000); _connector.setPort(0); _server.setConnectors(new Connector[] { _connector }); @@ -424,13 +505,11 @@ public class HttpExchangeTest extends TestCase if (request.getServerName().equals("jetty.eclipse.org")) { - // System.err.println("HANDLING Proxy"); response.getOutputStream().println("Proxy request: "+request.getRequestURL()); response.getOutputStream().println(request.getHeader(HttpHeaders.PROXY_AUTHORIZATION)); } else if (request.getMethod().equalsIgnoreCase("GET")) { - // System.err.println("HANDLING Hello "+request.getRequestURI()); response.getOutputStream().println("<hello>"); for (; i<100; i++) { @@ -440,12 +519,24 @@ public class HttpExchangeTest extends TestCase } response.getOutputStream().println("</hello>"); } + else if (request.getMethod().equalsIgnoreCase("SLEEP")) + { + Thread.sleep(1000); + } else { - // System.err.println("HANDLING "+request.getMethod()); - copyStream(request.getInputStream(),response.getOutputStream()); + response.setContentType(request.getContentType()); + int size=request.getContentLength(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(size>0?size:32768); + IO.copy(request.getInputStream(),bout); + response.getOutputStream().write(bout.toByteArray()); } } + catch(InterruptedException e) + { + System.err.println(e); + Log.debug(e); + } catch(IOException e) { e.printStackTrace(); @@ -458,7 +549,6 @@ public class HttpExchangeTest extends TestCase } finally { - // System.err.println("HANDLED "+i); } } }); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java index af29296bdb..cb4b6738ed 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java @@ -35,6 +35,7 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ @@ -63,6 +64,8 @@ public class HttpGetRedirectTest private Realm _realm; private String _protocol; private String _requestUrl; + private String _requestUrl2; + private RedirectHandler _handler; public void setUp() throws Exception @@ -73,10 +76,14 @@ public class HttpGetRedirectTest _server = new Server(); configureServer(_server); + org.eclipse.jetty.server.bio.SocketConnector connector = new org.eclipse.jetty.server.bio.SocketConnector(); + _server.addConnector(connector); _server.start(); int port = _server.getConnectors()[0].getLocalPort(); _requestUrl = _protocol+"://localhost:"+port+ "/content.txt"; + + _handler._toURL=_protocol+"://localhost:"+connector.getLocalPort()+ "/moved.txt"; } public void tearDown() @@ -92,7 +99,7 @@ public class HttpGetRedirectTest public void testGet() throws Exception { startClient(_realm); - + ContentExchange getExchange = new ContentExchange(); getExchange.setURL(_requestUrl); getExchange.setMethod(HttpMethods.GET); @@ -107,10 +114,10 @@ public class HttpGetRedirectTest content = getExchange.getResponseContent(); } - stopClient(); - assertEquals(HttpStatus.OK_200,responseStatus); assertEquals(_content,content); + + stopClient(); } protected void configureServer(Server server) @@ -121,8 +128,8 @@ public class HttpGetRedirectTest SelectChannelConnector connector = new SelectChannelConnector(); server.addConnector(connector); - Handler handler = new RedirectHandler(HttpStatus.MOVED_PERMANENTLY_301, "/content.txt", "/moved.txt", 1); - server.setHandler( handler ); + _handler = new RedirectHandler(HttpStatus.MOVED_PERMANENTLY_301, "/content.txt", "WAIT FOR IT", 2); + server.setHandler( _handler ); } @@ -162,46 +169,26 @@ public class HttpGetRedirectTest _realm = realm; } - public static void copyStream(InputStream in, OutputStream out) - { - try - { - byte[] buffer=new byte[1024]; - int len; - while ((len=in.read(buffer))>=0) - { - out.write(buffer,0,len); - } - } - catch (EofException e) - { - System.err.println(e); - } - catch (IOException e) - { - e.printStackTrace(); - } - } private static class RedirectHandler extends AbstractHandler { - private final String origUrl; - - private final int code; + private final String _fromURI; + private final int _code; + private final int _maxRedirects; + private int _redirectCount = 0; + private String _toURL; - private final int maxRedirects; - - private int redirectCount = 0; - - private final String currUrl; - - public RedirectHandler( final int code, final String currUrl, final String origUrl, final int maxRedirects ) + public RedirectHandler( final int code, final String fromURI, final String toURL, final int maxRedirects ) { - this.code = code; - this.currUrl = currUrl; - this.origUrl = origUrl; - this.maxRedirects = maxRedirects; + this._code = code; + this._fromURI = fromURI; + this._toURL = toURL; + this._maxRedirects = maxRedirects; + + if (_fromURI==null || _toURL==null) + throw new IllegalArgumentException(); + } public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) @@ -212,23 +199,18 @@ public class HttpGetRedirectTest return; } - if (request.getRequestURI().equals(currUrl)) + if (request.getRequestURI().equals(_fromURI)) { - redirectCount++; - - if ( maxRedirects < 0 || redirectCount <= maxRedirects ) - { - response.setStatus( code ); - response.setHeader( "Location", currUrl ); - } - else - { - response.setStatus( code ); - response.setHeader( "Location", origUrl ); - } + _redirectCount++; + + String location = ( _redirectCount <= _maxRedirects )?_fromURI:_toURL; + + response.setStatus( _code ); + response.setHeader( "Location", location ); + ( (Request) request ).setHandled( true ); } - else if (request.getRequestURI().equals(origUrl)) + else { PrintWriter out = response.getWriter(); out.write(_content); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java index 0737c01f64..60ae2f9e43 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.client; @@ -18,13 +18,10 @@ import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.Connector; @@ -32,10 +29,16 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -public class HttpHeadersTest extends TestCase +public class HttpHeadersTest { - private static String _content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. " + private static final String CONTENT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. " + "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque " + "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. " + "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam " @@ -48,75 +51,67 @@ public class HttpHeadersTest extends TestCase + "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse " + "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque."; - private File _docRoot; private Server _server; - private Connector _connector; private TestHeaderHandler _handler; private int _port; - public void setUp() throws Exception + @Before + public void init() throws Exception { - _docRoot = new File("target/test-output/docroot/"); - _docRoot.mkdirs(); - _docRoot.deleteOnExit(); + File docRoot = new File("target/test-output/docroot/"); + if (!docRoot.exists()) + assertTrue(docRoot.mkdirs()); + docRoot.deleteOnExit(); + + _server = new Server(); + Connector connector = new SelectChannelConnector(); + _server.addConnector(connector); + + _handler = new TestHeaderHandler(); + _server.setHandler(_handler); + + _server.start(); - startServer(); + _port = connector.getLocalPort(); } - public void tearDown() throws Exception + @After + public void destroy() throws Exception { - stopServer(); + _server.stop(); + _server.join(); } + @Test public void testHttpHeaders() throws Exception { - HttpClient client = new HttpClient(); - client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - client.start(); - - String requestUrl = "http://localhost:" + _port + "/header"; - - ContentExchange exchange = new ContentExchange(); - exchange.setURL(requestUrl); - exchange.setMethod(HttpMethods.GET); - exchange.addRequestHeader("User-Agent","Jetty-Client/7.0"); - - client.send(exchange); - int state = exchange.waitForDone(); - - String content = ""; - int responseStatus = exchange.getResponseStatus(); - if (responseStatus == HttpStatus.OK_200) + HttpClient httpClient = new HttpClient(); + httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + httpClient.start(); + try { - content = exchange.getResponseContent(); - } - - assertEquals(HttpStatus.OK_200,responseStatus); - assertEquals(_content,content); - assertEquals("Jetty-Client/7.0",_handler.headers.get("User-Agent")); - } - - protected void startServer() throws Exception - { - _server = new Server(0); + String requestUrl = "http://localhost:" + _port + "/header"; - _connector = new SelectChannelConnector(); - _server.addConnector(_connector); + ContentExchange exchange = new ContentExchange(); + exchange.setURL(requestUrl); + exchange.setMethod(HttpMethods.GET); + exchange.addRequestHeader("User-Agent","Jetty-Client/7.0"); - _handler = new TestHeaderHandler(); - _server.setHandler(_handler); + httpClient.send(exchange); - _server.start(); + int state = exchange.waitForDone(); + assertEquals(HttpExchange.STATUS_COMPLETED, state); + int responseStatus = exchange.getResponseStatus(); + assertEquals(HttpStatus.OK_200,responseStatus); - _port = _connector.getLocalPort(); - } + String content = exchange.getResponseContent(); - protected void stopServer() throws Exception - { - if (_server != null) + assertEquals(HttpHeadersTest.CONTENT,content); + assertEquals("Jetty-Client/7.0",_handler.headers.get("User-Agent")); + } + finally { - _server.stop(); - _server = null; + httpClient.stop(); } } @@ -138,7 +133,7 @@ public class HttpHeadersTest extends TestCase response.setContentType("text/plain"); response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().print(_content); + response.getWriter().print(CONTENT); baseRequest.setHandled(true); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/SecuredContentExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/SecuredContentExchangeTest.java index 679b0e1a4f..fb2152e8be 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/SecuredContentExchangeTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/SecuredContentExchangeTest.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.client; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -78,7 +79,7 @@ public class SecuredContentExchangeTest knownRoles.add("user"); knownRoles.add("admin"); - security.setConstraintMappings(new ConstraintMapping[] {mapping}, knownRoles); + security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); security.setAuthenticator(new BasicAuthenticator()); security.setLoginService(loginService); security.setStrict(false); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/SecuredErrorStatusTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/SecuredErrorStatusTest.java index 413ed1828c..5469ec072a 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/SecuredErrorStatusTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/SecuredErrorStatusTest.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.client; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -144,7 +145,7 @@ public class SecuredErrorStatusTest knownRoles.add("user"); knownRoles.add("admin"); - security.setConstraintMappings(new ConstraintMapping[] {mapping}, knownRoles); + security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); security.setAuthenticator(new BasicAuthenticator()); security.setLoginService(loginService); security.setStrict(false); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecuredContentExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecuredContentExchangeTest.java index 9f72fbd046..b1cf3a82b6 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecuredContentExchangeTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecuredContentExchangeTest.java @@ -14,6 +14,7 @@ package org.eclipse.jetty.client; import java.io.File; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -83,7 +84,7 @@ extends ContentExchangeTest knownRoles.add("user"); knownRoles.add("admin"); - security.setConstraintMappings(new ConstraintMapping[] {mapping}, knownRoles); + security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); security.setAuthenticator(new BasicAuthenticator()); security.setLoginService(loginService); security.setStrict(false); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecuredErrorStatusTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecuredErrorStatusTest.java index 8647262be5..37eef2b271 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecuredErrorStatusTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecuredErrorStatusTest.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.client; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -144,7 +145,7 @@ public class SslSecuredErrorStatusTest knownRoles.add("user"); knownRoles.add("admin"); - security.setConstraintMappings(new ConstraintMapping[] {mapping}, knownRoles); + security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); security.setAuthenticator(new BasicAuthenticator()); security.setLoginService(loginService); security.setStrict(false); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecurityListenerTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecurityListenerTest.java index 36646ff8ee..c7ee05bb54 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecurityListenerTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/SslSecurityListenerTest.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CyclicBarrier; @@ -170,7 +171,7 @@ public class SslSecurityListenerTest extends TestCase sh.setAuthenticator(authenticator); Set<String> roles = new HashSet<String>(Arrays.asList(new String[]{"user", "admin"})); - sh.setConstraintMappings(new ConstraintMapping[] { cm }, roles); + sh.setConstraintMappings(Collections.singletonList(cm), roles); _server.setHandler(sh); Handler testHandler = new AbstractHandler() diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/WebSocketUpgradeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/WebSocketUpgradeTest.java new file mode 100644 index 0000000000..e1bdfc41e2 --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/WebSocketUpgradeTest.java @@ -0,0 +1,249 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.client; + +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; + +import junit.framework.TestCase; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.websocket.WebSocket; +import org.eclipse.jetty.websocket.WebSocketConnection; +import org.eclipse.jetty.websocket.WebSocketHandler; + +/** + * Functional testing for HttpExchange. + */ +public class WebSocketUpgradeTest extends TestCase +{ + protected Server _server; + protected int _port; + protected HttpClient _httpClient; + protected Connector _connector; + protected ConcurrentLinkedQueue<TestWebSocket> _webSockets= new ConcurrentLinkedQueue<TestWebSocket>(); + protected WebSocketHandler _handler; + protected TestWebSocket _websocket; + final BlockingQueue<Object> _results = new ArrayBlockingQueue<Object>(100); + + @Override + protected void setUp() throws Exception + { + startServer(); + _httpClient=new HttpClient(); + _httpClient.setIdleTimeout(2000); + _httpClient.setTimeout(2500); + _httpClient.setConnectTimeout(1000); + _httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + _httpClient.setMaxConnectionsPerAddress(10); + _httpClient.start(); + } + + @Override + protected void tearDown() throws Exception + { + _httpClient.stop(); + Thread.sleep(500); + stopServer(); + } + + + public void testGetWithContentExchange() throws Exception + { + final WebSocket clientWS = new WebSocket() + { + Outbound _outbound; + + public void onConnect(Outbound outbound) + { + _outbound=outbound; + _results.add("clientWS.onConnect"); + _results.add(_outbound); + } + + public void onDisconnect() + { + } + + public void onMessage(byte frame, String data) + { + _results.add("clientWS.onMessage"); + _results.add(data); + } + + public void onMessage(byte frame, byte[] data, int offset, int length) + { + } + }; + + + HttpExchange httpExchange=new HttpExchange() + { + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.client.HttpExchange#onResponseStatus(org.eclipse.jetty.io.Buffer, int, org.eclipse.jetty.io.Buffer) + */ + @Override + protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException + { + waitFor(2); + _results.add(new Integer(status)); + super.onResponseStatus(version,status,reason); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.client.HttpExchange#onSwitchProtocol(org.eclipse.jetty.io.EndPoint) + */ + @Override + protected Connection onSwitchProtocol(EndPoint endp) throws IOException + { + waitFor(3); + WebSocketConnection connection = new WebSocketConnection(clientWS,endp); + + _results.add("onSwitchProtocol"); + _results.add(connection); + clientWS.onConnect(connection); + return connection; + } + + private void waitFor(int results) + { + try + { + int c=10; + while(_results.size()<results && c-->0) + Thread.sleep(10); + } + catch(InterruptedException e) + { + e.printStackTrace(); + } + } + }; + + httpExchange.setURL("http://localhost:"+_port+"/"); + httpExchange.setMethod(HttpMethods.GET); + + httpExchange.addRequestHeader("Upgrade","WebSocket"); + httpExchange.addRequestHeader("Connection","Upgrade"); + + _httpClient.send(httpExchange); + int status = httpExchange.waitForDone(); + assertEquals(HttpExchange.STATUS_COMPLETED, status); + + System.err.println("results="+_results); + + assertEquals("serverWS.onConnect", _results.poll(1,TimeUnit.SECONDS)); + TestWebSocket serverWS = (TestWebSocket)_results.poll(1,TimeUnit.SECONDS); + + assertEquals(new Integer(101), _results.poll(1,TimeUnit.SECONDS)); + + assertEquals("onSwitchProtocol", _results.poll(1,TimeUnit.SECONDS)); + WebSocketConnection client_conn=(WebSocketConnection)_results.poll(1,TimeUnit.SECONDS); + + assertEquals("clientWS.onConnect", _results.poll(1,TimeUnit.SECONDS)); + assertEquals(client_conn, _results.poll(1,TimeUnit.SECONDS)); + + client_conn.sendMessage("hello world"); + + assertEquals("serverWS.onMessage", _results.poll(1,TimeUnit.SECONDS)); + assertEquals("hello world", _results.poll(1,TimeUnit.SECONDS)); + + serverWS.sendMessage("buongiorno"); + + assertEquals("clientWS.onMessage", _results.poll(1,TimeUnit.SECONDS)); + assertEquals("buongiorno", _results.poll(1,TimeUnit.SECONDS)); + + } + + protected void newServer() throws Exception + { + _server=new Server(); + _server.setGracefulShutdown(500); + _connector=new SelectChannelConnector(); + + _connector.setPort(0); + _server.setConnectors(new Connector[] { _connector }); + } + + protected void startServer() throws Exception + { + newServer(); + _handler= new WebSocketHandler() + { + @Override + protected WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) + { + _websocket = new TestWebSocket(); + return _websocket; + } + }; + + _server.setHandler(_handler); + _server.start(); + _port=_connector.getLocalPort(); + } + + private void stopServer() throws Exception + { + _server.stop(); + _server.join(); + } + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + class TestWebSocket implements WebSocket + { + Outbound _outbound; + + public void onConnect(Outbound outbound) + { + _outbound=outbound; + _webSockets.add(this); + _results.add("serverWS.onConnect"); + _results.add(this); + } + + public void onMessage(byte frame, byte[] data,int offset, int length) + { + } + + public void onMessage(final byte frame, final String data) + { + _results.add("serverWS.onMessage"); + _results.add(data); + } + + public void onDisconnect() + { + _results.add("onDisconnect"); + _webSockets.remove(this); + } + + public void sendMessage(String msg) throws IOException + { + _outbound.sendMessage(msg); + } + } +} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java index 7c3386093b..9c70665e33 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java @@ -4,35 +4,36 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.client.security; -import junit.framework.TestCase; +import org.junit.Test; -public class SecurityResolverTest extends TestCase +public class SecurityResolverTest { + @Test public void testNothing() { - } + /* TODO public void testCredentialParsing() throws Exception { SecurityListener resolver = new SecurityListener(); Buffer value = new ByteArrayBuffer("basic a=b".getBytes()); - + assertEquals( "basic", resolver.scrapeAuthenticationType( value.toString() ) ); assertEquals( 1, resolver.scrapeAuthenticationDetails( value.toString() ).size() ); value = new ByteArrayBuffer("digest a=boo, c=\"doo\" , egg=foo".getBytes()); - + assertEquals( "digest", resolver.scrapeAuthenticationType( value.toString() ) ); Map<String,String> testMap = resolver.scrapeAuthenticationDetails( value.toString() ); assertEquals( 3, testMap.size() ); @@ -40,6 +41,6 @@ public class SecurityResolverTest extends TestCase assertEquals( "doo", testMap.get("c") ); assertEquals( "foo", testMap.get("egg") ); } - + */ } diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index 12f284228b..bbbf30da9f 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -54,10 +54,12 @@ </archive> </configuration> </plugin> - <!-- always include sources since jetty-xbean makes use of them --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.continuation.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java index 7cc7bfa19f..e547f13d1d 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java @@ -27,10 +27,10 @@ import javax.servlet.ServletResponseWrapper; * A continuation is a mechanism by which a HTTP Request can be suspended and * restarted after a timeout or an asynchronous event has occurred. * <p> - * The continuation mechanism is a portable mechansim that will work - * asychronously without additional configuration of all jetty-7, + * The continuation mechanism is a portable mechanism that will work + * asynchronously without additional configuration of all jetty-7, * jetty-8 and Servlet 3.0 containers. With the addition of - * the {@link ContinuationFilter}, the mechansism will also work + * the {@link ContinuationFilter}, the mechanism will also work * asynchronously on jetty-6 and non-asynchronously on any * servlet 2.5 container. * <p> @@ -172,8 +172,8 @@ public interface Continuation * the container with a suspended request, the thread is freed for other * tasks and the request is held until either: * <ul> - * <li>a call to {@link ServletRequest#resume()}.</li> - * <li>a call to {@link ServletRequest#complete()}.</li> + * <li>a call to {@link #resume()}.</li> + * <li>a call to {@link #complete()}.</li> * <li>the timeout expires.</li> * </ul> * <p> @@ -207,8 +207,8 @@ public interface Continuation * the container with a suspended request, the thread is freed for other * tasks and the request is held until either: * <ul> - * <li>a call to {@link ServletRequest#resume()}.</li> - * <li>a call to {@link ServletRequest#complete()}.</li> + * <li>a call to {@link #resume()}.</li> + * <li>a call to {@link #complete()}.</li> * <li>the timeout expires.</li> * </ul> * <p> @@ -241,11 +241,11 @@ public interface Continuation * </p> * <p> * If resume is called before a suspended request is returned to the - * container (ie the thread that called {@link #suspend(long)} is still + * container (ie the thread that called {@link #suspend()} is still * within the filter chain and/or servlet service method), then the resume * does not take effect until the call to the filter chain and/or servlet * returns to the container. In this case both {@link #isSuspended()} and - * {@link isResumed()} return true. Multiple calls to resume are ignored. + * {@link #isResumed()} return true. Multiple calls to resume are ignored. * </p> * <p> * Typically resume() is used after a call to {@link #suspend()} with @@ -254,7 +254,7 @@ public interface Continuation * had been passed a wrapped response. * </p> * - * @see {@link #suspend()} + * @see #suspend() * @exception IllegalStateException if the request is not suspended. * */ @@ -267,16 +267,16 @@ public interface Continuation * <p> * This method can be called by any thread that has been passed a reference * to a suspended request. When a request is completed, the associated - * response object commited and flushed. The request is not redispatched. + * response object committed and flushed. The request is not redispatched. * </p> * * <p> * If complete is called before a suspended request is returned to the - * container (ie the thread that called {@link #suspend(long)} is still + * container (ie the thread that called {@link #suspend()} is still * within the filter chain and/or servlet service method), then the complete * does not take effect until the call to the filter chain and/or servlet * returns to the container. In this case both {@link #isSuspended()} and - * {@link isResumed()} return true. + * {@link #isResumed()} return true. * </p> * * <p> @@ -295,7 +295,7 @@ public interface Continuation * not valid hold a request or continuation reference after the end of the * life cycle. * - * @see {@link #suspend()} + * @see #suspend() * @exception IllegalStateException * if the request is not suspended. * @@ -304,7 +304,7 @@ public interface Continuation /* ------------------------------------------------------------ */ /** - * @return true after {@link #suspend(long)} has been called and before the + * @return true after {@link #suspend()} has been called and before the * request has been redispatched due to being resumed, completed or * timed out. */ diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java index 3b64778392..6a90a5ad3c 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java @@ -96,8 +96,8 @@ public class ContinuationSupport * vary depending on the container in which the application is * deployed. It may be an implementation native to the container (eg * org.eclipse.jetty.server.AsyncContinuation) or one of the utility - * implementations provided such as {@link FauxContinuation} or - * {@link Servlet3Continuation}. + * implementations provided such as an internal <code>FauxContinuation</code> + * or a real implementation like {@link org.eclipse.jetty.continuation.Servlet3Continuation}. * @param request The request * @return a Continuation instance */ @@ -147,10 +147,10 @@ public class ContinuationSupport /* ------------------------------------------------------------ */ /** - * @param request - * @param response + * @param request the servlet request + * @param response the servlet response * @deprecated use {@link #getContinuation(ServletRequest)} - * @return + * @return the continuation */ @Deprecated public static Continuation getContinuation(final ServletRequest request, final ServletResponse response) diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java index 3d15be2d0a..1e801ba468 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java @@ -59,6 +59,7 @@ public class Servlet3Continuation implements Continuation public void onTimeout(AsyncEvent event) throws IOException { _initial=false; + System.err.println("Doing dispatch on timed out continuation for "+_request.getAttribute("FOO")); event.getAsyncContext().dispatch(); } }); diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index 37f3ec8de4..07681758d2 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -27,6 +27,23 @@ </executions> </plugin> <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + <configuration> + <descriptors> + <descriptor>config.xml</descriptor> + </descriptors> + </configuration> + </execution> + </executions> + </plugin> + <plugin> <!-- Required for OSGI --> @@ -38,10 +55,12 @@ </archive> </configuration> </plugin> - <!-- always include sources since jetty-xbean makes use of them --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.deploy.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> @@ -59,7 +78,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> - <version>4.7</version> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/jetty-deploy/src/main/config/etc/jetty-deploy.xml b/jetty-deploy/src/main/config/etc/jetty-deploy.xml new file mode 100644 index 0000000000..89fc9899e2 --- /dev/null +++ b/jetty-deploy/src/main/config/etc/jetty-deploy.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> + +<!-- =============================================================== --> +<!-- Configure the Jetty Deployers --> +<!-- =============================================================== --> + +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <!-- =========================================================== --> + <!-- Configure the deployment manager --> + <!-- --> + <!-- Sets up 2 monitored dir app providers that are configured --> + <!-- to behave in a similaraly to the legacy ContextDeployer --> + <!-- and WebAppDeployer from previous versions of Jetty. --> + <!-- =========================================================== --> + <Call name="addBean"> + <Arg> + <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager"> + <Set name="contexts"> + <Ref id="Contexts" /> + </Set> + <Call name="setContextAttribute"> + <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg> + <Arg>.*/servlet-api-[^/]*\.jar$</Arg> + </Call> + <!-- Providers of Apps via Context XML files. + Configured to behave similar to the legacy ContextDeployer --> + <Call name="addAppProvider"> + <Arg> + <New class="org.eclipse.jetty.deploy.providers.ContextProvider"> + <Set name="monitoredDir"><Property name="jetty.home" default="." />/contexts</Set> + <Set name="scanInterval">5</Set> + </New> + </Arg> + </Call> + <!-- Providers of Apps via WAR file existence. + Configured to behave similar to the legacy WebAppDeployer --> + <Call name="addAppProvider"> + <Arg> + <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> + <Set name="monitoredDir"><Property name="jetty.home" default="." />/webapps</Set> + <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set> + <Set name="scanInterval">5</Set> + <Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set> + </New> + </Arg> + </Call> + </New> + </Arg> + </Call> +</Configure> diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java index c881985096..4dc1f5a370 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java @@ -15,20 +15,9 @@ // ======================================================================== package org.eclipse.jetty.deploy; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.jetty.deploy.util.FileID; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.AttributesMap; -import org.eclipse.jetty.util.URIUtil; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.xml.XmlConfiguration; -import org.xml.sax.SAXException; +import org.omg.CORBA.portable.ApplicationException; /** * The information about an App that is managed by the {@link DeploymentManager} @@ -98,8 +87,8 @@ public class App * Create it if needed. * * @return the {@link ContextHandler} to use for the App when fully started. - * (Portions of which might be ignored when App is in the - * {@link AppState#STAGED} state} + * (Portions of which might be ignored when App is not yet + * {@link AppLifeCycle#DEPLOYED} or {@link AppLifeCycle#STARTED}) * @throws Exception */ public ContextHandler getContextHandler() throws Exception @@ -107,7 +96,15 @@ public class App if (_context == null) { _context = getAppProvider().createContextHandler(this); - this._context.setAttributes(new AttributesMap(_manager.getContextAttributes())); + + AttributesMap attributes = _manager.getContextAttributes(); + if (attributes!=null && attributes.size()>0) + { + // Merge the manager attributes under the existing attributes + attributes = new AttributesMap(attributes); + attributes.addAll(_context.getAttributes()); + _context.setAttributes(attributes); + } } return _context; } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java index ddc195bc1f..7738cecb32 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java @@ -29,7 +29,7 @@ import org.eclipse.jetty.util.log.Log; /** * The lifecycle of an App in the {@link DeploymentManager}. * - * Setups a the default {@link Graph}, and manages the bindings to the life cycle via the {@link DeployLifeCycleBinding} + * Setups a the default {@link Graph}, and manages the bindings to the life cycle via the {@link AppLifeCycle.Binding} * annotation. * <p> * <img src="doc-files/AppLifeCycle.png"> @@ -54,8 +54,6 @@ public class AppLifeCycle extends Graph * the node being processed * @param app * the app being processed - * @param deploymentManager - * the {@link DeploymentManager} tracking the {@link AppLifeCycle} and {@link App} * @throws Exception * if any problem severe enough to halt the AppLifeCycle processing */ diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java index 116e009728..0a7c6c29de 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java @@ -15,10 +15,10 @@ package org.eclipse.jetty.deploy; import java.io.File; import java.io.FilenameFilter; -import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.eclipse.jetty.deploy.providers.MonitoredDirAppProvider; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; @@ -48,7 +48,7 @@ import org.eclipse.jetty.xml.XmlConfiguration; * * <p> * The xml should configure the context and the instance is deployed to the {@link ContextHandlerCollection} specified - * by {@link #setContexts(Server)}. + * by {@link Server#setHandler(org.eclipse.jetty.server.Handler)}. * * <p> * Similarly, when one of these existing files is removed, the corresponding context is undeployed; when one of these @@ -88,7 +88,7 @@ public class ContextDeployer extends AbstractLifeCycle /** * Handle a new deployment * - * @see org.eclipse.jetty.util.Scanner.FileAddedListener#fileAdded(java.lang.String) + * @see org.eclipse.jetty.util.Scanner.DiscreteListener#fileAdded(java.lang.String) */ public void fileAdded(String filename) throws Exception { @@ -98,7 +98,7 @@ public class ContextDeployer extends AbstractLifeCycle /** * Handle a change to an existing deployment. Undeploy then redeploy. * - * @see org.eclipse.jetty.util.Scanner.FileChangedListener#fileChanged(java.lang.String) + * @see org.eclipse.jetty.util.Scanner.DiscreteListener#fileChanged(java.lang.String) */ public void fileChanged(String filename) throws Exception { @@ -108,7 +108,7 @@ public class ContextDeployer extends AbstractLifeCycle /** * Handle an undeploy. * - * @see org.eclipse.jetty.util.Scanner.FileRemovedListener#fileRemoved(java.lang.String) + * @see org.eclipse.jetty.util.Scanner.DiscreteListener#fileRemoved(java.lang.String) */ public void fileRemoved(String filename) throws Exception { @@ -123,8 +123,6 @@ public class ContextDeployer extends AbstractLifeCycle /** * Constructor - * - * @throws Exception */ public ContextDeployer() { @@ -245,7 +243,7 @@ public class ContextDeployer extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** - * @return + * @return the directory * @deprecated use {@link #setContextsDir(String)} */ @Deprecated @@ -256,7 +254,7 @@ public class ContextDeployer extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** - * @return + * @return the configuration directory * @deprecated use {@link #setContextsDir(String)} */ @Deprecated @@ -276,7 +274,7 @@ public class ContextDeployer extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** - * @return + * @return the configuration manager */ public ConfigurationManager getConfigurationManager() { @@ -319,7 +317,7 @@ public class ContextDeployer extends AbstractLifeCycle /** * Get a contextAttribute that will be set for every Context deployed by this deployer. * @param name - * @return + * @return the attribute value */ public Object getAttribute (String name) { @@ -450,7 +448,14 @@ public class ContextDeployer extends AbstractLifeCycle xmlConfiguration.setProperties(properties); ContextHandler context=(ContextHandler)xmlConfiguration.configure(); - context.setAttributes(new AttributesMap(_contextAttributes)); + + // merge attributes + if (_contextAttributes!=null && _contextAttributes.size()>0) + { + AttributesMap attributes = new AttributesMap(_contextAttributes); + attributes.addAll(context.getAttributes()); + context.setAttributes(attributes); + } return context; } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java index 381a496ef3..e138969663 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java @@ -24,7 +24,6 @@ import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.Set; import org.eclipse.jetty.deploy.bindings.StandardDeployer; import org.eclipse.jetty.deploy.bindings.StandardStarter; @@ -305,9 +304,9 @@ public class DeploymentManager extends AbstractLifeCycle /** * Get Set of {@link App}s by {@link Node} * - * @param state - * the state to look for. - * @return + * @param node + * the node to look for. + * @return the collection of apps for the node */ public Collection<App> getApps(Node node) { @@ -358,7 +357,7 @@ public class DeploymentManager extends AbstractLifeCycle * Get a contextAttribute that will be set for every Context deployed by this provider. * * @param name - * @return + * @return the context attribute value */ public Object getContextAttribute(String name) { diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/WebAppDeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/WebAppDeployer.java index a76e3491a1..b78c1d4641 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/WebAppDeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/WebAppDeployer.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.deploy; import java.util.ArrayList; +import org.eclipse.jetty.deploy.providers.MonitoredDirAppProvider; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; @@ -40,7 +41,7 @@ import org.eclipse.jetty.webapp.WebAppContext; * by {@link #getContexts()}. {@link ContextHandlerCollection#getContextClass()} * * <p> - * This deployer does not do hot deployment or undeployment. Nor does it support per webapplication configuration. For + * This deployer does not do hot deployment or undeployment. Nor does it support per web application configuration. For * these features see {@link ContextDeployer}. * * @see DeploymentManager @@ -149,7 +150,7 @@ public class WebAppDeployer extends AbstractLifeCycle /** * Get a contextAttribute that will be set for every Context deployed by this deployer. * @param name - * @return + * @return the attribute value */ public Object getAttribute (String name) { diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStarter.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStarter.java index a07b33beda..91b8395c43 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStarter.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStarter.java @@ -19,7 +19,6 @@ import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.AppLifeCycle; import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.util.log.Log; public class StandardStarter implements AppLifeCycle.Binding { diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java index 547bdb3519..02860e7b84 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java @@ -138,7 +138,7 @@ public class Graph /** * Find all edges that are connected {@link Edge#getFrom()} the specific node. * - * @param node + * @param from * the node with potential edges from it * @return the set of edges from the node */ diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java index 8a92c45893..92940acee7 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java @@ -16,7 +16,7 @@ import org.eclipse.jetty.xml.XmlConfiguration; /* ------------------------------------------------------------ */ /** Context directory App Provider. - * <p>This specialisation of {@link MonitoredDirAppProvider} is the + * <p>This specialization of {@link MonitoredDirAppProvider} is the * replacement for {@link ContextDeployer} and it will scan a directory * only for context.xml files. * @see ContextDeployer diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/MonitoredDirAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/MonitoredDirAppProvider.java index e3cf85da61..36ea012de7 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/MonitoredDirAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/MonitoredDirAppProvider.java @@ -17,7 +17,6 @@ package org.eclipse.jetty.deploy.providers; import java.io.File; import java.io.FilenameFilter; -import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -40,10 +39,8 @@ import org.eclipse.jetty.xml.XmlConfiguration; * AppProvider for Monitoring directories for contexts. * * A Context may either be a WAR, a directory or an XML descriptor. - * - * @deprecated - Use {@link ContextProvider} or {@link WebAppProvider} */ -public class MonitoredDirAppProvider extends AbstractLifeCycle implements AppProvider +public abstract class MonitoredDirAppProvider extends AbstractLifeCycle implements AppProvider { class MonitoredFilenameFilter implements FilenameFilter { diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java index 6d648b22eb..417ff6cc33 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java @@ -4,18 +4,15 @@ import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.net.MalformedURLException; -import java.util.HashMap; -import java.util.Map; import org.eclipse.jetty.deploy.App; -import org.eclipse.jetty.deploy.ConfigurationManager; import org.eclipse.jetty.deploy.WebAppDeployer; import org.eclipse.jetty.deploy.util.FileID; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.xml.XmlConfiguration; +import org.eclipse.jetty.webapp.WebInfConfiguration; /* ------------------------------------------------------------ */ @@ -31,6 +28,7 @@ public class WebAppProvider extends ScanningAppProvider private boolean _parentLoaderPriority = false; private String _defaultsDescriptor; private Filter _filter; + private File _tempDirectory; private String[] _configurationClasses; private static class Filter implements FilenameFilter @@ -40,13 +38,17 @@ public class WebAppProvider extends ScanningAppProvider public boolean accept(File dir, String name) { if (!dir.exists()) + { return false; + } String lowername = name.toLowerCase(); File file = new File(dir,name); // is it not a directory and not a war ? if (!file.isDirectory() && !lowername.endsWith(".war")) + { return false; + } // is it a directory for an existing war file? if (file.isDirectory() && @@ -61,7 +63,9 @@ public class WebAppProvider extends ScanningAppProvider { String context=name; if (!file.isDirectory()) + { context=context.substring(0,context.length()-4); + } if (new File(_contexts,context+".xml").exists() || new File(_contexts,context+".XML").exists() ) { @@ -116,7 +120,7 @@ public class WebAppProvider extends ScanningAppProvider { _parentLoaderPriority = parentLoaderPriority; } - + /* ------------------------------------------------------------ */ /** Get the defaultsDescriptor. * @return the defaultsDescriptor @@ -160,7 +164,7 @@ public class WebAppProvider extends ScanningAppProvider } catch (MalformedURLException e) { - e.printStackTrace(); + throw new RuntimeException(e); } catch (IOException e) { @@ -187,6 +191,27 @@ public class WebAppProvider extends ScanningAppProvider return _configurationClasses; } + /** + * Set the Work directory where unpacked WAR files are managed from. + * <p> + * Default is the same as the <code>java.io.tmpdir</code> System Property. + * + * @param directory the new work directory + */ + public void setTempDir(File directory) + { + _tempDirectory = directory; + } + + /** + * Get the user supplied Work Directory. + * + * @return the user supplied work directory (null if user has not set Temp Directory yet) + */ + public File getTempDir() + { + return _tempDirectory; + } /* ------------------------------------------------------------ */ public ContextHandler createContextHandler(final App app) throws Exception @@ -207,31 +232,54 @@ public class WebAppProvider extends ScanningAppProvider // Context Path is the same as the archive. context = context.substring(0,context.length() - 4); } - else + else + { throw new IllegalStateException("unable to create ContextHandler for "+app); + } // special case of archive (or dir) named "root" is / context - if (context.equalsIgnoreCase("root") || context.equalsIgnoreCase("root/")) + if (context.equalsIgnoreCase("root") || context.equalsIgnoreCase("root/")) + { context = URIUtil.SLASH; + } // Ensure "/" is Prepended to all context paths. - if (context.charAt(0) != '/') + if (context.charAt(0) != '/') + { context = "/" + context; + } // Ensure "/" is Not Trailing in context paths. - if (context.endsWith("/") && context.length() > 0) + if (context.endsWith("/") && context.length() > 0) + { context = context.substring(0,context.length() - 1); + } WebAppContext wah = new WebAppContext(); wah.setContextPath(context); wah.setWar(file.getAbsolutePath()); - if (_defaultsDescriptor != null) + if (_defaultsDescriptor != null) + { wah.setDefaultsDescriptor(_defaultsDescriptor); + } wah.setExtractWAR(_extractWars); wah.setParentLoaderPriority(_parentLoaderPriority); - if (_configurationClasses != null) + if (_configurationClasses != null) + { wah.setConfigurationClasses(_configurationClasses); + } + if (_tempDirectory != null) + { + /* Since the Temp Dir is really a context base temp directory, + * Lets set the Temp Directory in a way similar to how WebInfConfiguration does it, + * instead of setting the + * WebAppContext.setTempDirectory(File). + * If we used .setTempDirectory(File) all webapps will wind up in the + * same temp / work directory, overwriting each others work. + */ + wah.setAttribute(WebAppContext.BASETEMPDIR,_tempDirectory); + } return wah; } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java index 26acce7045..5caa04b68a 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java @@ -159,7 +159,7 @@ public class AppLifeCycleTest /** * Request multiple lifecycle paths with a single lifecycle instance. Just to ensure that there is no state - * maintained between {@link AppLifeCycle#findPath(Node, Node)} requests. + * maintained between {@link AppLifeCycle#getPath(Node, Node)} requests. * * @throws IOException */ diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/graph/GraphTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/graph/GraphTest.java index d2d74b0b21..cc284e1f4d 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/graph/GraphTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/graph/GraphTest.java @@ -1,9 +1,9 @@ package org.eclipse.jetty.deploy.graph; -import org.junit.Test; - import junit.framework.Assert; +import org.junit.Test; + public class GraphTest { diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java new file mode 100644 index 0000000000..8fc7cb5930 --- /dev/null +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java @@ -0,0 +1,76 @@ +package org.eclipse.jetty.deploy.providers; + +import java.io.File; + +import org.eclipse.jetty.deploy.test.XmlConfiguredJetty; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class WebAppProviderTest +{ + private static XmlConfiguredJetty jetty; + + @BeforeClass + public static void setupEnvironment() throws Exception + { + jetty = new XmlConfiguredJetty(); + jetty.addConfiguration("jetty.xml"); + jetty.addConfiguration("jetty-deploy-wars.xml"); + + // Setup initial context + jetty.copyContext("foo.xml","foo.xml"); + jetty.copyWebapp("foo-webapp-1.war","foo.war"); + + // Should not throw an Exception + jetty.load(); + + // Start it + jetty.start(); + } + + @AfterClass + public static void teardownEnvironment() throws Exception + { + // Stop jetty. + jetty.stop(); + } + + @Test + public void testStartupContext() + { + // Check Server for Handlers + jetty.printHandlers(System.out); + jetty.assertWebAppContextsExists("/foo"); + + File workDir = jetty.getJettyDir("workish"); + + // Test for regressions + assertDirNotExists("root of work directory",workDir,"webinf"); + assertDirNotExists("root of work directory",workDir,"jsp"); + + // Test for correct behavior + Assert.assertTrue("Should have generated directory in work directory: " + workDir,hasJettyGeneratedPath(workDir,"foo.war")); + } + + private static boolean hasJettyGeneratedPath(File basedir, String expectedWarFilename) + { + for (File path : basedir.listFiles()) + { + if (path.exists() && path.isDirectory() && path.getName().startsWith("Jetty_") && path.getName().contains(expectedWarFilename)) + { + System.out.println("Found expected generated directory: " + path); + return true; + } + } + + return false; + } + + public static void assertDirNotExists(String msg, File workDir, String subdir) + { + File dir = new File(workDir,subdir); + Assert.assertFalse("Should not have " + subdir + " in " + msg + " - " + workDir,dir.exists()); + } +} diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/MavenTestingUtils.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/MavenTestingUtils.java index e6f9e265a0..367d584aa2 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/MavenTestingUtils.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/MavenTestingUtils.java @@ -93,7 +93,8 @@ public class MavenTestingUtils * * @param test * the junit 3.x testcase to base this new directory on. - * @return + * @return the File path to the testcase specific testing directory underneath the + * <code>${basedir}/target</code> sub directory */ public static File getTargetTestingDir(TestCase test) { @@ -105,7 +106,8 @@ public class MavenTestingUtils * * @param testname * the testname to create directory against. - * @return + * @return the File path to the testname sepecific testing directory underneath the + * <code>${basedir}/target</code> sub directory */ public static File getTargetTestingDir(String testname) { diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java index e2e18f911e..89e03dd26f 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java @@ -59,7 +59,7 @@ public class XmlConfiguredJetty { this(MavenTestingUtils.getTestID()); } - + public XmlConfiguredJetty(String testname) throws IOException { xmlConfigurations = new ArrayList<URL>(); @@ -69,9 +69,10 @@ public class XmlConfiguredJetty // Ensure we have a new (pristene) directory to work with. int idx = 0; jettyHome = new File(jettyHomeBase + "#" + idx); - while(jettyHome.exists()) { - idx++; - jettyHome = new File(jettyHomeBase + "#" + idx); + while (jettyHome.exists()) + { + idx++; + jettyHome = new File(jettyHomeBase + "#" + idx); } deleteContents(jettyHome); // Prepare Jetty.Home (Test) dir @@ -91,15 +92,28 @@ public class XmlConfiguredJetty deleteContents(contextsDir); } contextsDir.mkdirs(); + File webappsDir = new File(jettyHome,"webapps"); if (webappsDir.exists()) { deleteContents(webappsDir); } webappsDir.mkdirs(); + File tmpDir = new File(jettyHome,"tmp"); + if (tmpDir.exists()) + { + deleteContents(tmpDir); + } tmpDir.mkdirs(); + File workishDir = new File(jettyHome,"workish"); + if (workishDir.exists()) + { + deleteContents(workishDir); + } + workishDir.mkdirs(); + // Setup properties System.setProperty("java.io.tmpdir",tmpDir.getAbsolutePath()); properties.setProperty("jetty.home",jettyHome.getAbsolutePath()); @@ -108,6 +122,7 @@ public class XmlConfiguredJetty properties.setProperty("test.resourcesdir",MavenTestingUtils.getTestResourcesDir().getAbsolutePath()); properties.setProperty("test.webapps",webappsDir.getAbsolutePath()); properties.setProperty("test.targetdir",MavenTestingUtils.getTargetDir().getAbsolutePath()); + properties.setProperty("test.workdir",workishDir.getAbsolutePath()); // Write out configuration for use by ConfigurationManager. File testConfig = MavenTestingUtils.getTargetFile("xml-configured-jetty.properties"); @@ -238,11 +253,11 @@ public class XmlConfiguredJetty private void deleteContents(File dir) { System.out.printf("Delete (dir) %s/%n",dir); - if(!dir.exists()) + if (!dir.exists()) { - return; + return; } - + for (File file : dir.listFiles()) { // Safety measure. only recursively delete within target directory. @@ -261,9 +276,7 @@ public class XmlConfiguredJetty public DeploymentManager getActiveDeploymentManager() { - List<DeploymentManager> depmans = server.getBeans(DeploymentManager.class); - Assert.assertEquals("DeploymentManager bean count",1,depmans.size()); - return depmans.get(0); + return server.getBean(DeploymentManager.class); } public File getJettyDir(String name) diff --git a/jetty-deploy/src/test/resources/jetty-deploy-wars.xml b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml new file mode 100644 index 0000000000..f336584c66 --- /dev/null +++ b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> + +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <Call name="addLifeCycle"> + <Arg> + <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager"> + <Set name="contexts"> + <Ref id="Contexts" /> + </Set> + + <!-- Providers of Apps --> + <Set name="appProviders"> + <Array type="org.eclipse.jetty.deploy.AppProvider"> + <Item> + <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> + <Set name="monitoredDir"><SystemProperty name="jetty.home" />/webapps</Set> + <Set name="scanInterval">1</Set> + <Set name="tempDir"><Property name="jetty.home" default="target" />/workish</Set> + </New> + </Item> + </Array> + </Set> + </New> + </Arg> + </Call> + +</Configure> diff --git a/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml b/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml index 841944926d..07cf8d2889 100644 --- a/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml +++ b/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml @@ -15,7 +15,7 @@ <Array type="org.eclipse.jetty.deploy.AppProvider"> <Item> <New class="org.eclipse.jetty.deploy.providers.ContextProvider"> - <Set name="monitoredDir"><Property name="jetty.home" />/contexts</Set> + <Set name="monitoredDir"><SystemProperty name="jetty.home" />/contexts</Set> <Set name="scanInterval">1</Set> <Set name="configurationManager"> <New class="org.eclipse.jetty.deploy.FileConfigurationManager"> @@ -28,9 +28,9 @@ </Item> <Item> <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> - <Set name="monitoredDir"><Property name="jetty.home" />/webapps</Set> + <Set name="monitoredDir"><SystemProperty name="jetty.home" />/webapps</Set> <Set name="scanInterval">1</Set> - <Set name="contextXmlDir"><Property name="jetty.home" />/contexts</Set> + <Set name="contextXmlDir"><SystemProperty name="jetty.home" />/contexts</Set> </New> </Item> </Array> diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index de13ded520..f0ac036c19 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -9,28 +9,44 @@ <name>Jetty :: Distribution Assemblies</name> <packaging>pom</packaging> <properties> - <assembly.directory>target/distribution</assembly.directory> + <eclipse-mirror>http://mirror.cc.vt.edu/pub/eclipse/eclipse/downloads/drops</eclipse-mirror> + <orbit-url>http://download.eclipse.org/tools/orbit/committers/drops/I20100628101947/bundles</orbit-url> + <assembly-directory>target/distribution</assembly-directory> + <eclipse-drop>R-3.6-201006080911</eclipse-drop> + <eclipse-ecj-version>3.6</eclipse-ecj-version> + <orbit-javax-activation-version>${javax-activation-version}.0.v201005080500</orbit-javax-activation-version> + <orbit-javax-el-version>2.1.0.v201004190952</orbit-javax-el-version> + <orbit-javax-mail-glassfish-version>${javax-mail-version}.v201005082020</orbit-javax-mail-glassfish-version> </properties> - <build> + <build> <plugins> <plugin> + <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> - <configuration> - <includeEmptyDirs>true</includeEmptyDirs> - <outputDirectory>${assembly.directory}</outputDirectory> - </configuration> <executions> <execution> + <id>copy-base-assembly-tree</id> <phase>generate-resources</phase> <goals> - <goal>resources</goal> + <goal>copy-resources</goal> </goals> + <configuration> + <useBuildFilters>false</useBuildFilters> + <includeEmptyDirs>true</includeEmptyDirs> + <outputDirectory>${assembly-directory}</outputDirectory> + <resources> + <resource> + <directory>${basedir}/src/main/resources</directory> + </resource> + </resources> + </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> + <version>1.4</version> <executions> <execution> <phase>generate-resources</phase> @@ -39,16 +55,38 @@ </goals> <configuration> <tasks> - <property name="orbit.base.url" value="http://download.eclipse.org/tools/orbit/downloads/drops/R20090529135407/bundles" /> - <mkdir dir="${assembly.directory}/lib" /> - <!-- - <get src="${orbit.base.url}/javax.servlet_2.5.0.v200806031605.jar" dest="${assembly.directory}/lib/servlet-api-2.5.jar" usetimestamp="true" verbose="true" /> - --> - <mkdir dir="${assembly.directory}/lib/jndi" /> - <get src="${orbit.base.url}/javax.activation_1.1.0.v200905021805.jar" dest="${assembly.directory}/lib/jndi/activation-1.1.jar" usetimestamp="true" verbose="true" /> - <get src="${orbit.base.url}/javax.mail_1.4.0.v200905040518.jar" dest="${assembly.directory}/lib/jndi/mail-1.4.jar" usetimestamp="true" verbose="true" /> - <copy file="../VERSION.txt" todir="${assembly.directory}" /> - <chmod dir="${assembly.directory}/bin" perm="755" includes="**/*.sh" /> + <!-- This is the Orbit Downloads Process --> + + <!-- Step 1: download orbit artifact into orbit-cache (if not present) --> + <property name="orbit-cache" value="${user.home}/.m2/eclipse-orbit" /> + + <mkdir dir="${orbit-cache}" /> + <get dest="${orbit-cache}" verbose="true" skipexisting="true"> + <url url="${orbit-url}/javax.activation_${orbit-javax-activation-version}.jar" /> + <url url="${orbit-url}/javax.mail.glassfish_${orbit-javax-mail-glassfish-version}.jar" /> + </get> + + <mkdir dir="${orbit-cache}/${eclipse-drop}" /> + <get dest="${orbit-cache}/${eclipse-drop}" verbose="true" skipexisting="true"> + <url url="${eclipse-mirror}/${eclipse-drop}/ecj-${eclipse-ecj-version}.jar" /> + </get> + + <!-- Step 2: copy the orbit artifact from orbit-cache to the appropriate lib directory --> + + <!-- ${jetty.home}/lib/ --> + <mkdir dir="${assembly-directory}/lib" /> + + <!-- ${jetty.home}/lib/jndi/ --> + <mkdir dir="${assembly-directory}/lib/jndi" /> + <copy todir="${assembly-directory}/lib/jndi"> + <fileset dir="${orbit-cache}"> + <include name="javax.activation_${orbit-javax-activation-version}.jar" /> + <include name="javax.mail.glassfish_${orbit-javax-mail-glassfish-version}.jar" /> + </fileset> + </copy> + + <copy file="../VERSION.txt" todir="${assembly-directory}" /> + <chmod dir="${assembly-directory}/bin" perm="755" includes="**/*.sh" /> </tasks> </configuration> </execution> @@ -68,7 +106,7 @@ <resourceBundle>org.eclipse.jetty.toolchain:jetty-artifact-remote-resources:1.0</resourceBundle> <resourceBundle>org.eclipse.jetty.toolchain:jetty-distribution-remote-resources:1.1</resourceBundle> </resourceBundles> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </configuration> </execution> </executions> @@ -93,7 +131,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -103,7 +141,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -113,7 +151,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -123,7 +161,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -133,7 +171,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -143,7 +181,17 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> + </artifactItem> + <artifactItem> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-deploy</artifactId> + <version>${project.version}</version> + <classifier>config</classifier> + <type>jar</type> + <overWrite>true</overWrite> + <includes>**</includes> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -153,7 +201,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -163,7 +211,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -173,7 +221,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> </artifactItem> </artifactItems> </configuration> @@ -193,7 +241,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -202,7 +250,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -211,7 +259,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -220,7 +268,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -229,7 +277,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -238,7 +286,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -247,7 +295,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -256,7 +304,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -265,7 +313,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <!-- Jetty Deploy --> <artifactItem> @@ -275,7 +323,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -284,7 +332,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -293,7 +341,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -302,7 +350,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -311,7 +359,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -320,7 +368,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -329,7 +377,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -338,7 +386,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -347,7 +395,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -356,7 +404,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> <artifactItem> <groupId>org.eclipse.jetty</groupId> @@ -365,7 +413,7 @@ <type>war</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/webapps</outputDirectory> + <outputDirectory>${assembly-directory}/webapps</outputDirectory> <destFileName>test.war</destFileName> </artifactItem> <artifactItem> @@ -375,7 +423,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}</outputDirectory> + <outputDirectory>${assembly-directory}</outputDirectory> <destFileName>start.jar</destFileName> </artifactItem> <artifactItem> @@ -385,7 +433,7 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> <destFileName>servlet-api-3.0.jar</destFileName> </artifactItem> <artifactItem> @@ -395,47 +443,11 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${assembly.directory}/lib</outputDirectory> + <outputDirectory>${assembly-directory}/lib</outputDirectory> </artifactItem> </artifactItems> </configuration> </execution> - <!-- - <execution> - <phase>generate-resources</phase> - <goals> - <goal>copy</goal> - </goals> - <configuration> - <artifactItems> - <artifactItem> - <groupId>org.apache.geronimo.specs</groupId> - <artifactId>geronimo-annotation_1.0_spec</artifactId> - <version>1.1.1</version> - <outputDirectory>${assembly.directory}/lib/annotations</outputDirectory> - </artifactItem> - <artifactItem> - <groupId>asm</groupId> - <artifactId>asm-commons</artifactId> - <version>3.1</version> - <outputDirectory>${assembly.directory}/lib/annotations</outputDirectory> - </artifactItem> - <artifactItem> - <groupId>asm</groupId> - <artifactId>asm</artifactId> - <version>3.1</version> - <outputDirectory>${assembly.directory}/lib/annotations</outputDirectory> - </artifactItem> - <artifactItem> - <groupId>asm</groupId> - <artifactId>asm-tree</artifactId> - <version>3.1</version> - <outputDirectory>${assembly.directory}/lib/annotations</outputDirectory> - </artifactItem> - </artifactItems> - </configuration> - </execution> - --> </executions> </plugin> <plugin> @@ -456,6 +468,22 @@ </execution> </executions> </plugin> + <!-- No point performing PMD in assembly project --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <!-- No point performing Findbugs in assembly project --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> </plugins> </build> <dependencies> @@ -531,4 +559,35 @@ <version>${project.version}</version> </dependency> </dependencies> + <!-- profiles> + <profile> + <id>release</id> + <build> + <plugins> + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <version>2.1</version> + <executions> + <execution> + <id>unpack-source</id> + <phase>generate-sources</phase> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <includes>**/*</includes> + <excludes>META-INF/**</excludes> + <includeGroupIds>org.eclipse.jetty</includeGroupIds> + <outputDirectory>${project.build.directory}/sources</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles --> </project> diff --git a/jetty-distribution/src/main/assembly/jetty-assembly.xml b/jetty-distribution/src/main/assembly/jetty-assembly.xml index 3c5a9cc881..eac183cc96 100644 --- a/jetty-distribution/src/main/assembly/jetty-assembly.xml +++ b/jetty-distribution/src/main/assembly/jetty-assembly.xml @@ -6,7 +6,7 @@ </formats> <fileSets> <fileSet> - <directory>${assembly.directory}</directory> + <directory>${assembly-directory}</directory> <outputDirectory></outputDirectory> <includes> <include>**</include> diff --git a/jetty-distribution/src/main/resources/README.txt b/jetty-distribution/src/main/resources/README.txt index 5d41b2c813..2a094bd58e 100644 --- a/jetty-distribution/src/main/resources/README.txt +++ b/jetty-distribution/src/main/resources/README.txt @@ -3,88 +3,64 @@ JETTY ===== The Jetty project is a 100% Java HTTP Server, HTTP Client -and Servlet Container. The core project is hosted by -the Eclipse Foundation at +and Servlet Container. - http://www.eclipse.org/jetty/ -The jetty integrations with 3rd party modules are hosted -by the Codehaus at +The Jetty @ eclipse project is based on the Jetty project at codehaus http://jetty.codehaus.org +Ongoing development is now at the eclipse foundation -JETTY DISTRIBUTION -================== - -This is the jetty-distribution module from Jetty @ eclipse -project and is based on the Jetty modules from eclipse plus -dependencies that have been through the eclipse IP -process and conditioning. + http://www.eclipse.org/jetty/ -This distribution and its dependencies are provided under -the terms and conditions of the Eclipse Foundation Software -User Agreement unless otherwise specified. -This distribution contains only the core functionality -of a servlet server and the HTTP client. +Jetty @ eclipse is open source and is dual licensed using the apache 2.0 and +eclipse public license 1.0. You may choose either license when distributing +jetty. -Some modules (eg annotations) are missing dependencies -which may be discovered by using the command - mvn dependency:tree -within the source module and placing them in the -lib/ext directory. Alternately we recommend the jetty-hightide -distribution for users that desire more third party integrations. -JETTY HIGHTIDE +BUILDING JETTY ============== -The Jetty-hightide distribution is available for -download via http://jetty.codehaus.org and contains -the core jetty modules, plus the 3rd party dependencies -and integrations needed to create a full featured -application server. - +Jetty uses maven 2 as its build system. Maven will fetch +the dependancies, build the server and assemble a runnable +version: -MAVEN -===== -All Jetty artifacts are available as maven dependencies -under the org.eclipse.jetty and org.mortbay.hightide group IDs + mvn install - http://repo1.maven.org/maven2/org/eclipse/jetty/ - http://repo2.maven.org/maven2/org/mortbay/jetty/ RUNNING JETTY ============= -The run directory is either the top-level of a distribution -or jetty-distribution/target/distribution directory when built from +The run directory is either the top-level of a binary release +or jetty-distribution/target/assembly-prep directory when built from source. To run with the default options: java -jar start.jar -To run with specific configuration file(s) - - java -jar start.jar etc/jetty.xml - -To see the available options +To see the available options and the default arguments +provided by the start.ini file: java -jar start.jar --help -To run with JSP support (if available) +To run with extra configuration file(s) appended, eg SSL + + java -jar start.jar etc/jetty-ssl.xml - java -jar start.jar OPTIONS=Server,jsp +To run with extra configuration file(s) prepended, eg logging & jmx -To run with JMX support + java -jar start.jar --pre=etc/jetty-logging.xml --pre=etc/jetty-jmx.xml - java -jar start.jar OPTIONS=Server,jmx etc/jetty-jmx.xml etc/jetty.xml +To run without the args from start.ini -To run with JSP & JMX support + java -jar start.jar --ini OPTIONS=Server,websocket etc/jetty.xml etc/jetty-deploy.xml etc/jetty-ssl.xml - java -jar start.jar OPTIONS=Server,jsp,jmx etc/jetty-jmx.xml etc/jetty.xml +to list the know OPTIONS: + java -jar start.jar --list-options diff --git a/jetty-distribution/src/main/resources/bin/jetty.sh b/jetty-distribution/src/main/resources/bin/jetty.sh index 5c3fda5f78..c0b1be6a7d 100755 --- a/jetty-distribution/src/main/resources/bin/jetty.sh +++ b/jetty-distribution/src/main/resources/bin/jetty.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Startup script for jetty under *nix systems (it works under NT/cygwin too). @@ -37,12 +37,8 @@ # # Configuration variables # -# JAVA_HOME -# Home of Java installation. -# # JAVA -# Command to invoke Java. If not set, $JAVA_HOME/bin/java will be -# used. +# Command to invoke Java. If not set, java (from the PATH) will be used. # # JAVA_OPTIONS # Extra options to pass to the JVM @@ -83,12 +79,10 @@ # JETTY_USER # if set, then used as a username to run the server as # -# Set to 0 if you do not want to use start-stop-daemon (especially on SUSE boxes) -START_STOP_DAEMON=1 usage() { - echo "Usage: $0 {start|stop|run|restart|check|supervise} [ CONFIGS ... ] " + echo "Usage: ${0##*/} [-d] {start|stop|run|restart|check|supervise} [ CONFIGS ... ] " exit 1 } @@ -100,70 +94,64 @@ usage() ################################################## findDirectory() { - OP=$1 - shift - for L in $* ; do - [ $OP $L ] || continue - echo $L - break - done + local L OP=$1 + shift + for L in "$@"; do + [ "$OP" "$L" ] || continue + printf %s "$L" + break + done } running() { - [ -f $1 ] || return 1 - PID=$(cat $1) - ps -p $PID >/dev/null 2>/dev/null || return 1 - return 0 + local PID=$(cat "$1" 2>/dev/null) || return 1 + kill -0 "$PID" 2>/dev/null } - - - +readConfig() +{ + (( DEBUG )) && echo "Reading $1.." + source "$1" +} ################################################## # Get the action & configs ################################################## - +CONFIGS=() +NO_START=0 +DEBUG=0 + +while [[ $1 = -* ]]; do + case $1 in + -d) DEBUG=1 ;; + esac + shift +done ACTION=$1 shift -ARGS="$*" -CONFIGS="" -NO_START=0 ################################################## -# See if there's a default configuration file +# Read any configuration files ################################################## -if [ -f /etc/default/jetty7 ] ; then - . /etc/default/jetty7 -elif [ -f /etc/default/jetty ] ; then - . /etc/default/jetty -fi - +for CONFIG in /etc/default/jetty{,7} $HOME/.jettyrc; do + if [ -f "$CONFIG" ] ; then + readConfig "$CONFIG" + fi +done -################################################## -# See if there's a user-specific configuration file -################################################## -if [ -f $HOME/.jettyrc ] ; then - . $HOME/.jettyrc -fi ################################################## # Set tmp if not already set. ################################################## - -if [ -z "$TMP" ] -then - TMP=/tmp -fi +TMPDIR=${TMPDIR:-/tmp} ################################################## # Jetty's hallmark ################################################## JETTY_INSTALL_TRACE_FILE="etc/jetty.xml" -TMPJ=$TMP/j$$ ################################################## @@ -171,11 +159,17 @@ TMPJ=$TMP/j$$ ################################################## if [ -z "$JETTY_HOME" ] then - JETTY_HOME_1=`dirname "$0"` - JETTY_HOME_1=`dirname "$JETTY_HOME_1"` - if [ -f "${JETTY_HOME_1}/${JETTY_INSTALL_TRACE_FILE}" ] ; + JETTY_SH=$0 + case "$JETTY_SH" in + /*) ;; + ./*) ;; + *) JETTY_SH=./$JETTY_SH ;; + esac + JETTY_HOME=${JETTY_SH%/*/*} + + if [ ! -f "${JETTY_SH%/*/*}/$JETTY_INSTALL_TRACE_FILE" ] then - JETTY_HOME=${JETTY_HOME_1} + JETTY_HOME= fi fi @@ -183,42 +177,57 @@ fi ################################################## # if no JETTY_HOME, search likely locations. ################################################## -if [ "$JETTY_HOME" = "" ] ; then - STANDARD_LOCATIONS=" \ - /usr/share \ - /usr/share/java \ - $HOME \ - $HOME/src \ - ${HOME}/opt/ \ - /opt \ - /java \ - /usr/local \ - /usr/local/share \ - /usr/local/share/java \ - /home \ - " - JETTY_DIR_NAMES=" \ - jetty-7 \ - jetty7 \ - jetty-7.* \ - jetty \ - Jetty-7 \ - Jetty7 \ - Jetty-7.* \ - Jetty \ - " +if [ -z "$JETTY_HOME" ] ; then + STANDARD_LOCATIONS=( + "/usr/share" + "/usr/share/java" + "${HOME}" + "${HOME}/src" + "${HOME}/opt" + "/opt" + "/java" + "/usr/local" + "/usr/local/share" + "/usr/local/share/java" + "/home" + ) + JETTY_DIR_NAMES=( + "jetty-7" + "jetty7" + "jetty-7.*" + "jetty" + "Jetty-7" + "Jetty7" + "Jetty-7.*" + "Jetty" + ) - JETTY_HOME= - for L in $STANDARD_LOCATIONS + for L in "${STANDARD_LOCATIONS[@]}" do - for N in $JETTY_DIR_NAMES - do - if [ -d $L/$N ] && [ -f "$L/${N}/${JETTY_INSTALL_TRACE_FILE}" ] ; - then - JETTY_HOME="$L/$N" - fi - done - [ ! -z "$JETTY_HOME" ] && break + for N in "${JETTY_DIR_NAMES[@]}" + do + POSSIBLE_JETTY_HOME=("$L/"$N) + if [ ! -d "$POSSIBLE_JETTY_HOME" ] + then + # Not a directory. skip. + unset POSSIBLE_JETTY_HOME + elif [ ! -f "$POSSIBLE_JETTY_HOME/$JETTY_INSTALL_TRACE_FILE" ] + then + # Trace file not found. skip. + unset POSSIBLE_JETTY_HOME + else + # Good hit, Use it + JETTY_HOME=$POSSIBLE_JETTY_HOME + # Break out of JETTY_DIR_NAMES loop + break + fi + done + if [ -n "$POSSIBLE_JETTY_HOME" ] + then + # We have found our JETTY_HOME + # Break out of STANDARD_LOCATIONS loop + break + fi done fi @@ -226,57 +235,25 @@ fi ################################################## # No JETTY_HOME yet? We're out of luck! ################################################## -if [ -z "$JETTY_HOME" ] ; then - echo "** ERROR: JETTY_HOME not set, you need to set it or install in a standard location" - exit 1 +if [ -z "$JETTY_HOME" ]; then + echo "** ERROR: JETTY_HOME not set, you need to set it or install in a standard location" + exit 1 fi -cd $JETTY_HOME -JETTY_HOME=`pwd` + +cd "$JETTY_HOME" +JETTY_HOME=$PWD + ##################################################### # Check that jetty is where we think it is ##################################################### -if [ ! -r $JETTY_HOME/$JETTY_INSTALL_TRACE_FILE ] +if [ ! -r "$JETTY_HOME/$JETTY_INSTALL_TRACE_FILE" ] then - echo "** ERROR: Oops! Jetty doesn't appear to be installed in $JETTY_HOME" - echo "** ERROR: $JETTY_HOME/$JETTY_INSTALL_TRACE_FILE is not readable!" - exit 1 + echo "** ERROR: Oops! Jetty doesn't appear to be installed in $JETTY_HOME" + echo "** ERROR: $JETTY_HOME/$JETTY_INSTALL_TRACE_FILE is not readable!" + exit 1 fi - -########################################################### -# Get the list of config.xml files from the command line. -########################################################### -if [ ! -z "$ARGS" ] -then - for A in $ARGS - do - if [ -f $A ] - then - CONF="$A" - elif [ -f $JETTY_HOME/etc/$A ] - then - CONF="$JETTY_HOME/etc/$A" - elif [ -f ${A}.xml ] - then - CONF="${A}.xml" - elif [ -f $JETTY_HOME/etc/${A}.xml ] - then - CONF="$JETTY_HOME/etc/${A}.xml" - else - echo "** ERROR: Cannot find configuration '$A' specified in the command line." - exit 1 - fi - if [ ! -r $CONF ] - then - echo "** ERROR: Cannot read configuration '$A' specified in the command line." - exit 1 - fi - CONFIGS="$CONFIGS $CONF" - done -fi - - ################################################## # Try to find this script's configuration file, # but only if no configurations were given on the @@ -286,170 +263,89 @@ if [ -z "$JETTY_CONF" ] then if [ -f /etc/jetty.conf ] then - JETTY_CONF=/etc/jetty.conf - elif [ -f "${JETTY_HOME}/etc/jetty.conf" ] + JETTY_CONF=/etc/jetty.conf + elif [ -f "$JETTY_HOME/etc/jetty.conf" ] then - JETTY_CONF="${JETTY_HOME}/etc/jetty.conf" + JETTY_CONF=$JETTY_HOME/etc/jetty.conf fi fi ################################################## -# Read the configuration file if one exists -################################################## -CONFIG_LINES= -if [ -z "$CONFIGS" ] && [ -f "$JETTY_CONF" ] && [ -r "$JETTY_CONF" ] -then - CONFIG_LINES=`cat $JETTY_CONF | grep -v "^[:space:]*#" | tr "\n" " "` -fi - -################################################## # Get the list of config.xml files from jetty.conf ################################################## -if [ ! -z "${CONFIG_LINES}" ] +if [ -z "$CONFIGS" ] && [ -f "$JETTY_CONF" ] && [ -r "$JETTY_CONF" ] then - for CONF in ${CONFIG_LINES} + while read -r CONF do - if [ ! -r "$CONF" ] - then - echo "** WARNING: Cannot read '$CONF' specified in '$JETTY_CONF'" - elif [ -f "$CONF" ] - then - # assume it's a configure.xml file - CONFIGS="$CONFIGS $CONF" - elif [ -d "$CONF" ] + if expr "$CONF" : '#' >/dev/null ; then + continue + fi + + if [ -d "$CONF" ] then # assume it's a directory with configure.xml files # for example: /etc/jetty.d/ # sort the files before adding them to the list of CONFIGS - XML_FILES=`ls ${CONF}/*.xml | sort | tr "\n" " "` - for FILE in ${XML_FILES} + for file in "$CONF/"*.xml do - if [ -r "$FILE" ] && [ -f "$FILE" ] - then - CONFIGS="$CONFIGS $FILE" - else - echo "** WARNING: Cannot read '$FILE' specified in '$JETTY_CONF'" - fi + if [ -r "$FILE" ] && [ -f "$FILE" ] + then + CONFIGS+=("$FILE") + else + echo "** WARNING: Cannot read '$FILE' specified in '$JETTY_CONF'" + fi done else - echo "** WARNING: Don''t know what to do with '$CONF' specified in '$JETTY_CONF'" + # assume it's a command line parameter (let start.jar deal with its validity) + CONFIGS+=("$CONF") fi - done + done < "$JETTY_CONF" fi ##################################################### -# Run the standard server if there's nothing else to run -##################################################### -if [ -z "$CONFIGS" ] -then - CONFIGS="${JETTY_HOME}/etc/jetty-logging.xml ${JETTY_HOME}/etc/jetty.xml" -fi - - -##################################################### # Find a location for the pid file ##################################################### -if [ -z "$JETTY_RUN" ] +if [ -z "$JETTY_RUN" ] then - JETTY_RUN=`findDirectory -w /var/run /usr/var/run /tmp` + JETTY_RUN=$(findDirectory -w /var/run /usr/var/run /tmp) fi ##################################################### # Find a PID for the pid file ##################################################### -if [ -z "$JETTY_PID" ] +if [ -z "$JETTY_PID" ] then JETTY_PID="$JETTY_RUN/jetty.pid" fi - -################################################## -# Check for JAVA_HOME -################################################## -if [ -z "$JAVA_HOME" ] -then - # If a java runtime is not defined, search the following - # directories for a JVM and sort by version. Use the highest - # version number. - - # Java search path - JAVA_LOCATIONS="\ - /usr/java \ - /usr/bin \ - /usr/local/bin \ - /usr/local/java \ - /usr/local/jdk \ - /usr/local/jre \ - /usr/lib/jvm \ - /opt/java \ - /opt/jdk \ - /opt/jre \ - " - JAVA_NAMES="java jdk jre" - for N in $JAVA_NAMES ; do - for L in $JAVA_LOCATIONS ; do - [ -d $L ] || continue - find $L -name "$N" ! -type d | grep -v threads | while read J ; do - [ -x $J ] || continue - VERSION=`eval $J -version 2>&1` - [ $? = 0 ] || continue - VERSION=`expr "$VERSION" : '.*"\(1.[0-9\.]*\)["_]'` - [ "$VERSION" = "" ] && continue - expr $VERSION \< 1.2 >/dev/null && continue - echo $VERSION:$J - done - done - done | sort | tail -1 > $TMPJ - JAVA=`cat $TMPJ | cut -d: -f2` - JVERSION=`cat $TMPJ | cut -d: -f1` - - JAVA_HOME=`dirname $JAVA` - while [ ! -z "$JAVA_HOME" -a "$JAVA_HOME" != "/" -a ! -f "$JAVA_HOME/lib/tools.jar" ] ; do - JAVA_HOME=`dirname $JAVA_HOME` - done - [ "$JAVA_HOME" = "" ] && JAVA_HOME= - - echo "Found JAVA=$JAVA in JAVA_HOME=$JAVA_HOME" -fi - - ################################################## -# Determine which JVM of version >1.2 -# Try to use JAVA_HOME +# Setup JAVA if unset ################################################## -if [ "$JAVA" = "" -a "$JAVA_HOME" != "" ] +if [ -z "$JAVA" ] then - if [ ! -z "$JAVACMD" ] - then - JAVA="$JAVACMD" - else - [ -x $JAVA_HOME/bin/jre -a ! -d $JAVA_HOME/bin/jre ] && JAVA=$JAVA_HOME/bin/jre - [ -x $JAVA_HOME/bin/java -a ! -d $JAVA_HOME/bin/java ] && JAVA=$JAVA_HOME/bin/java - fi + JAVA=$(which java) fi -if [ "$JAVA" = "" ] +if [ -z "$JAVA" ] then - echo "Cannot find a JRE or JDK. Please set JAVA_HOME to a >=1.2 JRE" 2>&2 - exit 1 + echo "Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH." 2>&2 + exit 1 fi -JAVA_VERSION=`expr "$($JAVA -version 2>&1 | head -1)" : '.*1\.\([0-9]\)'` - ##################################################### # See if JETTY_PORT is defined ##################################################### -if [ "$JETTY_PORT" != "" ] +if [ "$JETTY_PORT" ] then - JAVA_OPTIONS="$JAVA_OPTIONS -Djetty.port=$JETTY_PORT" + JAVA_OPTIONS+=("-Djetty.port=$JETTY_PORT") fi ##################################################### # See if JETTY_LOGS is defined ##################################################### -if [ "$JETTY_LOGS" != "" ] +if [ "$JETTY_LOGS" ] then - JAVA_OPTIONS="$JAVA_OPTIONS -Djetty.logs=$JETTY_LOGS" + JAVA_OPTIONS+=("-Djetty.logs=$JETTY_LOGS") fi ##################################################### @@ -464,203 +360,211 @@ esac ##################################################### # Add jetty properties to Java VM options. ##################################################### -JAVA_OPTIONS="$JAVA_OPTIONS -Djetty.home=$JETTY_HOME -Djava.io.tmpdir=$TMP" +JAVA_OPTIONS+=("-Djetty.home=$JETTY_HOME" "-Djava.io.tmpdir=$TMPDIR") -[ -f $JETTY_HOME/etc/start.config ] && JAVA_OPTIONS="-DSTART=$JETTY_HOME/etc/start.config $JAVA_OPTIONS" +[ -f "$JETTY_HOME/etc/start.config" ] && JAVA_OPTIONS=("-DSTART=$JETTY_HOME/etc/start.config" "${JAVA_OPTIONS[@]}") ##################################################### # This is how the Jetty server will be started ##################################################### JETTY_START=$JETTY_HOME/start.jar -[ ! -f $JETTY_START ] && JETTY_START=$JETTY_HOME/lib/start.jar +[ ! -f "$JETTY_START" ] && JETTY_START=$JETTY_HOME/lib/start.jar + +START_INI=$(dirname $JETTY_START)/start.ini +[ -r "$START_INI" ] || START_INI="" -RUN_ARGS="$JAVA_OPTIONS -jar $JETTY_START $JETTY_ARGS $CONFIGS" -RUN_CMD="$JAVA $RUN_ARGS" +RUN_ARGS=(${JAVA_OPTIONS[@]} -jar "$JETTY_START" $JETTY_ARGS "${CONFIGS[@]}") +RUN_CMD=("$JAVA" ${RUN_ARGS[@]}) ##################################################### # Comment these out after you're happy with what # the script is doing. ##################################################### -#echo "JETTY_HOME = $JETTY_HOME" -#echo "JETTY_CONF = $JETTY_CONF" -#echo "JETTY_RUN = $JETTY_RUN" -#echo "JETTY_PID = $JETTY_PID" -#echo "JETTY_ARGS = $JETTY_ARGS" -#echo "CONFIGS = $CONFIGS" -#echo "JAVA_OPTIONS = $JAVA_OPTIONS" -#echo "JAVA = $JAVA" - +if (( DEBUG )) +then + echo "JETTY_HOME = $JETTY_HOME" + echo "JETTY_CONF = $JETTY_CONF" + echo "JETTY_RUN = $JETTY_RUN" + echo "JETTY_PID = $JETTY_PID" + echo "JETTY_ARGS = $JETTY_ARGS" + echo "CONFIGS = ${CONFIGS[*]}" + echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}" + echo "JAVA = $JAVA" + echo "RUN_CMD = ${RUN_CMD}" +fi ################################################## # Do the action ################################################## case "$ACTION" in start) - echo -n "Starting Jetty: " - - if [ "$NO_START" = "1" ]; then - echo "Not starting jetty - NO_START=1 in /etc/default/jetty7"; - exit 0; - fi - - - if [ "$START_STOP_DAEMON" = "1" ] && type start-stop-daemon > /dev/null 2>&1 - then - [ x$JETTY_USER = x ] && JETTY_USER=$(whoami) - [ $UID = 0 ] && CH_USER="-c $JETTY_USER" - if start-stop-daemon -S -p$JETTY_PID $CH_USER -d $JETTY_HOME -b -m -a $JAVA -- $RUN_ARGS - then - sleep 1 - if running $JETTY_PID - then - echo OK - else - echo FAILED - fi - fi - - else - - if [ -f $JETTY_PID ] - then - if running $JETTY_PID - then - echo "Already Running!!" - exit 1 - else - # dead pid file - remove - rm -f $JETTY_PID - fi - fi - - if [ x$JETTY_USER != x ] - then - touch $JETTY_PID - chown $JETTY_USER $JETTY_PID - su - $JETTY_USER -c " - $RUN_CMD & - PID=\$! - disown \$PID - echo \$PID > $JETTY_PID" - else - $RUN_CMD & - PID=$! - disown $PID - echo $PID > $JETTY_PID - fi - - echo "STARTED Jetty `date`" + echo -n "Starting Jetty: " + + if (( NO_START )); then + echo "Not starting jetty - NO_START=1"; + exit + fi + + if type start-stop-daemon > /dev/null 2>&1 + then + unset CH_USER + if [ -n "$JETTY_USER" ] + then + CH_USER="-c$JETTY_USER" + fi + if start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon + then + sleep 1 + if running "$JETTY_PID" + then + echo "OK" + else + echo "FAILED" + fi + fi + + else + + if [ -f "$JETTY_PID" ] + then + if running $JETTY_PID + then + echo "Already Running!" + exit 1 + else + # dead pid file - remove + rm -f "$JETTY_PID" fi + fi + + if [ "$JETTY_USER" ] + then + touch "$JETTY_PID" + chown "$JETTY_USER" "$JETTY_PID" + # FIXME: Broken solution: wordsplitting, pathname expansion, arbitrary command execution, etc. + su - "$JETTY_USER" -c " + ${RUN_CMD[*]} --daemon & + disown \$! + echo \$! > '$JETTY_PID'" + else + "${RUN_CMD[@]}" & + disown $! + echo $! > "$JETTY_PID" + fi + + echo "STARTED Jetty `date`" + fi - ;; + ;; stop) - echo -n "Stopping Jetty: " - if [ "$START_STOP_DAEMON" = "1" ] && type start-stop-daemon > /dev/null 2>&1; then - start-stop-daemon -K -p $JETTY_PID -d $JETTY_HOME -a $JAVA -s HUP - sleep 1 - if running $JETTY_PID - then - sleep 3 - if running $JETTY_PID - then - sleep 30 - if running $JETTY_PID - then - start-stop-daemon -K -p $JETTY_PID -d $JETTY_HOME -a $JAVA -s KILL - fi - fi - fi - - rm -f $JETTY_PID - echo OK - else - PID=`cat $JETTY_PID 2>/dev/null` - TIMEOUT=30 - while running $JETTY_PID && [ $TIMEOUT -gt 0 ] - do - kill $PID 2>/dev/null - sleep 1 - let TIMEOUT=$TIMEOUT-1 - done - - [ $TIMEOUT -gt 0 ] || kill -9 $PID 2>/dev/null - - rm -f $JETTY_PID - echo OK - fi - ;; + echo -n "Stopping Jetty: " + if type start-stop-daemon > /dev/null 2>&1; then + start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s HUP + + TIMEOUT=30 + while running "$JETTY_PID"; do + if (( TIMEOUT-- == 0 )); then + start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s KILL + fi - restart) - JETTY_SH=$0 - if [ ! -f $JETTY_SH ]; then - if [ ! -f $JETTY_HOME/bin/jetty.sh ]; then - echo "$JETTY_HOME/bin/jetty.sh does not exist." - exit 1 - fi - JETTY_SH=$JETTY_HOME/bin/jetty.sh + sleep 1 + done + + rm -f "$JETTY_PID" + echo OK + else + PID=$(cat "$JETTY_PID" 2>/dev/null) + kill "$PID" 2>/dev/null + + TIMEOUT=30 + while running $JETTY_PID; do + if (( TIMEOUT-- == 0 )); then + kill -KILL "$PID" 2>/dev/null fi - $JETTY_SH stop $* - sleep 5 - $JETTY_SH start $* - ;; + + sleep 1 + done + + rm -f "$JETTY_PID" + echo OK + fi + + ;; + + restart) + JETTY_SH=$0 + if [ ! -f $JETTY_SH ]; then + if [ ! -f $JETTY_HOME/bin/jetty.sh ]; then + echo "$JETTY_HOME/bin/jetty.sh does not exist." + exit 1 + fi + JETTY_SH=$JETTY_HOME/bin/jetty.sh + fi + + "$JETTY_SH" stop "$@" + "$JETTY_SH" start "$@" + + ;; supervise) - # - # Under control of daemontools supervise monitor which - # handles restarts and shutdowns via the svc program. - # - exec $RUN_CMD - ;; + # + # Under control of daemontools supervise monitor which + # handles restarts and shutdowns via the svc program. + # + exec "${RUN_CMD[@]}" + + ;; run|demo) - echo "Running Jetty: " + echo "Running Jetty: " - if [ -f $JETTY_PID ] - then - if running $JETTY_PID - then - echo "Already Running!!" - exit 1 - else - # dead pid file - remove - rm -f $JETTY_PID - fi - fi + if [ -f "$JETTY_PID" ] + then + if running "$JETTY_PID" + then + echo "Already Running!" + exit 1 + else + # dead pid file - remove + rm -f "$JETTY_PID" + fi + fi - exec $RUN_CMD - ;; + exec "${RUN_CMD[@]}" - check) - echo "Checking arguments to Jetty: " - echo "JETTY_HOME = $JETTY_HOME" - echo "JETTY_CONF = $JETTY_CONF" - echo "JETTY_RUN = $JETTY_RUN" - echo "JETTY_PID = $JETTY_PID" - echo "JETTY_PORT = $JETTY_PORT" - echo "JETTY_LOGS = $JETTY_LOGS" - echo "CONFIGS = $CONFIGS" - echo "JAVA_OPTIONS = $JAVA_OPTIONS" - echo "JAVA = $JAVA" - echo "CLASSPATH = $CLASSPATH" - echo "RUN_CMD = $RUN_CMD" - echo - - if [ -f $JETTY_RUN/jetty.pid ] - then - echo "Jetty running pid="`cat $JETTY_RUN/jetty.pid` - exit 0 - fi - exit 1 - ;; + ;; -*) - usage - ;; -esac + check) + echo "Checking arguments to Jetty: " + echo "JETTY_HOME = $JETTY_HOME" + echo "JETTY_CONF = $JETTY_CONF" + echo "JETTY_RUN = $JETTY_RUN" + echo "JETTY_PID = $JETTY_PID" + echo "JETTY_PORT = $JETTY_PORT" + echo "JETTY_LOGS = $JETTY_LOGS" + echo "START_INI = $START_INI" + echo "CONFIGS = ${CONFIGS[*]}" + echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}" + echo "JAVA = $JAVA" + echo "CLASSPATH = $CLASSPATH" + echo "RUN_CMD = ${RUN_CMD[*]}" + echo + + if [ -f "$JETTY_RUN/jetty.pid" ] + then + echo "Jetty running pid=$(< "$JETTY_RUN/jetty.pid")" + exit 0 + fi + exit 1 -exit 0 + ;; + *) + usage + ;; +esac +exit 0 diff --git a/jetty-distribution/src/main/resources/contexts/javadoc.xml b/jetty-distribution/src/main/resources/contexts-available/resources.xml index 342e6b9957..87a8d32770 100644 --- a/jetty-distribution/src/main/resources/contexts/javadoc.xml +++ b/jetty-distribution/src/main/resources/contexts-available/resources.xml @@ -2,22 +2,21 @@ <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.eclipse.org/configure.dtd"> <!-- -Configure a custom context for the javadoc. +Configure a custom context for serving static resources -This context contains only a ServletHandler with a default servlet +This context contains only a ResourceHandler to serve static html files and images. --> <Configure class="org.eclipse.jetty.server.handler.ContextHandler"> <Call class="org.eclipse.jetty.util.log.Log" name="debug"><Arg>Configure javadoc.xml</Arg></Call> - <Set name="contextPath">/javadoc</Set> - <Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/javadoc/</Set> + <Set name="contextPath">/resources</Set> + <Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/resources/</Set> <Set name="handler"> <New class="org.eclipse.jetty.server.handler.ResourceHandler"> <Set name="welcomeFiles"> <Array type="String"> <Item>index.html</Item> - <Item>contents.html</Item> <!-- the index if javadoc not generated --> </Array> </Set> <Set name="cacheControl">max-age=3600,public</Set> diff --git a/jetty-distribution/src/main/resources/etc/jetty.conf b/jetty-distribution/src/main/resources/etc/jetty.conf new file mode 100644 index 0000000000..b79f3169fb --- /dev/null +++ b/jetty-distribution/src/main/resources/etc/jetty.conf @@ -0,0 +1,13 @@ +# ======================================================== +# jetty.conf Configuration for jetty.sh script +# -------------------------------------------------------- +# This file is used by the jetty.sh script to provide +# extra configuration arguments for the start.jar command +# created by that script. +# +# Each line in this file becomes an arguement to start.jar +# unless this file contains an --ini option, then these +# arguments will be in addition to those found in the +# start.ini file +# ======================================================= +--pre=etc/jetty-logging.xml diff --git a/jetty-distribution/src/main/resources/javadoc/README.txt b/jetty-distribution/src/main/resources/javadoc/README.txt deleted file mode 100644 index f6b026ed8a..0000000000 --- a/jetty-distribution/src/main/resources/javadoc/README.txt +++ /dev/null @@ -1,15 +0,0 @@ - -Javadocs are available at: - -http://download.eclipse.org/jetty/stable-7/apidocs/ - - -Jxr is available at: - -http://download.eclipse.org/jetty/stable-7/xref/ - - -For specific versions replace 'stable-7' with the version, for example the javadocs for jetty-7.0.0.RC5 would be at - -http://download.eclipse.org/jetty/7.0.0.RC5/apidocs/ - diff --git a/jetty-distribution/src/main/resources/javadoc/contents.html b/jetty-distribution/src/main/resources/javadoc/contents.html deleted file mode 100644 index 7cca04ae17..0000000000 --- a/jetty-distribution/src/main/resources/javadoc/contents.html +++ /dev/null @@ -1,4 +0,0 @@ - -<h1>Javadoc not generated</h1> -See the online version at <a -href="http://download.eclipse.org/jetty/">http://download.eclipse.org/jetty/</a>. diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/RunningStatsTest.java b/jetty-distribution/src/main/resources/lib/ext/.donotdelete index e69de29bb2..e69de29bb2 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/RunningStatsTest.java +++ b/jetty-distribution/src/main/resources/lib/ext/.donotdelete diff --git a/jetty-distribution/src/main/resources/logs/.donotdelete b/jetty-distribution/src/main/resources/logs/.donotdelete new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/jetty-distribution/src/main/resources/logs/.donotdelete diff --git a/jetty-distribution/src/main/resources/start.ini b/jetty-distribution/src/main/resources/start.ini index 5ae24f5d0b..a20537b258 100644 --- a/jetty-distribution/src/main/resources/start.ini +++ b/jetty-distribution/src/main/resources/start.ini @@ -1,10 +1,13 @@ #=========================================================== # Jetty start.jar arguments -#----------------------------------------------------------- # Each line of this file is prepended to the command line # arguments # of a call to: # java -jar start.jar [arg...] -# +#=========================================================== + + + +#=========================================================== # If the arguements in this file include JVM arguments # (eg -Xmx512m) or JVM System properties (eg com.sun.???), # then these will not take affect unless the --exec @@ -12,20 +15,46 @@ # is executed like: # eval $(java -jar start.jar --dry-run) # -#=========================================================== +# Below are some recommended options for Sun's JRE +#----------------------------------------------------------- +# --exec +# -Dcom.sun.management.jmxremote +# -Xmx2000m +# -Xmn512m +# -verbose:gc +# -XX:+PrintGCDateStamps +# -XX:+PrintGCTimeStamps +# -XX:+PrintGCDetails +# -XX:+PrintTenuringDistribution +# -XX:+PrintCommandLineFlags +# -XX:+DisableExplicitGC +# -XX:+UseConcMarkSweepGC +# -XX:ParallelCMSThreads=2 +# -XX:+CMSClassUnloadingEnabled +# -XX:+UseCMSCompactAtFullCollection +# -XX:CMSInitiatingOccupancyFraction=80 +#----------------------------------------------------------- + +#=========================================================== +# Start classpath OPTIONS. +# These control what classes are on the classpath +# for a full listing do +# java -jar start.jar --list-options +#----------------------------------------------------------- OPTIONS=Server,jmx,resources,websocket,ext +#----------------------------------------------------------- + #=========================================================== -# The following is an example of the ini args to run the -# server with a heap size, JMX remote enabled, JMX mbeans -# and ssl +# Configuration files. +# For a full list of available configuration files do +# java -jar start.jar --help #----------------------------------------------------------- -# --exec -# -Xmx512m -# -Dcom.sun.management.jmxremote -# OPTIONS=Server,jmx,resources -# etc/jetty-jmx.xml -# etc/jetty.xml +#etc/jetty-jmx.xml +etc/jetty.xml # etc/jetty-ssl.xml +# etc/jetty-requestlog.xml +etc/jetty-deploy.xml +etc/jetty-testrealm.xml #=========================================================== diff --git a/jetty-distribution/src/main/resources/webapps/.donotdelete b/jetty-distribution/src/main/resources/webapps/.donotdelete new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/jetty-distribution/src/main/resources/webapps/.donotdelete diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index b3cf361820..a40111ad68 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -20,6 +20,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> @@ -35,6 +36,11 @@ <goals> <goal>manifest</goal> </goals> + <configuration> + <instructions> + <Import-Package>javax.net.*,*</Import-Package> + </instructions> + </configuration> </execution> </executions> </plugin> @@ -56,16 +62,17 @@ </execution> </executions> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.http.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java index 560543218d..db0db7902f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java @@ -62,8 +62,7 @@ public abstract class AbstractGenerator implements Generator protected boolean _last = false; protected boolean _head = false; protected boolean _noContent = false; - protected boolean _close = false; - + protected Boolean _persistent = null; protected Buffer _header; // Buffer for HTTP header (and maybe small _content) protected Buffer _buffer; // Buffer for copy of passed _content @@ -79,8 +78,7 @@ public abstract class AbstractGenerator implements Generator * Constructor. * * @param buffers buffer pool - * @param headerBufferSize Size of the buffer to allocate for HTTP header - * @param contentBufferSize Size of the buffer to allocate for HTTP content + * @param io the end point */ public AbstractGenerator(Buffers buffers, EndPoint io) { @@ -89,6 +87,12 @@ public abstract class AbstractGenerator implements Generator } /* ------------------------------------------------------------------------------- */ + public abstract boolean isRequest(); + + /* ------------------------------------------------------------------------------- */ + public abstract boolean isResponse(); + + /* ------------------------------------------------------------------------------- */ public boolean isOpen() { return _endp.isOpen(); @@ -104,7 +108,7 @@ public abstract class AbstractGenerator implements Generator _last = false; _head = false; _noContent=false; - _close = false; + _persistent = null; _contentWritten = 0; _contentLength = HttpTokens.UNKNOWN_CONTENT; _date = null; @@ -134,7 +138,7 @@ public abstract class AbstractGenerator implements Generator throw new IllegalStateException("Flushed"); _last = false; - _close = false; + _persistent=null; _contentWritten = 0; _contentLength = HttpTokens.UNKNOWN_CONTENT; _content=null; @@ -252,13 +256,15 @@ public abstract class AbstractGenerator implements Generator */ public boolean isPersistent() { - return !_close; + return _persistent!=null + ?_persistent.booleanValue() + :(isRequest()?true:_version>HttpVersions.HTTP_1_0_ORDINAL); } /* ------------------------------------------------------------ */ public void setPersistent(boolean persistent) { - _close=!persistent; + _persistent=persistent; } /* ------------------------------------------------------------ */ @@ -402,7 +408,7 @@ public abstract class AbstractGenerator implements Generator { if (Log.isDebugEnabled()) Log.debug("ContentLength written=="+_contentWritten+" != contentLength=="+_contentLength); - _close = true; + _persistent = false; } } @@ -428,23 +434,30 @@ public abstract class AbstractGenerator implements Generator /* ------------------------------------------------------------ */ /** * Utility method to send an error response. If the builder is not committed, this call is - * equivalent to a setResponse, addcontent and complete call. + * equivalent to a setResponse, addContent and complete call. * - * @param code - * @param reason - * @param content - * @param close - * @throws IOException + * @param code The error code + * @param reason The error reason + * @param content Contents of the error page + * @param close True if the connection should be closed + * @throws IOException if there is a problem flushing the response */ public void sendError(int code, String reason, String content, boolean close) throws IOException { + if (close) + _persistent=false; if (!isCommitted()) { setResponse(code, reason); - _close = close; - completeHeader(null, false); if (content != null) + { + completeHeader(null, false); addContent(new View(new ByteArrayBuffer(content)), Generator.LAST); + } + else + { + completeHeader(null, true); + } complete(); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpBuffers.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpBuffers.java index 95bcdf84ab..351ef15938 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpBuffers.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpBuffers.java @@ -115,7 +115,7 @@ public abstract class HttpBuffers extends AbstractLifeCycle public Buffers getResponseBuffers() { - return _requestBuffers; + return _responseBuffers; } /** diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index e6813d6f5a..e98db730ac 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -285,17 +285,15 @@ public class HttpFields }; - - - - public final static String __01Jan1970=formatCookieDate(0); public final static Buffer __01Jan1970_BUFFER=new ByteArrayBuffer(__01Jan1970); /* -------------------------------------------------------------- */ - protected final ArrayList<Field> _fields = new ArrayList<Field>(20); - protected final HashMap<Buffer,Field> _bufferMap = new HashMap<Buffer,Field>(32); - protected int _revision; + private final ArrayList<Field> _fields = new ArrayList<Field>(20); + private final HashMap<Buffer,Field> _bufferMap = new HashMap<Buffer,Field>(32); + private final int _maxCookieVersion; + private int _revision; + @@ -305,8 +303,18 @@ public class HttpFields */ public HttpFields() { + _maxCookieVersion=1; } + /* ------------------------------------------------------------ */ + /** + * Constructor. + */ + public HttpFields(int maxCookieVersion) + { + _maxCookieVersion=maxCookieVersion; + } + /* -------------------------------------------------------------- */ /** * Get Collection of header names. @@ -981,7 +989,6 @@ public class HttpFields * Format a set cookie value * * @param cookie The cookie. - * @param cookie2 If true, use the alternate cookie 2 header */ public void addSetCookie(HttpCookie cookie) { @@ -996,12 +1003,19 @@ public class HttpFields cookie.isHttpOnly(), cookie.getVersion()); } - - /* ------------------------------------------------------------ */ + /** * Format a set cookie value - * @param cookie The cookie. - * @param cookie2 If true, use the alternate cookie 2 header + * + * @param name the name + * @param value the value + * @param domain the domain + * @param path the path + * @param maxAge the maximum age + * @param comment the comment (only present on versions > 0) + * @param isSecure true if secure cookie + * @param isHttpOnly true if for http only + * @param version version of cookie logic to use (0 == default behavior) */ public void addSetCookie( final String name, @@ -1012,19 +1026,29 @@ public class HttpFields final String comment, final boolean isSecure, final boolean isHttpOnly, - final int version) + int version) { + String delim=_maxCookieVersion==0?"":"\"\\\n\r\t\f\b%+ ;="; + // Check arguments if (name == null || name.length() == 0) throw new IllegalArgumentException("Bad cookie name"); // Format value and params StringBuilder buf = new StringBuilder(128); String name_value_params; - QuotedStringTokenizer.quoteIfNeeded(buf, name); + boolean quoted = QuotedStringTokenizer.quoteIfNeeded(buf, name, delim); buf.append('='); + String start=buf.toString(); if (value != null && value.length() > 0) - QuotedStringTokenizer.quoteIfNeeded(buf, value); + quoted|=QuotedStringTokenizer.quoteIfNeeded(buf, value, delim); + + // upgrade to version 1 cookies if quoted. + if (quoted&&version==0 && _maxCookieVersion>=1) + version=1; + if (version>_maxCookieVersion) + version=_maxCookieVersion; + if (version > 0) { buf.append(";Version="); @@ -1032,7 +1056,7 @@ public class HttpFields if (comment != null && comment.length() > 0) { buf.append(";Comment="); - QuotedStringTokenizer.quoteIfNeeded(buf, comment); + QuotedStringTokenizer.quoteIfNeeded(buf, comment, delim); } } if (path != null && path.length() > 0) @@ -1041,25 +1065,24 @@ public class HttpFields if (path.trim().startsWith("\"")) buf.append(path); else - QuotedStringTokenizer.quoteIfNeeded(buf,path); + QuotedStringTokenizer.quoteIfNeeded(buf,path,delim); } if (domain != null && domain.length() > 0) { buf.append(";Domain="); - QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase()); + QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(),delim); } if (maxAge >= 0) { - if (version == 0) - { - buf.append(";Expires="); - if (maxAge == 0) - buf.append(__01Jan1970); - else - formatCookieDate(buf, System.currentTimeMillis() + 1000L * maxAge); - } - else + // Always add the expires param as some browsers still don't handle max-age + buf.append(";Expires="); + if (maxAge == 0) + buf.append(__01Jan1970); + else + formatCookieDate(buf, System.currentTimeMillis() + 1000L * maxAge); + + if (version >0) { buf.append(";Max-Age="); buf.append(maxAge); @@ -1077,8 +1100,28 @@ public class HttpFields // TODO - straight to Buffer? name_value_params = buf.toString(); - put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER); + + // look for existing cookie + Field field = getField(HttpHeaders.SET_COOKIE_BUFFER); + if (field != null) + { + final int revision=_revision; + + while (field!=null) + { + if (field._revision!=revision || field._value!=null && field._value.toString().startsWith(start)) + { + field.reset(new ByteArrayBuffer(name_value_params),-1,revision); + return; + } + field=field._next; + } + } + add(HttpHeaders.SET_COOKIE_BUFFER, new ByteArrayBuffer(name_value_params)); + + // Expire responses with set-cookie headers so they do not get cached. + put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER); } /* -------------------------------------------------------------- */ @@ -1281,7 +1324,7 @@ public class HttpFields /** * List values in quality order. * - * @param enum Enumeration of values with quality parameters + * @param e Enumeration of values with quality parameters * @return values in quality order. */ public static List qualityList(Enumeration e) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index d70e689687..6e6149d7b8 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; @@ -17,21 +17,21 @@ import java.io.IOException; import java.io.InterruptedIOException; import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.io.BufferUtil; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ /** * HttpGenerator. Builds HTTP Messages. - * - * - * + * + * + * */ public class HttpGenerator extends AbstractGenerator { @@ -46,7 +46,7 @@ public class HttpGenerator extends AbstractGenerator static { int versionLength=HttpVersions.HTTP_1_1_BUFFER.length(); - + for (int i=0;i<__status.length;i++) { HttpStatus.Code code = HttpStatus.getCode(i); @@ -64,7 +64,7 @@ public class HttpGenerator extends AbstractGenerator bytes[versionLength+5+j]=(byte)reason.charAt(j); bytes[versionLength+5+reason.length()]=HttpTokens.CARRIAGE_RETURN; bytes[versionLength+6+reason.length()]=HttpTokens.LINE_FEED; - + __status[i] = new Status(); __status[i]._reason=new ByteArrayBuffer(bytes,versionLength+5,bytes.length-versionLength-7,Buffer.IMMUTABLE); __status[i]._schemeCode=new ByteArrayBuffer(bytes,0,versionLength+5,Buffer.IMMUTABLE); @@ -80,8 +80,8 @@ public class HttpGenerator extends AbstractGenerator return status._reason; return null; } - - + + // common _content private static final byte[] LAST_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'}; @@ -95,7 +95,7 @@ public class HttpGenerator extends AbstractGenerator // other statics private static final int CHUNK_SPACE = 12; - + public static void setServerVersion(String version) { SERVER=StringUtil.getBytes("Server: Jetty("+version+")\015\012"); @@ -107,14 +107,13 @@ public class HttpGenerator extends AbstractGenerator private boolean _needEOC = false; private boolean _bufferChunked = false; - + /* ------------------------------------------------------------------------------- */ /** * Constructor. - * + * * @param buffers buffer pool - * @param headerBufferSize Size of the buffer to allocate for HTTP header - * @param contentBufferSize Size of the buffer to allocate for HTTP content + * @param io the end point to use */ public HttpGenerator(Buffers buffers, EndPoint io) { @@ -140,7 +139,7 @@ public class HttpGenerator extends AbstractGenerator /* ------------------------------------------------------------ */ /** * Add content. - * + * * @param content * @param last * @throws IllegalArgumentException if <code>content</code> is {@link Buffer#isImmutable immutable}. @@ -153,7 +152,7 @@ public class HttpGenerator extends AbstractGenerator if (_noContent) throw new IllegalStateException("NO CONTENT"); - if (_last || _state==STATE_END) + if (_last || _state==STATE_END) { Log.debug("Ignoring extra content {}",content); content.clear(); @@ -167,7 +166,7 @@ public class HttpGenerator extends AbstractGenerator if (!_endp.isOpen()) throw new EofException(); flushBuffer(); - if (_content != null && _content.length()>0) + if (_content != null && _content.length()>0) { Buffer nc=_buffers.getBuffer(_content.length()+content.length()); nc.put(_content); @@ -194,13 +193,13 @@ public class HttpGenerator extends AbstractGenerator else if (!_bufferChunked) { // Yes - so we better check we have a buffer - if (_buffer == null) + if (_buffer == null) _buffer = _buffers.getBuffer(); // Copy _content to buffer; int len=_buffer.put(_content); _content.skip(len); - if (_content.length() == 0) + if (_content.length() == 0) _content = null; } } @@ -208,7 +207,7 @@ public class HttpGenerator extends AbstractGenerator /* ------------------------------------------------------------ */ /** * send complete response. - * + * * @param response */ public void sendResponse(Buffer response) throws IOException @@ -224,13 +223,13 @@ public class HttpGenerator extends AbstractGenerator // TODO this is not exactly right, but should do. _contentLength =_contentWritten = response.length(); - + } - + /* ------------------------------------------------------------ */ /** * Add content. - * + * * @param b byte * @return true if the buffers are full * @throws IOException @@ -239,8 +238,8 @@ public class HttpGenerator extends AbstractGenerator { if (_noContent) throw new IllegalStateException("NO CONTENT"); - - if (_last || _state==STATE_END) + + if (_last || _state==STATE_END) { Log.debug("Ignoring extra content {}",Byte.valueOf(b)); return false; @@ -250,23 +249,23 @@ public class HttpGenerator extends AbstractGenerator if (_content != null && _content.length()>0 || _bufferChunked) { flushBuffer(); - if (_content != null && _content.length()>0 || _bufferChunked) + if (_content != null && _content.length()>0 || _bufferChunked) throw new IllegalStateException("FULL"); } _contentWritten++; - + // Handle the _content if (_head) return false; - + // we better check we have a buffer - if (_buffer == null) + if (_buffer == null) _buffer = _buffers.getBuffer(); - + // Copy _content to buffer; _buffer.put(b); - + return _buffer.space()<=(_contentLength == HttpTokens.CHUNKED_CONTENT?CHUNK_SPACE:0); } @@ -281,8 +280,8 @@ public class HttpGenerator extends AbstractGenerator { if (_noContent) return -1; - - if (_last || _state==STATE_END) + + if (_last || _state==STATE_END) return -1; // Handle any unfinished business? @@ -290,23 +289,23 @@ public class HttpGenerator extends AbstractGenerator if (content != null && content.length()>0 || _bufferChunked) { flushBuffer(); - if (content != null && content.length()>0 || _bufferChunked) + if (content != null && content.length()>0 || _bufferChunked) throw new IllegalStateException("FULL"); } // we better check we have a buffer - if (_buffer == null) + if (_buffer == null) _buffer = _buffers.getBuffer(); _contentWritten-=_buffer.length(); - + // Handle the _content if (_head) return Integer.MAX_VALUE; - + return _buffer.space()-(_contentLength == HttpTokens.CHUNKED_CONTENT?CHUNK_SPACE:0); } - + /* ------------------------------------------------------------ */ @Override public boolean isBufferFull() @@ -318,22 +317,22 @@ public class HttpGenerator extends AbstractGenerator /* ------------------------------------------------------------ */ public void send1xx(int code) throws IOException { - if (_state != STATE_HEADER) + if (_state != STATE_HEADER) return; - + if (code<100||code>199) throw new IllegalArgumentException("!1xx"); Status status=__status[code]; if (status==null) throw new IllegalArgumentException(code+"?"); - + // get a header buffer - if (_header == null) + if (_header == null) _header = _buffers.getHeader(); - + _header.put(status._responseLine); _header.put(HttpTokens.CRLF); - + try { // nasty semi busy flush! @@ -351,34 +350,47 @@ public class HttpGenerator extends AbstractGenerator Log.debug(e); throw new InterruptedIOException(e.toString()); } - } - + + /* ------------------------------------------------------------ */ + @Override + public boolean isRequest() + { + return _method!=null; + } + + /* ------------------------------------------------------------ */ + @Override + public boolean isResponse() + { + return _method==null; + } + /* ------------------------------------------------------------ */ @Override public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException { - if (_state != STATE_HEADER) + if (_state != STATE_HEADER) return; - - // handle a reset - if (_method==null && _status==0) + + // handle a reset + if (isResponse() && _status==0) throw new EofException(); - if (_last && !allContentAdded) + if (_last && !allContentAdded) throw new IllegalStateException("last?"); _last = _last | allContentAdded; // get a header buffer - if (_header == null) + if (_header == null) _header = _buffers.getHeader(); - + boolean has_server = false; - - if (_method!=null) + + if (isRequest()) { - _close = false; - // Request + _persistent=true; + if (_version == HttpVersions.HTTP_0_9_ORDINAL) { _contentLength = HttpTokens.NO_CONTENT; @@ -402,22 +414,23 @@ public class HttpGenerator extends AbstractGenerator } else { - // Response + // Responses + if (_version == HttpVersions.HTTP_0_9_ORDINAL) { - _close = true; + _persistent = false; _contentLength = HttpTokens.EOF_CONTENT; _state = STATE_CONTENT; return; } else { - if (_version == HttpVersions.HTTP_1_0_ORDINAL) - _close = true; + if (_persistent==null) + _persistent= (_version > HttpVersions.HTTP_1_0_ORDINAL); // add response line Status status = _status<__status.length?__status[_status]:null; - + if (status==null) { _header.put(HttpVersions.HTTP_1_1_BUFFER); @@ -472,7 +485,7 @@ public class HttpGenerator extends AbstractGenerator } } } - + // Add headers if (_status>=200 && _date!=null) { @@ -522,20 +535,20 @@ public class HttpGenerator extends AbstractGenerator break; case HttpHeaders.TRANSFER_ENCODING_ORDINAL: - if (_version == HttpVersions.HTTP_1_1_ORDINAL) + if (_version == HttpVersions.HTTP_1_1_ORDINAL) transfer_encoding = field; // Do NOT add yet! break; case HttpHeaders.CONNECTION_ORDINAL: - if (_method!=null) + if (isRequest()) field.put(_header); - + int connection_value = field.getValueOrdinal(); switch (connection_value) { case -1: - { + { String[] values = field.getValue().split(","); for (int i=0;values!=null && i<values.length;i++) { @@ -547,10 +560,10 @@ public class HttpGenerator extends AbstractGenerator { case HttpHeaderValues.CLOSE_ORDINAL: close=true; - if (_method==null) - _close=true; + if (isResponse()) + _persistent=false; keep_alive=false; - if (_close && _method==null && _contentLength == HttpTokens.UNKNOWN_CONTENT) + if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT) _contentLength = HttpTokens.EOF_CONTENT; break; @@ -558,11 +571,11 @@ public class HttpGenerator extends AbstractGenerator if (_version == HttpVersions.HTTP_1_0_ORDINAL) { keep_alive = true; - if (_method==null) - _close = false; + if (isResponse()) + _persistent = true; } break; - + default: if (connection==null) connection=new StringBuilder(); @@ -580,13 +593,13 @@ public class HttpGenerator extends AbstractGenerator connection.append(values[i]); } } - + break; } case HttpHeaderValues.UPGRADE_ORDINAL: { // special case for websocket connection ordering - if (_method==null) + if (isResponse()) { field.put(_header); continue; @@ -595,9 +608,9 @@ public class HttpGenerator extends AbstractGenerator case HttpHeaderValues.CLOSE_ORDINAL: { close=true; - if (_method==null) - _close=true; - if (_close && _method==null && _contentLength == HttpTokens.UNKNOWN_CONTENT) + if (isResponse()) + _persistent=false; + if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT) _contentLength = HttpTokens.EOF_CONTENT; break; } @@ -606,8 +619,8 @@ public class HttpGenerator extends AbstractGenerator if (_version == HttpVersions.HTTP_1_0_ORDINAL) { keep_alive = true; - if (_method==null) - _close = false; + if (isResponse()) + _persistent=true; } break; } @@ -625,7 +638,7 @@ public class HttpGenerator extends AbstractGenerator break; case HttpHeaders.SERVER_ORDINAL: - if (getSendServerVersion()) + if (getSendServerVersion()) { has_server=true; field.put(_header); @@ -655,13 +668,13 @@ public class HttpGenerator extends AbstractGenerator // written yet? // Response known not to have a body - if (_contentWritten == 0 && _method==null && (_status < 200 || _status == 204 || _status == 304)) + if (_contentWritten == 0 && isResponse() && (_status < 200 || _status == 204 || _status == 304)) _contentLength = HttpTokens.NO_CONTENT; else if (_last) { // we have seen all the _content there is _contentLength = _contentWritten; - if (content_length == null && (_method==null || _contentLength>0 || content_type )) + if (content_length == null && (isResponse() || _contentLength>0 || content_type )) { // known length but not actually set. _header.put(HttpHeaders.CONTENT_LENGTH_BUFFER); @@ -674,8 +687,8 @@ public class HttpGenerator extends AbstractGenerator else { // No idea, so we must assume that a body is coming - _contentLength = (_close || _version < HttpVersions.HTTP_1_1_ORDINAL ) ? HttpTokens.EOF_CONTENT : HttpTokens.CHUNKED_CONTENT; - if (_method!=null && _contentLength==HttpTokens.EOF_CONTENT) + _contentLength = (!_persistent || _version < HttpVersions.HTTP_1_1_ORDINAL ) ? HttpTokens.EOF_CONTENT : HttpTokens.CHUNKED_CONTENT; + if (isRequest() && _contentLength==HttpTokens.EOF_CONTENT) { _contentLength=HttpTokens.NO_CONTENT; _noContent=true; @@ -684,12 +697,12 @@ public class HttpGenerator extends AbstractGenerator break; case HttpTokens.NO_CONTENT: - if (content_length == null && _method==null && _status >= 200 && _status != 204 && _status != 304) + if (content_length == null && isResponse() && _status >= 200 && _status != 204 && _status != 304) _header.put(CONTENT_LENGTH_0); break; case HttpTokens.EOF_CONTENT: - _close = _method==null; + _persistent = isRequest(); break; case HttpTokens.CHUNKED_CONTENT: @@ -720,12 +733,12 @@ public class HttpGenerator extends AbstractGenerator if (_contentLength==HttpTokens.EOF_CONTENT) { keep_alive=false; - _close=true; + _persistent=false; } - - if (_method==null) + + if (isResponse()) { - if (_close && (close || _version > HttpVersions.HTTP_1_0_ORDINAL)) + if (!_persistent && (close || _version > HttpVersions.HTTP_1_0_ORDINAL)) { _header.put(CONNECTION_CLOSE); if (connection!=null) @@ -754,7 +767,7 @@ public class HttpGenerator extends AbstractGenerator _header.put(CRLF); } } - + if (!has_server && _status>199 && getSendServerVersion()) _header.put(SERVER); @@ -764,30 +777,30 @@ public class HttpGenerator extends AbstractGenerator _state = STATE_CONTENT; } - + /* ------------------------------------------------------------ */ /** * Complete the message. - * + * * @throws IOException */ @Override public void complete() throws IOException { - if (_state == STATE_END) + if (_state == STATE_END) return; - + super.complete(); - + if (_state < STATE_FLUSHING) { _state = STATE_FLUSHING; - if (_contentLength == HttpTokens.CHUNKED_CONTENT) + if (_contentLength == HttpTokens.CHUNKED_CONTENT) _needEOC = true; } - + flushBuffer(); } @@ -796,17 +809,17 @@ public class HttpGenerator extends AbstractGenerator public long flushBuffer() throws IOException { try - { - if (_state == STATE_HEADER) + { + if (_state == STATE_HEADER) throw new IllegalStateException("State==HEADER"); - + prepareBuffers(); - + if (_endp == null) { - if (_needCRLF && _buffer!=null) + if (_needCRLF && _buffer!=null) _buffer.put(HttpTokens.CRLF); - if (_needEOC && _buffer!=null && !_head) + if (_needEOC && _buffer!=null && !_head) _buffer.put(LAST_CHUNK); _needCRLF=false; _needEOC=false; @@ -841,7 +854,7 @@ public class HttpGenerator extends AbstractGenerator case 0: { // Nothing more we can write now. - if (_header != null) + if (_header != null) _header.clear(); _bypass = false; @@ -872,8 +885,8 @@ public class HttpGenerator extends AbstractGenerator { if (_state == STATE_FLUSHING) _state = STATE_END; - if (_state==STATE_END && _close && _status!=100) - _endp.close(); + if (_state==STATE_END && _persistent != null && !_persistent && _status!=100 && _method==null) + _endp.shutdownOutput(); } else // Try to prepare more to write. @@ -904,7 +917,7 @@ public class HttpGenerator extends AbstractGenerator { int len = _buffer.put(_content); _content.skip(len); - if (_content.length() == 0) + if (_content.length() == 0) _content = null; } @@ -995,7 +1008,7 @@ public class HttpGenerator extends AbstractGenerator } } - if (_content != null && _content.length() == 0) + if (_content != null && _content.length() == 0) _content = null; } @@ -1013,7 +1026,7 @@ public class HttpGenerator extends AbstractGenerator (_buffer==null||_buffer.length()==0) && (_content==null||_content.length()==0); } - + @Override public String toString() { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 3d660700f5..b3ccf79002 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -26,18 +26,6 @@ import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; -/* ------------------------------------------------------------------------------- */ -/** - * - */ - -/* ------------------------------------------------------------ */ -/** - */ - -/* ------------------------------------------------------------ */ -/** - */ public class HttpParser implements Parser { // States @@ -110,8 +98,9 @@ public class HttpParser implements Parser /* ------------------------------------------------------------------------------- */ /** * Constructor. - * @param headerBufferSize size in bytes of header buffer - * @param contentBufferSize size in bytes of content buffer + * @param buffers the buffers to use + * @param endp the endpoint + * @param handler the even handler */ public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler) { @@ -237,7 +226,7 @@ public class HttpParser implements Parser /* ------------------------------------------------------------------------------- */ /** * Parse until next Event. - * @returns number of bytes filled from endpoint or -1 if fill never called. + * @return number of bytes filled from endpoint or -1 if fill never called. */ public long parseNext() throws IOException { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java index 84cafc46b4..e0dcba4b5f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java @@ -4,23 +4,21 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; -import org.eclipse.jetty.util.TypeUtil; - /** * <p> * HttpStatusCode enum class, for status codes based on various HTTP RFCs. (see * table below) * </p> - * + * * <table border="1" cellpadding="5"> * <tr> * <th>Enum</th> @@ -33,14 +31,14 @@ import org.eclipse.jetty.util.TypeUtil; * <th> * <a href="http://tools.ietf.org/html/rfc2518">RFC 2518 - WEBDAV</a></th> * </tr> - * + * * <tr> * <td><strong><code>Informational - 1xx</code></strong></td> * <td colspan="5">{@link #isInformational(int)}</td> * </tr> - * + * * <tr> - * <td>{@link #CONTINUE}</td> + * <td>{@link #CONTINUE_100}</td> * <td>100</td> * <td>Continue</td> * <td> </td> @@ -49,7 +47,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #SWITCHING_PROTOCOLS}</td> + * <td>{@link #SWITCHING_PROTOCOLS_101}</td> * <td>101</td> * <td>Switching Protocols</td> * <td> </td> @@ -58,7 +56,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #PROCESSING}</td> + * <td>{@link #PROCESSING_102}</td> * <td>102</td> * <td>Processing</td> * <td> </td> @@ -66,14 +64,14 @@ import org.eclipse.jetty.util.TypeUtil; * <td> * <a href="http://tools.ietf.org/html/rfc2518#section-10.1">Sec. 10.1</a></td> * </tr> - * + * * <tr> * <td><strong><code>Success - 2xx</code></strong></td> * <td colspan="5">{@link #isSuccess(int)}</td> * </tr> - * + * * <tr> - * <td>{@link #OK}</td> + * <td>{@link #OK_200}</td> * <td>200</td> * <td>OK</td> * <td> @@ -83,7 +81,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #CREATED}</td> + * <td>{@link #CREATED_201}</td> * <td>201</td> * <td>Created</td> * <td> @@ -93,7 +91,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #ACCEPTED}</td> + * <td>{@link #ACCEPTED_202}</td> * <td>202</td> * <td>Accepted</td> * <td> @@ -103,7 +101,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #NON_AUTHORITATIVE_INFORMATION}</td> + * <td>{@link #NON_AUTHORITATIVE_INFORMATION_203}</td> * <td>203</td> * <td>Non Authoritative Information</td> * <td> </td> @@ -112,7 +110,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #NO_CONTENT}</td> + * <td>{@link #NO_CONTENT_204}</td> * <td>204</td> * <td>No Content</td> * <td> @@ -122,7 +120,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #RESET_CONTENT}</td> + * <td>{@link #RESET_CONTENT_205}</td> * <td>205</td> * <td>Reset Content</td> * <td> </td> @@ -131,7 +129,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #PARTIAL_CONTENT}</td> + * <td>{@link #PARTIAL_CONTENT_206}</td> * <td>206</td> * <td>Partial Content</td> * <td> </td> @@ -140,7 +138,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #MULTI_STATUS}</td> + * <td>{@link #MULTI_STATUS_207}</td> * <td>207</td> * <td>Multi-Status</td> * <td> </td> @@ -159,14 +157,14 @@ import org.eclipse.jetty.util.TypeUtil; * >draft/01</a></td> * <td> </td> * </tr> - * + * * <tr> * <td><strong><code>Redirection - 3xx</code></strong></td> * <td colspan="5">{@link #isRedirection(int)}</td> * </tr> - * + * * <tr> - * <td>{@link #MULTIPLE_CHOICES}</td> + * <td>{@link #MULTIPLE_CHOICES_300}</td> * <td>300</td> * <td>Multiple Choices</td> * <td> @@ -176,7 +174,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #MOVED_PERMANENTLY}</td> + * <td>{@link #MOVED_PERMANENTLY_301}</td> * <td>301</td> * <td>Moved Permanently</td> * <td> @@ -186,7 +184,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #MOVED_TEMPORARILY}</td> + * <td>{@link #MOVED_TEMPORARILY_302}</td> * <td>302</td> * <td>Moved Temporarily</td> * <td> @@ -195,7 +193,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #FOUND}</td> + * <td>{@link #FOUND_302}</td> * <td>302</td> * <td>Found</td> * <td>(was "<code>302 Moved Temporarily</code>")</td> @@ -204,7 +202,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #SEE_OTHER}</td> + * <td>{@link #SEE_OTHER_303}</td> * <td>303</td> * <td>See Other</td> * <td> </td> @@ -213,7 +211,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #NOT_MODIFIED}</td> + * <td>{@link #NOT_MODIFIED_304}</td> * <td>304</td> * <td>Not Modified</td> * <td> @@ -223,7 +221,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #USE_PROXY}</td> + * <td>{@link #USE_PROXY_305}</td> * <td>305</td> * <td>Use Proxy</td> * <td> </td> @@ -241,7 +239,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #TEMPORARY_REDIRECT}</td> + * <td>{@link #TEMPORARY_REDIRECT_307}</td> * <td>307</td> * <td>Temporary Redirect</td> * <td> </td> @@ -249,14 +247,14 @@ import org.eclipse.jetty.util.TypeUtil; * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.8">Sec. 10.3.8</a></td> * <td> </td> * </tr> - * + * * <tr> * <td><strong><code>Client Error - 4xx</code></strong></td> * <td colspan="5">{@link #isClientError(int)}</td> * </tr> - * + * * <tr> - * <td>{@link #BAD_REQUEST}</td> + * <td>{@link #BAD_REQUEST_400}</td> * <td>400</td> * <td>Bad Request</td> * <td> @@ -266,7 +264,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #UNAUTHORIZED}</td> + * <td>{@link #UNAUTHORIZED_401}</td> * <td>401</td> * <td>Unauthorized</td> * <td> @@ -276,7 +274,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #PAYMENT_REQUIRED}</td> + * <td>{@link #PAYMENT_REQUIRED_402}</td> * <td>402</td> * <td>Payment Required</td> * <td> @@ -286,7 +284,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #FORBIDDEN}</td> + * <td>{@link #FORBIDDEN_403}</td> * <td>403</td> * <td>Forbidden</td> * <td> @@ -296,7 +294,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #NOT_FOUND}</td> + * <td>{@link #NOT_FOUND_404}</td> * <td>404</td> * <td>Not Found</td> * <td> @@ -306,7 +304,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #METHOD_NOT_ALLOWED}</td> + * <td>{@link #METHOD_NOT_ALLOWED_405}</td> * <td>405</td> * <td>Method Not Allowed</td> * <td> </td> @@ -315,7 +313,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #NOT_ACCEPTABLE}</td> + * <td>{@link #NOT_ACCEPTABLE_406}</td> * <td>406</td> * <td>Not Acceptable</td> * <td> </td> @@ -324,7 +322,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #PROXY_AUTHENTICATION_REQUIRED}</td> + * <td>{@link #PROXY_AUTHENTICATION_REQUIRED_407}</td> * <td>407</td> * <td>Proxy Authentication Required</td> * <td> </td> @@ -333,7 +331,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #REQUEST_TIMEOUT}</td> + * <td>{@link #REQUEST_TIMEOUT_408}</td> * <td>408</td> * <td>Request Timeout</td> * <td> </td> @@ -342,7 +340,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #CONFLICT}</td> + * <td>{@link #CONFLICT_409}</td> * <td>409</td> * <td>Conflict</td> * <td> </td> @@ -352,7 +350,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #GONE}</td> + * <td>{@link #GONE_410}</td> * <td>410</td> * <td>Gone</td> * <td> </td> @@ -362,7 +360,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #LENGTH_REQUIRED}</td> + * <td>{@link #LENGTH_REQUIRED_411}</td> * <td>411</td> * <td>Length Required</td> * <td> </td> @@ -372,7 +370,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #PRECONDITION_FAILED}</td> + * <td>{@link #PRECONDITION_FAILED_412}</td> * <td>412</td> * <td>Precondition Failed</td> * <td> </td> @@ -382,7 +380,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #REQUEST_ENTITY_TOO_LARGE}</td> + * <td>{@link #REQUEST_ENTITY_TOO_LARGE_413}</td> * <td>413</td> * <td>Request Entity Too Large</td> * <td> </td> @@ -392,7 +390,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #REQUEST_URI_TOO_LONG}</td> + * <td>{@link #REQUEST_URI_TOO_LONG_414}</td> * <td>414</td> * <td>Request-URI Too Long</td> * <td> </td> @@ -402,7 +400,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #UNSUPPORTED_MEDIA_TYPE}</td> + * <td>{@link #UNSUPPORTED_MEDIA_TYPE_415}</td> * <td>415</td> * <td>Unsupported Media Type</td> * <td> </td> @@ -412,7 +410,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #REQUESTED_RANGE_NOT_SATISFIABLE}</td> + * <td>{@link #REQUESTED_RANGE_NOT_SATISFIABLE_416}</td> * <td>416</td> * <td>Requested Range Not Satisfiable</td> * <td> </td> @@ -422,7 +420,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #EXPECTATION_FAILED}</td> + * <td>{@link #EXPECTATION_FAILED_417}</td> * <td>417</td> * <td>Expectation Failed</td> * <td> </td> @@ -495,7 +493,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #UNPROCESSABLE_ENTITY}</td> + * <td>{@link #UNPROCESSABLE_ENTITY_422}</td> * <td>422</td> * <td>Unprocessable Entity</td> * <td> </td> @@ -504,7 +502,7 @@ import org.eclipse.jetty.util.TypeUtil; * <a href="http://tools.ietf.org/html/rfc2518#section-10.3">Sec. 10.3</a></td> * </tr> * <tr> - * <td>{@link #LOCKED}</td> + * <td>{@link #LOCKED_423}</td> * <td>423</td> * <td>Locked</td> * <td> </td> @@ -513,7 +511,7 @@ import org.eclipse.jetty.util.TypeUtil; * <a href="http://tools.ietf.org/html/rfc2518#section-10.4">Sec. 10.4</a></td> * </tr> * <tr> - * <td>{@link #FAILED_DEPENDENCY}</td> + * <td>{@link #FAILED_DEPENDENCY_424}</td> * <td>424</td> * <td>Failed Dependency</td> * <td> </td> @@ -521,14 +519,14 @@ import org.eclipse.jetty.util.TypeUtil; * <td> * <a href="http://tools.ietf.org/html/rfc2518#section-10.5">Sec. 10.5</a></td> * </tr> - * + * * <tr> * <td><strong><code>Server Error - 5xx</code></strong></td> * <td colspan="5">{@link #isServerError(int)}</td> * </tr> - * + * * <tr> - * <td>{@link #INTERNAL_SERVER_ERROR}</td> + * <td>{@link #INTERNAL_SERVER_ERROR_500}</td> * <td>500</td> * <td>Internal Server Error</td> * <td> @@ -538,7 +536,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #NOT_IMPLEMENTED}</td> + * <td>{@link #NOT_IMPLEMENTED_501}</td> * <td>501</td> * <td>Not Implemented</td> * <td> @@ -548,7 +546,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #BAD_GATEWAY}</td> + * <td>{@link #BAD_GATEWAY_502}</td> * <td>502</td> * <td>Bad Gateway</td> * <td> @@ -558,7 +556,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #SERVICE_UNAVAILABLE}</td> + * <td>{@link #SERVICE_UNAVAILABLE_503}</td> * <td>503</td> * <td>Service Unavailable</td> * <td> @@ -568,7 +566,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #GATEWAY_TIMEOUT}</td> + * <td>{@link #GATEWAY_TIMEOUT_504}</td> * <td>504</td> * <td>Gateway Timeout</td> * <td> </td> @@ -577,7 +575,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #HTTP_VERSION_NOT_SUPPORTED}</td> + * <td>{@link #HTTP_VERSION_NOT_SUPPORTED_505}</td> * <td>505</td> * <td>HTTP Version Not Supported</td> * <td> </td> @@ -594,7 +592,7 @@ import org.eclipse.jetty.util.TypeUtil; * <td> </td> * </tr> * <tr> - * <td>{@link #INSUFFICIENT_STORAGE}</td> + * <td>{@link #INSUFFICIENT_STORAGE_507}</td> * <td>507</td> * <td>Insufficient Storage</td> * <td> </td> @@ -602,9 +600,9 @@ import org.eclipse.jetty.util.TypeUtil; * <td> * <a href="http://tools.ietf.org/html/rfc2518#section-10.6">Sec. 10.6</a></td> * </tr> - * + * * </table> - * + * * @version $Id$ */ public class HttpStatus @@ -612,7 +610,7 @@ public class HttpStatus public final static int CONTINUE_100 = 100; public final static int SWITCHING_PROTOCOLS_101 = 101; public final static int PROCESSING_102 = 102; - + public final static int OK_200 = 200; public final static int CREATED_201 = 201; public final static int ACCEPTED_202 = 202; @@ -621,7 +619,7 @@ public class HttpStatus public final static int RESET_CONTENT_205 = 205; public final static int PARTIAL_CONTENT_206 = 206; public final static int MULTI_STATUS_207 = 207; - + public final static int MULTIPLE_CHOICES_300 = 300; public final static int MOVED_PERMANENTLY_301 = 301; public final static int MOVED_TEMPORARILY_302 = 302; @@ -630,7 +628,7 @@ public class HttpStatus public final static int NOT_MODIFIED_304 = 304; public final static int USE_PROXY_305 = 305; public final static int TEMPORARY_REDIRECT_307 = 307; - + public final static int BAD_REQUEST_400 = 400; public final static int UNAUTHORIZED_401 = 401; public final static int PAYMENT_REQUIRED_402 = 402; @@ -652,7 +650,7 @@ public class HttpStatus public final static int UNPROCESSABLE_ENTITY_422 = 422; public final static int LOCKED_423 = 423; public final static int FAILED_DEPENDENCY_424 = 424; - + public final static int INTERNAL_SERVER_ERROR_500 = 500; public final static int NOT_IMPLEMENTED_501 = 501; public final static int BAD_GATEWAY_502 = 502; @@ -660,9 +658,9 @@ public class HttpStatus public final static int GATEWAY_TIMEOUT_504 = 504; public final static int HTTP_VERSION_NOT_SUPPORTED_505 = 505; public final static int INSUFFICIENT_STORAGE_507 = 507; - + public static final int MAX_CODE = 507; - + private static final Code[] codeMap = new Code[MAX_CODE+1]; @@ -673,7 +671,7 @@ public class HttpStatus codeMap[code._code] = code; } } - + public enum Code { @@ -843,7 +841,7 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - * HTTP/1.1</a>. - * + * * @return true if within range of codes that belongs to * <code>Informational</code> messages. */ @@ -858,7 +856,7 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - * HTTP/1.1</a>. - * + * * @return true if within range of codes that belongs to * <code>Success</code> messages. */ @@ -873,7 +871,7 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - * HTTP/1.1</a>. - * + * * @return true if within range of codes that belongs to * <code>Redirection</code> messages. */ @@ -888,7 +886,7 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - * HTTP/1.1</a>. - * + * * @return true if within range of codes that belongs to * <code>Client Error</code> messages. */ @@ -903,7 +901,7 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - * HTTP/1.1</a>. - * + * * @return true if within range of codes that belongs to * <code>Server Error</code> messages. */ @@ -916,7 +914,7 @@ public class HttpStatus /** * Get the HttpStatusCode for a specific code - * + * * @param code * the code to lookup. * @return the {@link HttpStatus} if found, or null if not found. @@ -929,10 +927,10 @@ public class HttpStatus } return null; } - + /** * Get the status message for a specific code. - * + * * @param code * the code to look up * @return the specific message, or the code number itself if code @@ -947,7 +945,7 @@ public class HttpStatus } else { - return TypeUtil.toString(code); + return Integer.toString(code); } } @@ -956,7 +954,7 @@ public class HttpStatus * <code>Informational</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. - * + * * @param code * the code to test. * @return true if within range of codes that belongs to @@ -972,7 +970,7 @@ public class HttpStatus * <code>Success</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. - * + * * @param code * the code to test. * @return true if within range of codes that belongs to @@ -988,7 +986,7 @@ public class HttpStatus * <code>Redirection</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. - * + * * @param code * the code to test. * @return true if within range of codes that belongs to @@ -1004,7 +1002,7 @@ public class HttpStatus * <code>Client Error</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. - * + * * @param code * the code to test. * @return true if within range of codes that belongs to @@ -1020,7 +1018,7 @@ public class HttpStatus * <code>Server Error</code> message category as defined in the <a * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>. - * + * * @param code * the code to test. * @return true if within range of codes that belongs to diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index 47c67c1a48..6612b7d124 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; @@ -37,12 +37,12 @@ import org.eclipse.jetty.util.Utf8StringBuilder; * <li>{@link #getQuery()} - query</li> * <li>{@link #getFragment()} - fragment</li> * </ul> - * + * */ public class HttpURI { - private static final byte[] __empty={}; - private final static int + private static final byte[] __empty={}; + private final static int START=0, AUTH_OR_PATH=1, SCHEME_OR_PATH=2, @@ -53,7 +53,7 @@ public class HttpURI PARAM=8, QUERY=9, ASTERISK=10; - + boolean _partial=false; byte[] _raw=__empty; String _rawString; @@ -68,14 +68,14 @@ public class HttpURI int _fragment; int _end; boolean _encoded=false; - + final Utf8StringBuilder _utf8b = new Utf8StringBuilder(64); - + public HttpURI() { - - } - + + } + /* ------------------------------------------------------------ */ /** * @param parsePartialAuth If True, parse auth without prior scheme, else treat all URIs starting with / as paths @@ -84,32 +84,106 @@ public class HttpURI { _partial=parsePartialAuth; } - + public HttpURI(String raw) { _rawString=raw; byte[] b = raw.getBytes(); parse(b,0,b.length); } - + public HttpURI(byte[] raw,int offset, int length) { parse2(raw,offset,length); } - + public void parse(String raw) { byte[] b = raw.getBytes(); parse2(b,0,b.length); _rawString=raw; } - + public void parse(byte[] raw,int offset, int length) { _rawString=null; parse2(raw,offset,length); } - + + + public void parseConnect(byte[] raw,int offset, int length) + { + _rawString=null; + _encoded=false; + _raw=raw; + int i=offset; + int e=offset+length; + int state=AUTH; + int m=offset; + _end=offset+length; + _scheme=offset; + _authority=offset; + _host=offset; + _port=_end; + _portValue=-1; + _path=_end; + _param=_end; + _query=_end; + _fragment=_end; + + loop: while (i<e) + { + char c=(char)(0xff&_raw[i]); + int s=i++; + + switch (state) + { + case AUTH: + { + switch (c) + { + case ':': + { + _port = s; + break loop; + } + case '[': + { + state = IPV6; + break; + } + } + continue; + } + + case IPV6: + { + switch (c) + { + case '/': + { + throw new IllegalArgumentException("No closing ']' for " + StringUtil.toString(_raw,offset,length,URIUtil.__CHARSET)); + } + case ']': + { + state = AUTH; + break; + } + } + + continue; + } + } + } + + if (_port<_path) + _portValue=TypeUtil.parseInt(_raw, _port+1, _path-_port-1,10); + else + throw new IllegalArgumentException("No port"); + _path=offset; + } + + private void parse2(byte[] raw,int offset, int length) { _encoded=false; @@ -132,7 +206,7 @@ public class HttpURI { char c=(char)(0xff&_raw[i]); int s=i++; - + state: switch (state) { case START: @@ -161,14 +235,14 @@ public class HttpURI _path=s; state=ASTERISK; break; - + default: if (Character.isLetterOrDigit(c)) state=SCHEME_OR_PATH; else throw new IllegalArgumentException("!(SCHEME|PATH|AUTH):"+StringUtil.toString(_raw,offset,length,URIUtil.__CHARSET)); } - + continue; } @@ -185,16 +259,16 @@ public class HttpURI { i--; state=PATH; - } + } else { _host=m; _port=m; state=PATH; - } + } continue; } - + case SCHEME_OR_PATH: { // short cut for http and https @@ -219,7 +293,7 @@ public class HttpURI c=':'; } } - + switch (c) { case ':': @@ -238,20 +312,20 @@ public class HttpURI } break; } - + case '/': { state = PATH; break; } - + case ';': { _param = s; state = PARAM; break; } - + case '?': { _param = s; @@ -259,7 +333,7 @@ public class HttpURI state = QUERY; break; } - + case '#': { _param = s; @@ -270,7 +344,7 @@ public class HttpURI } continue; } - + case AUTH: { switch (c) @@ -321,7 +395,7 @@ public class HttpURI continue; } - + case PORT: { if (c=='/') @@ -334,7 +408,7 @@ public class HttpURI } continue; } - + case PATH: { switch (c) @@ -366,7 +440,7 @@ public class HttpURI } continue; } - + case PARAM: { switch (c) @@ -386,7 +460,7 @@ public class HttpURI } continue; } - + case QUERY: { if (c=='#') @@ -396,7 +470,7 @@ public class HttpURI } continue; } - + case ASTERISK: { throw new IllegalArgumentException("only '*'"); @@ -407,62 +481,62 @@ public class HttpURI if (_port<_path) _portValue=TypeUtil.parseInt(_raw, _port+1, _path-_port-1,10); } - + private String toUtf8String(int offset,int length) { _utf8b.reset(); _utf8b.append(_raw,offset,length); return _utf8b.toString(); } - + public String getScheme() { if (_scheme==_authority) return null; int l=_authority-_scheme; - if (l==5 && - _raw[_scheme]=='h' && - _raw[_scheme+1]=='t' && - _raw[_scheme+2]=='t' && + if (l==5 && + _raw[_scheme]=='h' && + _raw[_scheme+1]=='t' && + _raw[_scheme+2]=='t' && _raw[_scheme+3]=='p' ) return HttpSchemes.HTTP; - if (l==6 && - _raw[_scheme]=='h' && - _raw[_scheme+1]=='t' && - _raw[_scheme+2]=='t' && - _raw[_scheme+3]=='p' && + if (l==6 && + _raw[_scheme]=='h' && + _raw[_scheme+1]=='t' && + _raw[_scheme+2]=='t' && + _raw[_scheme+3]=='p' && _raw[_scheme+4]=='s' ) return HttpSchemes.HTTPS; - + return toUtf8String(_scheme,_authority-_scheme-1); } - + public String getAuthority() { if (_authority==_path) return null; return toUtf8String(_authority,_path-_authority); } - + public String getHost() { if (_host==_port) return null; return toUtf8String(_host,_port-_host); } - + public int getPort() { return _portValue; } - + public String getPath() { if (_path==_param) return null; return toUtf8String(_path,_param-_path); } - + public String getDecodedPath() { if (_path==_param) @@ -475,7 +549,7 @@ public class HttpURI for (int i=_path;i<_param;i++) { byte b = _raw[i]; - + if (b=='%') { if ((i+2)>=_param) @@ -488,13 +562,13 @@ public class HttpURI n++; continue; } - + if (bytes==null) { bytes=new byte[length]; System.arraycopy(_raw,_path,bytes,0,n); } - + bytes[n++]=b; } @@ -505,47 +579,47 @@ public class HttpURI _utf8b.append(bytes,0,n); return _utf8b.toString(); } - + public String getPathAndParam() { if (_path==_query) return null; return toUtf8String(_path,_query-_path); } - + public String getCompletePath() { if (_path==_end) return null; return toUtf8String(_path,_end-_path); } - + public String getParam() { if (_param==_query) return null; return toUtf8String(_param+1,_query-_param-1); } - + public String getQuery() { if (_query==_fragment) return null; return toUtf8String(_query+1,_fragment-_query-1); } - + public String getQuery(String encoding) { if (_query==_fragment) return null; return StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding); } - + public boolean hasQuery() { return (_fragment>_query); } - + public String getFragment() { if (_fragment==_end) @@ -553,7 +627,7 @@ public class HttpURI return toUtf8String(_fragment+1,_end-_fragment-1); } - public void decodeQueryTo(MultiMap parameters) + public void decodeQueryTo(MultiMap parameters) { if (_query==_fragment) return; @@ -561,12 +635,12 @@ public class HttpURI UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters,_utf8b); } - public void decodeQueryTo(MultiMap parameters, String encoding) + public void decodeQueryTo(MultiMap parameters, String encoding) throws UnsupportedEncodingException { if (_query==_fragment) return; - + if (encoding==null || StringUtil.isUTF8(encoding)) UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters); else @@ -580,7 +654,7 @@ public class HttpURI _rawString=""; _encoded=false; } - + @Override public String toString() { @@ -588,10 +662,10 @@ public class HttpURI _rawString=toUtf8String(_scheme,_end-_scheme); return _rawString; } - + public void writeTo(Utf8StringBuilder buf) { buf.append(_raw,_scheme,_end-_scheme); } - + } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 146db9d433..8086084198 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -4,44 +4,48 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; +import java.net.CookieHandler; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; -import junit.framework.TestCase; - import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.View; -import org.eclipse.jetty.io.BufferCache.CachedBuffer; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; -/* ------------------------------------------------------------------------------- */ /** - * + * */ -public class HttpFieldsTest extends TestCase +public class HttpFieldsTest { - public void testPut() - throws Exception + @Test + public void testPut() throws Exception { HttpFields header = new HttpFields(); - + header.put("name0", "value0"); header.put("name1", "value1"); - + assertEquals("value0",header.getStringField("name0")); assertEquals("value1",header.getStringField("name1")); assertNull(header.getStringField("name2")); - + int matches=0; Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) @@ -53,35 +57,34 @@ public class HttpFieldsTest extends TestCase matches++; } assertEquals(2, matches); - - matches=0; + e = header.getValues("name0"); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value0"); assertEquals(false, e.hasMoreElements()); } - - public void testCRLF() - throws Exception + + @Test + public void testCRLF() throws Exception { HttpFields header = new HttpFields(); header.put("name0", "value\r\n0"); header.put("name\r\n1", "value1"); header.put("name:2", "value:\r\n2"); - + ByteArrayBuffer buffer = new ByteArrayBuffer(1024); header.put(buffer); assertTrue(buffer.toString().contains("name0: value0")); assertTrue(buffer.toString().contains("name1: value1")); - assertTrue(buffer.toString().contains("name2: value:2")); + assertTrue(buffer.toString().contains("name2: value:2")); } - - public void testCachedPut() - throws Exception + + @Test + public void testCachedPut() throws Exception { HttpFields header = new HttpFields(); - + header.put("Connection", "keep-alive"); assertEquals(HttpHeaderValues.KEEP_ALIVE, header.getStringField(HttpHeaders.CONNECTION)); @@ -96,15 +99,13 @@ public class HttpFieldsTest extends TestCase matches++; } assertEquals(1, matches); - - } - - public void testRePut() - throws Exception + + @Test + public void testRePut() throws Exception { HttpFields header = new HttpFields(); - + header.put("name0", "value0"); header.put("name1", "xxxxxx"); header.put("name2", "value2"); @@ -112,14 +113,14 @@ public class HttpFieldsTest extends TestCase assertEquals("value0",header.getStringField("name0")); assertEquals("xxxxxx",header.getStringField("name1")); assertEquals("value2",header.getStringField("name2")); - + header.put("name1", "value1"); - + assertEquals("value0",header.getStringField("name0")); assertEquals("value1",header.getStringField("name1")); assertEquals("value2",header.getStringField("name2")); assertNull(header.getStringField("name3")); - + int matches=0; Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) @@ -133,19 +134,18 @@ public class HttpFieldsTest extends TestCase matches++; } assertEquals(3, matches); - - matches=0; + e = header.getValues("name1"); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value1"); assertEquals(false, e.hasMoreElements()); } - - public void testRemovePut() - throws Exception + + @Test + public void testRemovePut() throws Exception { HttpFields header = new HttpFields(); - + header.put("name0", "value0"); header.put("name1", "value1"); header.put("name2", "value2"); @@ -153,14 +153,14 @@ public class HttpFieldsTest extends TestCase assertEquals("value0",header.getStringField("name0")); assertEquals("value1",header.getStringField("name1")); assertEquals("value2",header.getStringField("name2")); - + header.remove("name1"); - + assertEquals("value0",header.getStringField("name0")); assertNull(header.getStringField("name1")); assertEquals("value2",header.getStringField("name2")); assertNull(header.getStringField("name3")); - + int matches=0; Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) @@ -174,18 +174,16 @@ public class HttpFieldsTest extends TestCase matches++; } assertEquals(2, matches); - - matches=0; + e = header.getValues("name1"); assertEquals(false, e.hasMoreElements()); } - - public void testAdd() - throws Exception + @Test + public void testAdd() throws Exception { HttpFields fields = new HttpFields(); - + fields.add("name0", "value0"); fields.add("name1", "valueA"); fields.add("name2", "value2"); @@ -193,14 +191,14 @@ public class HttpFieldsTest extends TestCase assertEquals("value0",fields.getStringField("name0")); assertEquals("valueA",fields.getStringField("name1")); assertEquals("value2",fields.getStringField("name2")); - + fields.add("name1", "valueB"); - + assertEquals("value0",fields.getStringField("name0")); assertEquals("valueA",fields.getStringField("name1")); assertEquals("value2",fields.getStringField("name2")); assertNull(fields.getStringField("name3")); - + int matches=0; Enumeration e = fields.getFieldNames(); while (e.hasMoreElements()) @@ -214,8 +212,7 @@ public class HttpFieldsTest extends TestCase matches++; } assertEquals(3, matches); - - matches=0; + e = fields.getValues("name1"); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "valueA"); @@ -223,9 +220,9 @@ public class HttpFieldsTest extends TestCase assertEquals(e.nextElement(), "valueB"); assertEquals(false, e.hasMoreElements()); } - - public void testReuse() - throws Exception + + @Test + public void testReuse() throws Exception { HttpFields header = new HttpFields(); Buffer n1=new ByteArrayBuffer("name1"); @@ -237,21 +234,21 @@ public class HttpFieldsTest extends TestCase vb.put((byte)'u'); vb.put((byte)'e'); vb.put((byte)'1'); - + header.put("name0", "value0"); header.put(n1,va); header.put("name2", "value2"); - + assertEquals("value0",header.getStringField("name0")); assertEquals("value1",header.getStringField("name1")); assertEquals("value2",header.getStringField("name2")); assertNull(header.getStringField("name3")); - + header.remove(n1); assertNull(header.getStringField("name1")); header.put(n1,vb); assertEquals("value1",header.getStringField("name1")); - + int matches=0; Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) @@ -265,40 +262,38 @@ public class HttpFieldsTest extends TestCase matches++; } assertEquals(3, matches); - - matches=0; + e = header.getValues("name1"); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value1"); assertEquals(false, e.hasMoreElements()); } - - public void testDestroy() - throws Exception + + @Test + public void testDestroy() throws Exception { HttpFields header = new HttpFields(); - + header.put(new ByteArrayBuffer("name0"), new View(new ByteArrayBuffer("value0"))); assertTrue(header.getFieldNames().hasMoreElements()); assertNotNull(header.getStringField("name0")); assertNull(header.getStringField("name1")); - + header.destroy(); - + assertNull(header.getStringField("name0")); } - public void testCase() - throws Exception + @Test + public void testCase() throws Exception { HttpFields fields= new HttpFields(); - Enumeration e; Set s; // 0123456789012345678901234567890 byte[] b ="Message-IDmessage-idvalueVALUE".getBytes(); ByteArrayBuffer buf= new ByteArrayBuffer(512); buf.put(b); - + View headUC= new View.CaseInsensitive(buf); View headLC= new View.CaseInsensitive(buf); View valUC = new View(buf); @@ -327,7 +322,7 @@ public class HttpFieldsTest extends TestCase assertTrue(s.contains("message-id")); assertEquals("value",fields.getStringField("Message-ID").toLowerCase()); assertEquals("value",fields.getStringField("message-id").toLowerCase()); - + fields.clear(); fields.add("header","value"); @@ -349,19 +344,19 @@ public class HttpFieldsTest extends TestCase assertTrue(s.contains("message-id")); assertEquals("value",fields.getStringField("Message-ID").toLowerCase()); assertEquals("value",fields.getStringField("message-id").toLowerCase()); - + } - - public void testHttpHeaderValues() - throws Exception + + @Test + public void testHttpHeaderValues() throws Exception { assertTrue(((CachedBuffer)HttpHeaderValues.CACHE.lookup("unknown value")).getOrdinal()<0); assertTrue(((CachedBuffer)HttpHeaderValues.CACHE.lookup("close")).getOrdinal()>=0); assertTrue(((CachedBuffer)HttpHeaderValues.CACHE.lookup("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)")).getOrdinal()>=0); } - public void testSetCookie() - throws Exception + @Test + public void testSetCookie() throws Exception { HttpFields fields = new HttpFields(); fields.addSetCookie("minimal","value",null,null,-1,null,false,false,-1); @@ -370,27 +365,57 @@ public class HttpFieldsTest extends TestCase fields.clear(); fields.addSetCookie("everything","value","domain","path",0,"comment",true,true,0); assertEquals("everything=value;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",fields.getStringField("Set-Cookie")); - + fields.clear(); fields.addSetCookie("ev erything","va lue","do main","pa th",1,"co mment",true,true,2); - assertEquals("\"ev erything\"=\"va lue\";Version=2;Comment=\"co mment\";Path=\"pa th\";Domain=\"do main\";Max-Age=1;Secure;HttpOnly",fields.getStringField("Set-Cookie")); + String setCookie=fields.getStringField("Set-Cookie"); + assertTrue(setCookie.startsWith("\"ev erything\"=\"va lue\";Version=1;Comment=\"co mment\";Path=\"pa th\";Domain=\"do main\";Expires=")); + assertTrue(setCookie.endsWith("GMT;Max-Age=1;Secure;HttpOnly")); fields.clear(); + fields.addSetCookie("name","value",null,null,-1,null,false,false,0); + setCookie=fields.getStringField("Set-Cookie"); + assertEquals(-1,setCookie.indexOf("Version=")); + fields.clear(); + fields.addSetCookie("name","v a l u e",null,null,-1,null,false,false,0); + setCookie=fields.getStringField("Set-Cookie"); + assertEquals(17,setCookie.indexOf("Version=1")); + + fields.clear(); fields.addSetCookie("json","{\"services\":[\"cwa\", \"aa\"]}",null,null,-1,null,false,false,-1); assertEquals("json=\"{\\\"services\\\":[\\\"cwa\\\", \\\"aa\\\"]}\"",fields.getStringField("Set-Cookie")); - + + fields.clear(); + fields.addSetCookie("name","value","domain",null,-1,null,false,false,-1); + fields.addSetCookie("name","other","domain",null,-1,null,false,false,-1); + assertEquals("name=other;Domain=domain",fields.getStringField("Set-Cookie")); + fields.addSetCookie("name","more","domain",null,-1,null,false,false,-1); + assertEquals("name=more;Domain=domain",fields.getStringField("Set-Cookie")); + fields.addSetCookie("foo","bar","domain",null,-1,null,false,false,-1); + fields.addSetCookie("foo","bob","domain",null,-1,null,false,false,-1); + assertEquals("name=more;Domain=domain",fields.getStringField("Set-Cookie")); + + Enumeration e=fields.getValues("Set-Cookie"); + assertEquals("name=more;Domain=domain",e.nextElement()); + assertEquals("foo=bob;Domain=domain",e.nextElement()); + + fields=new HttpFields(0); + fields.addSetCookie("name","value==",null,null,-1,null,false,false,0); + setCookie=fields.getStringField("Set-Cookie"); + assertEquals("name=value==",setCookie); + } - - private Set enum2set(Enumeration e) + + private Set<String> enum2set(Enumeration<String> e) { - HashSet s=new HashSet(); + Set<String> s=new HashSet<String>(); while(e.hasMoreElements()) - s.add(e.nextElement().toString().toLowerCase()); + s.add(e.nextElement().toLowerCase()); return s; } - - public void testDateFields() - throws Exception + + @Test + public void testDateFields() throws Exception { HttpFields fields = new HttpFields(); @@ -414,7 +439,7 @@ public class HttpFieldsTest extends TestCase assertEquals(d2,d3); assertEquals(d3+2000,d4); assertEquals(951825600000L,d5); - + d1 = fields.getDateField("D1"); d2 = fields.getDateField("D2"); d3 = fields.getDateField("D3"); @@ -426,28 +451,28 @@ public class HttpFieldsTest extends TestCase assertEquals(d2,d3); assertEquals(d3+2000,d4); assertEquals(951825600000L,d5); - + fields.putDateField("D2",d1); assertEquals("Fri, 31 Dec 1999 23:59:59 GMT",fields.getStringField("D2")); } - - public void testLongFields() - throws Exception + + @Test + public void testLongFields() throws Exception { HttpFields header = new HttpFields(); - + header.put("I1", "42"); header.put("I2", " 43 99"); header.put("I3", "-44;"); header.put("I4", " - 45abc"); header.put("N1", " - "); header.put("N2", "xx"); - + long i1=header.getLongField("I1"); long i2=header.getLongField("I2"); long i3=header.getLongField("I3"); long i4=header.getLongField("I4"); - + try{ header.getLongField("N1"); assertTrue(false); @@ -456,7 +481,7 @@ public class HttpFieldsTest extends TestCase { assertTrue(true); } - + try{ header.getLongField("N2"); assertTrue(false); @@ -465,24 +490,24 @@ public class HttpFieldsTest extends TestCase { assertTrue(true); } - + assertEquals(42,i1); assertEquals(43,i2); assertEquals(-44,i3); assertEquals(-45,i4); - + header.putLongField("I5", 46); header.putLongField("I6",-47); assertEquals("46",header.getStringField("I5")); assertEquals("-47",header.getStringField("I6")); - + } - public void testToString() - throws Exception + @Test + public void testToString() throws Exception { HttpFields header = new HttpFields(); - + header.put(new ByteArrayBuffer("name0"), new View(new ByteArrayBuffer("value0"))); header.put(new ByteArrayBuffer("name1"), new View(new ByteArrayBuffer("value1".getBytes()))); String s1=header.toString(); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java index e08612fd85..56d97cef67 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java @@ -4,119 +4,116 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; import java.io.IOException; -import junit.framework.TestCase; - import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.io.View; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -public class HttpGeneratorClientTest extends TestCase +public class HttpGeneratorClientTest { public final static String CONTENT="The quick brown fox jumped over the lazy dog.\nNow is the time for all good men to come to the aid of the party\nThe moon is blue to a fish in love.\n"; public final static String[] connect={null,"keep-alive","close"}; - public HttpGeneratorClientTest(String arg0) - { - super(arg0); - } - - public void testContentLength() - throws Exception + @Test + public void testContentLength() throws Exception { Buffer bb=new ByteArrayBuffer(8096); Buffer sb=new ByteArrayBuffer(1500); ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[0],4096); HttpGenerator generator = new HttpGenerator(new SimpleBuffers(sb,bb),endp); - + generator.setRequest("GET","/usr"); - + HttpFields fields = new HttpFields(); fields.add("Header","Value"); fields.add("Content-Type","text/plain"); - + String content = "The quick brown fox jumped over the lazy dog"; fields.addLongField("Content-Length",content.length()); - + generator.completeHeader(fields,false); - + generator.addContent(new ByteArrayBuffer(content),true); generator.flushBuffer(); generator.complete(); generator.flushBuffer(); - + String result=endp.getOut().toString().replace("\r\n","|").replace('\r','|').replace('\n','|'); assertEquals("GET /usr HTTP/1.1|Header: Value|Content-Type: text/plain|Content-Length: 44||"+content,result); } - public void testAutoContentLength() - throws Exception + @Test + public void testAutoContentLength() throws Exception { Buffer bb=new ByteArrayBuffer(8096); Buffer sb=new ByteArrayBuffer(1500); ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[0],4096); HttpGenerator generator = new HttpGenerator(new SimpleBuffers(sb,bb),endp); - + generator.setRequest("GET","/usr"); - + HttpFields fields = new HttpFields(); fields.add("Header","Value"); fields.add("Content-Type","text/plain"); - + String content = "The quick brown fox jumped over the lazy dog"; generator.addContent(new ByteArrayBuffer(content),true); generator.completeHeader(fields,true); - + generator.flushBuffer(); generator.complete(); generator.flushBuffer(); - + String result=endp.getOut().toString().replace("\r\n","|").replace('\r','|').replace('\n','|'); assertEquals("GET /usr HTTP/1.1|Header: Value|Content-Type: text/plain|Content-Length: 44||"+content,result); } - public void testChunked() - throws Exception + @Test + public void testChunked() throws Exception { Buffer bb=new ByteArrayBuffer(8096); Buffer sb=new ByteArrayBuffer(1500); ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[0],4096); HttpGenerator generator = new HttpGenerator(new SimpleBuffers(sb,bb),endp); - + generator.setRequest("GET","/usr"); - + HttpFields fields = new HttpFields(); fields.add("Header","Value"); fields.add("Content-Type","text/plain"); - + String content = "The quick brown fox jumped over the lazy dog"; generator.completeHeader(fields,false); - + generator.addContent(new ByteArrayBuffer(content),false); generator.flushBuffer(); generator.complete(); generator.flushBuffer(); - + String result=endp.getOut().toString().replace("\r\n","|").replace('\r','|').replace('\n','|'); assertEquals("GET /usr HTTP/1.1|Header: Value|Content-Type: text/plain|Transfer-Encoding: chunked||2C|"+content+"|0||",result); } - - public void testHTTP() - throws Exception + + @Test + public void testHTTP() throws Exception { Buffer bb=new ByteArrayBuffer(8096); Buffer sb=new ByteArrayBuffer(1500); @@ -125,7 +122,7 @@ public class HttpGeneratorClientTest extends TestCase HttpGenerator hb = new HttpGenerator(new SimpleBuffers(sb,bb),endp); Handler handler = new Handler(); HttpParser parser=null; - + // For HTTP version for (int v=9;v<=11;v++) { @@ -140,13 +137,13 @@ public class HttpGeneratorClientTest extends TestCase { String t="v="+v+",r="+r+",chunks="+chunks+",c="+c+",tr="+tr[r]; // System.err.println(t); - + hb.reset(true); endp.reset(); fields.clear(); // System.out.println("TEST: "+t); - + try { tr[r].build(v,hb,connect[c],null,chunks, fields); @@ -160,15 +157,15 @@ public class HttpGeneratorClientTest extends TestCase } String request=endp.getOut().toString(); // System.out.println(request+(hb.isPersistent()?"...\n":"---\n")); - + assertTrue(t,hb.isPersistent()); - + if (v==9) { assertEquals(t,"GET /context/path/info\r\n", request); continue; } - + parser=new HttpParser(new ByteArrayBuffer(request.getBytes()), handler); try { @@ -180,14 +177,14 @@ public class HttpGeneratorClientTest extends TestCase throw e; continue; } - + if (tr[r].body!=null) assertEquals(t,tr[r].body, this.content); if (v==10) assertTrue(t,hb.isPersistent() || tr[r].values[1]==null || c==2 || c==0); else assertTrue(t,hb.isPersistent() || c==2); - + assertTrue(t,tr[r].values[1]==null || content.length()==Integer.parseInt(tr[r].values[1])); } } @@ -195,23 +192,21 @@ public class HttpGeneratorClientTest extends TestCase } } - - - static final String[] headers= { "Content-Type","Content-Length","Connection","Transfer-Encoding","Other"}; - class TR + private static final String[] headers= { "Content-Type","Content-Length","Connection","Transfer-Encoding","Other"}; + private class TR { - String[] values=new String[headers.length]; - String body; - - TR(String ct, String cl ,String content) + private String[] values=new String[headers.length]; + private String body; + + private TR(String ct, String cl ,String content) { values[0]=ct; values[1]=cl; values[4]="value"; this.body=content; } - - void build(int version,HttpGenerator hb, String connection, String te, int chunks, HttpFields fields) + + private void build(int version,HttpGenerator hb, String connection, String te, int chunks, HttpFields fields) throws Exception { values[2]=connection; @@ -219,14 +214,14 @@ public class HttpGeneratorClientTest extends TestCase hb.setRequest(HttpMethods.GET,"/context/path/info"); hb.setVersion(version); - + for (int i=0;i<headers.length;i++) { - if (values[i]==null) + if (values[i]==null) continue; fields.put(new ByteArrayBuffer(headers[i]),new ByteArrayBuffer(values[i])); } - + if (body!=null) { int inc=1+body.length()/chunks; @@ -262,15 +257,15 @@ public class HttpGeneratorClientTest extends TestCase } hb.complete(); } - + @Override public String toString() { return "["+values[0]+","+values[1]+","+(body==null?"none":"_content")+"]"; } } - - private TR[] tr = + + private final TR[] tr = { /* 0 */ new TR(null,null,null), /* 1 */ new TR(null,null,CONTENT), @@ -279,20 +274,20 @@ public class HttpGeneratorClientTest extends TestCase /* 5 */ new TR("text/html",null,CONTENT), /* 7 */ new TR("text/html",""+CONTENT.length(),CONTENT), }; - - - String content; - String f0; - String f1; - String f2; - String[] hdr; - String[] val; - int h; - - class Handler extends HttpParser.EventHandler - { - int index=0; - + + + private String content; + private String f0; + private String f1; + private String f2; + private String[] hdr; + private String[] val; + private int h; + + private class Handler extends HttpParser.EventHandler + { + private int index=0; + @Override public void content(Buffer ref) { @@ -302,7 +297,6 @@ public class HttpGeneratorClientTest extends TestCase index+=ref.length(); } - @Override public void startRequest(Buffer tok0, Buffer tok1, Buffer tok2) { @@ -319,7 +313,6 @@ public class HttpGeneratorClientTest extends TestCase // System.out.println(f0+" "+f1+" "+f2); } - /* (non-Javadoc) * @see org.eclipse.jetty.EventHandler#startResponse(org.eclipse.io.Buffer, int, org.eclipse.io.Buffer) */ @@ -355,8 +348,5 @@ public class HttpGeneratorClientTest extends TestCase public void messageComplete(long contentLength) { } - - } - } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorTest.java index fcf5195acd..56a1c786d1 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorTest.java @@ -4,66 +4,62 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; - import java.io.IOException; -import junit.framework.TestCase; - import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.io.View; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** - * + * * * To change the template for this generated type comment go to * Window - Preferences - Java - Code Generation - Code and Comments */ -public class HttpGeneratorTest extends TestCase +public class HttpGeneratorTest { public final static String CONTENT="The quick brown fox jumped over the lazy dog.\nNow is the time for all good men to come to the aid of the party\nThe moon is blue to a fish in love.\n"; public final static String[] connect={null,"keep-alive","close","TE, close"}; - public HttpGeneratorTest(String arg0) - { - super(arg0); - } - - public void testRequest() - throws Exception + @Test + public void testRequest() throws Exception { Buffer bb=new ByteArrayBuffer(8096); Buffer sb=new ByteArrayBuffer(1500); HttpFields fields = new HttpFields(); ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[0],4096); HttpGenerator hg = new HttpGenerator(new SimpleBuffers(sb,bb),endp); - + fields.add("Host","something"); fields.add("User-Agent","test"); - + hg.setRequest("GET","/index.html"); hg.setVersion(11); hg.completeHeader(fields,true); hg.complete(); - + assertTrue(endp.getOut().toString().indexOf("GET /index.html HTTP/1.1")==0); assertTrue(endp.getOut().toString().indexOf("Content-Length")==-1); - } - - public void testHTTP() - throws Exception + + @Test + public void testHTTP() throws Exception { Buffer bb=new ByteArrayBuffer(8096); Buffer sb=new ByteArrayBuffer(1500); @@ -72,7 +68,7 @@ public class HttpGeneratorTest extends TestCase HttpGenerator hb = new HttpGenerator(new SimpleBuffers(sb,bb),endp); Handler handler = new Handler(); HttpParser parser=null; - + // For HTTP version for (int v=9;v<=11;v++) { @@ -85,18 +81,18 @@ public class HttpGeneratorTest extends TestCase // For none, keep-alive, close for (int c=0;c<(v==11?connect.length:(connect.length-1));c++) { - + String t="v="+v+",r="+r+",chunks="+chunks+",connect="+connect[c]+",tr="+tr[r]; // System.err.println(t); - + hb.reset(true); endp.reset(); fields.clear(); - + tr[r].build(v,hb,"OK\r\nTest",connect[c],null,chunks, fields); String response=endp.getOut().toString(); // System.out.println("RESPONSE: "+t+"\n"+response+(hb.isPersistent()?"...\n":"---\n")); - + if (v==9) { assertFalse(t,hb.isPersistent()); @@ -104,7 +100,7 @@ public class HttpGeneratorTest extends TestCase assertEquals(t,tr[r].body, response); continue; } - + parser=new HttpParser(new ByteArrayBuffer(response.getBytes()), handler); try { @@ -116,17 +112,17 @@ public class HttpGeneratorTest extends TestCase throw e; continue; } - + if (tr[r].body!=null) assertEquals(t,tr[r].body, this.content); if (v==10) assertTrue(t,hb.isPersistent() || tr[r].values[1]==null || c==2 || c==0); else assertTrue(t,hb.isPersistent() || c==2 || c==3); - + if (v>9) assertEquals("OK Test",f2); - + assertTrue(t,tr[r].values[1]==null || content.length()==Integer.parseInt(tr[r].values[1])); } } @@ -134,16 +130,14 @@ public class HttpGeneratorTest extends TestCase } } - - - static final String[] headers= { "Content-Type","Content-Length","Connection","Transfer-Encoding","Other"}; - class TR + private static final String[] headers= { "Content-Type","Content-Length","Connection","Transfer-Encoding","Other"}; + private class TR { - int code; - String[] values=new String[headers.length]; - String body; - - TR(int code,String ct, String cl ,String content) + private int code; + private String[] values=new String[headers.length]; + private String body; + + private TR(int code,String ct, String cl ,String content) { this.code=code; values[0]=ct; @@ -151,22 +145,21 @@ public class HttpGeneratorTest extends TestCase values[4]="value"; this.body=content; } - - void build(int version,HttpGenerator hb,String reason, String connection, String te, int chunks, HttpFields fields) - throws Exception + + private void build(int version,HttpGenerator hb,String reason, String connection, String te, int chunks, HttpFields fields) throws Exception { values[2]=connection; values[3]=te; hb.setVersion(version); hb.setResponse(code,reason); - + for (int i=0;i<headers.length;i++) { - if (values[i]==null) + if (values[i]==null) continue; fields.put(new ByteArrayBuffer(headers[i]),new ByteArrayBuffer(values[i])); } - + if (body!=null) { int inc=1+body.length()/chunks; @@ -198,15 +191,15 @@ public class HttpGeneratorTest extends TestCase } hb.complete(); } - + @Override public String toString() { return "["+code+","+values[0]+","+values[1]+","+(body==null?"none":"_content")+"]"; } } - - private TR[] tr = + + private final TR[] tr = { /* 0 */ new TR(200,null,null,null), /* 1 */ new TR(200,null,null,CONTENT), @@ -217,19 +210,19 @@ public class HttpGeneratorTest extends TestCase /* 6 */ new TR(200,"text/html",""+CONTENT.length(),null), /* 7 */ new TR(200,"text/html",""+CONTENT.length(),CONTENT), }; - - String content; - String f0; - String f1; - String f2; - String[] hdr; - String[] val; - int h; - - class Handler extends HttpParser.EventHandler - { - int index=0; - + + private String content; + private String f0; + private String f1; + private String f2; + private String[] hdr; + private String[] val; + private int h; + + private class Handler extends HttpParser.EventHandler + { + private int index=0; + @Override public void content(Buffer ref) { @@ -239,7 +232,6 @@ public class HttpGeneratorTest extends TestCase index+=ref.length(); } - @Override public void startRequest(Buffer tok0, Buffer tok1, Buffer tok2) { @@ -256,7 +248,6 @@ public class HttpGeneratorTest extends TestCase // System.out.println(f0+" "+f1+" "+f2); } - /* (non-Javadoc) * @see org.eclipse.jetty.EventHandler#startResponse(org.eclipse.io.Buffer, int, org.eclipse.io.Buffer) */ @@ -292,8 +283,5 @@ public class HttpGeneratorTest extends TestCase public void messageComplete(long contentLength) { } - - } - } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 6069ea59c7..70a2462115 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -4,67 +4,34 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; import java.io.UnsupportedEncodingException; -import junit.framework.TestCase; - import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.io.bio.StringEndPoint; import org.eclipse.jetty.util.StringUtil; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** - * * - * To change this generated comment edit the template variable "typecomment": - * Window>Preferences>Java>Templates. - * To enable and disable the creation of type comments go to - * Window>Preferences>Java>Code Generation. */ -public class HttpParserTest extends TestCase +public class HttpParserTest { - /** - * Constructor for HttpParserTest. - * @param arg0 - */ - public HttpParserTest(String arg0) - { - super(arg0); - } - - public static void main(String[] args) - { - junit.textui.TestRunner.run(HttpParserTest.class); - } - - /** - * @see TestCase#setUp() - */ - protected void setUp() throws Exception - { - super.setUp(); - } - - /** - * @see TestCase#tearDown() - */ - protected void tearDown() throws Exception - { - super.tearDown(); - } - - public void testLineParse0() - throws Exception + @Test + public void testLineParse0() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput("POST /foo HTTP/1.0\015\012" + "\015\012"); @@ -80,8 +47,8 @@ public class HttpParserTest extends TestCase assertEquals(-1, h); } - public void testLineParse1() - throws Exception + @Test + public void testLineParse1() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput("GET /999\015\012"); @@ -98,8 +65,8 @@ public class HttpParserTest extends TestCase assertEquals(-1, h); } - public void testLineParse2() - throws Exception + @Test + public void testLineParse2() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput("POST /222 \015\012"); @@ -116,8 +83,8 @@ public class HttpParserTest extends TestCase assertEquals(-1, h); } - public void testLineParse3() - throws Exception + @Test + public void testLineParse3() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput("POST /fo\u0690 HTTP/1.0\015\012" + "\015\012"); @@ -133,8 +100,8 @@ public class HttpParserTest extends TestCase assertEquals(-1, h); } - public void testLineParse4() - throws Exception + @Test + public void testLineParse4() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput("POST /foo?param=\u0690 HTTP/1.0\015\012" + "\015\012"); @@ -150,8 +117,8 @@ public class HttpParserTest extends TestCase assertEquals(-1, h); } - public void testConnect() - throws Exception + @Test + public void testConnect() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput("CONNECT 192.168.1.2:80 HTTP/1.1\015\012" + "\015\012"); @@ -168,8 +135,8 @@ public class HttpParserTest extends TestCase assertEquals(-1, h); } - public void testHeaderParse() - throws Exception + @Test + public void testHeaderParse() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput( @@ -207,14 +174,14 @@ public class HttpParserTest extends TestCase assertEquals(5, h); } - public void testChunkParse() - throws Exception + @Test + public void testChunkParse() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput( "GET /chunk HTTP/1.0\015\012" + "Header1: value1\015\012" - + "Transfer-Encoding: chunked\015\012" + + "Transfer-Encoding: chunked\015\012" + "\015\012" + "a;\015\012" + "0123456789\015\012" @@ -237,14 +204,14 @@ public class HttpParserTest extends TestCase assertEquals("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content); } - public void testMultiParse() - throws Exception + @Test + public void testMultiParse() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput( "GET /mp HTTP/1.0\015\012" + "Header1: value1\015\012" - + "Transfer-Encoding: chunked\015\012" + + "Transfer-Encoding: chunked\015\012" + "\015\012" + "a;\015\012" + "0123456789\015\012" @@ -253,11 +220,11 @@ public class HttpParserTest extends TestCase + "0\015\012" + "POST /foo HTTP/1.0\015\012" + "Header2: value2\015\012" - + "Content-Length: 0\015\012" + + "Content-Length: 0\015\012" + "\015\012" + "PUT /doodle HTTP/1.0\015\012" + "Header3: value3\015\012" - + "Content-Length: 10\015\012" + + "Content-Length: 10\015\012" + "\015\012" + "0123456789\015\012"); @@ -293,15 +260,15 @@ public class HttpParserTest extends TestCase assertEquals("Header3", hdr[0]); assertEquals("value3", val[0]); assertEquals("0123456789", _content); - } + @Test public void testStreamParse() throws Exception { StringEndPoint io=new StringEndPoint(); String http="GET / HTTP/1.0\015\012" + "Header1: value1\015\012" - + "Transfer-Encoding: chunked\015\012" + + "Transfer-Encoding: chunked\015\012" + "\015\012" + "a;\015\012" + "0123456789\015\012" @@ -314,11 +281,10 @@ public class HttpParserTest extends TestCase + "\015\012" + "PUT /doodle HTTP/1.0\015\012" + "Header3: value3\015\012" - + "Content-Length: 10\015\012" + + "Content-Length: 10\015\012" + "\015\012" + "0123456789\015\012"; - int[] tests= { 1024, @@ -333,7 +299,7 @@ public class HttpParserTest extends TestCase 64, 32 }; - + for (int t= 0; t < tests.length; t++) { String tst="t"+tests[t]; @@ -345,10 +311,9 @@ public class HttpParserTest extends TestCase Handler handler = new Handler(); HttpParser parser= new HttpParser(buffers,io, handler); - - + io.setInput(http); - + parser.parse(); assertEquals(tst,"GET", f0); assertEquals(tst,"/", f1); @@ -357,7 +322,7 @@ public class HttpParserTest extends TestCase assertEquals(tst,"Header1", hdr[0]); assertEquals(tst,"value1", val[0]); assertEquals(tst,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content); - + parser.parse(); assertEquals(tst,"POST", f0); assertEquals(tst,"/foo", f1); @@ -366,7 +331,7 @@ public class HttpParserTest extends TestCase assertEquals(tst,"Header2", hdr[0]); assertEquals(tst,"value2", val[0]); assertEquals(tst,null, _content); - + parser.parse(); assertEquals(tst,"PUT", f0); assertEquals(tst,"/doodle", f1); @@ -385,16 +350,16 @@ public class HttpParserTest extends TestCase } } - public void testResponseParse0() - throws Exception + @Test + public void testResponseParse0() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput( - "HTTP/1.1 200 Correct\015\012" - + "Content-Length: 10\015\012" - + "Content-Type: text/plain\015\012" - + "\015\012" - + "0123456789\015\012"); + "HTTP/1.1 200 Correct\015\012" + + "Content-Length: 10\015\012" + + "Content-Type: text/plain\015\012" + + "\015\012" + + "0123456789\015\012"); ByteArrayBuffer buffer= new ByteArrayBuffer(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); @@ -404,19 +369,19 @@ public class HttpParserTest extends TestCase assertEquals("HTTP/1.1", f0); assertEquals("200", f1); assertEquals("Correct", f2); - assertEquals(_content.length(), 10); - assertTrue(headerCompleted); - assertTrue(messageCompleted); + assertEquals(_content.length(), 10); + assertTrue(headerCompleted); + assertTrue(messageCompleted); } - public void testResponseParse1() - throws Exception + @Test + public void testResponseParse1() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput( - "HTTP/1.1 304 Not-Modified\015\012" - + "Connection: close\015\012" - + "\015\012"); + "HTTP/1.1 304 Not-Modified\015\012" + + "Connection: close\015\012" + + "\015\012"); ByteArrayBuffer buffer= new ByteArrayBuffer(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); @@ -426,23 +391,23 @@ public class HttpParserTest extends TestCase assertEquals("HTTP/1.1", f0); assertEquals("304", f1); assertEquals("Not-Modified", f2); - assertTrue(headerCompleted); - assertTrue(messageCompleted); + assertTrue(headerCompleted); + assertTrue(messageCompleted); } - public void testResponseParse2() - throws Exception + @Test + public void testResponseParse2() throws Exception { StringEndPoint io=new StringEndPoint(); io.setInput( - "HTTP/1.1 204 No-Content\015\012" - + "Connection: close\015\012" - + "\015\012" - + "HTTP/1.1 200 Correct\015\012" - + "Content-Length: 10\015\012" - + "Content-Type: text/plain\015\012" - + "\015\012" - + "0123456789\015\012"); + "HTTP/1.1 204 No-Content\015\012" + + "Connection: close\015\012" + + "\015\012" + + "HTTP/1.1 200 Correct\015\012" + + "Content-Length: 10\015\012" + + "Content-Type: text/plain\015\012" + + "\015\012" + + "0123456789\015\012"); ByteArrayBuffer buffer= new ByteArrayBuffer(4096); SimpleBuffers buffers=new SimpleBuffers(buffer,null); @@ -452,34 +417,34 @@ public class HttpParserTest extends TestCase assertEquals("HTTP/1.1", f0); assertEquals("204", f1); assertEquals("No-Content", f2); - assertTrue(headerCompleted); - assertTrue(messageCompleted); + assertTrue(headerCompleted); + assertTrue(messageCompleted); parser.parse(); assertEquals("HTTP/1.1", f0); assertEquals("200", f1); assertEquals("Correct", f2); - assertEquals(_content.length(), 10); - assertTrue(headerCompleted); - assertTrue(messageCompleted); + assertEquals(_content.length(), 10); + assertTrue(headerCompleted); + assertTrue(messageCompleted); } - String _content; - String f0; - String f1; - String f2; - String[] hdr; - String[] val; - int h; - - boolean headerCompleted; - boolean messageCompleted; - - class Handler extends HttpParser.EventHandler - { - HttpFields fields; - boolean request; - + private String _content; + private String f0; + private String f1; + private String f2; + private String[] hdr; + private String[] val; + private int h; + + private boolean headerCompleted; + private boolean messageCompleted; + + private class Handler extends HttpParser.EventHandler + { + private HttpFields fields; + private boolean request; + public void content(Buffer ref) { if (_content==null) @@ -487,7 +452,6 @@ public class HttpParserTest extends TestCase _content= _content + ref; } - public void startRequest(Buffer tok0, Buffer tok1, Buffer tok2) { try @@ -507,12 +471,11 @@ public class HttpParserTest extends TestCase } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + throw new RuntimeException(e); } - messageCompleted = false; - headerCompleted = false; + messageCompleted = false; + headerCompleted = false; } public void parsedHeader(Buffer name, Buffer value) @@ -533,28 +496,27 @@ public class HttpParserTest extends TestCase throw new IllegalStateException(); } - headerCompleted = true; + headerCompleted = true; } public void messageComplete(long contentLength) { - messageCompleted = true; + messageCompleted = true; } - public void startResponse(Buffer version, int status, Buffer reason) { request=false; f0 = version.toString(); - f1 = Integer.toString(status); - f2 = reason.toString(); + f1 = Integer.toString(status); + f2 = reason.toString(); fields=new HttpFields(); hdr= new String[9]; val= new String[9]; - messageCompleted = false; - headerCompleted = false; + messageCompleted = false; + headerCompleted = false; } } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java index 55c0b5d0fe..b0b5a282de 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java @@ -4,19 +4,22 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; -import junit.framework.TestCase; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; -public class HttpStatusCodeTest extends TestCase +public class HttpStatusCodeTest { + @Test public void testInvalidGetCode() { assertNull("Invalid code: 800", HttpStatus.getCode(800)); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java index dffa6f2cd5..4bb7a15255 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java @@ -4,53 +4,24 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; import junit.framework.TestCase; +import org.junit.Test; - -/* ------------------------------------------------------------ */ /** - * Top level test harness. - * - * + * */ public class PathMapTest extends TestCase { - /** - * Constructor for HttpParserTest. - * - * @param arg0 - */ - public PathMapTest(String arg0) - { - super(arg0); - } - - /** - * @see TestCase#setUp() - */ - protected void setUp() throws Exception - { - super.setUp(); - } - - /** - * @see TestCase#tearDown() - */ - protected void tearDown() throws Exception - { - super.tearDown(); - } - - /* --------------------------------------------------------------- */ + @Test public void testPathMap() throws Exception { PathMap p = new PathMap(); @@ -65,28 +36,28 @@ public class PathMapTest extends TestCase p.put("/", "8"); p.put("/XXX:/YYY", "9"); - String[][] tests = { - { "/abs/path", "1"}, - { "/abs/path/xxx", "8"}, + String[][] tests = { + { "/abs/path", "1"}, + { "/abs/path/xxx", "8"}, { "/abs/pith", "8"}, - { "/abs/path/longer", "2"}, - { "/abs/path/", "8"}, + { "/abs/path/longer", "2"}, + { "/abs/path/", "8"}, { "/abs/path/xxx", "8"}, - { "/animal/bird/eagle/bald", "3"}, + { "/animal/bird/eagle/bald", "3"}, { "/animal/fish/shark/grey", "4"}, - { "/animal/insect/bug", "5"}, - { "/animal", "5"}, + { "/animal/insect/bug", "5"}, + { "/animal", "5"}, { "/animal/", "5"}, { "/animal/x", "5"}, { "/animal/*", "5"}, - { "/suffix/path.tar.gz", "6"}, + { "/suffix/path.tar.gz", "6"}, { "/suffix/path.gz", "7"}, - { "/animal/path.gz", "5"}, + { "/animal/path.gz", "5"}, { "/Other/path", "8"},}; - for (int i = 0; i < tests.length; i++) + for (String[] test : tests) { - assertEquals(tests[i][0], tests[i][1], p.getMatch(tests[i][0]).getValue()); + assertEquals(test[0], test[1], p.getMatch(test[0]).getValue()); } assertEquals("Get absolute path", "1", p.get("/abs/path")); @@ -158,10 +129,11 @@ public class PathMapTest extends TestCase /** * See JIRA issue: JETTY-88. */ + @Test public void testPathMappingsOnlyMatchOnDirectoryNames() throws Exception { String spec = "/xyz/*"; - + assertMatch(spec, "/xyz"); assertMatch(spec, "/xyz/"); assertMatch(spec, "/xyz/123"); diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index 83704ee2ad..9255af14b4 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -20,6 +20,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> @@ -50,16 +51,17 @@ </execution> </executions> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.io.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AsyncEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AsyncEndPoint.java index 753b8b54b6..f7167b4d91 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AsyncEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AsyncEndPoint.java @@ -45,4 +45,15 @@ public interface AsyncEndPoint extends EndPoint * it becomes writable. */ public void scheduleWrite(); + + /* ------------------------------------------------------------ */ + /** Schedule a call to the idle timeout + */ + public void scheduleIdle(); + + /* ------------------------------------------------------------ */ + /** Cancel a call to the idle timeout + */ + public void cancelIdle(); + } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java b/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java index 11e6e65036..0cc471143b 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/BufferUtil.java @@ -254,9 +254,9 @@ public class BufferUtil { boolean started= false; // This assumes constant time int arithmatic - for (int i= 0; i < decDivisors.length; i++) + for (int i= 0; i < decDivisorsL.length; i++) { - if (n < decDivisors[i]) + if (n < decDivisorsL[i]) { if (started) buffer.put((byte)'0'); @@ -264,25 +264,68 @@ public class BufferUtil } started= true; - long d= n / decDivisors[i]; + long d= n / decDivisorsL[i]; buffer.put(DIGIT[(int)d]); - n= n - d * decDivisors[i]; + n= n - d * decDivisorsL[i]; } } } public static Buffer toBuffer(long value) { - ByteArrayBuffer buf=new ByteArrayBuffer(16); + ByteArrayBuffer buf=new ByteArrayBuffer(32); putDecLong(buf, value); return buf; } private final static int[] decDivisors= - { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 }; + { + 1000000000, + 100000000, + 10000000, + 1000000, + 100000, + 10000, + 1000, + 100, + 10, + 1 + }; private final static int[] hexDivisors= - { 0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 1 }; + { + 0x10000000, + 0x1000000, + 0x100000, + 0x10000, + 0x1000, + 0x100, + 0x10, + 0x1 + }; + + private final static long[] decDivisorsL= + { + 1000000000000000000L, + 100000000000000000L, + 10000000000000000L, + 1000000000000000L, + 100000000000000L, + 10000000000000L, + 1000000000000L, + 100000000000L, + 10000000000L, + 1000000000L, + 100000000L, + 10000000L, + 1000000L, + 100000L, + 10000L, + 1000L, + 100L, + 10L, + 1L + }; public static void putCRLF(Buffer buffer) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java index 484e3660b5..1c89fb0059 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java @@ -24,13 +24,15 @@ import java.io.IOException; */ public class ByteArrayEndPoint implements ConnectedEndPoint { - byte[] _inBytes; - ByteArrayBuffer _in; - ByteArrayBuffer _out; - boolean _closed; - boolean _nonBlocking; - boolean _growOutput; - Connection _connection; + protected byte[] _inBytes; + protected ByteArrayBuffer _in; + protected ByteArrayBuffer _out; + protected boolean _closed; + protected boolean _nonBlocking; + protected boolean _growOutput; + protected Connection _connection; + protected int _maxIdleTime; + /* ------------------------------------------------------------ */ /** @@ -151,6 +153,14 @@ public class ByteArrayEndPoint implements ConnectedEndPoint /* ------------------------------------------------------------ */ /* + * @see org.eclipse.io.EndPoint#shutdownOutput() + */ + public void shutdownOutput() throws IOException + { + } + + /* ------------------------------------------------------------ */ + /* * @see org.eclipse.io.EndPoint#close() */ public void close() throws IOException @@ -353,5 +363,23 @@ public class ByteArrayEndPoint implements ConnectedEndPoint _growOutput=growOutput; } + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.io.EndPoint#getMaxIdleTime() + */ + public int getMaxIdleTime() + { + return _maxIdleTime; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.io.EndPoint#setMaxIdleTime(int) + */ + public void setMaxIdleTime(int timeMs) throws IOException + { + _maxIdleTime=timeMs; + } + } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java index 24e7fb9fc6..95a33e242c 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java @@ -16,16 +16,19 @@ package org.eclipse.jetty.io; import java.io.IOException; - /** * * A transport EndPoint */ public interface EndPoint { + /** + * Shutdown any backing output stream associated with the endpoint + */ + void shutdownOutput() throws IOException; /** - * Close any backing stream associated with the buffer + * Close any backing stream associated with the endpoint */ void close() throws IOException; @@ -149,4 +152,25 @@ public interface EndPoint */ public void flush() throws IOException; + + /* ------------------------------------------------------------ */ + /** Get the max idle time in ms. + * <p>The max idle time is the time the endpoint can be idle before + * extraordinary handling takes place. This loosely corresponds to + * the {@link java.net.Socket#getSoTimeout()} for blocking connections, + * but {@link AsyncEndPoint} implementations must use other mechanisms + * to implement the max idle time. + * @return the max idle time in ms. + */ + public int getMaxIdleTime(); + + /* ------------------------------------------------------------ */ + /** Set the max idle time. + * @param timeMs the max idle time in MS. + * @throws IOException if the timeout cannot be set. + */ + public void setMaxIdleTime(int timeMs) throws IOException; + + + } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java index 03a2e72f0d..7be12a17d1 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java @@ -11,7 +11,6 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== - package org.eclipse.jetty.io; import java.io.BufferedWriter; @@ -28,74 +27,106 @@ import org.eclipse.jetty.util.log.Log; /** * A wrapper for the {@link java.io.PrintWriter} that re-throws the instances of * {@link java.io.IOException} thrown by the underlying implementation of - * {@link java.io.Writer} as {@link RunimeIOException} instances. + * {@link java.io.Writer} as {@link RuntimeIOException} instances. */ public class UncheckedPrintWriter extends PrintWriter -{ - private boolean autoFlush = false; - +{ + private boolean _autoFlush = false; + private boolean _throwUnchecked=true; + /* ------------------------------------------------------------ */ /** - * Line separator string. This is the value of the line.separator - * property at the moment that the stream was created. + * Line separator string. This is the value of the line.separator property + * at the moment that the stream was created. */ - private String lineSeparator; - - public UncheckedPrintWriter (Writer out) + private String _lineSeparator; + + public UncheckedPrintWriter(Writer out) { - this(out, false); + this(out,false); } /* ------------------------------------------------------------ */ - /** + /** * Create a new PrintWriter. - * - * @param out A character-output stream - * @param autoFlush A boolean; if true, the println() methods will flush - * the output buffer + * + * @param out + * A character-output stream + * @param autoFlush + * A boolean; if true, the println() methods will flush the + * output buffer */ public UncheckedPrintWriter(Writer out, boolean autoFlush) { - super(out, autoFlush); - this.autoFlush = autoFlush; - this.lineSeparator = System.getProperty("line.separator"); + super(out,autoFlush); + this._autoFlush = autoFlush; + this._lineSeparator = System.getProperty("line.separator"); } /* ------------------------------------------------------------ */ /** * Create a new PrintWriter, without automatic line flushing, from an - * existing OutputStream. This convenience constructor creates the - * necessary intermediate OutputStreamWriter, which will convert characters - * into bytes using the default character encoding. - * - * @param out An output stream - * + * existing OutputStream. This convenience constructor creates the necessary + * intermediate OutputStreamWriter, which will convert characters into bytes + * using the default character encoding. + * + * @param out + * An output stream + * * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream) */ public UncheckedPrintWriter(OutputStream out) { - this(out, false); + this(out,false); } /* ------------------------------------------------------------ */ /** - * Create a new PrintWriter from an existing OutputStream. This - * convenience constructor creates the necessary intermediate - * OutputStreamWriter, which will convert characters into bytes using the - * default character encoding. - * - * @param out An output stream - * @param autoFlush A boolean; if true, the println() methods will flush - * the output buffer - * + * Create a new PrintWriter from an existing OutputStream. This convenience + * constructor creates the necessary intermediate OutputStreamWriter, which + * will convert characters into bytes using the default character encoding. + * + * @param out + * An output stream + * @param autoFlush + * A boolean; if true, the println() methods will flush the + * output buffer + * * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream) */ public UncheckedPrintWriter(OutputStream out, boolean autoFlush) { - this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush); + this(new BufferedWriter(new OutputStreamWriter(out)),autoFlush); + } + + /* ------------------------------------------------------------ */ + private void setError(Throwable th) + { + setError(); + if (_throwUnchecked) + throw new RuntimeIOException(th); + Log.debug(th); } /* ------------------------------------------------------------ */ + /** Are unchecked exceptions thrown. + * @return True if {@link RuntimeIOException}s are thrown + */ + public boolean isUncheckedPrintWriter() + { + return _throwUnchecked; + } + + /* ------------------------------------------------------------ */ + /** Set if unchecked exceptions are thrown + * @param uncheckedPrintWriter True if {@link RuntimeIOException}s are to be thrown + */ + public void setUncheckedPrintWriter(boolean uncheckedPrintWriter) + { + _throwUnchecked = uncheckedPrintWriter; + } + + /* ------------------------------------------------------------ */ /** Check to make sure that the stream has not been closed */ private void isOpen() throws IOException { @@ -104,281 +135,326 @@ public class UncheckedPrintWriter extends PrintWriter } /* ------------------------------------------------------------ */ - /** - * Flush the stream. + /** + * Flush the stream. */ @Override - public void flush() { - try { - synchronized (lock) { + public void flush() + { + try + { + synchronized (lock) + { isOpen(); out.flush(); } } - catch (IOException ex) { - Log.debug(ex); - setError(); - throw new UncheckedIOException(ex); + catch (IOException ex) + { + setError(ex); } } /* ------------------------------------------------------------ */ - /** - * Close the stream. + /** + * Close the stream. */ @Override - public void close() { - try { - synchronized (lock) { + public void close() + { + try + { + synchronized (lock) + { out.close(); } } - catch (IOException ex) { - Log.debug(ex); - setError(); - throw new UncheckedIOException(ex); + catch (IOException ex) + { + setError(ex); } } /* ------------------------------------------------------------ */ - /** + /** * Write a single character. - * @param c int specifying a character to be written. + * + * @param c + * int specifying a character to be written. */ @Override - public void write(int c) { - try { - synchronized (lock) { + public void write(int c) + { + try + { + synchronized (lock) + { isOpen(); out.write(c); } } - catch (InterruptedIOException x) { + catch (InterruptedIOException x) + { Thread.currentThread().interrupt(); } - catch (IOException ex) { - Log.debug(ex); - setError(); - throw new UncheckedIOException(ex); + catch (IOException ex) + { + setError(ex); } } /* ------------------------------------------------------------ */ - /** - * Write a portion of an array of characters. - * @param buf Array of characters - * @param off Offset from which to start writing characters - * @param len Number of characters to write + /** + * Write a portion of an array of characters. + * + * @param buf + * Array of characters + * @param off + * Offset from which to start writing characters + * @param len + * Number of characters to write */ @Override - public void write(char buf[], int off, int len) { - try { - synchronized (lock) { + public void write(char buf[], int off, int len) + { + try + { + synchronized (lock) + { isOpen(); - out.write(buf, off, len); + out.write(buf,off,len); } } - catch (InterruptedIOException x) { + catch (InterruptedIOException x) + { Thread.currentThread().interrupt(); } - catch (IOException ex) { - Log.debug(ex); - setError(); - throw new UncheckedIOException(ex); + catch (IOException ex) + { + setError(ex); } } /* ------------------------------------------------------------ */ /** - * Write an array of characters. This method cannot be inherited from the + * Write an array of characters. This method cannot be inherited from the * Writer class because it must suppress I/O exceptions. - * @param buf Array of characters to be written + * + * @param buf + * Array of characters to be written */ @Override - public void write(char buf[]) { - this.write(buf, 0, buf.length); + public void write(char buf[]) + { + this.write(buf,0,buf.length); } /* ------------------------------------------------------------ */ - /** - * Write a portion of a string. - * @param s A String - * @param off Offset from which to start writing characters - * @param len Number of characters to write + /** + * Write a portion of a string. + * + * @param s + * A String + * @param off + * Offset from which to start writing characters + * @param len + * Number of characters to write */ @Override - public void write(String s, int off, int len) { - try { - synchronized (lock) { + public void write(String s, int off, int len) + { + try + { + synchronized (lock) + { isOpen(); - out.write(s, off, len); + out.write(s,off,len); } } - catch (InterruptedIOException x) { + catch (InterruptedIOException x) + { Thread.currentThread().interrupt(); } - catch (IOException ex) { - Log.debug(ex); - setError(); - throw new UncheckedIOException(ex); + catch (IOException ex) + { + setError(ex); } } /* ------------------------------------------------------------ */ /** - * Write a string. This method cannot be inherited from the Writer class + * Write a string. This method cannot be inherited from the Writer class * because it must suppress I/O exceptions. - * @param s String to be written + * + * @param s + * String to be written */ @Override - public void write(String s) { - this.write(s, 0, s.length()); + public void write(String s) + { + this.write(s,0,s.length()); } - private void newLine() { - try { - synchronized (lock) { + private void newLine() + { + try + { + synchronized (lock) + { isOpen(); - out.write(lineSeparator); - if (autoFlush) + out.write(_lineSeparator); + if (_autoFlush) out.flush(); } } - catch (InterruptedIOException x) { + catch (InterruptedIOException x) + { Thread.currentThread().interrupt(); } - catch (IOException ex) { - Log.debug(ex); - setError(); - throw new UncheckedIOException(ex); + catch (IOException ex) + { + setError(ex); } } - - /* Methods that do not terminate lines */ - /* ------------------------------------------------------------ */ - /** - * Print a boolean value. The string produced by <code>{@link + /** + * Print a boolean value. The string produced by <code>{@link * java.lang.String#valueOf(boolean)}</code> is translated into bytes * according to the platform's default character encoding, and these bytes * are written in exactly the manner of the <code>{@link * #write(int)}</code> method. - * - * @param b The <code>boolean</code> to be printed + * + * @param b + * The <code>boolean</code> to be printed */ @Override - public void print(boolean b) { - this.write(b ? "true" : "false"); + public void print(boolean b) + { + this.write(b?"true":"false"); } /* ------------------------------------------------------------ */ /** - * Print a character. The character is translated into one or more bytes + * Print a character. The character is translated into one or more bytes * according to the platform's default character encoding, and these bytes * are written in exactly the manner of the <code>{@link * #write(int)}</code> method. - * - * @param c The <code>char</code> to be printed + * + * @param c + * The <code>char</code> to be printed */ @Override - public void print(char c) { + public void print(char c) + { this.write(c); } /* ------------------------------------------------------------ */ /** - * Print an integer. The string produced by <code>{@link + * Print an integer. The string produced by <code>{@link * java.lang.String#valueOf(int)}</code> is translated into bytes according - * to the platform's default character encoding, and these bytes are - * written in exactly the manner of the <code>{@link #write(int)}</code> - * method. - * - * @param i The <code>int</code> to be printed - * @see java.lang.Integer#toString(int) + * to the platform's default character encoding, and these bytes are written + * in exactly the manner of the <code>{@link #write(int)}</code> method. + * + * @param i + * The <code>int</code> to be printed + * @see java.lang.Integer#toString(int) */ @Override - public void print(int i) { + public void print(int i) + { this.write(String.valueOf(i)); } /* ------------------------------------------------------------ */ /** - * Print a long integer. The string produced by <code>{@link - * java.lang.String#valueOf(long)}</code> is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the <code>{@link #write(int)}</code> - * method. - * - * @param l The <code>long</code> to be printed - * @see java.lang.Long#toString(long) + * Print a long integer. The string produced by <code>{@link + * java.lang.String#valueOf(long)}</code> is translated into bytes according + * to the platform's default character encoding, and these bytes are written + * in exactly the manner of the <code>{@link #write(int)}</code> method. + * + * @param l + * The <code>long</code> to be printed + * @see java.lang.Long#toString(long) */ @Override - public void print(long l) { + public void print(long l) + { this.write(String.valueOf(l)); } /* ------------------------------------------------------------ */ /** - * Print a floating-point number. The string produced by <code>{@link + * Print a floating-point number. The string produced by <code>{@link * java.lang.String#valueOf(float)}</code> is translated into bytes * according to the platform's default character encoding, and these bytes * are written in exactly the manner of the <code>{@link #write(int)}</code> * method. - * - * @param f The <code>float</code> to be printed - * @see java.lang.Float#toString(float) + * + * @param f + * The <code>float</code> to be printed + * @see java.lang.Float#toString(float) */ @Override - public void print(float f) { + public void print(float f) + { this.write(String.valueOf(f)); } /* ------------------------------------------------------------ */ /** - * Print a double-precision floating-point number. The string produced by + * Print a double-precision floating-point number. The string produced by * <code>{@link java.lang.String#valueOf(double)}</code> is translated into * bytes according to the platform's default character encoding, and these * bytes are written in exactly the manner of the <code>{@link * #write(int)}</code> method. - * - * @param d The <code>double</code> to be printed - * @see java.lang.Double#toString(double) + * + * @param d + * The <code>double</code> to be printed + * @see java.lang.Double#toString(double) */ @Override - public void print(double d) { + public void print(double d) + { this.write(String.valueOf(d)); } /* ------------------------------------------------------------ */ /** - * Print an array of characters. The characters are converted into bytes + * Print an array of characters. The characters are converted into bytes * according to the platform's default character encoding, and these bytes * are written in exactly the manner of the <code>{@link #write(int)}</code> * method. - * - * @param s The array of chars to be printed - * - * @throws NullPointerException If <code>s</code> is <code>null</code> + * + * @param s + * The array of chars to be printed + * + * @throws NullPointerException + * If <code>s</code> is <code>null</code> */ @Override - public void print(char s[]) { + public void print(char s[]) + { this.write(s); } /* ------------------------------------------------------------ */ /** - * Print a string. If the argument is <code>null</code> then the string - * <code>"null"</code> is printed. Otherwise, the string's characters are + * Print a string. If the argument is <code>null</code> then the string + * <code>"null"</code> is printed. Otherwise, the string's characters are * converted into bytes according to the platform's default character * encoding, and these bytes are written in exactly the manner of the * <code>{@link #write(int)}</code> method. - * - * @param s The <code>String</code> to be printed + * + * @param s + * The <code>String</code> to be printed */ @Override - public void print(String s) { - if (s == null) { + public void print(String s) + { + if (s == null) + { s = "null"; } this.write(s); @@ -386,46 +462,49 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** - * Print an object. The string produced by the <code>{@link + * Print an object. The string produced by the <code>{@link * java.lang.String#valueOf(Object)}</code> method is translated into bytes * according to the platform's default character encoding, and these bytes * are written in exactly the manner of the <code>{@link #write(int)}</code> * method. - * - * @param obj The <code>Object</code> to be printed - * @see java.lang.Object#toString() + * + * @param obj + * The <code>Object</code> to be printed + * @see java.lang.Object#toString() */ @Override - public void print(Object obj) { + public void print(Object obj) + { this.write(String.valueOf(obj)); } - - /* Methods that do terminate lines */ - /* ------------------------------------------------------------ */ /** - * Terminate the current line by writing the line separator string. The - * line separator string is defined by the system property + * Terminate the current line by writing the line separator string. The line + * separator string is defined by the system property * <code>line.separator</code>, and is not necessarily a single newline * character (<code>'\n'</code>). */ @Override - public void println() { + public void println() + { this.newLine(); } /* ------------------------------------------------------------ */ /** - * Print a boolean value and then terminate the line. This method behaves - * as though it invokes <code>{@link #print(boolean)}</code> and then + * Print a boolean value and then terminate the line. This method behaves as + * though it invokes <code>{@link #print(boolean)}</code> and then * <code>{@link #println()}</code>. - * - * @param x the <code>boolean</code> value to be printed + * + * @param x + * the <code>boolean</code> value to be printed */ @Override - public void println(boolean x) { - synchronized (lock) { + public void println(boolean x) + { + synchronized (lock) + { this.print(x); this.println(); } @@ -433,15 +512,18 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** - * Print a character and then terminate the line. This method behaves as + * Print a character and then terminate the line. This method behaves as * though it invokes <code>{@link #print(char)}</code> and then <code>{@link * #println()}</code>. - * - * @param x the <code>char</code> value to be printed + * + * @param x + * the <code>char</code> value to be printed */ @Override - public void println(char x) { - synchronized (lock) { + public void println(char x) + { + synchronized (lock) + { this.print(x); this.println(); } @@ -449,15 +531,18 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** - * Print an integer and then terminate the line. This method behaves as + * Print an integer and then terminate the line. This method behaves as * though it invokes <code>{@link #print(int)}</code> and then <code>{@link * #println()}</code>. - * - * @param x the <code>int</code> value to be printed + * + * @param x + * the <code>int</code> value to be printed */ @Override - public void println(int x) { - synchronized (lock) { + public void println(int x) + { + synchronized (lock) + { this.print(x); this.println(); } @@ -465,15 +550,18 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** - * Print a long integer and then terminate the line. This method behaves - * as though it invokes <code>{@link #print(long)}</code> and then + * Print a long integer and then terminate the line. This method behaves as + * though it invokes <code>{@link #print(long)}</code> and then * <code>{@link #println()}</code>. - * - * @param x the <code>long</code> value to be printed + * + * @param x + * the <code>long</code> value to be printed */ @Override - public void println(long x) { - synchronized (lock) { + public void println(long x) + { + synchronized (lock) + { this.print(x); this.println(); } @@ -481,15 +569,18 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** - * Print a floating-point number and then terminate the line. This method + * Print a floating-point number and then terminate the line. This method * behaves as though it invokes <code>{@link #print(float)}</code> and then * <code>{@link #println()}</code>. - * - * @param x the <code>float</code> value to be printed + * + * @param x + * the <code>float</code> value to be printed */ @Override - public void println(float x) { - synchronized (lock) { + public void println(float x) + { + synchronized (lock) + { this.print(x); this.println(); } @@ -498,15 +589,18 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** * Print a double-precision floating-point number and then terminate the - * line. This method behaves as though it invokes <code>{@link + * line. This method behaves as though it invokes <code>{@link * #print(double)}</code> and then <code>{@link #println()}</code>. - * - * @param x the <code>double</code> value to be printed + * + * @param x + * the <code>double</code> value to be printed */ /* ------------------------------------------------------------ */ @Override - public void println(double x) { - synchronized (lock) { + public void println(double x) + { + synchronized (lock) + { this.print(x); this.println(); } @@ -514,15 +608,18 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** - * Print an array of characters and then terminate the line. This method + * Print an array of characters and then terminate the line. This method * behaves as though it invokes <code>{@link #print(char[])}</code> and then * <code>{@link #println()}</code>. - * - * @param x the array of <code>char</code> values to be printed + * + * @param x + * the array of <code>char</code> values to be printed */ @Override - public void println(char x[]) { - synchronized (lock) { + public void println(char x[]) + { + synchronized (lock) + { this.print(x); this.println(); } @@ -530,15 +627,18 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** - * Print a String and then terminate the line. This method behaves as - * though it invokes <code>{@link #print(String)}</code> and then + * Print a String and then terminate the line. This method behaves as though + * it invokes <code>{@link #print(String)}</code> and then * <code>{@link #println()}</code>. - * - * @param x the <code>String</code> value to be printed + * + * @param x + * the <code>String</code> value to be printed */ @Override - public void println(String x) { - synchronized (lock) { + public void println(String x) + { + synchronized (lock) + { this.print(x); this.println(); } @@ -546,15 +646,18 @@ public class UncheckedPrintWriter extends PrintWriter /* ------------------------------------------------------------ */ /** - * Print an Object and then terminate the line. This method behaves as + * Print an Object and then terminate the line. This method behaves as * though it invokes <code>{@link #print(Object)}</code> and then * <code>{@link #println()}</code>. - * - * @param x the <code>Object</code> value to be printed + * + * @param x + * the <code>Object</code> value to be printed */ @Override - public void println(Object x) { - synchronized (lock) { + public void println(Object x) + { + synchronized (lock) + { this.print(x); this.println(); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java index 35dc953312..9f45293647 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 2004-2010 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,9 +29,9 @@ import org.eclipse.jetty.util.log.Log; */ public class SocketEndPoint extends StreamEndPoint { - Socket _socket; - InetSocketAddress _local; - InetSocketAddress _remote; + final Socket _socket; + final InetSocketAddress _local; + final InetSocketAddress _remote; /** * @@ -41,6 +41,23 @@ public class SocketEndPoint extends StreamEndPoint { super(socket.getInputStream(),socket.getOutputStream()); _socket=socket; + _local=(InetSocketAddress)_socket.getLocalSocketAddress(); + _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); + super.setMaxIdleTime(_socket.getSoTimeout()); + } + + /** + * + */ + protected SocketEndPoint(Socket socket, int maxIdleTime) + throws IOException + { + super(socket.getInputStream(),socket.getOutputStream()); + _socket=socket; + _local=(InetSocketAddress)_socket.getLocalSocketAddress(); + _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); + _socket.setSoTimeout(maxIdleTime>0?maxIdleTime:0); + super.setMaxIdleTime(maxIdleTime); } /* (non-Javadoc) @@ -52,27 +69,25 @@ public class SocketEndPoint extends StreamEndPoint return super.isOpen() && _socket!=null && !_socket.isClosed() && !_socket.isInputShutdown() && !_socket.isOutputShutdown(); } + + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.io.bio.StreamEndPoint#shutdownOutput() + */ + @Override + public void shutdownOutput() throws IOException + { + if (!_socket.isClosed() && !_socket.isOutputShutdown()) + _socket.shutdownOutput(); + } + /* (non-Javadoc) * @see org.eclipse.io.BufferIO#close() */ @Override public void close() throws IOException { - if (!_socket.isClosed() && !_socket.isOutputShutdown()) - { - try - { - _socket.shutdownOutput(); - } - catch(IOException e) - { - Log.ignore(e); - } - catch(UnsupportedOperationException e) - { - Log.ignore(e); - } - } _socket.close(); _in=null; _out=null; @@ -86,9 +101,6 @@ public class SocketEndPoint extends StreamEndPoint @Override public String getLocalAddr() { - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) return StringUtil.ALL_INTERFACES; @@ -102,9 +114,6 @@ public class SocketEndPoint extends StreamEndPoint @Override public String getLocalHost() { - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) return StringUtil.ALL_INTERFACES; @@ -119,8 +128,6 @@ public class SocketEndPoint extends StreamEndPoint public int getLocalPort() { if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null) return -1; return _local.getPort(); } @@ -133,8 +140,6 @@ public class SocketEndPoint extends StreamEndPoint public String getRemoteAddr() { if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return null; InetAddress addr = _remote.getAddress(); return ( addr == null ? null : addr.getHostAddress() ); @@ -148,8 +153,6 @@ public class SocketEndPoint extends StreamEndPoint public String getRemoteHost() { if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return null; return _remote.getAddress().getCanonicalHostName(); } @@ -162,8 +165,6 @@ public class SocketEndPoint extends StreamEndPoint public int getRemotePort() { if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return -1; return _remote.getPort(); } @@ -177,4 +178,18 @@ public class SocketEndPoint extends StreamEndPoint { return _socket; } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.io.bio.StreamEndPoint#setMaxIdleTime(int) + */ + @Override + public void setMaxIdleTime(int timeMs) throws IOException + { + if (timeMs!=getMaxIdleTime()) + _socket.setSoTimeout(timeMs>0?timeMs:0); + super.setMaxIdleTime(timeMs); + } + + } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java index 355ac3bd81..24e1b9e0ab 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java @@ -31,6 +31,7 @@ public class StreamEndPoint implements EndPoint { InputStream _in; OutputStream _out; + int _maxIdleTime; /** * @@ -72,6 +73,10 @@ public class StreamEndPoint implements EndPoint return !isOpen(); } + public void shutdownOutput() throws IOException + { + } + /* * @see org.eclipse.io.BufferIO#close() */ @@ -280,5 +285,17 @@ public class StreamEndPoint implements EndPoint { return false; } + + /* ------------------------------------------------------------ */ + public int getMaxIdleTime() + { + return _maxIdleTime; + } + + /* ------------------------------------------------------------ */ + public void setMaxIdleTime(int timeMs) throws IOException + { + _maxIdleTime=timeMs; + } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java index 762e9380df..c9628b86ab 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java @@ -29,27 +29,58 @@ import org.eclipse.jetty.util.log.Log; /** + * Channel End Point. + * <p>Holds the channel and socket for an NIO endpoint. * - * - * To change the template for this generated type comment go to - * Window - Preferences - Java - Code Generation - Code and Comments */ public class ChannelEndPoint implements EndPoint { protected final ByteChannel _channel; protected final ByteBuffer[] _gather2=new ByteBuffer[2]; protected final Socket _socket; - protected InetSocketAddress _local; - protected InetSocketAddress _remote; + protected final InetSocketAddress _local; + protected final InetSocketAddress _remote; + protected int _maxIdleTime; /** * */ - public ChannelEndPoint(ByteChannel channel) + public ChannelEndPoint(ByteChannel channel) throws IOException { super(); this._channel = channel; _socket=(channel instanceof SocketChannel)?((SocketChannel)channel).socket():null; + if (_socket!=null) + { + _local=(InetSocketAddress)_socket.getLocalSocketAddress(); + _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); + _maxIdleTime=_socket.getSoTimeout(); + } + else + { + _local=_remote=null; + } + } + + /** + * + */ + protected ChannelEndPoint(ByteChannel channel, int maxIdleTime) throws IOException + { + this._channel = channel; + _maxIdleTime=maxIdleTime; + _socket=(channel instanceof SocketChannel)?((SocketChannel)channel).socket():null; + if (_socket!=null) + { + _local=(InetSocketAddress)_socket.getLocalSocketAddress(); + _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); + _socket.setSoTimeout(_maxIdleTime); + } + else + { + _local=_remote=null; + } + } public boolean isBlocking() @@ -78,34 +109,23 @@ public class ChannelEndPoint implements EndPoint /* (non-Javadoc) * @see org.eclipse.io.EndPoint#close() */ - public void close() throws IOException + public void shutdownOutput() throws IOException { - if (_channel.isOpen()) + if (_channel.isOpen() && _channel instanceof SocketChannel) { - try - { - if (_channel instanceof SocketChannel) - { - // TODO - is this really required? - Socket socket= ((SocketChannel)_channel).socket(); - if (!socket.isClosed()&&!socket.isOutputShutdown()) - socket.shutdownOutput(); - } - } - catch(IOException e) - { - Log.ignore(e); - } - catch(UnsupportedOperationException e) - { - Log.ignore(e); - } - finally - { - _channel.close(); - } + Socket socket= ((SocketChannel)_channel).socket(); + if (!socket.isClosed()&&!socket.isOutputShutdown()) + socket.shutdownOutput(); } } + + /* (non-Javadoc) + * @see org.eclipse.io.EndPoint#close() + */ + public void close() throws IOException + { + _channel.close(); + } /* (non-Javadoc) * @see org.eclipse.io.EndPoint#fill(org.eclipse.io.Buffer) @@ -317,13 +337,8 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return null; - - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) return StringUtil.ALL_INTERFACES; - return _local.getAddress().getHostAddress(); } @@ -335,13 +350,8 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return null; - - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) return StringUtil.ALL_INTERFACES; - return _local.getAddress().getCanonicalHostName(); } @@ -353,9 +363,6 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return 0; - - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); if (_local==null) return -1; return _local.getPort(); @@ -369,10 +376,6 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return null; - - if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return null; return _remote.getAddress().getHostAddress(); @@ -386,10 +389,6 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return null; - - if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return null; return _remote.getAddress().getCanonicalHostName(); @@ -403,10 +402,6 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return 0; - - if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - return _remote==null?-1:_remote.getPort(); } @@ -442,4 +437,21 @@ public class ChannelEndPoint implements EndPoint { return false; } + + /* ------------------------------------------------------------ */ + public int getMaxIdleTime() + { + return _maxIdleTime; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.io.bio.StreamEndPoint#setMaxIdleTime(int) + */ + public void setMaxIdleTime(int timeMs) throws IOException + { + if (_socket!=null && timeMs!=_maxIdleTime) + _socket.setSoTimeout(timeMs>0?timeMs:0); + _maxIdleTime=timeMs; + } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java index 87c97a84ed..7f5f2afc79 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java @@ -46,10 +46,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, private boolean _readBlocked; private boolean _writeBlocked; private boolean _open; - private final Timeout.Task _idleTask = new IdleTask(); + private volatile long _idleTimestamp; /* ------------------------------------------------------------ */ public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) + throws IOException { super(channel); @@ -61,7 +62,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, _key = key; _connection = _manager.newConnection(channel,this); - _manager.endPointOpened(this); scheduleIdle(); } @@ -198,13 +198,22 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, /* ------------------------------------------------------------ */ public void scheduleIdle() { - _selectSet.scheduleIdle(_idleTask); + _idleTimestamp=System.currentTimeMillis(); } /* ------------------------------------------------------------ */ public void cancelIdle() { - _selectSet.cancelIdle(_idleTask); + _idleTimestamp=0; + } + + /* ------------------------------------------------------------ */ + public void checkIdleTimestamp(long now) + { + if (_idleTimestamp!=0 && _maxIdleTime!=0 && now>(_idleTimestamp+_maxIdleTime)) + { + idleExpired(); + } } /* ------------------------------------------------------------ */ @@ -336,6 +345,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, finally { _writeBlocked=false; + if (_idleTimestamp!=-1) + scheduleIdle(); } } return true; @@ -424,7 +435,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, cancelIdle(); if (_open) - _manager.endPointClosed(this); + { + _selectSet.destroyEndPoint(this); + } _open=false; _key = null; } @@ -437,7 +450,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, } else { - if (_key.isValid()) + if (_key!=null && _key.isValid()) _key.interestOps(0); else _key=null; @@ -450,7 +463,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, cancelIdle(); if (_open) - _manager.endPointClosed(this); + { + _selectSet.destroyEndPoint(this); + } _open=false; _key = null; } @@ -548,41 +563,27 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, synchronized(this) { return "SCEP@" + hashCode() + "\t[d=" + _dispatched + ",io=" + _interestOps+ - ",w=" + _writable + ",b=" + _readBlocked + "|" + _writeBlocked + "]"; + ",w=" + _writable + ",rb=" + _readBlocked + ",wb=" + _writeBlocked + "]"; } } /* ------------------------------------------------------------ */ - public Timeout.Task getTimeoutTask() - { - return _idleTask; - } - - /* ------------------------------------------------------------ */ public SelectSet getSelectSet() { return _selectSet; } /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - private class IdleTask extends Timeout.Task + /** + * Don't set the SoTimeout + * @see org.eclipse.jetty.io.nio.ChannelEndPoint#setMaxIdleTime(int) + */ + @Override + public void setMaxIdleTime(int timeMs) throws IOException { - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.thread.Timeout.Task#expire() - */ - @Override - public void expired() - { - idleExpired(); - } - - @Override - public String toString() - { - return "TimeoutTask:" + SelectChannelEndPoint.this.toString(); - } + _maxIdleTime=timeMs; } + + + } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java index 1c30409a02..52d47e0d1e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java @@ -21,7 +21,11 @@ import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.ArrayList; -import java.util.List; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentMap; import org.eclipse.jetty.io.ConnectedEndPoint; import org.eclipse.jetty.io.Connection; @@ -39,32 +43,31 @@ import org.eclipse.jetty.util.thread.Timeout.Task; * <p> * This class works around a number of know JVM bugs. For details * see http://wiki.eclipse.org/Jetty/Feature/JVM_NIO_Bug - * */ public abstract class SelectorManager extends AbstractLifeCycle { // TODO Tune these by approx system speed. private static final int __JVMBUG_THRESHHOLD=Integer.getInteger("org.mortbay.io.nio.JVMBUG_THRESHHOLD",512).intValue(); private static final int __MONITOR_PERIOD=Integer.getInteger("org.mortbay.io.nio.MONITOR_PERIOD",1000).intValue(); - private static final int __MAX_SELECTS=Integer.getInteger("org.mortbay.io.nio.MAX_SELECTS",15000).intValue(); + private static final int __MAX_SELECTS=Integer.getInteger("org.mortbay.io.nio.MAX_SELECTS",25000).intValue(); private static final int __BUSY_PAUSE=Integer.getInteger("org.mortbay.io.nio.BUSY_PAUSE",50).intValue(); private static final int __BUSY_KEY=Integer.getInteger("org.mortbay.io.nio.BUSY_KEY",-1).intValue(); - private long _maxIdleTime; + private int _maxIdleTime; + private int _lowResourcesMaxIdleTime; private long _lowResourcesConnections; - private long _lowResourcesMaxIdleTime; - private transient SelectSet[] _selectSet; + private SelectSet[] _selectSet; private int _selectSets=1; private volatile int _set; /* ------------------------------------------------------------ */ /** * @param maxIdleTime The maximum period in milli seconds that a connection may be idle before it is closed. - * @see {@link #setLowResourcesMaxIdleTime(long)} + * @see #setLowResourcesMaxIdleTime(long) */ public void setMaxIdleTime(long maxIdleTime) { - _maxIdleTime=maxIdleTime; + _maxIdleTime=(int)maxIdleTime; } /* ------------------------------------------------------------ */ @@ -80,7 +83,7 @@ public abstract class SelectorManager extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** - * @return + * @return the max idle time */ public long getMaxIdleTime() { @@ -89,21 +92,33 @@ public abstract class SelectorManager extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** - * @return + * @return the number of select sets in use */ public int getSelectSets() { return _selectSets; } - + + /* ------------------------------------------------------------ */ + /** + * @param i + * @return The select set + */ + public SelectSet getSelectSet(int i) + { + return _selectSet[i]; + } /* ------------------------------------------------------------ */ /** Register a channel * @param channel * @param att Attached Object - * @throws IOException */ public void register(SocketChannel channel, Object att) { + // The ++ increment here is not atomic, but it does not matter. + // so long as the value changes sometimes, then connections will + // be distributed over the available sets. + int s=_set++; s=s%_selectSets; SelectSet[] sets=_selectSet; @@ -116,10 +131,8 @@ public abstract class SelectorManager extends AbstractLifeCycle } /* ------------------------------------------------------------ */ - /** Register a serverchannel + /** Register a {@link ServerSocketChannel} * @param acceptChannel - * @return - * @throws IOException */ public void register(ServerSocketChannel acceptChannel) { @@ -144,7 +157,7 @@ public abstract class SelectorManager extends AbstractLifeCycle * Set the number of connections, which if exceeded places this manager in low resources state. * This is not an exact measure as the connection count is averaged over the select sets. * @param lowResourcesConnections the number of connections - * @see {@link #setLowResourcesMaxIdleTime(long)} + * @see #setLowResourcesMaxIdleTime(long) */ public void setLowResourcesConnections(long lowResourcesConnections) { @@ -163,11 +176,11 @@ public abstract class SelectorManager extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** * @param lowResourcesMaxIdleTime the period in ms that a connection is allowed to be idle when this SelectSet has more connections than {@link #getLowResourcesConnections()} - * @see {@link #setMaxIdleTime(long)} + * @see #setMaxIdleTime(long) */ public void setLowResourcesMaxIdleTime(long lowResourcesMaxIdleTime) { - _lowResourcesMaxIdleTime=lowResourcesMaxIdleTime; + _lowResourcesMaxIdleTime=(int)lowResourcesMaxIdleTime; } /* ------------------------------------------------------------ */ @@ -184,8 +197,8 @@ public abstract class SelectorManager extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** - * @param key - * @return + * @param key the selection key + * @return the SocketChannel created on accept * @throws IOException */ protected abstract SocketChannel acceptChannel(SelectionKey key) throws IOException; @@ -245,10 +258,11 @@ public abstract class SelectorManager extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** + * Create a new end point * @param channel * @param selectSet - * @param sKey - * @return + * @param sKey the selection key + * @return the new endpoint {@link SelectChannelEndPoint} * @throws IOException */ protected abstract SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey sKey) throws IOException; @@ -295,13 +309,13 @@ public abstract class SelectorManager extends AbstractLifeCycle public class SelectSet { private final int _setID; - private final Timeout _idleTimeout; private final Timeout _timeout; - private final List<Object>[] _changes; - - private int _change; - private int _nextSet; + + private final ConcurrentLinkedQueue<Object> _changes = new ConcurrentLinkedQueue<Object>(); + private Selector _selector; + + private int _nextSet; private volatile Thread _selecting; private int _jvmBug; private int _selects; @@ -315,21 +329,20 @@ public abstract class SelectorManager extends AbstractLifeCycle private int _jvmFix0; private int _jvmFix1; private int _jvmFix2; + private volatile long _idleTick; + private ConcurrentMap<SelectChannelEndPoint,Object> _endPoints = new ConcurrentHashMap<SelectChannelEndPoint, Object>(); /* ------------------------------------------------------------ */ SelectSet(int acceptorID) throws Exception { _setID=acceptorID; - _idleTimeout = new Timeout(this); - _idleTimeout.setDuration(getMaxIdleTime()); + _idleTick = System.currentTimeMillis(); _timeout = new Timeout(this); _timeout.setDuration(0L); - _changes = new List[] {new ArrayList(),new ArrayList()}; // create a selector; _selector = Selector.open(); - _change=0; _monitorStart=System.currentTimeMillis(); _monitorNext=_monitorStart+__MONITOR_PERIOD; _log=_monitorStart+60000; @@ -338,10 +351,7 @@ public abstract class SelectorManager extends AbstractLifeCycle /* ------------------------------------------------------------ */ public void addChange(Object point) { - synchronized (_changes) - { - _changes[_change].add(point); - } + _changes.add(point); } /* ------------------------------------------------------------ */ @@ -356,12 +366,6 @@ public abstract class SelectorManager extends AbstractLifeCycle } /* ------------------------------------------------------------ */ - public void cancelIdle(Timeout.Task task) - { - task.cancel(); - } - - /* ------------------------------------------------------------ */ /** * Select and dispatch tasks found from changes and the selector. * @@ -372,44 +376,36 @@ public abstract class SelectorManager extends AbstractLifeCycle try { _selecting=Thread.currentThread(); - List<?> changes; - final Selector selector; - synchronized (_changes) - { - changes=_changes[_change]; - _change=_change==0?1:0; - selector=_selector; - } + final Selector selector=_selector; // Make any key changes required - final int size=changes.size(); - for (int i = 0; i < size; i++) + Object change; + int changes=_changes.size(); + while (changes-->0 && (change=_changes.poll())!=null) { try { - Object o = changes.get(i); - - if (o instanceof EndPoint) + if (change instanceof EndPoint) { // Update the operations for a key. - SelectChannelEndPoint endpoint = (SelectChannelEndPoint)o; + SelectChannelEndPoint endpoint = (SelectChannelEndPoint)change; endpoint.doUpdateKey(); } - else if (o instanceof Runnable) + else if (change instanceof Runnable) { - dispatch((Runnable)o); + dispatch((Runnable)change); } - else if (o instanceof ChangeSelectableChannel) + else if (change instanceof ChangeSelectableChannel) { // finish accepting/connecting this connection - final ChangeSelectableChannel asc = (ChangeSelectableChannel)o; + final ChangeSelectableChannel asc = (ChangeSelectableChannel)change; final SelectableChannel channel=asc._channel; final Object att = asc._attachment; if ((channel instanceof SocketChannel) && ((SocketChannel)channel).isConnected()) { SelectionKey key = channel.register(selector,SelectionKey.OP_READ,att); - SelectChannelEndPoint endpoint = newEndPoint((SocketChannel)channel,this,key); + SelectChannelEndPoint endpoint = createEndPoint((SocketChannel)channel,key); key.attach(endpoint); endpoint.schedule(); } @@ -418,14 +414,14 @@ public abstract class SelectorManager extends AbstractLifeCycle channel.register(selector,SelectionKey.OP_CONNECT,att); } } - else if (o instanceof SocketChannel) + else if (change instanceof SocketChannel) { - final SocketChannel channel=(SocketChannel)o; + final SocketChannel channel=(SocketChannel)change; if (channel.isConnected()) { SelectionKey key = channel.register(selector,SelectionKey.OP_READ,null); - SelectChannelEndPoint endpoint = newEndPoint(channel,this,key); + SelectChannelEndPoint endpoint = createEndPoint(channel,key); key.attach(endpoint); endpoint.schedule(); } @@ -434,17 +430,17 @@ public abstract class SelectorManager extends AbstractLifeCycle channel.register(selector,SelectionKey.OP_CONNECT,null); } } - else if (o instanceof ServerSocketChannel) + else if (change instanceof ServerSocketChannel) { - ServerSocketChannel channel = (ServerSocketChannel)o; + ServerSocketChannel channel = (ServerSocketChannel)change; channel.register(getSelector(),SelectionKey.OP_ACCEPT); } - else if (o instanceof ChangeTask) + else if (change instanceof ChangeTask) { - ((ChangeTask)o).run(); + ((ChangeTask)change).run(); } else - throw new IllegalArgumentException(o.toString()); + throw new IllegalArgumentException(change.toString()); } catch (Exception e) { @@ -454,28 +450,15 @@ public abstract class SelectorManager extends AbstractLifeCycle Log.debug(e); } } - changes.clear(); - long idle_next; long retry_next; long now=System.currentTimeMillis(); - synchronized (this) - { - _idleTimeout.setNow(now); - _timeout.setNow(now); - - if (_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections) - _idleTimeout.setDuration(_lowResourcesMaxIdleTime); - else - _idleTimeout.setDuration(_maxIdleTime); - idle_next=_idleTimeout.getTimeToNext(); - retry_next=_timeout.getTimeToNext(); - } + _timeout.setNow(now); + + retry_next=_timeout.getTimeToNext(); // workout how low to wait in select - long wait = 1000L; // not getMaxIdleTime() as the now value of the idle timers needs to be updated. - if (idle_next >= 0 && wait > idle_next) - wait = idle_next; + long wait = 1000L; if (wait > 0 && retry_next >= 0 && wait > retry_next) wait = retry_next; @@ -498,7 +481,6 @@ public abstract class SelectorManager extends AbstractLifeCycle long before=now; int selected=selector.select(wait); now = System.currentTimeMillis(); - _idleTimeout.setNow(now); _timeout.setNow(now); _selects++; @@ -521,16 +503,16 @@ public abstract class SelectorManager extends AbstractLifeCycle if (now>_log) { if (_paused>0) - Log.info(this+" Busy selector - injecting delay "+_paused+" times"); + Log.debug(this+" Busy selector - injecting delay "+_paused+" times"); if (_jvmFix2>0) - Log.info(this+" JVM BUG(s) - injecting delay"+_jvmFix2+" times"); + Log.debug(this+" JVM BUG(s) - injecting delay"+_jvmFix2+" times"); if (_jvmFix1>0) - Log.info(this+" JVM BUG(s) - recreating selector "+_jvmFix1+" times, cancelled keys "+_jvmFix0+" times"); + Log.debug(this+" JVM BUG(s) - recreating selector "+_jvmFix1+" times, cancelled keys "+_jvmFix0+" times"); else if(Log.isDebugEnabled() && _jvmFix0>0) - Log.info(this+" JVM BUG(s) - cancelled keys "+_jvmFix0+" times"); + Log.debug(this+" JVM BUG(s) - cancelled keys "+_jvmFix0+" times"); _paused=0; _jvmFix2=0; _jvmFix1=0; @@ -679,7 +661,8 @@ public abstract class SelectorManager extends AbstractLifeCycle { // bind connections to this select set. SelectionKey cKey = channel.register(_selectSet[_nextSet].getSelector(), SelectionKey.OP_READ); - SelectChannelEndPoint endpoint=newEndPoint(channel,_selectSet[_nextSet],cKey); + + SelectChannelEndPoint endpoint=_selectSet[_nextSet].createEndPoint(channel,cKey); cKey.attach(endpoint); if (endpoint != null) endpoint.schedule(); @@ -709,7 +692,7 @@ public abstract class SelectorManager extends AbstractLifeCycle if (connected) { key.interestOps(SelectionKey.OP_READ); - SelectChannelEndPoint endpoint = newEndPoint(channel,this,key); + SelectChannelEndPoint endpoint = createEndPoint(channel,key); key.attach(endpoint); endpoint.schedule(); } @@ -723,7 +706,7 @@ public abstract class SelectorManager extends AbstractLifeCycle { // Wrap readable registered channel in an endpoint SocketChannel channel = (SocketChannel)key.channel(); - SelectChannelEndPoint endpoint = newEndPoint(channel,this,key); + SelectChannelEndPoint endpoint = createEndPoint(channel,key); key.attach(endpoint); if (key.isReadable()) endpoint.schedule(); @@ -749,9 +732,6 @@ public abstract class SelectorManager extends AbstractLifeCycle // Everything always handled selector.selectedKeys().clear(); - // tick over the timers - _idleTimeout.tick(now); - _timeout.setNow(now); Task task = _timeout.expired(); while (task!=null) @@ -763,6 +743,27 @@ public abstract class SelectorManager extends AbstractLifeCycle task = _timeout.expired(); } + + // Idle tick + if (now-_idleTick>1000) + { + _idleTick=now; + + final long idle_now=((_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections)) + ?(now+_maxIdleTime-_lowResourcesMaxIdleTime) + :now; + + dispatch(new Runnable() + { + public void run() + { + for (SelectChannelEndPoint endp:_endPoints.keySet()) + { + endp.checkIdleTimestamp(idle_now); + } + } + }); + } } catch (CancelledKeyException e) { @@ -783,15 +784,7 @@ public abstract class SelectorManager extends AbstractLifeCycle /* ------------------------------------------------------------ */ public long getNow() { - return _idleTimeout.getNow(); - } - - /* ------------------------------------------------------------ */ - public void scheduleIdle(Timeout.Task task) - { - if (_idleTimeout.getDuration() <= 0) - return; - _idleTimeout.schedule(task); + return _timeout.getNow(); } /* ------------------------------------------------------------ */ @@ -819,6 +812,22 @@ public abstract class SelectorManager extends AbstractLifeCycle if (selector!=null) selector.wakeup(); } + + /* ------------------------------------------------------------ */ + private SelectChannelEndPoint createEndPoint(SocketChannel channel, SelectionKey sKey) throws IOException + { + SelectChannelEndPoint endp = newEndPoint(channel,this,sKey); + endPointOpened(endp); + _endPoints.put(endp,this); + return endp; + } + + /* ------------------------------------------------------------ */ + public void destroyEndPoint(SelectChannelEndPoint endp) + { + _endPoints.remove(endp); + endPointClosed(endp); + } /* ------------------------------------------------------------ */ Selector getSelector() @@ -864,7 +873,6 @@ public abstract class SelectorManager extends AbstractLifeCycle selecting=_selecting!=null; } - _idleTimeout.cancelAll(); _timeout.cancelAll(); try { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslSelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslSelectChannelEndPoint.java index 04c9c21225..0133c62920 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslSelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslSelectChannelEndPoint.java @@ -11,7 +11,7 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -package org.eclipse.jetty.http.ssl; +package org.eclipse.jetty.io.nio; import java.io.IOException; import java.nio.ByteBuffer; @@ -24,13 +24,9 @@ import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import org.eclipse.jetty.http.Parser; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.io.nio.NIOBuffer; -import org.eclipse.jetty.io.nio.SelectChannelEndPoint; -import org.eclipse.jetty.io.nio.SelectorManager; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -54,12 +50,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint private final SSLEngine _engine; private final SSLSession _session; - private final ByteBuffer _inBuffer; - private final NIOBuffer _inNIOBuffer; - private final ByteBuffer _outBuffer; - private final NIOBuffer _outNIOBuffer; + private volatile NIOBuffer _inNIOBuffer; + private volatile NIOBuffer _outNIOBuffer; - private final NIOBuffer[] _reuseBuffer=new NIOBuffer[2]; private final ByteBuffer[] _gather=new ByteBuffer[2]; private boolean _closing=false; @@ -70,7 +63,6 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint private final boolean _debug = __log.isDebugEnabled(); // snapshot debug status for optimizer - /* ------------------------------------------------------------ */ public SslSelectChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine) throws IOException @@ -82,15 +74,46 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint _engine=engine; _session=engine.getSession(); - // TODO pool buffers and use only when needed. - _outNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize()); - _outBuffer=_outNIOBuffer.getByteBuffer(); - _inNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize()); - _inBuffer=_inNIOBuffer.getByteBuffer(); - if (_debug) __log.debug(_session+" channel="+channel); } - + + /* ------------------------------------------------------------ */ + private void needOutBuffer() + { + if (_outNIOBuffer==null) + { + _outNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize()); + } + } + + /* ------------------------------------------------------------ */ + private void needInBuffer() + { + if (_inNIOBuffer==null) + { + _inNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize()); + } + } + + /* ------------------------------------------------------------ */ + private void freeOutBuffer() + { + if (_outNIOBuffer.length()==0) + { + _buffers.returnBuffer(_outNIOBuffer); + _outNIOBuffer=null; + } + } + + /* ------------------------------------------------------------ */ + private void freeInBuffer() + { + if (_inNIOBuffer.length()==0) + { + _buffers.returnBuffer(_inNIOBuffer); + _inNIOBuffer=null; + } + } /* ------------------------------------------------------------ */ /** @@ -120,43 +143,11 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint { Log.info(""+_result); } - - /* ------------------------------------------------------------ */ - /* (non-Javadoc) - * @see org.eclipse.io.nio.SelectChannelEndPoint#idleExpired() - */ - @Override - protected void idleExpired() - { - try - { - getSelectManager().dispatch(new Runnable() - { - public void run() - { - doIdleExpired(); - } - }); - } - catch(Exception e) - { - Log.ignore(e); - } - } - - /* ------------------------------------------------------------ */ - protected void doIdleExpired() - { - super.idleExpired(); - } - /* ------------------------------------------------------------ */ @Override - public void close() throws IOException + public void shutdownOutput() throws IOException { // TODO - this really should not be done in a loop here - but with async callbacks. - - _closing=true; long end=System.currentTimeMillis()+((SocketChannel)_channel).socket().getSoTimeout(); try { @@ -224,19 +215,22 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint case NEED_WRAP: { + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); try - { + { _outNIOBuffer.compact(); int put=_outNIOBuffer.putIndex(); - _outBuffer.position(put); + out_buffer.position(put); _result=null; - _result=_engine.wrap(__NO_BUFFERS,_outBuffer); + _result=_engine.wrap(__NO_BUFFERS,out_buffer); if (_debug) __log.debug(_session+" close wrap "+_result); _outNIOBuffer.setPutIndex(put+_result.bytesProduced()); } finally { - _outBuffer.position(0); + out_buffer.position(0); + freeOutBuffer(); } break; @@ -244,26 +238,33 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } } } - catch(IOException e) + catch (InterruptedException e) { Log.ignore(e); } - catch (InterruptedException e) + } + + + /* ------------------------------------------------------------ */ + @Override + public void close() throws IOException + { + try + { + _closing=true; + shutdownOutput(); + } + catch(IOException e) { Log.ignore(e); } finally { super.close(); - if (_inNIOBuffer!=null) _buffers.returnBuffer(_inNIOBuffer); if (_outNIOBuffer!=null) _buffers.returnBuffer(_outNIOBuffer); - if (_reuseBuffer[0]!=null) - _buffers.returnBuffer(_reuseBuffer[0]); - if (_reuseBuffer[1]!=null) - _buffers.returnBuffer(_reuseBuffer[1]); } } @@ -271,7 +272,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint /* ------------------------------------------------------------ */ /** Fill the buffer with unencrypted bytes. - * Called by a {@link Parser} instance when more data is + * Called by a Http Parser when more data is * needed to continue parsing a request or a response. */ @Override @@ -373,7 +374,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint // The SSL needs to send some handshake data to the other side, // so let fill become a flush for a little bit. wraps++; - synchronized(_outBuffer) + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); + synchronized(out_buffer) { try { @@ -381,9 +384,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint // generate required handshake messages into _outNIOBuffer _outNIOBuffer.compact(); int put=_outNIOBuffer.putIndex(); - _outBuffer.position(); + out_buffer.position(); _result=null; - _result=_engine.wrap(__NO_BUFFERS,_outBuffer); + _result=_engine.wrap(__NO_BUFFERS,out_buffer); if (_debug) __log.debug(_session+" fill wrap "+_result); switch(_result.getStatus()) { @@ -398,13 +401,14 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } finally { - _outBuffer.position(0); + out_buffer.position(0); } } // flush the encrypted outNIOBuffer flush(); - + freeOutBuffer(); + break; } } @@ -450,7 +454,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint if (buffer!=null) available+=buffer.length(); - int tries=0; + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); loop: while (true) { if (_outNIOBuffer.length()>0) @@ -529,15 +534,15 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint case NEED_WRAP: { checkRenegotiate(); - synchronized(_outBuffer) + synchronized(out_buffer) { try { _outNIOBuffer.compact(); int put=_outNIOBuffer.putIndex(); - _outBuffer.position(); + out_buffer.position(); _result=null; - _result=_engine.wrap(__NO_BUFFERS,_outBuffer); + _result=_engine.wrap(__NO_BUFFERS,out_buffer); if (_debug) __log.debug(_session+" flush wrap "+_result); switch(_result.getStatus()) { @@ -551,7 +556,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } finally { - _outBuffer.position(0); + out_buffer.position(0); } } @@ -563,7 +568,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } } } - + + freeOutBuffer(); return consumed; } @@ -571,6 +577,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint @Override public void flush() throws IOException { + if (_outNIOBuffer==null) + return; + int len=_outNIOBuffer.length(); if (isBufferingOutput()) { @@ -612,6 +621,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint */ private boolean unwrap(ByteBuffer buffer) throws IOException { + needInBuffer(); + ByteBuffer in_buffer=_inNIOBuffer.getByteBuffer(); + if (_inNIOBuffer.hasContent()) _inNIOBuffer.compact(); else @@ -636,7 +648,11 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint { if (_inNIOBuffer.length()==0) { - _outNIOBuffer.clear(); + if (_outNIOBuffer!=null) + { + _outNIOBuffer.clear(); + freeOutBuffer(); + } throw e; } break; @@ -648,7 +664,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint { if(!isOpen()) { - _outNIOBuffer.clear(); + if (_outNIOBuffer!=null) + _outNIOBuffer.clear(); throw new EofException(); } return false; @@ -659,12 +676,12 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint { // inBuffer is the NIO buffer inside the _inNIOBuffer, // so update its position and limit from the inNIOBuffer. - _inBuffer.position(_inNIOBuffer.getIndex()); - _inBuffer.limit(_inNIOBuffer.putIndex()); + in_buffer.position(_inNIOBuffer.getIndex()); + in_buffer.limit(_inNIOBuffer.putIndex()); _result=null; // Do the unwrap - _result=_engine.unwrap(_inBuffer,buffer); + _result=_engine.unwrap(in_buffer,buffer); if (_debug) __log.debug(_session+" unwrap unwrap "+_result); // skip the bytes consumed @@ -673,8 +690,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint finally { // reset the buffer so it can be managed by the _inNIOBuffer again. - _inBuffer.position(0); - _inBuffer.limit(_inBuffer.capacity()); + in_buffer.position(0); + in_buffer.limit(in_buffer.capacity()); + freeInBuffer(); } // handle the unwrap results @@ -692,7 +710,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint if(!isOpen()) { _inNIOBuffer.clear(); - _outNIOBuffer.clear(); + if (_outNIOBuffer!=null) + _outNIOBuffer.clear(); throw new EofException(); } return (total_filled > 0); @@ -712,51 +731,44 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint /* ------------------------------------------------------------ */ - private ByteBuffer extractOutputBuffer(Buffer buffer,int n) + private ByteBuffer extractOutputBuffer(Buffer buffer) { if (buffer.buffer() instanceof NIOBuffer) - { - NIOBuffer nBuf=(NIOBuffer)buffer.buffer(); - return nBuf.getByteBuffer(); - } - else - { - if (_reuseBuffer[n]==null) - _reuseBuffer[n] = (NIOBuffer)_buffers.getBuffer(_session.getApplicationBufferSize()); - NIOBuffer buf = _reuseBuffer[n]; - buf.clear(); - buf.put(buffer); - return buf.getByteBuffer(); - } + return ((NIOBuffer)buffer.buffer()).getByteBuffer(); + + return ByteBuffer.wrap(buffer.array()); } /* ------------------------------------------------------------ */ private int wrap(final Buffer header, final Buffer buffer) throws IOException { - _gather[0]=extractOutputBuffer(header,0); + _gather[0]=extractOutputBuffer(header); + synchronized(_gather[0]) { _gather[0].position(header.getIndex()); _gather[0].limit(header.putIndex()); - _gather[1]=extractOutputBuffer(buffer,1); + _gather[1]=extractOutputBuffer(buffer); synchronized(_gather[1]) { _gather[1].position(buffer.getIndex()); _gather[1].limit(buffer.putIndex()); - synchronized(_outBuffer) + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); + synchronized(out_buffer) { int consumed=0; try { _outNIOBuffer.clear(); - _outBuffer.position(0); - _outBuffer.limit(_outBuffer.capacity()); + out_buffer.position(0); + out_buffer.limit(out_buffer.capacity()); _result=null; - _result=_engine.wrap(_gather,_outBuffer); + _result=_engine.wrap(_gather,out_buffer); if (_debug) __log.debug(_session+" wrap wrap "+_result); _outNIOBuffer.setGetIndex(0); _outNIOBuffer.setPutIndex(_result.bytesProduced()); @@ -764,7 +776,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } finally { - _outBuffer.position(0); + out_buffer.position(0); if (consumed>0) { @@ -783,6 +795,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint _gather[1].limit(_gather[1].capacity()); } assert consumed==0; + + freeOutBuffer(); } } } @@ -810,22 +824,26 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint /* ------------------------------------------------------------ */ private int wrap(final Buffer buffer) throws IOException { - _gather[0]=extractOutputBuffer(buffer,0); + _gather[0]=extractOutputBuffer(buffer); synchronized(_gather[0]) { + ByteBuffer bb; + _gather[0].position(buffer.getIndex()); _gather[0].limit(buffer.putIndex()); int consumed=0; - synchronized(_outBuffer) + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); + synchronized(out_buffer) { try { _outNIOBuffer.clear(); - _outBuffer.position(0); - _outBuffer.limit(_outBuffer.capacity()); + out_buffer.position(0); + out_buffer.limit(out_buffer.capacity()); _result=null; - _result=_engine.wrap(_gather[0],_outBuffer); + _result=_engine.wrap(_gather[0],out_buffer); if (_debug) __log.debug(_session+" wrap wrap "+_result); _outNIOBuffer.setGetIndex(0); _outNIOBuffer.setPutIndex(_result.bytesProduced()); @@ -833,7 +851,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } finally { - _outBuffer.position(0); + out_buffer.position(0); if (consumed>0) { @@ -844,6 +862,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint _gather[0].limit(_gather[0].capacity()); } assert consumed==0; + + freeOutBuffer(); } } } @@ -869,14 +889,16 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint @Override public boolean isBufferingInput() { - return _inNIOBuffer.hasContent(); + final Buffer in = _inNIOBuffer; + return in==null?false:_inNIOBuffer.hasContent(); } /* ------------------------------------------------------------ */ @Override public boolean isBufferingOutput() { - return _outNIOBuffer.hasContent(); + final NIOBuffer b=_outNIOBuffer; + return b==null?false:b.hasContent(); } /* ------------------------------------------------------------ */ @@ -896,6 +918,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint @Override public String toString() { - return super.toString()+","+_engine.getHandshakeStatus()+", in/out="+_inNIOBuffer.length()+"/"+_outNIOBuffer.length()+" "+_result; + final NIOBuffer i=_inNIOBuffer; + final NIOBuffer o=_outNIOBuffer; + return super.toString()+","+_engine.getHandshakeStatus()+", in/out="+ + (i==null?0:_inNIOBuffer.length())+"/"+(o==null?0:o.length())+" "+_result; } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferCacheTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/BufferCacheTest.java index 542c9b7ef0..3d7d6e8a79 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferCacheTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/BufferCacheTest.java @@ -4,61 +4,42 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.io; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; -/* ------------------------------------------------------------------------------- */ /** - * - * + * */ -public class BufferCacheTest extends TestCase +public class BufferCacheTest { - final static String[] S= - { "S0", "S1", "s2", "s3" }; - - BufferCache cache; - - public BufferCacheTest(String arg0) - { - super(arg0); - } + private final static String[] S = {"S0", "S1", "s2", "s3" }; - public static void main(String[] args) - { - junit.textui.TestRunner.run(BufferCacheTest.class); - } + private BufferCache cache; - /** - * @see TestCase#setUp() - */ - @Override - protected void setUp() throws Exception + @Before + public void init() throws Exception { - super.setUp(); cache=new BufferCache(); cache.add(S[1],1); cache.add(S[2],2); cache.add(S[3],3); } - /** - * @see TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - } - + @Test public void testLookupIndex() { for (int i=0; i<S.length; i++) @@ -75,6 +56,7 @@ public class BufferCacheTest extends TestCase } } + @Test public void testGetBuffer() { for (int i=0; i<S.length; i++) @@ -90,6 +72,7 @@ public class BufferCacheTest extends TestCase } } + @Test public void testLookupBuffer() { for (int i=0; i<S.length; i++) @@ -100,35 +83,37 @@ public class BufferCacheTest extends TestCase assertEquals(S[i],b.toString()); if (i>0) - assertTrue(""+i,S[i]==b.toString()); + assertSame(""+i, S[i], b.toString()); else { - assertTrue(""+i,S[i]!=b.toString()); - assertEquals(""+i,S[i],b.toString()); + assertNotSame(""+i, S[i], b.toString()); + assertEquals(""+i, S[i], b.toString()); } } } + @Test public void testLookupPartialBuffer() { cache.add("44444",4); - + ByteArrayBuffer buf=new ByteArrayBuffer("44444"); Buffer b=cache.lookup(buf); assertEquals("44444",b.toString()); assertEquals(4,cache.getOrdinal(b)); - + buf=new ByteArrayBuffer("4444"); b=cache.lookup(buf); assertEquals(-1,cache.getOrdinal(b)); - + buf=new ByteArrayBuffer("44444x"); b=cache.lookup(buf); assertEquals(-1,cache.getOrdinal(b)); - + } + @Test public void testInsensitiveLookupBuffer() { for (int i=0; i<S.length; i++) @@ -139,12 +124,13 @@ public class BufferCacheTest extends TestCase assertTrue("test"+i,S[i].equalsIgnoreCase(b.toString())); if (i>0) - assertTrue("test"+i,S[i]==b.toString()); + assertSame("test"+i, S[i], b.toString()); else - assertTrue("test"+i,S[i]!=b.toString()); + assertNotSame("test"+i, S[i], b.toString()); } } + @Test public void testToString() { for (int i=0; i<S.length; i++) @@ -155,10 +141,9 @@ public class BufferCacheTest extends TestCase assertEquals(S[i],b); if (i>0) - assertTrue(S[i]==b); + assertSame(S[i], b); else - assertTrue(S[i]!=b); + assertNotSame(S[i], b); } } - } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/BufferTest.java index c335c27a92..fc96d189bb 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/BufferTest.java @@ -4,49 +4,40 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.io; import java.io.File; -import junit.framework.TestCase; - import org.eclipse.jetty.io.nio.DirectNIOBuffer; import org.eclipse.jetty.io.nio.IndirectNIOBuffer; import org.eclipse.jetty.io.nio.RandomAccessFileBuffer; import org.eclipse.jetty.util.StringUtil; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** - * * - * To change the template for this generated type comment go to - * Window - Preferences - Java - Code Generation - Code and Comments */ -public class BufferTest extends TestCase +public class BufferTest { - Buffer[] buffer; - - public static void main(String[] args) - { - } + private Buffer[] buffer; - /* - * @see TestCase#setUp() - */ - @Override - protected void setUp() throws Exception + @Before + public void init() throws Exception { - super.setUp(); File file = File.createTempFile("test",".buf"); file.deleteOnExit(); - file.createNewFile(); - + buffer=new Buffer[]{ new RandomAccessFileBuffer(file,10), new ByteArrayBuffer(10), @@ -55,37 +46,25 @@ public class BufferTest extends TestCase }; } - /* - * @see TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - } - - /* - * - */ - public void testBuffer() - throws Exception + @Test + public void testBuffer() throws Exception { for (int i=0;i<buffer.length;i++) { String t="t"+i; Buffer b = buffer[i]; - + assertEquals(t,0,b.length()); assertEquals(t,10,b.capacity()); assertEquals(t,10,b.space()); - + b.put((byte)0); b.put((byte)1); b.put((byte)2); assertEquals(t,3,b.length()); assertEquals(t,10,b.capacity()); assertEquals(t,7,b.space()); - + assertEquals(t,0,b.get()); assertEquals(t,1,b.get()); assertEquals(t,1,b.length()); @@ -93,34 +72,34 @@ public class BufferTest extends TestCase assertEquals(t,7,b.space()); b.compact(); assertEquals(t,9,b.space()); - + byte[] ba = { (byte)-1, (byte)3,(byte)4,(byte)5,(byte)6 }; - + b.put(ba,1,3); assertEquals(t,4,b.length()); assertEquals(t,6,b.space()); - + byte[] bg = new byte[4]; b.get(bg,1,2); assertEquals(t,2,bg[1]); assertEquals(t,3,bg[2]); - + //test getting 0 bytes returns 0 int count = b.get(bg,0,0); assertEquals(t,0, count); - + //read up to end count = b.get(bg,0,2); assertEquals(t, 2, count); - + //test reading past end returns -1 count = b.get(bg,0,1); assertEquals(t, -1, count); } } - - public void testHash() - throws Exception + + @Test + public void testHash() throws Exception { Buffer[] b= { @@ -129,42 +108,43 @@ public class BufferTest extends TestCase new DirectNIOBuffer(4096), }; b[2].put("TeSt1234 ".getBytes(StringUtil.__UTF8)); - + for (int i=0;i<b.length;i++) - assertEquals("t"+i,b[0].hashCode(),b[i].hashCode()); + assertEquals("t"+i,b[0].hashCode(),b[i].hashCode()); } - - public void testGet () - throws Exception + + @Test + public void testGet () throws Exception { Buffer buff = new ByteArrayBuffer(new byte[]{(byte)0,(byte)1,(byte)2,(byte)3,(byte)4,(byte)5}); - + byte[] readbuff = new byte[2]; - + int count = buff.get(readbuff, 0, 2); assertEquals(2, count); assertEquals(readbuff[0], (byte)0); assertEquals(readbuff[1], (byte)1); - + count = buff.get(readbuff, 0, 2); assertEquals(2, count); assertEquals(readbuff[0], (byte)2); assertEquals(readbuff[1], (byte)3); - + count = buff.get(readbuff, 0, 0); assertEquals(0, count); - + readbuff[0]=(byte)9; readbuff[1]=(byte)9; - + count = buff.get(readbuff, 0, 2); assertEquals(2, count); - + count = buff.get(readbuff, 0, 2); assertEquals(-1, count); - + } - + + @Test public void testInsensitive() { Buffer cs0 = new ByteArrayBuffer("Test 1234"); @@ -184,7 +164,7 @@ public class BufferTest extends TestCase assertTrue( cs0.equals(ci1)); assertTrue( cs0.equals(ci2)); assertTrue(!cs0.equals(ci3)); - + assertTrue( cs1.equals(cs0)); assertTrue( cs1.equals(cs1)); assertTrue(!cs1.equals(cs2)); @@ -193,7 +173,7 @@ public class BufferTest extends TestCase assertTrue( cs1.equals(ci1)); assertTrue( cs1.equals(ci2)); assertTrue(!cs1.equals(ci3)); - + assertTrue(!cs2.equals(cs0)); assertTrue(!cs2.equals(cs1)); assertTrue( cs2.equals(cs2)); @@ -211,8 +191,8 @@ public class BufferTest extends TestCase assertTrue(!cs3.equals(ci1)); assertTrue(!cs3.equals(ci2)); assertTrue( cs3.equals(ci3)); - - + + assertTrue( ci0.equals(cs0)); assertTrue( ci0.equals(cs1)); assertTrue( ci0.equals(cs2)); @@ -221,7 +201,7 @@ public class BufferTest extends TestCase assertTrue( ci0.equals(ci1)); assertTrue( ci0.equals(ci2)); assertTrue(!ci0.equals(ci3)); - + assertTrue( ci1.equals(cs0)); assertTrue( ci1.equals(cs1)); assertTrue( ci1.equals(cs2)); @@ -230,7 +210,7 @@ public class BufferTest extends TestCase assertTrue( ci1.equals(ci1)); assertTrue( ci1.equals(ci2)); assertTrue(!ci1.equals(ci3)); - + assertTrue( ci2.equals(cs0)); assertTrue( ci2.equals(cs1)); assertTrue( ci2.equals(cs2)); @@ -251,6 +231,7 @@ public class BufferTest extends TestCase } + @Test public void testView() { Buffer b = new ByteArrayBuffer(" Test 1234 ".getBytes()); @@ -259,7 +240,7 @@ public class BufferTest extends TestCase View v0 = new View(b); View v1 = new View(b); View v2 = new View(v0); - + String s=b.toString(); String s0=v0.toString(); String s1=v1.toString(); @@ -267,15 +248,13 @@ public class BufferTest extends TestCase String s3=v0.toString(); String s4=v1.toString(); String s5=v2.toString(); - + assertEquals(s, s0); assertEquals(s0, s1); assertEquals(s1, s2); assertEquals(s2, s3); assertEquals(s3, s4); assertEquals(s4, s5); - - } - + } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferUtilTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/BufferUtilTest.java index 1db375bee5..ce053e789e 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/BufferUtilTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/BufferUtilTest.java @@ -4,43 +4,29 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.io; -import junit.framework.TestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; -/* ------------------------------------------------------------------------------- */ /** - * + * */ -public class BufferUtilTest extends TestCase +public class BufferUtilTest { - - /** - * Constructor for BufferUtilTest. - * @param arg0 - */ - public BufferUtilTest(String arg0) - { - super(arg0); - } - - public static void main(String[] args) - { - junit.textui.TestRunner.run(BufferUtilTest.class); - } - - public void testToInt() - throws Exception + @Test + public void testToInt() throws Exception { - Buffer buf[] = + Buffer buf[] = { new ByteArrayBuffer("0"), new ByteArrayBuffer(" 42 "), @@ -50,29 +36,29 @@ public class BufferUtilTest extends TestCase new ByteArrayBuffer("-2147483648"), new ByteArrayBuffer("2147483647"), }; - + int val[] = { 0,42,43,-44,-45,-2147483648,2147483647 }; - + for (int i=0;i<buf.length;i++) assertEquals("t"+i, val[i], BufferUtil.toInt(buf[i])); } - public void testPutInt() - throws Exception + @Test + public void testPutInt() throws Exception { int val[] = { - 0,42,43,-44,-45,-2147483648,2147483647 + 0,42,43,-44,-45,Integer.MIN_VALUE,Integer.MAX_VALUE }; - + String str[] = { - "0","42","43","-44","-45","-2147483648","2147483647" + "0","42","43","-44","-45",""+Integer.MIN_VALUE,""+Integer.MAX_VALUE }; - + Buffer buffer = new ByteArrayBuffer(12); for (int i=0;i<val.length;i++) @@ -80,22 +66,45 @@ public class BufferUtilTest extends TestCase buffer.clear(); BufferUtil.putDecInt(buffer,val[i]); assertEquals("t"+i,str[i],BufferUtil.to8859_1_String(buffer)); - } + } + } + + @Test + public void testPutLong() throws Exception + { + long val[] = + { + 0L,42L,43L,-44L,-45L,Long.MIN_VALUE,Long.MAX_VALUE + }; + + String str[] = + { + "0","42","43","-44","-45",""+Long.MIN_VALUE,""+Long.MAX_VALUE + }; + + Buffer buffer = new ByteArrayBuffer(50); + + for (int i=0;i<val.length;i++) + { + buffer.clear(); + BufferUtil.putDecLong(buffer,val[i]); + assertEquals("t"+i,str[i],BufferUtil.to8859_1_String(buffer)); + } } - public void testPutHexInt() - throws Exception + @Test + public void testPutHexInt() throws Exception { int val[] = { 0,42,43,-44,-45,-2147483648,2147483647 }; - + String str[] = { "0","2A","2B","-2C","-2D","-80000000","7FFFFFFF" }; - + Buffer buffer = new ByteArrayBuffer(12); for (int i=0;i<val.length;i++) @@ -103,6 +112,6 @@ public class BufferUtilTest extends TestCase buffer.clear(); BufferUtil.putHexInt(buffer,val[i]); assertEquals("t"+i,str[i],BufferUtil.to8859_1_String(buffer)); - } + } } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java new file mode 100644 index 0000000000..c0a7d1a9dd --- /dev/null +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java @@ -0,0 +1,75 @@ +package org.eclipse.jetty.io; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.channels.SelectionKey; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.rmi.server.ServerCloneException; +import java.util.concurrent.Exchanger; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.net.ServerSocketFactory; + +import org.eclipse.jetty.io.bio.SocketEndPoint; +import org.eclipse.jetty.io.nio.IndirectNIOBuffer; +import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SelectorManager; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SelectorManager.SelectSet; +import org.junit.Assert; +import org.junit.Test; + +public class EndPointTest +{ + @Test + public void testSocketEndPoints() throws Exception + { + final ServerSocket server = new ServerSocket(); + server.bind(null); + + final Exchanger<Socket> accepted = new Exchanger<Socket>(); + new Thread(){ + public void run() + { + try + { + accepted.exchange(server.accept()); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }.start(); + + Socket s0 = new Socket(server.getInetAddress(),server.getLocalPort()); + Socket s1 = accepted.exchange(null,5,TimeUnit.SECONDS); + + SocketEndPoint in = new SocketEndPoint(s0); + SocketEndPoint out = new SocketEndPoint(s1); + + check(in,out); + } + + + private void check(EndPoint in, EndPoint out) throws Exception + { + String data="Now is the time for all good men to come to the aid of the party"; + Buffer send = new ByteArrayBuffer(data); + Buffer receive = new IndirectNIOBuffer(4096); + + int lo=out.flush(send); + int li=in.fill(receive); + + Assert.assertEquals(data.length(),lo); + Assert.assertEquals(data.length(),li); + Assert.assertEquals(data,receive.toString()); + + in.close(); + out.close(); + } +} diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java index 3d72037d2a..6b22b7d5d2 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.io; @@ -16,38 +16,17 @@ package org.eclipse.jetty.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import junit.framework.TestSuite; - import org.eclipse.jetty.util.IO; +import org.junit.Test; +import static org.junit.Assert.assertEquals; -/* ------------------------------------------------------------ */ -/** Util meta Tests. - * +/** + * */ -public class IOTest extends junit.framework.TestCase +public class IOTest { - public IOTest(String name) - { - super(name); - } - - public static junit.framework.Test suite() { - TestSuite suite = new TestSuite(IOTest.class); - return suite; - } - - /* ------------------------------------------------------------ */ - /** main. - */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - - - - /* ------------------------------------------------------------ */ + @Test public void testIO() throws InterruptedException { // Only a little test @@ -64,15 +43,13 @@ public class IOTest extends junit.framework.TestCase "The quick brown fox jumped over the lazy dog"); } - - - /* ------------------------------------------------------------ */ + @Test public void testStringSpeed() { String s="012345678901234567890000000000000000000000000"; char[] ca = new char[s.length()]; int loops=1000000; - + long start=System.currentTimeMillis(); long result=0; for (int loop=0;loop<loops;loop++) @@ -82,7 +59,7 @@ public class IOTest extends junit.framework.TestCase } long end=System.currentTimeMillis(); System.err.println("charAt "+(end-start)+" "+result); - + start=System.currentTimeMillis(); result=0; for (int loop=0;loop<loops;loop++) @@ -93,6 +70,5 @@ public class IOTest extends junit.framework.TestCase } end=System.currentTimeMillis(); System.err.println("getChars "+(end-start)+" "+result); - } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ThreadLocalBuffersTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ThreadLocalBuffersTest.java index 86b99325ab..fcf773b583 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ThreadLocalBuffersTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ThreadLocalBuffersTest.java @@ -4,56 +4,34 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.io; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicLong; -import junit.framework.TestCase; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; public class ThreadLocalBuffersTest - extends TestCase { public boolean _stress = Boolean.getBoolean("STRESS"); - private int _headerBufferSize = 6 * 1024; - - InnerBuffers httpBuffers; - - List<Thread> threadList = new ArrayList<Thread>(); - - int numThreads = _stress?100:10; - - int runTestLength = _stress?5000:1000; - - boolean runTest = false; - - AtomicLong buffersRetrieved; - - @Override - protected void setUp() - throws Exception - { - super.setUp(); - } - - @Override - protected void tearDown() - throws Exception - { - super.tearDown(); - } - - public void execAbstractBuffer() - throws Exception + private InnerBuffers httpBuffers; + private List<Thread> threadList = new ArrayList<Thread>(); + private int numThreads = _stress?100:10; + private int runTestLength = _stress?5000:1000; + private boolean runTest = false; + private AtomicLong buffersRetrieved; + + private void execAbstractBuffer() throws Exception { threadList.clear(); buffersRetrieved = new AtomicLong( 0 ); @@ -94,54 +72,50 @@ public class ThreadLocalBuffersTest System.out.println( "Buffers Retrieved: " + totalBuffersRetrieved ); System.out.println( "Memory Used: " + ( mem1 - mem0 ) ); - for ( Iterator<Thread> i = threadList.iterator(); i.hasNext(); ) - { - Thread t = i.next(); + for (Thread t : threadList) t.stop(); - } } - public void testAbstractBuffers() - throws Exception + @Test + public void testAbstractBuffers() throws Exception { execAbstractBuffer( ); } - public void testDifferentSizes() - throws Exception + @Test + public void testDifferentSizes() throws Exception { InnerBuffers buffers = new InnerBuffers(); buffers.setHeaderSize(128); buffers.setBufferSize(256); - + Buffer h1 = buffers.getHeader(); Buffer h2 = buffers.getHeader(); Buffer b1 = buffers.getBuffer(); Buffer b2 = buffers.getBuffer(); Buffer b3 = buffers.getBuffer(512); - + buffers.returnBuffer(h1); buffers.returnBuffer(h2); buffers.returnBuffer(b1); buffers.returnBuffer(b2); buffers.returnBuffer(b3); - + assertTrue(h1==buffers.getHeader()); // pooled header assertTrue(h2!=buffers.getHeader()); // b2 replaced h2 in other slot assertTrue(b1==buffers.getBuffer()); // pooled buffer assertTrue(b2!=buffers.getBuffer()); // b3 replaced b2 in other slot assertTrue(b3==buffers.getBuffer(512)); // b2 from other slot - + buffers.returnBuffer(h1); buffers.returnBuffer(h2); buffers.returnBuffer(b1); - + assertTrue(h1==buffers.getHeader()); // pooled header assertTrue(h2==buffers.getHeader()); // h2 in other slot assertTrue(b1==buffers.getBuffer()); // pooled buffer assertTrue(b2!=buffers.getBuffer()); // new buffer assertTrue(b3!=buffers.getBuffer(512)); // new buffer - // check that sizes are respected buffers.returnBuffer(b3); @@ -149,22 +123,21 @@ public class ThreadLocalBuffersTest buffers.returnBuffer(b2); buffers.returnBuffer(h1); buffers.returnBuffer(h2); - + assertTrue(h1==buffers.getHeader()); // pooled header assertTrue(h2==buffers.getHeader()); // h2 in other slot assertTrue(b1==buffers.getBuffer()); // pooled buffer assertTrue(b2!=buffers.getBuffer()); // new buffer assertTrue(b3!=buffers.getBuffer(512)); // new buffer } - - public void testSameSizes() - throws Exception + + @Test + public void testSameSizes() throws Exception { - Buffer buffer=null; InnerBuffers buffers = new InnerBuffers(); buffers.setHeaderSize(128); buffers.setBufferSize(128); - + Buffer h1 = buffers.getHeader(); Buffer h2 = buffers.getHeader(); Buffer b1 = buffers.getBuffer(); @@ -176,26 +149,25 @@ public class ThreadLocalBuffersTest known.add(b1); known.add(b2); known.add(h1); - + buffers.returnBuffer(h1); buffers.returnBuffer(h2); buffers.returnBuffer(b1); buffers.returnBuffer(b2); buffers.returnBuffer(b3); - + assertTrue(h1==buffers.getHeader()); // pooled header - buffer=buffers.getHeader(); + Buffer buffer = buffers.getHeader(); for (Buffer b:known) assertTrue(b!=buffer); // new buffer assertTrue(h2==buffers.getBuffer()); // h2 used from buffer slot assertTrue(b3==buffers.getBuffer()); // b1 from other slot buffer=buffers.getBuffer(128); for (Buffer b:known) assertTrue(b!=buffer); // new buffer - buffers.returnBuffer(h1); buffers.returnBuffer(h2); buffers.returnBuffer(b1); - + assertTrue(h1==buffers.getHeader()); // pooled header buffer=buffers.getHeader(); for (Buffer b:known) assertTrue(b!=buffer); // new buffer @@ -205,7 +177,7 @@ public class ThreadLocalBuffersTest buffers.returnBuffer(h1); buffers.returnBuffer(b1); buffers.returnBuffer(h2); - + assertTrue(h1==buffers.getHeader()); // pooled header assertTrue(h2==buffers.getHeader()); // h2 from other slot buffer=buffers.getHeader(); @@ -213,19 +185,17 @@ public class ThreadLocalBuffersTest assertTrue(b1==buffers.getBuffer()); // b1 used from buffer slot buffer=buffers.getBuffer(); for (Buffer b:known) assertTrue(b!=buffer); // new buffer - - } - static class HeaderBuffer extends ByteArrayBuffer + private static class HeaderBuffer extends ByteArrayBuffer { public HeaderBuffer(int size) { super(size); } } - - static class InnerBuffers extends ThreadLocalBuffers + + private static class InnerBuffers extends ThreadLocalBuffers { @Override protected Buffer newBuffer(int size) @@ -244,21 +214,13 @@ public class ThreadLocalBuffersTest } } - - /** - * generic buffer peeper - * - * - */ - class BufferPeeper - extends Thread + private class BufferPeeper extends Thread { - private String _bufferName; + private final String _bufferName; public BufferPeeper( String bufferName ) { _bufferName = bufferName; - start(); } @@ -269,15 +231,12 @@ public class ThreadLocalBuffersTest { try { - if ( runTest ) { Buffer buf = httpBuffers.getHeader(); - buffersRetrieved.getAndIncrement(); - - buf.put( new Byte( "2" ).byteValue() ); + buf.put(new Byte("2")); // sleep( threadWaitTime ); @@ -296,5 +255,4 @@ public class ThreadLocalBuffersTest } } } - } diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index 8b13df9370..563ee66196 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -38,10 +38,12 @@ </archive> </configuration> </plugin> - <!-- always include sources since jetty-xbean makes use of them --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.jaspi.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java index e640e376ac..70764bd872 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java @@ -115,12 +115,15 @@ public class JaspiAuthenticator implements Authenticator { Set<UserIdentity> ids = clientSubject.getPrivateCredentials(UserIdentity.class); UserIdentity userIdentity; - if (ids.size() > 0) { + if (ids.size() > 0) + { userIdentity = ids.iterator().next(); -// return new FormAuthenticator.FormAuthentication(this,ids.iterator().next()); } else { CallerPrincipalCallback principalCallback = _callbackHandler.getThreadCallerPrincipalCallback(); - if (principalCallback == null) throw new NullPointerException("No CallerPrincipalCallback"); + if (principalCallback == null) + { + return Authentication.UNAUTHENTICATED; + } Principal principal = principalCallback.getPrincipal(); if (principal == null) { String principalName = principalCallback.getName(); diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java index 15caef790f..d11a8d9bc8 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java @@ -37,7 +37,6 @@ import org.eclipse.jetty.server.UserIdentity; * * Idiot class required by jaspi stupidity * - * @#*($)#@&^)$@#&*$@ * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $ */ public class ServletCallbackHandler implements CallbackHandler diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index 818fc1a077..f10980de95 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -23,6 +23,11 @@ <goals> <goal>manifest</goal> </goals> + <configuration> + <instructions> + <Import-Package>javax.management.*,*</Import-Package> + </instructions> + </configuration> </execution> </executions> </plugin> @@ -33,7 +38,7 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> @@ -55,11 +60,12 @@ </execution> </executions> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.jmx.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> @@ -67,6 +73,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-jmx/src/main/config/etc/jetty-jmx.xml b/jetty-jmx/src/main/config/etc/jetty-jmx.xml index 4df07109f3..bdce9d4298 100644 --- a/jetty-jmx/src/main/config/etc/jetty-jmx.xml +++ b/jetty-jmx/src/main/config/etc/jetty-jmx.xml @@ -1,12 +1,12 @@ <?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> -<!-- =============================================================== --> -<!-- Configure the JVM JMX Server --> -<!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -DOPTIONS=jmx -jar start.jar etc/jetty-jmx.xml etc/jetty.xml --> -<!-- =============================================================== --> +<!-- ============================================================================ --> +<!-- To correctly start Jetty with JMX module enabled, this configuration --> +<!-- file must appear first in the list of the configuration files. --> +<!-- The simplest way to achieve this is to add etc/jetty-jmx.xml as the --> +<!-- first file in configuration file list at the end of start.ini file. --> +<!-- ============================================================================ --> <Configure id="Server" class="org.eclipse.jetty.server.Server"> <!-- =========================================================== --> @@ -50,8 +50,37 @@ </Arg> </Call> </Ref> + + <!-- In order to connect to the JMX server remotely from a different + process, possibly running on a different host, Jetty JMX module + can create a remote JMX connector. It requires RMI registry to + be started prior to creating the connector server because the + JMX specification uses RMI to facilitate connections. + --> - <!-- optionally add a remote JMX connector + <!-- Optionally start the RMI registry. Normally RMI registry runs on + port 1099. The argument below can be changed in order to comply + with the firewall requirements. + --> + <!-- + <Call name="createRegistry" class="java.rmi.registry.LocateRegistry"> + <Arg type="java.lang.Integer">1099</Arg> + <Call name="sleep" class="java.lang.Thread"> + <Arg type="java.lang.Integer">1000</Arg> + </Call> + </Call> + --> + + <!-- Optionally add a remote JMX connector. The parameters of the constructor + below specify the JMX service URL, and the object name string for the + connector server bean. The parameters of the JMXServiceURL constructor + specify the protocol that clients will use to connect to the remote JMX + connector (RMI), the hostname of the server (local hostname), port number + (automatically assigned), and the URL path. Note that URL path contains + the RMI registry hostname and port number, that may need to be modified + in order to comply with the firewall requirements. + --> + <!-- <New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer"> <Arg> <New class="javax.management.remote.JMXServiceURL"> @@ -65,6 +94,5 @@ <Call name="start" /> </New> --> - </Configure> diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java index cbf35f6dfb..8311374d56 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.jmx; @@ -20,13 +20,11 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; - import javax.management.MBeanServer; import javax.management.ObjectInstance; import javax.management.ObjectName; import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.Container; import org.eclipse.jetty.util.component.Container.Relationship; @@ -36,7 +34,7 @@ import org.eclipse.jetty.util.thread.ShutdownThread; /* ------------------------------------------------------------ */ /** - * Container class for the MBean instances + * Container class for the MBean instances */ public class MBeanContainer extends AbstractLifeCycle implements Container.Listener { @@ -49,21 +47,21 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste /* ------------------------------------------------------------ */ /** * Lookup an object name by instance - * + * * @param object instance for which object name is looked up * @return object name associated with specified instance, or null if not found */ public synchronized ObjectName findMBean(Object object) { ObjectName bean = (ObjectName)_beans.get(object); - return bean==null?null:bean; + return bean==null?null:bean; } /* ------------------------------------------------------------ */ /** * Lookup an instance by object name - * - * @param oname object name of instance + * + * @param oname object name of instance * @return instance associated with specified object name, or null if not found */ public synchronized Object findBean(ObjectName oname) @@ -80,7 +78,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste /* ------------------------------------------------------------ */ /** * Constructs MBeanContainer - * + * * @param server instance of MBeanServer for use by container */ public MBeanContainer(MBeanServer server) @@ -96,62 +94,62 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste Log.ignore(e); } } - + /* ------------------------------------------------------------ */ /** * Retrieve instance of MBeanServer used by container - * + * * @return instance of MBeanServer */ public MBeanServer getMBeanServer() { return _server; } - + /* ------------------------------------------------------------ */ /** * Set domain to be used to add MBeans - * + * * @param domain domain name */ public void setDomain (String domain) { _domain = domain; } - + /* ------------------------------------------------------------ */ /** * Retrieve domain name used to add MBeans - * + * * @return domain name */ public String getDomain() { return _domain; } - + /* ------------------------------------------------------------ */ /** * Implementation of Container.Listener interface - * + * * @see org.eclipse.jetty.util.component.Container.Listener#add(org.eclipse.jetty.util.component.Container.Relationship) */ public synchronized void add(Relationship relationship) - { + { ObjectName parent=(ObjectName)_beans.get(relationship.getParent()); if (parent==null) { addBean(relationship.getParent()); parent=(ObjectName)_beans.get(relationship.getParent()); } - + ObjectName child=(ObjectName)_beans.get(relationship.getChild()); if (child==null) { addBean(relationship.getChild()); child=(ObjectName)_beans.get(relationship.getChild()); } - + if (parent!=null && child!=null) _relations.add(parent,relationship); } @@ -159,7 +157,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste /* ------------------------------------------------------------ */ /** * Implementation of Container.Listener interface - * + * * @see org.eclipse.jetty.util.component.Container.Listener#remove(org.eclipse.jetty.util.component.Container.Relationship) */ public synchronized void remove(Relationship relationship) @@ -173,7 +171,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste /* ------------------------------------------------------------ */ /** * Implementation of Container.Listener interface - * + * * @see org.eclipse.jetty.util.component.Container.Listener#removeBean(java.lang.Object) */ public synchronized void removeBean(Object obj) @@ -192,7 +190,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste relation.getContainer().update(relation.getParent(),relation.getChild(),null,relation.getRelationship(),true); } } - + try { _server.unregisterMBean(bean); @@ -208,11 +206,11 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste } } } - + /* ------------------------------------------------------------ */ /** * Implementation of Container.Listener interface - * + * * @see org.eclipse.jetty.util.component.Container.Listener#addBean(java.lang.Object) */ public synchronized void addBean(Object obj) @@ -221,7 +219,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste { if (obj == null || _beans.containsKey(obj)) return; - + Object mbean = ObjectMBean.mbeanFor(obj); if (mbean == null) return; @@ -232,7 +230,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste ((ObjectMBean) mbean).setMBeanContainer(this); oname = ((ObjectMBean)mbean).getObjectName(); } - + //no override mbean object name, so make a generic one if (oname == null) { @@ -240,7 +238,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste int dot = type.lastIndexOf('.'); if (dot >= 0) type = type.substring(dot + 1); - + String name=null; if (mbean instanceof ObjectMBean) { @@ -261,11 +259,11 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste name=name.replace(':','_').replace('*','_').replace('?','_').replace('=','_').replace(',','_').replace(' ','_'); } } - + String basis=(name!=null&&name.length()>1)?("type="+type+",name="+name):("type="+type); - + Integer count = (Integer) _unique.get(basis); - count = TypeUtil.newInteger(count == null ? 0 : (1 + count.intValue())); + count = count == null ? 0 : 1 + count; _unique.put(basis, count); //if no explicit domain, create one @@ -275,7 +273,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste oname = ObjectName.getInstance(domain+":"+basis+",id="+count); } - + ObjectInstance oinstance = _server.registerMBean(mbean, oname); Log.debug("Registered {}" , oinstance.getObjectName()); _beans.put(obj, oinstance.getObjectName()); @@ -286,7 +284,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste Log.warn("bean: "+obj,e); } } - + /* ------------------------------------------------------------ */ /** * Perform actions needed to start lifecycle diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java index 6cba39de59..7ab8ebde5d 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java @@ -337,7 +337,7 @@ public class ObjectMBean implements DynamicMBean catch (InvocationTargetException e) { Log.warn(Log.EXCEPTION, e); - throw new ReflectionException((Exception) e.getTargetException()); + throw new ReflectionException(new Exception(e.getCause())); } } @@ -405,7 +405,7 @@ public class ObjectMBean implements DynamicMBean catch (InvocationTargetException e) { Log.warn(Log.EXCEPTION, e); - throw new ReflectionException((Exception) e.getTargetException()); + throw new ReflectionException(new Exception(e.getCause())); } } @@ -470,7 +470,7 @@ public class ObjectMBean implements DynamicMBean catch (InvocationTargetException e) { Log.warn(Log.EXCEPTION, e); - throw new ReflectionException((Exception) e.getTargetException()); + throw new ReflectionException(new Exception(e.getCause())); } finally { diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/jmx/AbstractConnector-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/jmx/AbstractConnector-mbean.properties index e2d97a4860..fd7667217d 100644 --- a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/jmx/AbstractConnector-mbean.properties +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/jmx/AbstractConnector-mbean.properties @@ -16,5 +16,4 @@ confidentialPort: Port to use for confidential redirections. confidentialScheme: Scheme to use for confidential redirections. integralPort: Port to use for integral redirections. integralScheme: Scheme to use for integral redirections. -lowResourcesConnections: The number of connections, which if exceeded represents low resources lowResourcesMaxIdleTime: The period in ms that a connection may be idle when the connector has low resources, before it is closed. diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/nio/jmx/SelectChannelConnector-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/nio/jmx/SelectChannelConnector-mbean.properties index 096a4b4aad..dbe718d5b0 100644 --- a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/nio/jmx/SelectChannelConnector-mbean.properties +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/nio/jmx/SelectChannelConnector-mbean.properties @@ -1 +1,2 @@ SelectChannelConnector: HTTP connector using NIO ByteChannels and Selectors +lowResourcesConnections: The number of connections, which if exceeded represents low resources diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/session/jmx/AbstractSessionManager-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/session/jmx/AbstractSessionManager-mbean.properties index 2bc03eb42a..385f28a420 100644 --- a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/session/jmx/AbstractSessionManager-mbean.properties +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/session/jmx/AbstractSessionManager-mbean.properties @@ -9,15 +9,10 @@ sessionCookie: The set session cookie sessionDomain: The domain of the session cookie or null for the default sessionPath: The path of the session cookie or null for the default sessionsTotal: The total number of sessions -sessionsMax: The maximum number of simultaneous sessions -sessionTimeMax: The maximum session lifetime in seconds -sessionTimeMean: The mean session lifetime in seconds -sessionTimeStdDev: The standard deviation of session lifetime in seconds sessionIdPathParameterName: The name to use for URL session tracking statsReset(): Reset statistics sessions: Current instantaneous number of sessions sessionsMax: Maximum number of simultaneous sessions since statsReset() was called -sessionsMin: Minimum number of simultaneous sessions since statsReset() was called sessionTimeMax: Maximum amount of time in seconds session remained valid since statsReset() was called sessionTimeTotal: Total amount of time in seconds sessions remained valid since statsReset() was called sessionTimeMean: Mean amount of time in seconds a session remained valid since statsReset() was called diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/DoSFilter-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/DoSFilter-mbean.properties new file mode 100644 index 0000000000..6a1f31aa49 --- /dev/null +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/DoSFilter-mbean.properties @@ -0,0 +1,12 @@ +DoSFilter: Limit exposure to abuse from request flooding, whether malicious, or as a result of a misconfigured client. +maxRequestsPerSec: maximum number of requests from a connection per second. Requests in excess of this are first delayed, then throttled. +delayMs: delay (in milliseconds) that is applied to all requests over the rate limit, before they are considered at all, 0 - no delay, -1 - reject request. +maxWaitMs: maximum amount of time (in milliseconds) the filter will blocking wait for the throttle semaphore. +throttledRequests: number of requests over the rate limit able to be considered at once. +throttleMs: amount of time (in milliseconds) to async wait for semaphore. +maxRequestMs: maximum amount of time (in milliseconds) to allow the request to process. +maxIdleTrackerMs: maximum amount of time (in milliseconds) to keep track of request rates for a connection, before deciding that the user has gone away, and discarding it. +insertHeaders: insert the DoSFilter headers into the response. +trackSessions: usage rate is tracked by session if a session exists. +remotePort: usage rate is tracked by IP+port (effectively connection) if session tracking is not used. +ipWhitelist: list of IP addresses that will not be rate limited.
\ No newline at end of file diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/QoSFilter-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/QoSFilter-mbean.properties new file mode 100644 index 0000000000..c781d638aa --- /dev/null +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/QoSFilter-mbean.properties @@ -0,0 +1,4 @@ +QoSFilter: Quality of Service Filter. +maxRequests: maximum number of requests allowed to be processedat the same time. +waitMs: (short) amount of time (in milliseconds) that the filter would wait for the semaphore to become available before suspending a request. +suspendMs: amount of time (in milliseconds) that the filter would suspend a request for while waiting for the semaphore to become available. diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java index 28b52a60e8..132ff3b06a 100644 --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java @@ -4,51 +4,32 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.jmx; - -import junit.framework.TestCase; - +import com.acme.Derived; import org.eclipse.jetty.server.Server; +import org.junit.Test; -import com.acme.Derived; +import static org.junit.Assert.assertTrue; -public class ObjectMBeanTest extends TestCase +public class ObjectMBeanTest { - public ObjectMBeanTest(String arg0) - { - super(arg0); - } - - public static void main(String[] args) - { - junit.textui.TestRunner.run(ObjectMBeanTest.class); - } - - protected void setUp() throws Exception - { - super.setUp(); - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - + @Test public void testMbeanInfo() { Derived derived = new Derived(); ObjectMBean mbean = new ObjectMBean(derived); assertTrue(mbean.getMBeanInfo()!=null); // TODO do more than just run it } - + + @Test public void testMbeanFor() { Derived derived = new Derived(); diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index fccb29330e..b7b8ad561a 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -23,6 +23,11 @@ <goals> <goal>manifest</goal> </goals> + <configuration> + <instructions> + <Import-Package>javax.naming.*,*</Import-Package> + </instructions> + </configuration> </execution> </executions> </plugin> @@ -33,16 +38,17 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.jndi.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> @@ -50,6 +56,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> @@ -61,7 +68,7 @@ <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> - <version>${mail-version}</version> + <version>${javax-mail-version}</version> <exclusions> <exclusion> <groupId>javax.activation</groupId> @@ -80,9 +87,9 @@ <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> - <version>${activation-version}</version> - </dependency> + <version>${javax-activation-version}</version> + </dependency> </dependencies> </profile> - </profiles> + </profiles> </project> diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java index ca00153e1b..75e626a72c 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java @@ -151,7 +151,7 @@ public class ContextFactory implements ObjectFactory * Keep trying ancestors of the given classloader to find one to which * the context is bound. * @param loader - * @return + * @return the context from the parent class loader */ public Context getParentClassLoaderContext (ClassLoader loader) { diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java index df635a6eab..0f2cf7bb18 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java @@ -41,11 +41,11 @@ public class NamingUtil /* ------------------------------------------------------------ */ /** - * Bind an object to a context ensuring all subcontexts + * Bind an object to a context ensuring all sub-contexts * are created if necessary * * @param ctx the context into which to bind - * @param name the name relative to context to bind + * @param nameStr the name relative to context to bind * @param obj the object to be bound * @exception NamingException if an error occurs */ diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java index 80e95d677b..e6ff384f54 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java @@ -111,7 +111,7 @@ public class MailSessionReference extends Reference implements ObjectFactory * @param arg1 not used * @param arg2 not used * @param arg3 not used - * @return + * @return the object found * @throws Exception */ public Object getObjectInstance(Object ref, Name arg1, Context arg2, Hashtable arg3) throws Exception diff --git a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/factories/TestMailSessionReference.java b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/factories/TestMailSessionReference.java index 6933005225..f76fb42aa5 100644 --- a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/factories/TestMailSessionReference.java +++ b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/factories/TestMailSessionReference.java @@ -4,17 +4,16 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.jndi.factories; import java.util.Properties; - import javax.mail.Session; import javax.naming.Context; import javax.naming.InitialContext; @@ -22,19 +21,20 @@ import javax.naming.LinkRef; import javax.naming.Name; import javax.naming.NameParser; -import junit.framework.TestCase; - import org.eclipse.jetty.jndi.NamingUtil; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** - * TestMailSessionReference - * * */ -public class TestMailSessionReference extends TestCase +public class TestMailSessionReference { - public void testMailSessionReference () - throws Exception + @Test + public void testMailSessionReference () throws Exception { InitialContext icontext = new InitialContext(); MailSessionReference sref = new MailSessionReference(); @@ -52,20 +52,20 @@ public class TestMailSessionReference extends TestCase Properties sessionProps = session.getProperties(); assertEquals(props, sessionProps); assertTrue (session.getDebug()); - + Context foo = icontext.createSubcontext("foo"); NameParser parser = icontext.getNameParser(""); Name objectNameInNamespace = parser.parse(icontext.getNameInNamespace()); objectNameInNamespace.addAll(parser.parse("mail/Session")); - + NamingUtil.bind(foo, "mail/Session", new LinkRef(objectNameInNamespace.toString())); - + Object o = foo.lookup("mail/Session"); assertNotNull(o); Session fooSession = (Session)o; assertEquals(props, fooSession.getProperties()); assertTrue(fooSession.getDebug()); - + icontext.destroySubcontext("mail"); icontext.destroySubcontext("foo"); } diff --git a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestJNDI.java b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestJNDI.java index 614a0ac3f4..c4bc048078 100644 --- a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestJNDI.java +++ b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestJNDI.java @@ -4,21 +4,19 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.jndi.java; - import java.net.URL; import java.net.URLClassLoader; import java.util.HashMap; import java.util.Hashtable; - import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.LinkRef; @@ -32,57 +30,31 @@ import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.naming.spi.ObjectFactory; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - import org.eclipse.jetty.jndi.NamingContext; import org.eclipse.jetty.util.log.Log; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; - -public class TestJNDI extends TestCase +/** + * + */ +public class TestJNDI { - - public static class MyObjectFactory implements ObjectFactory { public static String myString = "xxx"; - public Object getObjectInstance(Object obj, - Name name, - Context nameCtx, - Hashtable environment) - throws Exception - { - return myString; - } - } - - public TestJNDI (String name) - { - super (name); - } - - - public static Test suite () - { - return new TestSuite (TestJNDI.class); - } - - public void setUp () - throws Exception - { - } - - - public void tearDown () - throws Exception - { + public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception + { + return myString; + } } - public void testIt () - throws Exception + @Test + public void testIt() throws Exception { try { @@ -99,9 +71,6 @@ public class TestJNDI extends TestCase initCtxA.bind ("blah", "123"); assertEquals ("123", initCtxA.lookup("blah")); - - - InitialContext initCtx = new InitialContext(); Context sub0 = (Context)initCtx.lookup("java:"); @@ -109,7 +78,6 @@ public class TestJNDI extends TestCase Name n = sub0.getNameParser("").parse("/red/green/"); - if(Log.isDebugEnabled())Log.debug("get(0)="+n.get(0)); if(Log.isDebugEnabled())Log.debug("getPrefix(1)="+n.getPrefix(1)); n = n.getSuffix(1); @@ -166,42 +134,35 @@ public class TestJNDI extends TestCase //expected exception } - - //check bindings at comp Context sub1 = (Context)initCtx.lookup("java:comp"); Context sub2 = sub1.createSubcontext ("env"); initCtx.bind ("java:comp/env/rubbish", "abc"); - assertEquals ("abc", (String)initCtx.lookup("java:comp/env/rubbish")); - - + assertEquals ("abc", initCtx.lookup("java:comp/env/rubbish")); //check binding LinkRefs LinkRef link = new LinkRef ("java:comp/env/rubbish"); initCtx.bind ("java:comp/env/poubelle", link); - assertEquals ("abc", (String)initCtx.lookup("java:comp/env/poubelle")); + assertEquals ("abc", initCtx.lookup("java:comp/env/poubelle")); //check binding References StringRefAddr addr = new StringRefAddr("blah", "myReferenceable"); Reference ref = new Reference (java.lang.String.class.getName(), addr, MyObjectFactory.class.getName(), - (String)null); + null); initCtx.bind ("java:comp/env/quatsch", ref); - assertEquals (MyObjectFactory.myString, (String)initCtx.lookup("java:comp/env/quatsch")); + assertEquals (MyObjectFactory.myString, initCtx.lookup("java:comp/env/quatsch")); //test binding something at java: Context sub3 = initCtx.createSubcontext("java:zero"); initCtx.bind ("java:zero/one", "ONE"); assertEquals ("ONE", initCtx.lookup("java:zero/one")); - - - - //change the current thread's classloader to check distinct naming + //change the current thread's classloader to check distinct naming currentThread.setContextClassLoader(childLoader2); Context otherSub1 = (Context)initCtx.lookup("java:comp"); @@ -215,7 +176,6 @@ public class TestJNDI extends TestCase //expected } - //put the thread's classloader back currentThread.setContextClassLoader(childLoader1); @@ -227,11 +187,11 @@ public class TestJNDI extends TestCase initCtx.rebind ("java:comp/env/mullheim", "hij"); assertEquals ("hij", initCtx.lookup("java:comp/env/mullheim")); - //test that the other bindings are already there - assertEquals ("xyz", (String)initCtx.lookup("java:comp/env/poubelle")); + //test that the other bindings are already there + assertEquals ("xyz", initCtx.lookup("java:comp/env/poubelle")); //test java:/comp/env/stuff - assertEquals ("xyz", (String)initCtx.lookup("java:/comp/env/poubelle/")); + assertEquals ("xyz", initCtx.lookup("java:/comp/env/poubelle/")); //test list Names NamingEnumeration nenum = initCtx.list ("java:comp/env"); @@ -244,10 +204,10 @@ public class TestJNDI extends TestCase assertEquals (4, results.size()); - assertEquals ("java.lang.String", (String)results.get("rubbish")); - assertEquals ("javax.naming.LinkRef", (String)results.get("poubelle")); - assertEquals ("java.lang.String", (String)results.get("mullheim")); - assertEquals ("javax.naming.Reference", (String)results.get("quatsch")); + assertEquals ("java.lang.String", results.get("rubbish")); + assertEquals ("javax.naming.LinkRef", results.get("poubelle")); + assertEquals ("java.lang.String", results.get("mullheim")); + assertEquals ("javax.naming.Reference", results.get("quatsch")); //test list Bindings NamingEnumeration benum = initCtx.list("java:comp/env"); @@ -265,13 +225,11 @@ public class TestJNDI extends TestCase InitialContext closeInit = new InitialContext(); closeInit.close(); - - //check locking the context Context ectx = (Context)initCtx.lookup("java:comp"); ectx.bind("crud", "xxx"); ectx.addToEnvironment("org.eclipse.jndi.immutable", "TRUE"); - assertEquals ("xxx", (String)initCtx.lookup("java:comp/crud")); + assertEquals ("xxx", initCtx.lookup("java:comp/crud")); try { ectx.bind("crud2", "xxx2"); @@ -282,7 +240,7 @@ public class TestJNDI extends TestCase } //test what happens when you close an initial context that was used - initCtx.close(); + initCtx.close(); } finally { @@ -290,6 +248,5 @@ public class TestJNDI extends TestCase Context comp = (Context)ic.lookup("java:comp"); comp.destroySubcontext("env"); } - } - + } } diff --git a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java index 23a9955c43..0caa18fcef 100644 --- a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java +++ b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.jndi.java; @@ -18,41 +18,37 @@ import javax.naming.Name; import javax.naming.NameNotFoundException; import javax.naming.NameParser; -import junit.framework.TestCase; - import org.eclipse.jetty.jndi.NamingUtil; +import org.junit.After; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; -public class TestLocalJNDI extends TestCase +/** + * + */ +public class TestLocalJNDI { - - - public void setUp () - throws Exception - { - } - - - public void tearDown () - throws Exception + @After + public void tearDown() throws Exception { InitialContext ic = new InitialContext(); ic.destroySubcontext("a"); } - - - public void testLocal () - throws Exception + + @Test + public void testLocal () throws Exception { - InitialContext ic = new InitialContext(); NameParser parser = ic.getNameParser(""); ic.bind("foo", "xxx"); - + Object o = ic.lookup("foo"); assertNotNull(o); assertEquals("xxx", (String)o); - + ic.unbind("foo"); try { @@ -72,17 +68,16 @@ public class TestLocalJNDI extends TestCase Context c = (Context)ic.lookup("a/b/c"); o = c.lookup("d"); assertNotNull(o); - assertEquals("333", (String)o); + assertEquals("333", (String)o); assertEquals("333", ic.lookup(name)); ic.destroySubcontext("a"); - + name = parser.parse(""); name.add("x"); Name suffix = parser.parse("y/z"); name.addAll(suffix); - NamingUtil.bind(ic, name.toString(), "555"); + NamingUtil.bind(ic, name.toString(), "555"); assertEquals("555", ic.lookup(name)); ic.destroySubcontext("x"); } - } diff --git a/jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF index 50b1a5c580..6fc66ebd32 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF +++ b/jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Jetty-OSGi-Jasper integration Fragment-Host: org.eclipse.jetty.osgi.boot Bundle-SymbolicName: org.eclipse.jetty.osgi.boot.jsp;singleton:=true -Bundle-Version: 8.0.0.M0.qualifier +Bundle-Version: 8.0.0.qualifier Bundle-Vendor: Mort Bay Consulting Bundle-RequiredExecutionEnvironment: J2SE-1.6 Import-Package: javax.el;version="2.2", diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index abf6876280..575fb5a1c1 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -2,7 +2,7 @@ <parent> <groupId>org.eclipse.jetty.osgi</groupId> <artifactId>jetty-osgi-project</artifactId> - <version>8.0.0.M0-SNAPSHOT</version> + <version>8.0.0.M1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> @@ -96,11 +96,12 @@ </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.osgi.boot.jasper.*,org.eclipse.jetty.osgi.boot.jsp.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml.tycho b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml.tycho deleted file mode 100644 index 3f4c536781..0000000000 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml.tycho +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <modelVersion>4.0.0</modelVersion> - <parent> - <artifactId>jetty-osgi</artifactId> - <version>8.0.0.M0-SNAPSHOT</version> - <groupId>org.eclipse.jetty.osgi</groupId> - </parent> - <artifactId>org.eclipse.jetty.osgi.boot.jsp</artifactId> - <packaging>eclipse-plugin</packaging> - -</project> diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java index 084fac8b49..d1ea7b8122 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java @@ -118,7 +118,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto * Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root * and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars. * - * @return + * @return array of URLs * @throws Exception */ public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception @@ -148,7 +148,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto { Bundle tldBundle = FrameworkUtil.getBundle(cl); File tldBundleLocation = locatorHelper.getBundleInstallLocation(tldBundle); - if (tldBundleLocation.isDirectory()) + if (tldBundleLocation != null && tldBundleLocation.isDirectory()) { // try to find the jar files inside this folder for (File f : tldBundleLocation.listFiles()) @@ -170,7 +170,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto } } - else + else if (tldBundleLocation != null) { urls.add(tldBundleLocation.toURI().toURL()); } diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java index 8e84cbdf11..46a9ce31bc 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java @@ -12,7 +12,7 @@ // ======================================================================== package org.eclipse.jetty.osgi.boot.jsp; -import org.eclipse.jetty.osgi.boot.internal.webapp.WebappRegistrationHelper; +import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleDeployerHelper; import org.eclipse.jetty.osgi.boot.jasper.PluggableWebAppRegistrationCustomizerImpl; import org.eclipse.jetty.osgi.boot.jasper.WebappRegistrationCustomizerImpl; import org.osgi.framework.BundleActivator; @@ -36,13 +36,8 @@ public class FragmentActivator implements BundleActivator * */ public void start(BundleContext context) throws Exception { - WebappRegistrationHelper.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl()); - WebappRegistrationHelper.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl()); -// try { -// FragmentActivator.class.getClassLoader().loadClass("does.not.exist"); -// } catch (Throwable t) { -// t.printStackTrace(); -// } + WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl()); + WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl()); } /** diff --git a/jetty-osgi/jetty-osgi-boot-logback/pom.xml b/jetty-osgi/jetty-osgi-boot-logback/pom.xml index fc30d33975..262aa86f5e 100644 --- a/jetty-osgi/jetty-osgi-boot-logback/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-logback/pom.xml @@ -2,7 +2,7 @@ <parent> <groupId>org.eclipse.jetty.osgi</groupId> <artifactId>jetty-osgi-project</artifactId> - <version>8.0.0.M1</version> + <version>8.0.0.M1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> @@ -95,11 +95,12 @@ </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.osgi.boot.logback.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-osgi/jetty-osgi-boot-logback/pom.xml.tycho b/jetty-osgi/jetty-osgi-boot-logback/pom.xml.tycho index 6f8277e581..b09cf8d687 100644 --- a/jetty-osgi/jetty-osgi-boot-logback/pom.xml.tycho +++ b/jetty-osgi/jetty-osgi-boot-logback/pom.xml.tycho @@ -4,7 +4,7 @@ <modelVersion>4.0.0</modelVersion> <parent> <artifactId>jetty-osgi</artifactId> - <version>7.0.1-SNAPSHOT</version> + <version>8.0.0.M1-SNAPSHOT</version> <groupId>org.eclipse.jetty.osgi</groupId> </parent> <artifactId>org.eclipse.jetty.osgi.boot.logback</artifactId> diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index b21be87966..f37149d358 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -2,7 +2,7 @@ <parent> <groupId>org.eclipse.jetty.osgi</groupId> <artifactId>jetty-osgi-project</artifactId> - <version>8.0.0.M1</version> + <version>8.0.0.M1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> @@ -65,11 +65,12 @@ </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.osgi.boot.warurl.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho deleted file mode 100644 index b30ae7a464..0000000000 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <modelVersion>4.0.0</modelVersion> - <parent> - <artifactId>jetty-osgi</artifactId> - <version>7.0.1-SNAPSHOT</version> - <groupId>org.eclipse.jetty.osgi</groupId> - </parent> - <groupId>org.eclipse.jetty.osgi</groupId> - <artifactId>org.eclipse.jetty.osgi.boot.warurl</artifactId> - <version>7.0.1.qualifier</version> - <packaging>eclipse-plugin</packaging> -</project> diff --git a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java index ec31f3c24a..744a43c2ec 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java +++ b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java @@ -99,7 +99,7 @@ public class WarURLConnection extends URLConnection /** * @param url The file url (for example) - * @param The manifest to use as a replacement to the jar file inside + * @param mf The manifest to use as a replacement to the jar file inside * the file url. */ public WarURLConnection(URL url, Manifest mf) throws IOException diff --git a/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF index 861d73ad82..e302c3dd48 100644 --- a/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF +++ b/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF @@ -2,66 +2,16 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Jetty OSGi bootstrap Bundle-SymbolicName: org.eclipse.jetty.osgi.boot;singleton:=true +Bundle-Vendor: Mort Bay Consulting Bundle-Version: 8.0.0.qualifier Bundle-Activator: org.eclipse.jetty.osgi.boot.JettyBootstrapActivator -Bundle-Vendor: Mort Bay Consulting -Export-Package: org, - org.eclipse, - org.eclipse.jetty, - org.eclipse.jetty.osgi, - org.eclipse.jetty.osgi.boot, - org.eclipse.jetty.osgi.boot.internal, - org.eclipse.jetty.osgi.boot.internal.jsp, - org.eclipse.jetty.osgi.boot.internal.serverfactory, - org.eclipse.jetty.osgi.boot.internal.webapp, - org.eclipse.jetty.osgi.boot.utils, - org.eclipse.jetty.osgi.boot.utils.internal -Require-Bundle: org.eclipse.jetty.ajp;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.annotations;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.client;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.continuation;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.deploy;bundle-version="[8.0, - 9)", - org.eclipse.jetty.http;bundle-version="[8.0, - 9)", - org.eclipse.jetty.io;bundle-version="[8.0, - 9)", - org.eclipse.jetty.jmx;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.jndi;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.plus;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.rewrite;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.security;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.server;bundle-version="[8.0, - 9)", - org.eclipse.jetty.servlet;bundle-version="[8.0, - 9)", - org.eclipse.jetty.servlets;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.util;bundle-version="[8.0, - 9)", - org.eclipse.jetty.webapp;bundle-version="[8.0, - 9)", - org.eclipse.jetty.websocket;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.xml;bundle-version="[8.0, - 9)" -Bundle-RequiredExecutionEnvironment: J2SE-1.6 Import-Package: javax.mail;version="1.4.0";resolution:=optional, javax.mail.event;version="1.4.0";resolution:=optional, javax.mail.internet;version="1.4.0";resolution:=optional, javax.mail.search;version="1.4.0";resolution:=optional, javax.mail.util;version="1.4.0";resolution:=optional, - javax.servlet;version="2.5.0", - javax.servlet.http;version="2.5.0", + javax.servlet;version="3.0", + javax.servlet.http;version="3.0", javax.transaction;version="1.1.0";resolution:=optional, javax.transaction.xa;version="1.1.0";resolution:=optional, org.osgi.framework, @@ -73,4 +23,29 @@ Import-Package: javax.mail;version="1.4.0";resolution:=optional, org.slf4j;resolution:=optional, org.slf4j.spi;resolution:=optional, org.slf4j.helpers;resolution:=optional + org.xml.sax, + org.xml.sax.helpers +Bundle-RequiredExecutionEnvironment: J2SE-1.6 +Bundle-Classpath: . +Require-Bundle: org.eclipse.jetty.ajp;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.annotations;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.client;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.continuation;bundle-version="[7.0,9)";resolution:=optional, + org.eclipse.jetty.deploy;bundle-version="[8.0,9)", + org.eclipse.jetty.http;bundle-version="[8.0,9)", + org.eclipse.jetty.io;bundle-version="[8.0,9)", + org.eclipse.jetty.jmx;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.jndi;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.plus;bundle-version="[8.0,9.0)";resolution:=optional, + org.eclipse.jetty.rewrite;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.security;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.server;bundle-version="[8.0,9)", + org.eclipse.jetty.servlet;bundle-version="[8.0,9)", + org.eclipse.jetty.servlets;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.util;bundle-version="[8.0,9)", + org.eclipse.jetty.webapp;bundle-version="[8.0,9)", + org.eclipse.jetty.websocket;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.xml;bundle-version="[8.0,9)" +Export-Package: org.eclipse.jetty.osgi.boot, + org.eclipse.jetty.osgi.boot.utils Bundle-ActivationPolicy: lazy diff --git a/jetty-osgi/jetty-osgi-boot/build.properties b/jetty-osgi/jetty-osgi-boot/build.properties index d9a9ce1f7f..ba1366d090 100644 --- a/jetty-osgi/jetty-osgi-boot/build.properties +++ b/jetty-osgi/jetty-osgi-boot/build.properties @@ -3,13 +3,6 @@ output.. = target/classes/ bin.includes = META-INF/,\ .,\ jettyhome/ -bin.excludes = jettyhome/logs/2009_09_21.request.log,\ - jettyhome/lib/atomikos-util-3.5.8.jar,\ - jettyhome/lib/transactions-3.5.8.jar,\ - jettyhome/lib/transactions-api-3.5.8.jar,\ - jettyhome/lib/transactions-jdbc-3.5.8.jar,\ - jettyhome/lib/transactions-jta-3.5.8.jar,\ - jettyhome/lib/ext/derby-10.4.1.3.jar,\ - jettyhome/lib/ext/derbytools-10.4.1.3.jar -src.includes = META-INF/,\ - jettyhome/ +bin.excludes = jettyhome/logs/*.log,\ + jettyhome/lib/* +src.includes = jettyhome/ diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/README b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/README deleted file mode 100644 index dbc9fa7156..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/README +++ /dev/null @@ -1,2 +0,0 @@ -This folder contains the default jetty configurations file for the server. -In production, it is likely to be a different folder outside of the jetty's bootstrap plugin.
\ No newline at end of file diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jdbcRealm.properties b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jdbcRealm.properties deleted file mode 100644 index 48104d88ad..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jdbcRealm.properties +++ /dev/null @@ -1,72 +0,0 @@ -# -# This is a sample properties file for the org.eclipse.jetty.security.JDBCLoginService -# implemtation of the UserRealm interface. This allows Jetty users authentication -# to work from a database. -# -# +-------+ +------------+ +-------+ -# | users | | user_roles | | roles | -# +-------+ +------------+ +-------+ -# | id | /| user_id |\ | id | -# | user -------| role_id |------- role | -# | pwd | \| |/ | | -# +-------+ +------------+ +-------+ -# -# -# 'cachetime' is a time in seconds to cache positive database -# lookups in internal hash table. Set to 0 to disable caching. -# -# -# For MySQL: -# create a MYSQL user called "jetty" with password "jetty" -# -# Create the tables: -# create table users -# ( -# id integer primary key, -# username varchar(100) not null unique key, -# pwd varchar(20) not null -# ); -# -# create table roles -# ( -# id integer primary key, -# role varchar(100) not null unique key -# ); -# -# create table user_roles -# ( -# user_id integer not null, -# role_id integer not null, -# unique key (user_id, role_id), -# index(user_id) -# ); -# -# I'm not sure unique key with a first component of user_id will be -# user by MySQL in query, so additional index wouldn't hurt. -# -# To test JDBC implementation: -# -# mysql> insert into users values (1, 'admin', 'password'); -# mysql> insert into roles values (1, 'server-administrator'); -# mysql> insert into roles values (2, 'content-administrator'); -# mysql> insert into user_roles values (1, 1); -# mysql> insert into user_roles values (1, 2); -# -# Replace HashUserRealm in etc/admin.xml with JDBCUserRealm and -# set path to properties file. -# -jdbcdriver = org.gjt.mm.mysql.Driver -url = jdbc:mysql://localhost/jetty -username = jetty -password = jetty -usertable = users -usertablekey = id -usertableuserfield = username -usertablepasswordfield = pwd -roletable = roles -roletablekey = id -roletablerolefield = role -userroletable = user_roles -userroletableuserkey = user_id -userroletablerolekey = role_id -cachetime = 300 diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-ajp.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-ajp.xml deleted file mode 100644 index 04a775ec3e..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-ajp.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- Add a AJP listener on port 8009 --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.ajp.Ajp13SocketConnector"> - <Set name="port">8009</Set> - </New> - </Arg> - </Call> - -</Configure> - diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-bio-ssl.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-bio-ssl.xml deleted file mode 100644 index 0b0c6fc16f..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-bio-ssl.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configure SSL for the Jetty Server --> -<!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml --> -<!-- =============================================================== --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ssl.SslSocketConnector"> - <Set name="Port">9443</Set> - <Set name="maxIdleTime">30000</Set> - <Set name="Keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> - <Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - <Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - <Set name="truststore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> - <Set name="trustPassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - </New> - </Arg> - </Call> -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-bio.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-bio.xml deleted file mode 100644 index 3c4c8a6b80..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-bio.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Mixin configuration for Block socket connector --> -<!-- --> -<!-- =============================================================== --> - - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- Use this connector if NIO is not available. --> - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.bio.SocketConnector"> - <Set name="port"><SystemProperty name="jetty.bio.port" default="8081"/></Set> - <Set name="maxIdleTime">50000</Set> - <Set name="lowResourceMaxIdleTime">1500</Set> - </New> - </Arg> - </Call> - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-debug.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-debug.xml deleted file mode 100644 index afc972e5ab..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-debug.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"> - -<!-- =============================================================== --> -<!-- Mixin the DebugHandler --> -<!-- =============================================================== --> - - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - <Get id="oldhandler" name="handler"/> - <Set name="handler"> - <New id="DebugHandler" class="org.eclipse.jetty.server.handler.DebugHandler"> - <Set name="handler"><Ref id="oldhandler"/></Set> - <Set name="outputStream"> - <New class="org.eclipse.jetty.util.RolloverFileOutputStream"> - <Arg type="String"><SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg> - <Arg type="boolean">true</Arg> <!-- append --> - <Arg type="int">90</Arg> <!-- retain days --> - </New> - </Set> - </New> - </Set> -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-fileserver.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-fileserver.xml deleted file mode 100644 index de15b38724..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-fileserver.xml +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - - -<Configure id="FileServer" class="org.eclipse.jetty.server.Server"> - - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> - <Set name="port">8080</Set> - </New> - </Arg> - </Call> - - <Set name="handler"> - <New class="org.eclipse.jetty.server.handler.HandlerList"> - <Set name="handlers"> - <Array type="org.eclipse.jetty.server.Handler"> - <Item> - <New class="org.eclipse.jetty.server.handler.ResourceHandler"> - <Set name="directoriesListed">true</Set> - <Set name="welcomeFiles"> - <Array type="String"><Item>index.html</Item></Array> - </Set> - <Set name="resourceBase">.</Set> - </New> - </Item> - <Item> - <New class="org.eclipse.jetty.server.handler.DefaultHandler"> - </New> - </Item> - </Array> - </Set> - </New> - </Set> - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-jaas.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-jaas.xml deleted file mode 100644 index e5bab94b5f..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-jaas.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"> - -<Configure id="Server" class="org.mortbay.jetty.Server"> - - - <!-- ======================================================== --> - <!-- java.security.auth.login.config System property --> - <!-- This is usually a runtime parameter to the jvm, but --> - <!-- it is placed here for convenience. --> - <!-- ======================================================== --> - <Call class="java.lang.System" name="setProperty"> - <Arg>java.security.auth.login.config</Arg> - <Arg><SystemProperty name="jetty.home" default="." />/etc/login.conf</Arg> - </Call> - - - <!-- ======================================================== --> - <!-- An example JAAS realm setup --> - <!-- For more information see the jetty wiki at --> - <!-- http://http://docs.codehaus.org/display/JETTY/JAAS --> - <!-- ======================================================== --> - <Set name="UserRealms"> - <Array type="org.mortbay.jetty.security.UserRealm"> - <Item> - <New class="org.mortbay.jetty.plus.jaas.JAASUserRealm"> - <Set name="Name">Test JAAS Realm</Set> - <Set name="LoginModuleName">xyz</Set> - </New> - </Item> - </Array> - </Set> - - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-jmx.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-jmx.xml deleted file mode 100644 index 2d48b6ca20..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-jmx.xml +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configure the JVM JMX Server --> -<!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -DOPTIONS=jmx -jar start.jar etc/jetty-jmx.xml etc/jetty.xml --> -<!-- =============================================================== --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- =========================================================== --> - <!-- Initialize an mbean server --> - <!-- =========================================================== --> - <Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer"/> - - <!-- =========================================================== --> - <!-- Initialize the Jetty MBean container --> - <!-- =========================================================== --> - <New id="MBeanContainer" class="org.eclipse.jetty.jmx.MBeanContainer"> - <Arg><Ref id="MBeanServer"/></Arg> - </New> - - <!-- Add to the Server to listen for object events --> - <Get id="Container" name="container"> - <Call name="addEventListener"> - <Arg><Ref id="MBeanContainer"/></Arg> - </Call> - </Get> - - <!-- Add to the Server as a lifecycle --> - <!-- Only do this if you know you will only have a single jetty server --> - <Call name="addBean"> - <Arg><Ref id="MBeanContainer"/></Arg> - </Call> - - <!-- Add the static log --> - <Get id="Logger" class="org.eclipse.jetty.util.log.Log" name="log"/> - <Ref id="MBeanContainer"> - <Call name="addBean"> - <Arg><Ref id="Logger"/></Arg> - </Call> - </Ref> - - <!-- optionally add a remote JMX connector - <Call id="jmxConnector" class="javax.management.remote.JMXConnectorServerFactory" name="newJMXConnectorServer"> - <Arg> - <New class="javax.management.remote.JMXServiceURL"> - <Arg>service:jmx:rmi:///jndi/rmi:///jettymbeanserver</Arg> - </New> - </Arg> - <Arg/> - <Arg><Ref id="MBeanServer"/></Arg> - <Call name="start"/> - </Call> - --> - -</Configure> - diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-logging.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-logging.xml deleted file mode 100644 index 09b590abe6..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-logging.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - - -<!-- =============================================================== --> -<!-- Configure stderr and stdout to a Jetty rollover log file --> -<!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -jar start.jar etc/jetty-logging.xml etc/jetty.xml --> -<!-- =============================================================== --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <New id="ServerLog" class="java.io.PrintStream"> - <Arg> - <New class="org.eclipse.jetty.util.RolloverFileOutputStream"> - <Arg><SystemProperty name="jetty.home" default="."/>/logs/yyyy_mm_dd.stderrout.log</Arg> - <Arg type="boolean">false</Arg> - <Arg type="int">90</Arg> - <Arg><Call class="java.util.TimeZone" name="getTimeZone"><Arg>GMT</Arg></Call></Arg> - <Get id="ServerLogName" name="datedFilename"/> - </New> - </Arg> - </New> - - <Call class="org.eclipse.jetty.util.log.Log" name="info"><Arg>Redirecting stderr/stdout to <Ref id="ServerLogName"/></Arg></Call> - <Call class="java.lang.System" name="setErr"><Arg><Ref id="ServerLog"/></Arg></Call> - <Call class="java.lang.System" name="setOut"><Arg><Ref id="ServerLog"/></Arg></Call> - -</Configure> - - - diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-osgi-default.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-osgi-default.xml new file mode 100644 index 0000000000..dc7b48fb67 --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-osgi-default.xml @@ -0,0 +1,148 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> + +<!-- =============================================================== --> +<!-- Configure the Jetty Server --> +<!-- --> +<!-- Documentation of this file format can be found at: --> +<!-- http://docs.codehaus.org/display/JETTY/jetty.xml --> +<!-- --> +<!-- =============================================================== --> + + +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <!-- =========================================================== --> + <!-- Server Thread Pool --> + <!-- =========================================================== --> + <Set name="ThreadPool"> + <!-- Default queued blocking threadpool + --> + <New class="org.eclipse.jetty.util.thread.QueuedThreadPool"> + <Set name="minThreads">10</Set> + <Set name="maxThreads">200</Set> + </New> + + <!-- Optional Java 5 bounded threadpool with job queue + <New class="org.eclipse.jetty.util.thread.ExecutorThreadPool"> + <Arg name="coreSize" type="int">25</Arg> + <Arg name="maxSize" type="int">50</Arg> + <Arg name="maxIdleMs" type="long">30000</Arg> + </New> + --> + </Set> + + + + <!-- =========================================================== --> + <!-- Set connectors --> + <!-- =========================================================== --> + + <Call name="addConnector"> + <Arg> + <New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> + <Set name="host"><Property name="jetty.host" /></Set> + <Set name="port"><Property name="jetty.port" default="8080"/></Set> + <Set name="maxIdleTime">300000</Set> + <Set name="Acceptors">2</Set> + <Set name="statsOn">false</Set> + <Set name="confidentialPort">8443</Set> + <Set name="lowResourcesConnections">20000</Set> + <Set name="lowResourcesMaxIdleTime">5000</Set> + </New> + </Arg> + </Call> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- To add a HTTP blocking connector --> + <!-- mixin jetty-bio.xml: --> + <!-- java -jar start.jar etc/jetty.xml etc/jetty-bio.xml --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- To allow Jetty to be started from xinetd --> + <!-- mixin jetty-xinetd.xml: --> + <!-- java -jar start.jar etc/jetty.xml etc/jetty-xinetd.xml --> + <!-- --> + <!-- See jetty-xinetd.xml for further instructions. --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <!-- =========================================================== --> + <!-- Set handler Collection Structure --> + <!-- =========================================================== --> + <Set name="handler"> + <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection"> + <Set name="handlers"> + <Array type="org.eclipse.jetty.server.Handler"> + <Item> + <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/> + </Item> + <Item> + <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/> + </Item> + <Item> + <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/> + </Item> + </Array> + </Set> + </New> + </Set> + + <!-- =========================================================== --> + <!-- Configure the deployment manager --> + <!-- --> + <!-- Sets up 2 monitored dir app providers that are configured --> + <!-- to behave in a similaraly to the legacy ContextDeployer --> + <!-- and WebAppDeployer from previous versions of Jetty. --> + <!-- =========================================================== --> + <Call name="addBean"> + <Arg> + <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager"> + <Set name="contexts"> + <Ref id="Contexts" /> + </Set> + <Call name="setContextAttribute"> + <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg> + <Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg> + </Call> + <!-- Providers of OSGi Apps --> + <Call name="addAppProvider"> + <Arg> + <New class="org.eclipse.jetty.osgi.boot.OSGiAppProvider"> + <!-- + <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set> + --> + <Set name="scanInterval">5</Set> + <Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set> + <!-- comma separated list of bundle symbolic names that + contain custom tag libraries (*.tld files) + if those bundles don't exist or can't be loaded no errors or warning will be issued! + this default value is to plug the tld files of the reference implementation of JSF --> + <Set name="tldBundles"><Property name="org.eclipse.jetty.osgi.tldsbundles" default="javax.faces.jsf-impl" /></Set> + </New> + </Arg> + </Call> + + </New> + </Arg> + </Call> + + <!-- =========================================================== --> + <!-- extra options --> + <!-- =========================================================== --> + <Set name="stopAtShutdown">true</Set> + <Set name="sendServerVersion">true</Set> + <Set name="sendDateHeader">true</Set> + <Set name="gracefulShutdown">1000</Set> + + <!-- jetty-jndi by default --> + <Call class="java.lang.System" name="setProperty"> + <Arg>java.naming.factory.initial</Arg> + <Arg><Property name="java.naming.factory.initial" default="org.eclipse.jetty.jndi.InitialContextFactory"/></Arg> + </Call> + <Call class="java.lang.System" name="setProperty"> + <Arg>java.naming.factory.url.pkgs</Arg> + <Arg><Property name="java.naming.factory.url.pkgs" default="org.eclipse.jetty.jndi"/></Arg> + </Call> + +</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-plus.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-plus.xml deleted file mode 100644 index 3a9375f314..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-plus.xml +++ /dev/null @@ -1,81 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configure Jetty Plus features --> -<!-- --> -<!-- This file sets up a WebAppDeployer to automatically deploy all --> -<!-- webapps in $jetty.home/webapps-plus at startup time, and to --> -<!-- enable all of them with Plus features (jndi etc). --> -<!-- --> -<!-- You can instead configure individual webapps with Jetty Plus --> -<!-- features by using the ContextDeployer (configured in --> -<!-- $jetty.home/etc/jetty.xml), and ensuring that you set the --> -<!-- same set of classes listed below in the "plusConfig" as the --> -<!-- webapp's configurationClasses. --> -<!-- --> -<!-- For more information about Jetty Plus, see the Jetty wiki at --> -<!-- http://docs.codehaus.org/display/JETTY/Jetty+Wiki --> -<!-- =============================================================== --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- =========================================================== --> - <!-- Example JAAS realm setup. --> - <!-- The LoginModuleName must be exactly the same as in the --> - <!-- login.conf file, and the realm Name must be the same as in --> - <!-- the web.xml file. --> - <!-- =========================================================== --> - <!-- - <Call name="addLoginService"> - <Arg> - <New class="org.eclipse.jetty.plus.jaas.JAASLoginService"> - <Set name="name">xyzrealm</Set> - <Set name="LoginModuleName">xyz</Set> - </New> - </Arg> - </Call> - --> - - <!-- =========================================================== --> - <!-- Configurations for WebAppContexts --> - <!-- Sequence of configurations to enable Plus features. --> - <!-- =========================================================== --> - <Array id="plusConfig" type="java.lang.String"> - <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item> - <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item> - <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item> - <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item> - <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item> - <Item>org.eclipse.jetty.plus.webapp.Configuration</Item> - <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item> - <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item> - </Array> - - <!-- =========================================================== --> - <!-- Deploy all webapps in webapps-plus --> - <!-- =========================================================== --> - <!-- Uncomment the following to set up a WebAppDeployer that will --> - <!-- deploy webapps from a directory called webapps-plus. Note --> - <!-- that you will need to create this directory first! --> - <!-- - <Call name="addLifeCycle"> - <Arg> - <New class="org.eclipse.jetty.deploy.WebAppDeployer"> - <Set name="contexts"><Ref id="Contexts"/></Set> - <Set name="webAppDir"><SystemProperty name="jetty.home" default="."/>/webapps-plus</Set> - <Set name="parentLoaderPriority">false</Set> - <Set name="extract">true</Set> - <Set name="allowDuplicates">false</Set> - <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set> - <Set name="configurationClasses"><Ref id="plusConfig"/></Set> - <Call name="setAttribute"> - <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg> - <Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg> - </Call> - </New> - </Arg> - </Call> - --> - -</Configure> - diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-proxy.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-proxy.xml deleted file mode 100644 index 9fe82f1429..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-proxy.xml +++ /dev/null @@ -1,64 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configure the Jetty Server --> -<!-- --> -<!-- Documentation of this file format can be found at: --> -<!-- http://docs.codehaus.org/display/JETTY/jetty.xml --> -<!-- --> -<!-- =============================================================== --> - - -<Configure id="Proxy" class="org.eclipse.jetty.server.Server"> - - <!-- =========================================================== --> - <!-- Server Thread Pool --> - <!-- =========================================================== --> - <Set name="ThreadPool"> - <!-- Default queued blocking threadpool - --> - <New class="org.eclipse.jetty.util.thread.QueuedThreadPool"> - <Set name="minThreads">10</Set> - <Set name="maxThreads">50</Set> - </New> - </Set> - - - <!-- =========================================================== --> - <!-- Set connectors --> - <!-- =========================================================== --> - - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> - <Set name="host"><SystemProperty name="jetty.host" /></Set> - <Set name="port"><SystemProperty name="jetty.port" default="8888"/></Set> - <Set name="maxIdleTime">300000</Set> - <Set name="Acceptors">2</Set> - <Set name="statsOn">false</Set> - <Set name="lowResourcesConnections">20000</Set> - <Set name="lowResourcesMaxIdleTime">5000</Set> - </New> - </Arg> - </Call> - - <!-- =========================================================== --> - <Set name="handler"> - <New id="Servlets" class="org.eclipse.jetty.servlet.ServletHandler"> - <Call name="addServletWithMapping"> - <Arg>org.eclipse.jetty.servlets.ProxyServlet</Arg> - <Arg>/</Arg> - </Call> - </New> - </Set> - - <!-- =========================================================== --> - <!-- extra options --> - <!-- =========================================================== --> - <Set name="stopAtShutdown">true</Set> - <Set name="sendServerVersion">true</Set> - <Set name="sendDateHeader">true</Set> - <Set name="gracefulShutdown">1000</Set> - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-rewrite.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-rewrite.xml deleted file mode 100644 index da0eb7b2cd..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-rewrite.xml +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Mixin the RewriteHandler --> -<!-- =============================================================== --> - - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- =========================================================== --> - <!-- configure rewrite handler --> - <!-- =========================================================== --> - <Get id="oldhandler" name="handler"/> - - <Set name="handler"> - <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler"> - <Set name="handler"><Ref id="oldhandler"/></Set> - <Set name="rewriteRequestURI">true</Set> - <Set name="rewritePathInfo">false</Set> - <Set name="originalPathAttribute">requestedPath</Set> - - <!-- Add rule to protect against IE ssl bug --> - <Call name="addRule"> - <Arg> - <New class="org.eclipse.jetty.rewrite.handler.MsieSslRule"/> - </Arg> - </Call> - - <!-- protect favicon handling --> - <Call name="addRule"> - <Arg> - <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule"> - <Set name="pattern">/favicon.ico</Set> - <Set name="name">Cache-Control</Set> - <Set name="value">Max-Age=3600,public</Set> - <Set name="terminating">true</Set> - </New> - </Arg> - </Call> - - - <!-- use legacy API for some rewrites --> - <Call name="addRewriteRule"> - <Arg>/some/old/context/*</Arg> - <Arg>/test/dump/newcontext</Arg> - </Call> - <Call name="addRewriteRule"> - <Arg>/test/dump/rewrite/*</Arg> - <Arg>/test/dump/rewritten</Arg> - </Call> - <Call name="addRewriteRule"> - <Arg>/test/dump/rewrite/protect/*</Arg> - <Arg/> - </Call> - <Call name="addRewriteRule"> - <Arg>/test/*</Arg> - <Arg/> - </Call> - <Call name="addRewriteRule"> - <Arg>/*</Arg> - <Arg>/test</Arg> - </Call> - - <!-- add a regex rule --> - <Call name="addRule"> - <Arg> - <New class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule"> - <Set name="regex">/test/dump/regex/([^/]*)/(.*)</Set> - <Set name="replacement">/test/dump/$2/$1</Set> - </New> - </Arg> - </Call> - </New> - </Set> - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-setuid.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-setuid.xml deleted file mode 100644 index 9a30af7450..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-setuid.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"> - - -<!-- =============================================================== --> -<!-- Configure the Jetty SetUIDServer --> -<!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -jar start.jar etc/jetty-setuid.xml etc/jetty.xml --> -<!-- =============================================================== --> -<Configure id="Server" class="org.mortbay.setuid.SetUIDServer"> - <Set name="startServerAsPrivileged">false</Set> - <Set name="umask">2</Set> - <Set name="uid">jetty</Set> - <Set name="gid">jetty</Set> -</Configure> - diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-ssl.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-ssl.xml deleted file mode 100644 index f2ec1a4085..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-ssl.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configure SSL for the Jetty Server --> -<!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml --> -<!-- =============================================================== --> -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- if NIO is not available, use org.eclipse.jetty.server.ssl.SslSocketConnector --> - - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector"> - <Set name="Port"><Property name="jetty.port.ssl" default="8443" /></Set> - <Set name="maxIdleTime">30000</Set> - <Set name="Acceptors">2</Set> - <Set name="AcceptQueueSize">100</Set> - <Set name="Keystore"><Property name="jetty.home" default="." />/etc/keystore</Set> - <Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - <Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - <Set name="truststore"><Property name="jetty.home" default="." />/etc/keystore</Set> - <Set name="trustPassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - </New> - </Arg> - </Call> -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-sslengine.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-sslengine.xml deleted file mode 100644 index d908abbc93..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-sslengine.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configure SSL for the Jetty Server --> -<!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml --> -<!-- =============================================================== --> -<Configure id="Server" class="org.mortbay.jetty.Server"> - <Call name="addConnector"> - <Arg> - <New class="org.mortbay.jetty.security.SslSelectChannelConnector"> - <Set name="Port">8444</Set> - <Set name="maxIdleTime">30000</Set> - <Set name="Acceptors">2</Set> - <Set name="AcceptQueueSize">100</Set> - <Set name="Keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> - <Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - <Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - </New> - </Arg> - </Call> - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-stats.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-stats.xml deleted file mode 100644 index e0a0c7fec3..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-stats.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Mixin the Statistics Handler --> -<!-- =============================================================== --> - - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <Get id="oldhandler" name="handler"/> - - <Set name="handler"> - <New id="StatsHandler" class="org.eclipse.jetty.server.handler.StatisticsHandler"> - <Set name="handler"><Ref id="oldhandler"/></Set> - </New> - </Set> - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-win32-service.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-win32-service.xml deleted file mode 100644 index 20287ce772..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-win32-service.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configure the Jetty Server --> -<!-- --> -<!-- Documentation of this file format can be found at: --> -<!-- http://docs.codehaus.org/display/JETTY/jetty.xml --> -<!-- --> -<!-- =============================================================== --> - - -<Configure id="Server" class="org.mortbay.jetty.Server"> - - - <Call name="addLifeCycle"> - <Arg> - <New class="org.mortbay.jetty.win32service.Win32Service"> - <Set name="server"><Ref id="Server"/></Set> - </New> - </Arg> - </Call> - - <Set name="stopAtShutdown">true</Set> - <!-- ensure/prevent Server: header being sent to browsers --> - <Set name="sendServerVersion">true</Set> - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-xinetd.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-xinetd.xml deleted file mode 100644 index 0b6582572b..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-xinetd.xml +++ /dev/null @@ -1,56 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configuration for starting up Jetty using inetd/xinetd --> -<!-- This feature requires at least Java 5 --> -<!-- --> -<!-- Making it a mixin for convenience, but note that if used --> -<!-- with jetty.xml, Jetty will use multiple connectors --> -<!-- =============================================================== --> - -<!-- Sample xinetd configuration (restart xinetd after adding the configuration file) - -service jetty -{ - disable = no - - id = jetty - type = UNLISTED - wait = yes - socket_type = stream - - # change this - user = username - group = groupname - port = 2001 - - # sample script for running jetty as a service - # replace $JETTY_HOME with /path/to/jetty_home/ - server = $JETTY_HOME/bin/jetty-xinetd.sh -} - ---> - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - <Call name="addConnector"> - <Arg> - <!-- Inherited channel (from inetd/xinetd) --> - <New class="org.eclipse.jetty.server.nio.InheritedChannelConnector"> - - - <!-- Optional. Fallback in case System.inheritedChannel() does not give a ServerSocketChannel - <Set name="port"><SystemProperty name="jetty.service.port" default="8082"/></Set> - --> - - <!-- sane defaults --> - <Set name="maxIdleTime">300000</Set> - <Set name="Acceptors">2</Set> - <Set name="statsOn">false</Set> - <Set name="lowResourcesConnections">20000</Set> - <Set name="lowResourcesMaxIdleTime">5000</Set> - </New> - </Arg> - </Call> -</Configure> - diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml deleted file mode 100644 index 0f8e63625b..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml +++ /dev/null @@ -1,289 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- =============================================================== --> -<!-- Configure the Jetty Server --> -<!-- --> -<!-- Documentation of this file format can be found at: --> -<!-- http://docs.codehaus.org/display/JETTY/jetty.xml --> -<!-- --> -<!-- =============================================================== --> - - -<Configure id="Server" class="org.eclipse.jetty.server.Server"> - - <!-- =========================================================== --> - <!-- Server Thread Pool --> - <!-- =========================================================== --> - <Set name="ThreadPool"> - <!-- Default queued blocking threadpool - --> - <New class="org.eclipse.jetty.util.thread.QueuedThreadPool"> - <Set name="minThreads">10</Set> - <Set name="maxThreads">200</Set> - </New> - - <!-- Optional Java 5 bounded threadpool with job queue - <New class="org.eclipse.jetty.util.thread.ExecutorThreadPool"> - <Arg name="coreSize" type="int">25</Arg> - <Arg name="maxSize" type="int">50</Arg> - <Arg name="maxIdleMs" type="long">30000</Arg> - </New> - --> - </Set> - - - - <!-- =========================================================== --> - <!-- Set connectors --> - <!-- =========================================================== --> - - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> - <Set name="host"><Property name="jetty.host" /></Set> - <Set name="port"><Property name="jetty.port" default="8080"/></Set> - <Set name="maxIdleTime">300000</Set> - <Set name="Acceptors">2</Set> - <Set name="statsOn">false</Set> - <Set name="confidentialPort">8443</Set> - <Set name="lowResourcesConnections">20000</Set> - <Set name="lowResourcesMaxIdleTime">5000</Set> - </New> - </Arg> - </Call> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- To add a HTTPS SSL connector --> - <!-- mixin jetty-ssl.xml: --> - <!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <Call name="addConnector"> - <Arg> - <New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector"> - <Set name="Port"><Property name="jetty.port.ssl" default="8443" /></Set> - <Set name="maxIdleTime">30000</Set> - <Set name="Acceptors">2</Set> - <Set name="AcceptQueueSize">100</Set> - <Set name="Keystore"><Property name="jetty.home" default="." />/etc/keystore</Set> - <Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - <Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - <Set name="truststore"><Property name="jetty.home" default="." />/etc/keystore</Set> - <Set name="trustPassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - </New> - </Arg> - </Call> - - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- To add a HTTP blocking connector --> - <!-- mixin jetty-bio.xml: --> - <!-- java -jar start.jar etc/jetty.xml etc/jetty-bio.xml --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- To allow Jetty to be started from xinetd --> - <!-- mixin jetty-xinetd.xml: --> - <!-- java -jar start.jar etc/jetty.xml etc/jetty-xinetd.xml --> - <!-- --> - <!-- See jetty-xinetd.xml for further instructions. --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <!-- =========================================================== --> - <!-- Set handler Collection Structure --> - <!-- =========================================================== --> - <Set name="handler"> - <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection"> - <Set name="handlers"> - <Array type="org.eclipse.jetty.server.Handler"> - <Item> - <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/> - </Item> - <Item> - <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/> - </Item> - <Item> - <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/> - </Item> - </Array> - </Set> - </New> - </Set> - - <!-- =========================================================== --> - <!-- Configure the deployment manager --> - <!-- --> - <!-- Sets up 2 monitored dir app providers that are configured --> - <!-- to behave in a similaraly to the legacy ContextDeployer --> - <!-- and WebAppDeployer from previous versions of Jetty. --> - <!-- =========================================================== --> - <Call name="addBean"> - <Arg> - <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager"> - <Set name="contexts"> - <Ref id="Contexts" /> - </Set> - <Call name="setContextAttribute"> - <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg> - <Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg> - </Call> - <!-- Providers of Apps via Context XML files. - Configured to behave similar to the legacy ContextDeployer --> - <Call name="addAppProvider"> - <Arg> - <New class="org.eclipse.jetty.deploy.providers.ContextProvider"> - <Set name="monitoredDir"><Property name="jetty.home" default="." />/contexts</Set> - <Set name="scanInterval">5</Set> - </New> - </Arg> - </Call> - <!-- Providers of Apps via WAR file existence. - Configured to behave similar to the legacy WebAppDeployer --> - <Call name="addAppProvider"> - <Arg> - <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> - <Set name="monitoredDir"><Property name="jetty.home" default="." />/webapps</Set> - <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set> - <Set name="scanInterval">5</Set> - <Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set> - </New> - </Arg> - </Call> - <!-- Providers of OSGi Apps --> - <Call name="addAppProvider"> - <Arg> - <New class="org.eclipse.jetty.osgi.boot.OSGiAppProvider"> - <Set name="monitoredDir"><Property name="jetty.home" default="." />/webapps</Set> - <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set> - <Set name="scanInterval">5</Set> - <Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set> - <!-- comma separated list of bundle symbolic names that - contain custom tag libraries (*.tld files) - if those bundles don't exist or can't be loaded no errors or warning will be issued! - this default value is to plug the tld files of the reference implementation of JSF --> - <Set name="tldBundles"><Property name="org.eclipse.jetty.osgi.tldsbundles" default="javax.faces.jsf-impl" /></Set> - </New> - </Arg> - </Call> - - </New> - </Arg> - </Call> - - <!-- =========================================================== --> - <!-- Configure the context deployer --> - <!-- A context deployer will deploy contexts described in --> - <!-- configuration files discovered in a directory. --> - <!-- The configuration directory can be scanned for hot --> - <!-- deployments at the configured scanInterval. --> - <!-- --> - <!-- This deployer is configured to deploy contexts configured --> - <!-- in the $JETTY_HOME/contexts directory --> - <!-- --> - <!-- =========================================================== --> - <!-- - <Call name="addBean"> - <Arg> - <New class="org.eclipse.jetty.deploy.ContextDeployer"> - <Set name="contexts"><Ref id="Contexts"/></Set> - <Set name="configurationDir"><Property name="jetty.home" default="."/>/contexts</Set> - <Set name="scanInterval">5</Set> - <Call name="setAttribute"> - <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg> - <Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg> - </Call> - </New> - </Arg> - </Call> - --> - - <!-- =========================================================== --> - <!-- Configure the webapp deployer. --> - <!-- A webapp deployer will deploy standard webapps discovered --> - <!-- in a directory at startup, without the need for additional --> - <!-- configuration files. It does not support hot deploy or --> - <!-- non standard contexts (see ContextDeployer above). --> - <!-- --> - <!-- This deployer is configured to deploy webapps from the --> - <!-- $JETTY_HOME/webapps directory --> - <!-- --> - <!-- Normally only one type of deployer need be used. --> - <!-- --> - <!-- =========================================================== --> - <!-- - <Call name="addBean"> - <Arg> - <New class="org.eclipse.jetty.deploy.WebAppDeployer"> - <Set name="contexts"><Ref id="Contexts"/></Set> - <Set name="webAppDir"><Property name="jetty.home" default="."/>/webapps</Set> - <Set name="parentLoaderPriority">false</Set> - <Set name="extract">true</Set> - <Set name="allowDuplicates">false</Set> - <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set> - <Call name="setAttribute"> - <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg> - <Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg> - </Call> - </New> - </Arg> - </Call> - --> - - <!-- =========================================================== --> - <!-- Configure Authentication Login Service --> - <!-- Realms may be configured for the entire server here, or --> - <!-- they can be configured for a specific web app in a context --> - <!-- configuration (see $(jetty.home)/contexts/test.xml for an --> - <!-- example). --> - <!-- =========================================================== --> - <Call name="addBean"> - <Arg> - <New class="org.eclipse.jetty.security.HashLoginService"> - <Set name="name">Test Realm</Set> - <Set name="config"><Property name="jetty.home" default="."/>/etc/realm.properties</Set> - <Set name="refreshInterval">0</Set> - </New> - </Arg> - </Call> - - <!-- =========================================================== --> - <!-- Configure Request Log --> - <!-- Request logs may be configured for the entire server here, --> - <!-- or they can be configured for a specific web app in a --> - <!-- contexts configuration (see $(jetty.home)/contexts/test.xml --> - <!-- for an example). --> - <!-- =========================================================== --> - <Ref id="RequestLog"> - <Set name="requestLog"> - <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> - <Set name="filename"><Property name="jetty.home" default="."/>/logs/yyyy_mm_dd.request.log</Set> - <Set name="filenameDateFormat">yyyy_MM_dd</Set> - <Set name="retainDays">90</Set> - <Set name="append">true</Set> - <Set name="extended">false</Set> - <Set name="logCookies">false</Set> - <Set name="LogTimeZone">GMT</Set> - </New> - </Set> - </Ref> - - <!-- =========================================================== --> - <!-- extra options --> - <!-- =========================================================== --> - <Set name="stopAtShutdown">true</Set> - <Set name="sendServerVersion">true</Set> - <Set name="sendDateHeader">true</Set> - <Set name="gracefulShutdown">1000</Set> - - <!-- jetty-jndi by default --> - <Call class="java.lang.System" name="setProperty"> - <Arg>java.naming.factory.initial</Arg> - <Arg><SystemProperty name="java.naming.factory.initial" default="org.eclipse.jetty.jndi.InitialContextFactory"/></Arg> - </Call> - <Call class="java.lang.System" name="setProperty"> - <Arg>java.naming.factory.url.pkgs</Arg> - <Arg><SystemProperty name="java.naming.factory.url.pkgs" default="org.eclipse.jetty.jndi"/></Arg> - </Call> - -</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/login.conf b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/login.conf deleted file mode 100644 index 731956c870..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/login.conf +++ /dev/null @@ -1,5 +0,0 @@ -xyz { -org.mortbay.jetty.plus.jaas.spi.PropertyFileLoginModule required -debug="true" -file="${jetty.home}/etc/login.properties"; -}; diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/login.properties b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/login.properties deleted file mode 100644 index 61e3203731..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/login.properties +++ /dev/null @@ -1 +0,0 @@ -me=me,me,roleA diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/webdefault.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/webdefault.xml deleted file mode 100644 index 0078e77dd7..0000000000 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/webdefault.xml +++ /dev/null @@ -1,404 +0,0 @@ -<?xml version="1.0" encoding="ISO-8859-1"?> - -<!-- ===================================================================== --> -<!-- This file contains the default descriptor for web applications. --> -<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> -<!-- The intent of this descriptor is to include jetty specific or common --> -<!-- configuration for all webapps. If a context has a webdefault.xml --> -<!-- descriptor, it is applied before the contexts own web.xml file --> -<!-- --> -<!-- A context may be assigned a default descriptor by: --> -<!-- + Calling WebApplicationContext.setDefaultsDescriptor --> -<!-- + Passed an arg to addWebApplications --> -<!-- --> -<!-- This file is used both as the resource within the jetty.jar (which is --> -<!-- used as the default if no explicit defaults descriptor is set) and it --> -<!-- is copied to the etc directory of the Jetty distro and explicitly --> -<!-- by the jetty.xml file. --> -<!-- --> -<!-- ===================================================================== --> -<web-app - xmlns="http://java.sun.com/xml/ns/javaee" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" - metadata-complete="true" - version="2.5"> - - <description> - Default web.xml file. - This file is applied to a Web application before it's own WEB_INF/web.xml file - </description> - - - <!-- ==================================================================== --> - <!-- Context params to control Session Cookies --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- UNCOMMENT TO ACTIVATE - <context-param> - <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name> - <param-value>127.0.0.1</param-value> - </context-param> - - <context-param> - <param-name>org.eclipse.jetty.servlet.SessionPath</param-name> - <param-value>/</param-value> - </context-param> - - <context-param> - <param-name>org.eclipse.jetty.servlet.MaxAge</param-name> - <param-value>-1</param-value> - </context-param> - --> - - - <!-- ==================================================================== --> - <!-- The default servlet. --> - <!-- This servlet, normally mapped to /, provides the handling for static --> - <!-- content, OPTIONS and TRACE methods for the context. --> - <!-- The following initParameters are supported: --> - <!-- --> - <!-- acceptRanges If true, range requests and responses are --> - <!-- supported --> - <!-- --> - <!-- dirAllowed If true, directory listings are returned if no --> - <!-- welcome file is found. Else 403 Forbidden. --> - <!-- --> - <!-- welcomeServlets If true, attempt to dispatch to welcome files --> - <!-- that are servlets, if no matching static --> - <!-- resources can be found. --> - <!-- --> - <!-- redirectWelcome If true, redirect welcome file requests --> - <!-- else use request dispatcher forwards --> - <!-- --> - <!-- gzip If set to true, then static content will be served--> - <!-- as gzip content encoded if a matching resource is --> - <!-- found ending with ".gz" --> - <!-- --> - <!-- resoureBase Can be set to replace the context resource base --> - <!-- --> - <!-- relativeResourceBase --> - <!-- Set with a pathname relative to the base of the --> - <!-- servlet context root. Useful for only serving --> - <!-- static content from only specific subdirectories. --> - <!-- --> - <!-- useFileMappedBuffer --> - <!-- If set to true (the default), a memory mapped --> - <!-- file buffer will be used to serve static content --> - <!-- when using an NIO connector. Setting this value --> - <!-- to false means that a direct buffer will be used --> - <!-- instead. If you are having trouble with Windows --> - <!-- file locking, set this to false. --> - <!-- --> - <!-- cacheControl If set, all static content will have this value --> - <!-- set as the cache-control header. --> - <!-- --> - <!-- maxCacheSize Maximum size of the static resource cache --> - <!-- --> - <!-- maxCachedFileSize Maximum size of any single file in the cache --> - <!-- --> - <!-- maxCachedFiles Maximum number of files in the cache --> - <!-- --> - <!-- cacheType "nio", "bio" or "both" to determine the type(s) --> - <!-- of resource cache. A bio cached buffer may be used--> - <!-- by nio but is not as efficient as a nio buffer. --> - <!-- An nio cached buffer may not be used by bio. --> - <!-- --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <servlet> - <servlet-name>default</servlet-name> - <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class> - <init-param> - <param-name>acceptRanges</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <param-name>dirAllowed</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <param-name>welcomeServlets</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>redirectWelcome</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>maxCacheSize</param-name> - <param-value>256000000</param-value> - </init-param> - <init-param> - <param-name>maxCachedFileSize</param-name> - <param-value>10000000</param-value> - </init-param> - <init-param> - <param-name>maxCachedFiles</param-name> - <param-value>1000</param-value> - </init-param> - <init-param> - <param-name>cacheType</param-name> - <param-value>both</param-value> - </init-param> - <init-param> - <param-name>gzip</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <param-name>useFileMappedBuffer</param-name> - <param-value>true</param-value> - </init-param> - <!-- - <init-param> - <param-name>cacheControl</param-name> - <param-value>max-age=3600,public</param-value> - </init-param> - --> - <load-on-startup>0</load-on-startup> - </servlet> - - <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> - - - <!-- ==================================================================== --> - <!-- JSP Servlet --> - <!-- This is the jasper JSP servlet from the jakarta project --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- The JSP page compiler and execution servlet, which is the mechanism --> - <!-- used by Glassfish to support JSP pages. Traditionally, this servlet --> - <!-- is mapped to URL patterh "*.jsp". This servlet supports the --> - <!-- following initialization parameters (default values are in square --> - <!-- brackets): --> - <!-- --> - <!-- checkInterval If development is false and reloading is true, --> - <!-- background compiles are enabled. checkInterval --> - <!-- is the time in seconds between checks to see --> - <!-- if a JSP page needs to be recompiled. [300] --> - <!-- --> - <!-- compiler Which compiler Ant should use to compile JSP --> - <!-- pages. See the Ant documenation for more --> - <!-- information. [javac] --> - <!-- --> - <!-- classdebuginfo Should the class file be compiled with --> - <!-- debugging information? [true] --> - <!-- --> - <!-- classpath What class path should I use while compiling --> - <!-- generated servlets? [Created dynamically --> - <!-- based on the current web application] --> - <!-- Set to ? to make the container explicitly set --> - <!-- this parameter. --> - <!-- --> - <!-- development Is Jasper used in development mode (will check --> - <!-- for JSP modification on every access)? [true] --> - <!-- --> - <!-- enablePooling Determines whether tag handler pooling is --> - <!-- enabled [true] --> - <!-- --> - <!-- fork Tell Ant to fork compiles of JSP pages so that --> - <!-- a separate JVM is used for JSP page compiles --> - <!-- from the one Tomcat is running in. [true] --> - <!-- --> - <!-- ieClassId The class-id value to be sent to Internet --> - <!-- Explorer when using <jsp:plugin> tags. --> - <!-- [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93] --> - <!-- --> - <!-- javaEncoding Java file encoding to use for generating java --> - <!-- source files. [UTF-8] --> - <!-- --> - <!-- keepgenerated Should we keep the generated Java source code --> - <!-- for each page instead of deleting it? [true] --> - <!-- --> - <!-- logVerbosityLevel The level of detailed messages to be produced --> - <!-- by this servlet. Increasing levels cause the --> - <!-- generation of more messages. Valid values are --> - <!-- FATAL, ERROR, WARNING, INFORMATION, and DEBUG. --> - <!-- [WARNING] --> - <!-- --> - <!-- mappedfile Should we generate static content with one --> - <!-- print statement per input line, to ease --> - <!-- debugging? [false] --> - <!-- --> - <!-- --> - <!-- reloading Should Jasper check for modified JSPs? [true] --> - <!-- --> - <!-- suppressSmap Should the generation of SMAP info for JSR45 --> - <!-- debugging be suppressed? [false] --> - <!-- --> - <!-- dumpSmap Should the SMAP info for JSR45 debugging be --> - <!-- dumped to a file? [false] --> - <!-- False if suppressSmap is true --> - <!-- --> - <!-- scratchdir What scratch directory should we use when --> - <!-- compiling JSP pages? [default work directory --> - <!-- for the current web application] --> - <!-- --> - <!-- tagpoolMaxSize The maximum tag handler pool size [5] --> - <!-- --> - <!-- xpoweredBy Determines whether X-Powered-By response --> - <!-- header is added by generated servlet [false] --> - <!-- --> - <!-- If you wish to use Jikes to compile JSP pages: --> - <!-- Set the init parameter "compiler" to "jikes". Define --> - <!-- the property "-Dbuild.compiler.emacs=true" when starting Jetty --> - <!-- to cause Jikes to emit error messages in a format compatible with --> - <!-- Jasper. --> - <!-- If you get an error reporting that jikes can't use UTF-8 encoding, --> - <!-- try setting the init parameter "javaEncoding" to "ISO-8859-1". --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <servlet id="jsp"> - <servlet-name>jsp</servlet-name> - <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> - <init-param> - <param-name>logVerbosityLevel</param-name> - <param-value>DEBUG</param-value> - </init-param> - <init-param> - <param-name>fork</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>xpoweredBy</param-name> - <param-value>false</param-value> - </init-param> - <!-- - <init-param> - <param-name>classpath</param-name> - <param-value>?</param-value> - </init-param> - --> - <load-on-startup>0</load-on-startup> - </servlet> - - <servlet-mapping> - <servlet-name>jsp</servlet-name> - <url-pattern>*.jsp</url-pattern> - <url-pattern>*.jspf</url-pattern> - <url-pattern>*.jspx</url-pattern> - <url-pattern>*.xsp</url-pattern> - <url-pattern>*.JSP</url-pattern> - <url-pattern>*.JSPF</url-pattern> - <url-pattern>*.JSPX</url-pattern> - <url-pattern>*.XSP</url-pattern> - </servlet-mapping> - - <!-- ==================================================================== --> - <!-- Dynamic Servlet Invoker. --> - <!-- This servlet invokes anonymous servlets that have not been defined --> - <!-- in the web.xml or by other means. The first element of the pathInfo --> - <!-- of a request passed to the envoker is treated as a servlet name for --> - <!-- an existing servlet, or as a class name of a new servlet. --> - <!-- This servlet is normally mapped to /servlet/* --> - <!-- This servlet support the following initParams: --> - <!-- --> - <!-- nonContextServlets If false, the invoker can only load --> - <!-- servlets from the contexts classloader. --> - <!-- This is false by default and setting this --> - <!-- to true may have security implications. --> - <!-- --> - <!-- verbose If true, log dynamic loads --> - <!-- --> - <!-- * All other parameters are copied to the --> - <!-- each dynamic servlet as init parameters --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- Uncomment for dynamic invocation - <servlet> - <servlet-name>invoker</servlet-name> - <servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class> - <init-param> - <param-name>verbose</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>nonContextServlets</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>dynamicParam</param-name> - <param-value>anyValue</param-value> - </init-param> - <load-on-startup>0</load-on-startup> - </servlet> - - <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping> - --> - - - - <!-- ==================================================================== --> - <session-config> - <session-timeout>30</session-timeout> - </session-config> - - <!-- ==================================================================== --> - <!-- Default MIME mappings --> - <!-- The default MIME mappings are provided by the mime.properties --> - <!-- resource in the org.eclipse.jetty.server.jar file. Additional or modified --> - <!-- mappings may be specified here --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- UNCOMMENT TO ACTIVATE - <mime-mapping> - <extension>mysuffix</extension> - <mime-type>mymime/type</mime-type> - </mime-mapping> - --> - - <!-- ==================================================================== --> - <welcome-file-list> - <welcome-file>index.html</welcome-file> - <welcome-file>index.htm</welcome-file> - <welcome-file>index.jsp</welcome-file> - </welcome-file-list> - - <!-- ==================================================================== --> - <locale-encoding-mapping-list> - <locale-encoding-mapping><locale>ar</locale><encoding>ISO-8859-6</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>be</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>bg</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>ca</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>cs</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>da</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>de</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>el</locale><encoding>ISO-8859-7</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>en</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>es</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>et</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>fi</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>fr</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>hr</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>hu</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>is</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>it</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>iw</locale><encoding>ISO-8859-8</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>ja</locale><encoding>Shift_JIS</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>ko</locale><encoding>EUC-KR</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>lt</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>lv</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>mk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>nl</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>no</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>pl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>pt</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>ro</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>ru</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>sh</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>sk</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>sl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>sq</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>sr</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>sv</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>tr</locale><encoding>ISO-8859-9</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>uk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>zh</locale><encoding>GB2312</encoding></locale-encoding-mapping> - <locale-encoding-mapping><locale>zh_TW</locale><encoding>Big5</encoding></locale-encoding-mapping> - </locale-encoding-mapping-list> - - <security-constraint> - <web-resource-collection> - <web-resource-name>Disable TRACE</web-resource-name> - <url-pattern>/</url-pattern> - <http-method>TRACE</http-method> - </web-resource-collection> - <auth-constraint/> - </security-constraint> - -</web-app> - diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index a3e659924b..daf9f05ebc 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -2,7 +2,7 @@ <parent> <groupId>org.eclipse.jetty.osgi</groupId> <artifactId>jetty-osgi-project</artifactId> - <version>8.0.0.M1</version> + <version>8.0.0.M1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> @@ -78,11 +78,12 @@ </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.osgi.boot.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml.tycho b/jetty-osgi/jetty-osgi-boot/pom.xml.tycho deleted file mode 100644 index 22cf4d5aa6..0000000000 --- a/jetty-osgi/jetty-osgi-boot/pom.xml.tycho +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <modelVersion>4.0.0</modelVersion> - <parent> - <artifactId>jetty-osgi</artifactId> - <groupId>org.eclipse.jetty.osgi</groupId> - <version>7.0.1-SNAPSHOT</version> - </parent> - - <artifactId>org.eclipse.jetty.osgi.boot</artifactId> - <packaging>eclipse-plugin</packaging> - - <!--build> - <resources> - <resource> - <excludes> - <exclude>jettyhome/lib/ext/*.jar</exclude> - <exclude>jettyhome/logs/*.log</exclude> - </excludes> - </resource> - </resources> - </build--> -</project> diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java index 1c7250fcef..a7484296bf 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java @@ -18,8 +18,11 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.Properties; -import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerExtender; +import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper; +import org.eclipse.jetty.osgi.boot.internal.serverfactory.JettyServerServiceTracker; +import org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper; import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerServiceTracker; +import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer; import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; @@ -27,8 +30,8 @@ import org.eclipse.jetty.webapp.WebAppContext; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.BundleTracker; /** * Experiment: bootstrap jetty's complete distrib from an OSGi bundle. Progress: @@ -65,6 +68,11 @@ public class JettyBootstrapActivator implements BundleActivator private Server _server; private JettyContextHandlerServiceTracker _jettyContextHandlerTracker; private PackageAdminServiceTracker _packageAdminServiceTracker; + private BundleTracker _webBundleTracker; + +// private ServiceRegistration _jettyServerFactoryService; + private JettyServerServiceTracker _jettyServerServiceTracker; + /** * Setup a new jetty Server, registers it as a service. Setup the Service @@ -82,25 +90,30 @@ public class JettyBootstrapActivator implements BundleActivator // should activate. _packageAdminServiceTracker = new PackageAdminServiceTracker(context); - // todo: replace all this by the ManagedFactory so that we can start - // multiple jetty servers. - _server = new Server(); - // expose the server as a service. - _registeredServer = context.registerService(_server.getClass().getName(),_server,new Properties()); + _jettyServerServiceTracker = new JettyServerServiceTracker(); + context.addServiceListener(_jettyServerServiceTracker,"(objectclass=" + Server.class.getName() + ")"); + + //Register the Jetty Server Factory as a ManagedServiceFactory: +// Properties jettyServerMgdFactoryServiceProps = new Properties(); +// jettyServerMgdFactoryServiceProps.put("pid", OSGiWebappConstants.MANAGED_JETTY_SERVER_FACTORY_PID); +// _jettyServerFactoryService = context.registerService( +// ManagedServiceFactory.class.getName(), new JettyServersManagedFactory(), +// jettyServerMgdFactoryServiceProps); + + _jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(_jettyServerServiceTracker); + // the tracker in charge of the actual deployment // and that will configure and start the jetty server. - _jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(context,_server); - - // TODO: add a couple more checks on the properties? - // kind of nice not to so we can debug what is missing easily. context.addServiceListener(_jettyContextHandlerTracker,"(objectclass=" + ContextHandler.class.getName() + ")"); - // now ready to support the Extender pattern: - JettyContextHandlerExtender jettyContexHandlerExtender = new JettyContextHandlerExtender(); - context.addBundleListener(jettyContexHandlerExtender); - - jettyContexHandlerExtender.init(context); - + //see if we shoult start a default jetty instance right now. + DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context); + + // now ready to support the Extender pattern: + _webBundleTracker = new BundleTracker(context, + Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer()); + _webBundleTracker.open(); + } /* @@ -113,32 +126,68 @@ public class JettyBootstrapActivator implements BundleActivator { try { + + if (_webBundleTracker != null) + { + _webBundleTracker.close(); + _webBundleTracker = null; + } if (_jettyContextHandlerTracker != null) { _jettyContextHandlerTracker.stop(); context.removeServiceListener(_jettyContextHandlerTracker); + _jettyContextHandlerTracker = null; + } + if (_jettyServerServiceTracker != null) + { + _jettyServerServiceTracker.stop(); + context.removeServiceListener(_jettyServerServiceTracker); + _jettyServerServiceTracker = null; } if (_packageAdminServiceTracker != null) { _packageAdminServiceTracker.stop(); context.removeServiceListener(_packageAdminServiceTracker); + _packageAdminServiceTracker = null; } if (_registeredServer != null) { try { _registeredServer.unregister(); - _registeredServer = null; } catch (IllegalArgumentException ill) { // already unregistered. } + finally + { + _registeredServer = null; + } } +// if (_jettyServerFactoryService != null) +// { +// try +// { +// _jettyServerFactoryService.unregister(); +// } +// catch (IllegalArgumentException ill) +// { +// // already unregistered. +// } +// finally +// { +// _jettyServerFactoryService = null; +// } +// } + } finally { - _server.stop(); + if (_server != null) + { + _server.stop(); + } INSTANCE = null; } } @@ -148,8 +197,8 @@ public class JettyBootstrapActivator implements BundleActivator * registers it as an OSGi service. The tracker * {@link JettyContextHandlerServiceTracker} will do the actual deployment. * - * @param context - * The current bundle context + * @param contributor + * The bundle * @param webappFolderPath * The path to the root of the webapp. Must be a path relative to * bundle; either an absolute path. @@ -171,18 +220,15 @@ public class JettyBootstrapActivator implements BundleActivator * registers it as an OSGi service. The tracker * {@link JettyContextHandlerServiceTracker} will do the actual deployment. * - * @param context - * The current bundle context + * @param contributor + * The bundle * @param webappFolderPath * The path to the root of the webapp. Must be a path relative to * bundle; either an absolute path. * @param contextPath * The context path. Must start with "/" - * @param thisBundleInstallationOverride - * The location to a folder where the context file is located - * This overrides the default behavior that consists of using the - * location where the bundle is installed. Useful when in fact - * the webapp contributed is not inside a bundle. + * @param dic + * TODO: parameter description * @throws Exception */ public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception @@ -220,17 +266,15 @@ public class JettyBootstrapActivator implements BundleActivator * @param contextFilePath * The path to the file inside the bundle that defines the * context. - * @param thisBundleInstallationOverride - * The location to a folder where the context file is located - * This overrides the default behavior that consists of using the - * location where the bundle is installed. Useful when in fact - * the webapp contributed is not inside a bundle. + * @param dic + * TODO: parameter description * @throws Exception */ public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception { ContextHandler contextHandler = new ContextHandler(); dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH,contextFilePath); + dic.put(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE,Boolean.TRUE.toString()); contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic); } @@ -238,5 +282,6 @@ public class JettyBootstrapActivator implements BundleActivator { // todo } + }
\ No newline at end of file diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java index 9ddc27bc74..eb93a8f3f7 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) 2009 Mortbay, Inc. +// Copyright (c) 2009-2010 Mortbay, Inc. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,6 +25,8 @@ import org.eclipse.jetty.deploy.providers.ContextProvider; import org.eclipse.jetty.deploy.providers.ScanningAppProvider; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.WebAppContext; +import org.osgi.framework.Bundle; /** * AppProvider for OSGi. Supports the configuration of ContextHandlers and @@ -43,7 +45,7 @@ import org.eclipse.jetty.util.resource.Resource; public class OSGiAppProvider extends ScanningAppProvider implements AppProvider { - private boolean _extractWars = false; + private boolean _extractWars = true; private boolean _parentLoaderPriority = false; private String _defaultsDescriptor; private String _tldBundles; @@ -91,8 +93,6 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider /** * Default OSGiAppProvider consutructed when none are defined in the * jetty.xml configuration. - * - * @param contextsDir */ public OSGiAppProvider() { @@ -111,7 +111,7 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider this(); setMonitoredDir(Resource.newResource(contextsDir.toURI())); } - + /** * Returns the ContextHandler that was created by WebappRegistractionHelper * @@ -140,19 +140,39 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider super.setDeploymentManager(deploymentManager); } + private static String getOriginId(Bundle contributor, String pathInBundle) + { + return contributor.getSymbolicName() + "-" + contributor.getVersion().toString() + + (pathInBundle.startsWith("/") ? pathInBundle : "/" + pathInBundle); + } + + /** + * @param context + * @throws Exception + */ + public void addContext(Bundle contributor, String pathInBundle, ContextHandler context) throws Exception + { + addContext(getOriginId(contributor, pathInBundle), context); + } /** * @param context * @throws Exception */ - public void addContext(ContextHandler context) throws Exception + public void addContext(String originId, ContextHandler context) throws Exception { // TODO apply configuration specific to this provider + if (context instanceof WebAppContext) + { + ((WebAppContext)context).setExtractWAR(isExtract()); + } // wrap context as an App - App app = new App(getDeploymentManager(),this,context.getDisplayName(),context); + App app = new App(getDeploymentManager(),this,originId,context); getDeployedApps().put(context.getDisplayName(),app); getDeploymentManager().addApp(app); } + + /** * Called by the scanner of the context files directory. If we find the @@ -274,6 +294,17 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider return null; } } + + public boolean isExtract() + { + return _extractWars; + } + + public void setExtract(boolean extract) + { + _extractWars=extract; + } + /* ------------------------------------------------------------ */ /** diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java new file mode 100644 index 0000000000..c2bddc290c --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java @@ -0,0 +1,51 @@ +// ======================================================================== +// Copyright (c) 2009 Intalio, Inc. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// Contributors: +// Hugues Malphettes - initial API and implementation +// ======================================================================== +package org.eclipse.jetty.osgi.boot; + +/** + * Name of the properties that configure a jetty Server OSGi service. + */ +public class OSGiServerConstants +{ + //for managed jetty instances, name of the configuration parameters + /** + * PID of the jetty servers's ManagedFactory + */ + public static final String MANAGED_JETTY_SERVER_FACTORY_PID = "org.eclipse.jetty.osgi.boot.managedserverfactory"; + + /** + * The associated value of that configuration parameter is the name under which this + * instance of the jetty server is tracked. + * When a ContextHandler is deployed and it specifies the managedServerName property, it is deployed + * on the corresponding jetty managed server or it throws an exception: jetty server not available. + */ + public static final String MANAGED_JETTY_SERVER_NAME = "managedServerName"; + /** + * Name of the 'default' jetty server instance. + * Usually the first one to be created. + */ + public static final String MANAGED_JETTY_SERVER_DEFAULT_NAME = "defaultJettyServer"; + + /** + * List of URLs to the jetty.xml files that configure th server. + */ + public static final String MANAGED_JETTY_XML_CONFIG_URLS = "jetty.etc.config.urls"; + + /** + * List of URLs to the folders where the legacy J2EE shared libraries are stored aka lib/ext, lib/jsp etc. + */ + public static final String MANAGED_JETTY_SHARED_LIB_FOLDER_URLS = "managedJettySharedLibFolderUrls"; + +} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java index c6c35d74f8..c6abc47c5b 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java @@ -15,7 +15,7 @@ package org.eclipse.jetty.osgi.boot; /** - * + * Name of the service properties for a ContextHandler that configure a webapp deployed on jetty OSGi. */ public class OSGiWebappConstants { @@ -66,13 +66,5 @@ public class OSGiWebappConstants * location if not null useful to install webapps or jetty context files * that are in fact not embedded in a bundle */ - public static final String SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE = "thisBundleInstall"; - - // sys prop config of jetty: - /** - * contains a comma separated list of pathes to the etc/jetty-*.xml files - * used to configure jetty. By default the value is 'etc/jetty.xml' when the - * path is relative the file is resolved relatively to jettyhome. - */ - public static final String SYS_PROP_JETTY_ETC_FILES = "jetty.etc.files"; + public static final String SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE = "thisBundleInstall"; } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java index 67104b7173..9c989c7f7e 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java @@ -30,7 +30,7 @@ public class TldLocatableURLClassloaderWithInsertedJettyClassloader extends TldL /** * - * @param osgiClassLoader + * @param osgiClassLoaderParent * The parent classloader * @param internalClassLoader * The classloader that will be at the same level than the diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java new file mode 100644 index 0000000000..7456cba037 --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java @@ -0,0 +1,253 @@ +// ======================================================================== +// Copyright (c) 2010 Intalio, Inc. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// Contributors: +// Hugues Malphettes - initial API and implementation +// ======================================================================== +package org.eclipse.jetty.osgi.boot.internal.serverfactory; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Properties; +import java.util.StringTokenizer; + +import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator; +import org.eclipse.jetty.osgi.boot.OSGiServerConstants; +import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper; +import org.eclipse.jetty.server.Server; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; + +/** + * Called by the {@link JettyBootstrapActivator} during the starting of the bundle. + * If the system property 'jetty.home' is defined and points to a folder, + * then setup the corresponding jetty server and starts it. + */ +public class DefaultJettyAtJettyHomeHelper { + + /** + * contains a comma separated list of pathes to the etc/jetty-*.xml files + * used to configure jetty. By default the value is 'etc/jetty.xml' when the + * path is relative the file is resolved relatively to jettyhome. + */ + public static final String SYS_PROP_JETTY_ETC_FILES = OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS; + + /** + * Usual system property used as the hostname for a typical jetty configuration. + */ + public static final String SYS_PROP_JETTY_HOME = "jetty.home"; + /** + * System property to point to a bundle that embeds a jetty configuration + * and that jetty configuration should be the default jetty server. + * First we look for jetty.home. If we don't find it then we look for this property. + */ + public static final String SYS_PROP_JETTY_HOME_BUNDLE = "jetty.home.bundle"; + /** + * Usual system property used as the hostname for a typical jetty configuration. + */ + public static final String SYS_PROP_JETTY_HOST = "jetty.host"; + /** + * Usual system property used as the port for http for a typical jetty configuration. + */ + public static final String SYS_PROP_JETTY_PORT = "jetty.port"; + /** + * Usual system property used as the port for https for a typical jetty configuration. + */ + public static final String SYS_PROP_JETTY_PORT_SSL = "jetty.port.ssl"; + + + /** + * Called by the JettyBootStrapActivator. + * If the system property jetty.home is defined and points to a folder, + * deploys the corresponding jetty server. + * <p> + * If the system property jetty.home.bundle is defined and points to a bundle. + * Look for the configuration of jetty inside that bundle and deploys the corresponding bundle. + * </p> + * <p> + * In both cases reads the system property 'jetty.etc.config.urls' to locate the configuration + * files for the deployed jetty. It is a comma spearate list of URLs or relative paths inside the bundle or folder + * to the config files. If underfined it defaults to 'etc/jetty.xml'. + * </p> + * <p> + * In both cases the system properties jetty.host, jetty.port and jetty.port.ssl are passed to the configuration files + * that might use them as part of their properties. + * </p> + */ + public static void startJettyAtJettyHome(BundleContext bundleContext) + { + String jettyHomeSysProp = System.getProperty(SYS_PROP_JETTY_HOME); + String jettyHomeBundleSysProp = System.getProperty(SYS_PROP_JETTY_HOME_BUNDLE); + File jettyHome = null; + Bundle jettyHomeBundle = null; + if (jettyHomeSysProp != null) + { + if (jettyHomeBundleSysProp != null) + { + System.err.println("WARN: both the jetty.home property and the jetty.home.bundle property are defined." + + " jetty.home.bundle is not taken into account."); + } + jettyHome = new File(jettyHomeSysProp); + if (!jettyHome.exists() || !jettyHome.isDirectory()) + { + System.err.println("Unable to locate the jetty.home folder " + jettyHomeSysProp); + return; + } + } + else if (jettyHomeBundleSysProp != null) + { + for (Bundle b : bundleContext.getBundles()) + { + if (b.getSymbolicName().equals(jettyHomeBundleSysProp)) + { + jettyHomeBundle = b; + break; + } + } + if (jettyHomeBundle == null) + { + System.err.println("Unable to find the jetty.home.bundle named " + jettyHomeSysProp); + return; + } + + } + if (jettyHome == null && jettyHomeBundle == null) + { + System.err.println("No default jetty started."); + return; + } + try + { + Server server = new Server(); + Properties properties = new Properties(); + properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME); + + String configURLs = jettyHome != null ? getJettyConfigurationURLs(jettyHome) : getJettyConfigurationURLs(jettyHomeBundle); + properties.put(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS, configURLs); + + System.err.println("Configuring the default jetty server with " + configURLs); + + //these properties usually are the ones passed to this type of configuration. + setProperty(properties,SYS_PROP_JETTY_HOME,System.getProperty(SYS_PROP_JETTY_HOME)); + setProperty(properties,SYS_PROP_JETTY_HOST,System.getProperty(SYS_PROP_JETTY_HOST)); + setProperty(properties,SYS_PROP_JETTY_PORT,System.getProperty(SYS_PROP_JETTY_PORT)); + setProperty(properties,SYS_PROP_JETTY_PORT_SSL,System.getProperty(SYS_PROP_JETTY_PORT_SSL)); + + bundleContext.registerService(Server.class.getName(), server, properties); + } + catch (Throwable t) + { + t.printStackTrace(); + } + } + + /** + * Minimum setup for the location of the configuration files given a jettyhome folder. + * Reads the system property jetty.etc.config.urls and look for the corresponding jetty + * configuration files that will be used to setup the jetty server. + * @param jettyhome + * @return + */ + private static String getJettyConfigurationURLs(File jettyhome) + { + String jettyetc = System.getProperty(SYS_PROP_JETTY_ETC_FILES,"etc/jetty.xml"); + StringTokenizer tokenizer = new StringTokenizer(jettyetc,";,", false); + StringBuilder res = new StringBuilder(); + while (tokenizer.hasMoreTokens()) + { + String next = tokenizer.nextToken().trim(); + if (!next.startsWith("/") && next.indexOf(':') == -1) + { + try { + next = new File(jettyhome, next).toURI().toURL().toString(); + } catch (MalformedURLException e) { + e.printStackTrace(); + continue; + } + } + appendToCommaSeparatedList(res, next); + } + return res.toString(); + } + + /** + * Minimum setup for the location of the configuration files given a configuration + * embedded inside a bundle. + * Reads the system property jetty.etc.config.urls and look for the corresponding jetty + * configuration files that will be used to setup the jetty server. + * @param jettyhome + * @return + */ + private static String getJettyConfigurationURLs(Bundle configurationBundle) + { + String jettyetc = System.getProperty(SYS_PROP_JETTY_ETC_FILES,"etc/jetty.xml"); + System.err.println("jettyetc=" + jettyetc); + StringTokenizer tokenizer = new StringTokenizer(jettyetc,";,", false); + StringBuilder res = new StringBuilder(); + + while (tokenizer.hasMoreTokens()) + { + String etcFile = tokenizer.nextToken().trim(); + if (etcFile.startsWith("/") || etcFile.indexOf(":") != -1) + { + appendToCommaSeparatedList(res, etcFile); + } + else + { + Enumeration<URL> enUrls = BundleFileLocatorHelper.DEFAULT + .findEntries(configurationBundle, etcFile); + + //default for org.eclipse.osgi.boot where we look inside jettyhome for the default embedded configuration. + //default inside jettyhome. this way fragments to the bundle can define their own configuration. + if ((enUrls == null || !enUrls.hasMoreElements()) && etcFile.endsWith("etc/jetty.xml")) + { + enUrls = BundleFileLocatorHelper.DEFAULT + .findEntries(configurationBundle, "/jettyhome/etc/jetty-osgi-default.xml"); + System.err.println("Configuring jetty with the default embedded configuration:" + + "bundle: " + configurationBundle.getSymbolicName() + + " config: /jettyhome/etc/jetty-osgi-default.xml"); + } + if (enUrls == null || !enUrls.hasMoreElements()) + { + System.err.println("Unable to locate a jetty configuration file for " + etcFile); + } + if (enUrls != null) + { + while (enUrls.hasMoreElements()) + { + appendToCommaSeparatedList(res, enUrls.nextElement().toString()); + } + } + } + } + return res.toString(); + } + + private static void appendToCommaSeparatedList(StringBuilder buffer, String value) + { + if (buffer.length() != 0) + { + buffer.append(","); + } + buffer.append(value); + } + + private static void setProperty(Properties properties, String key, String value) + { + if (value != null) + { + properties.put(key, value); + } + } + +} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/IManagedJettyServerRegistry.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/IManagedJettyServerRegistry.java new file mode 100644 index 0000000000..796447496d --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/IManagedJettyServerRegistry.java @@ -0,0 +1,28 @@ +// ======================================================================== +// Copyright (c) 2010 Intalio, Inc. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// Contributors: +// Hugues Malphettes - initial API and implementation +// ======================================================================== +package org.eclipse.jetty.osgi.boot.internal.serverfactory; + +/** + * Keeps track of the running jetty servers. They are named. + */ +public interface IManagedJettyServerRegistry { + + /** + * @param managedServerName The server name + * @return the corresponding jetty server wrapped with its deployment properties. + */ + public ServerInstanceWrapper getServerInstanceWrapper(String managedServerName); + +} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java new file mode 100644 index 0000000000..200647cecc --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java @@ -0,0 +1,161 @@ +// ======================================================================== +// Copyright (c) 2009-2010 Intalio, Inc. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.osgi.boot.internal.serverfactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.eclipse.jetty.osgi.boot.OSGiServerConstants; +import org.eclipse.jetty.server.Server; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; + +/** + * Deploy the jetty server instances when they are registered as an OSGi service. + */ +public class JettyServerServiceTracker implements ServiceListener, IManagedJettyServerRegistry +{ + + /** + * Servers indexed by PIDs. PIDs are generated by the ConfigurationAdmin service. + */ + private Map<String, ServerInstanceWrapper> _serversIndexedByName = new HashMap<String, ServerInstanceWrapper>(); + /** The context-handler to deactivate indexed by ServerInstanceWrapper */ + private Map<ServiceReference, ServerInstanceWrapper> _indexByServiceReference = new HashMap<ServiceReference, ServerInstanceWrapper>(); + + + /** + * Stops each one of the registered servers. + */ + public void stop() + { + //not sure that this is really useful but here we go. + for (ServerInstanceWrapper wrapper : _serversIndexedByName.values()) + { + try + { + wrapper.stop(); + } + catch (Throwable t) + { + + } + } + } + + + /** + * Receives notification that a service has had a lifecycle change. + * + * @param ev + * The <code>ServiceEvent</code> object. + */ + public void serviceChanged(ServiceEvent ev) + { + ServiceReference sr = ev.getServiceReference(); + switch (ev.getType()) + { + case ServiceEvent.MODIFIED: + case ServiceEvent.UNREGISTERING: + { + ServerInstanceWrapper instance = unregisterInIndex(ev.getServiceReference()); + if (instance != null) + { + try + { + instance.stop(); + } + catch (Exception e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + if (ev.getType() == ServiceEvent.UNREGISTERING) + { + break; + } + else + { + // modified, meaning: we reload it. now that we stopped it; + // we can register it. + } + case ServiceEvent.REGISTERED: + { + Bundle contributor = sr.getBundle(); + Server server = (Server)contributor.getBundleContext().getService(sr); + ServerInstanceWrapper wrapper = registerInIndex(server, sr); + Properties props = new Properties(); + for (String key : sr.getPropertyKeys()) + { + Object value = sr.getProperty(key); + props.put(key, value); + } + wrapper.start(server, props); + break; + } + } + } + + private ServerInstanceWrapper registerInIndex(Server server, ServiceReference sr) + { + String name = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME); + if (name == null) + { + throw new IllegalArgumentException("The property " + + OSGiServerConstants.MANAGED_JETTY_SERVER_NAME + " is mandatory"); + } + ServerInstanceWrapper wrapper = new ServerInstanceWrapper(name); + _indexByServiceReference.put(sr,wrapper); + _serversIndexedByName.put(name,wrapper); + return wrapper; + } + + /** + * Returns the ContextHandler to stop. + * + * @param reg + * @return the ContextHandler to stop. + */ + private ServerInstanceWrapper unregisterInIndex(ServiceReference sr) + { + ServerInstanceWrapper handler = _indexByServiceReference.remove(sr); + if (handler == null) + { + // a warning? + return null; + } + String name = handler.getManagedServerName(); + if (name != null) + { + _serversIndexedByName.remove(name); + } + return handler; + } + + /** + * @param managedServerName The server name + * @return the corresponding jetty server wrapped with its deployment properties. + */ + public ServerInstanceWrapper getServerInstanceWrapper(String managedServerName) + { + return _serversIndexedByName.get(managedServerName == null + ? OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME : managedServerName); + } + + +} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServersManagedFactory.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServersManagedFactory.java index d6b8aa9853..31ad22534b 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServersManagedFactory.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServersManagedFactory.java @@ -14,45 +14,30 @@ // ======================================================================== package org.eclipse.jetty.osgi.boot.internal.serverfactory; +import java.net.URL; import java.util.Dictionary; import java.util.HashMap; +import java.util.Hashtable; import java.util.Map; +import java.util.StringTokenizer; +import org.eclipse.jetty.osgi.boot.OSGiServerConstants; +import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; import org.eclipse.jetty.server.Server; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedServiceFactory; /** - * This is a work in progress. <br/> - * In particular there is a lot of work required during the update of the - * configuration of a server. It might not be practical to in fact support that - * and re-deploy the webapps in the same state than before the server was - * stopped. - * <p> - * jetty servers are managed as OSGi services registered here. try to find out - * if a configuration will fail (ports already opened etc). - * </p> - * <p> - * Try to enable the creation and configuration of jetty servers in all the - * usual standard ways. The configuration of the server is defined by the - * properties passed to the service: - * <ol> - * <li>First look for jettyfactory. If the value is a jetty server, use that - * server</li> - * <li>Then look for jettyhome key. The value should be a java.io.File or a - * String that is a path to the folder It is required that a etc/jetty.xml file - * will be loated from that folder.</li> - * <li>Then look for a jettyxml key. The value should be a java.io.File or an - * InputStream that contains a jetty configuration file.</li> - * <li>TODO: More ways to configure a jetty server? (other IOCs like spring, - * equinox properties...)</li> - * <li>Throw an exception if none of the relevant parameters are found</li> - * </ol> - * </p> + * Manages the deployment of jetty server instances. + * Not sure this is bringing much compared to the JettyServerServiceTracker. * * @author hmalphettes */ -public class JettyServersManagedFactory implements ManagedServiceFactory +public class JettyServersManagedFactory implements ManagedServiceFactory, IManagedJettyServerRegistry { /** @@ -79,7 +64,18 @@ public class JettyServersManagedFactory implements ManagedServiceFactory */ public static final String JETTY_HTTPS_PORT = "jetty.http.port"; - private Map<String, Server> _servers = new HashMap<String, Server>(); + /** + * Servers indexed by PIDs. PIDs are generated by the ConfigurationAdmin service. + */ + private Map<String, ServerInstanceWrapper> _serversIndexedByPID = new HashMap<String, ServerInstanceWrapper>(); + /** + * PID -> {@link OSGiWebappConstants#MANAGED_JETTY_SERVER_NAME} + */ + private Map<String, String> _serversNameIndexedByPID = new HashMap<String, String>(); + /** + * {@link OSGiWebappConstants#MANAGED_JETTY_SERVER_NAME} -> PID + */ + private Map<String, String> _serversPIDIndexedByName = new HashMap<String, String>(); /** * Return a descriptive name of this factory. @@ -93,24 +89,43 @@ public class JettyServersManagedFactory implements ManagedServiceFactory public void updated(String pid, Dictionary properties) throws ConfigurationException { - Server server = _servers.get(pid); + ServerInstanceWrapper serverInstanceWrapper = getServerByPID(pid); deleted(pid); // do we need to collect the currently deployed http services and // webapps // to be able to re-deploy them later? // probably not. simply restart and see the various service trackers // do everything that is needed. - + String name = (String)properties.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME); + if (name == null) + { + throw new ConfigurationException(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, + "The name of the server is mandatory"); + } + serverInstanceWrapper = new ServerInstanceWrapper(name); + _serversIndexedByPID.put(pid, serverInstanceWrapper); + _serversNameIndexedByPID.put(pid, name); + _serversPIDIndexedByName.put(name, pid); + serverInstanceWrapper.start(new Server(), properties); } public synchronized void deleted(String pid) { - Server server = (Server)_servers.remove(pid); + ServerInstanceWrapper server = (ServerInstanceWrapper)_serversIndexedByPID.remove(pid); + String name = _serversNameIndexedByPID.remove(pid); + if (name != null) + { + _serversPIDIndexedByName.remove(name); + } + else + { + //something incorrect going on. + } if (server != null) { try { - server.stop(); + server.stop(); } catch (Exception e) { @@ -119,4 +134,74 @@ public class JettyServersManagedFactory implements ManagedServiceFactory } } + public synchronized ServerInstanceWrapper getServerByPID(String pid) + { + return _serversIndexedByPID.get(pid); + } + + /** + * @param managedServerName The server name + * @return the corresponding jetty server wrapped with its deployment properties. + */ + public ServerInstanceWrapper getServerInstanceWrapper(String managedServerName) + { + String pid = _serversPIDIndexedByName.get(managedServerName); + return pid != null ? _serversIndexedByPID.get(pid) : null; + } + + /** + * Helper method to create and configure a new Jetty Server via the ManagedServiceFactory + * @param contributor + * @param serverName + * @param urlsToJettyXml + * @throws Exception + */ + public static void createNewServer(Bundle contributor, String serverName, String urlsToJettyXml) throws Exception + { + ServiceReference configurationAdminReference = + contributor.getBundleContext().getServiceReference( ConfigurationAdmin.class.getName() ); + + ConfigurationAdmin confAdmin = (ConfigurationAdmin) contributor.getBundleContext() + .getService( configurationAdminReference ); + + Configuration configuration = confAdmin.createFactoryConfiguration( + OSGiServerConstants.MANAGED_JETTY_SERVER_FACTORY_PID, contributor.getLocation() ); + Dictionary properties = new Hashtable(); + properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, serverName); + + StringBuilder actualBundleUrls = new StringBuilder(); + StringTokenizer tokenizer = new StringTokenizer(urlsToJettyXml, ",", false); + while (tokenizer.hasMoreTokens()) + { + if (actualBundleUrls.length() != 0) + { + actualBundleUrls.append(","); + } + String token = tokenizer.nextToken(); + if (token.indexOf(':') != -1) + { + //a complete url. no change needed: + actualBundleUrls.append(token); + } + else if (token.startsWith("/")) + { + //url relative to the contributor bundle: + URL url = contributor.getEntry(token); + if (url == null) + { + actualBundleUrls.append(token); + } + else + { + actualBundleUrls.append(url.toString()); + } + } + + } + + properties.put(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS, actualBundleUrls.toString()); + configuration.update(properties); + + } + } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java new file mode 100644 index 0000000000..7e4afc5b29 --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java @@ -0,0 +1,422 @@ +// ======================================================================== +// Copyright (c) 2009 Intalio, Inc. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.osgi.boot.internal.serverfactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.eclipse.jetty.deploy.AppProvider; +import org.eclipse.jetty.deploy.DeploymentManager; +import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator; +import org.eclipse.jetty.osgi.boot.OSGiAppProvider; +import org.eclipse.jetty.osgi.boot.OSGiServerConstants; +import org.eclipse.jetty.osgi.boot.internal.jsp.TldLocatableURLClassloader; +import org.eclipse.jetty.osgi.boot.internal.webapp.LibExtClassLoaderHelper; +import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleDeployerHelper; +import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer; +import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.xml.XmlConfiguration; +import org.xml.sax.SAXParseException; + + +/** + * Exposes a Jetty Server to be managed by an OSGi ManagedServiceFactory + * Configure and start it. + * Can also be used from the ManagedServiceFactory + */ +public class ServerInstanceWrapper { + + private static Logger __logger = Log.getLogger(ServerInstanceWrapper.class.getName()); + + private final String _managedServerName; + + /** + * The managed jetty server + */ + private Server _server; + private ContextHandlerCollection _ctxtHandler; + + /** + * This is the class loader that should be the parent classloader of any + * webapp classloader. It is in fact the _libExtClassLoader with a trick to + * let the TldScanner find the jars where the tld files are. + */ + private ClassLoader _commonParentClassLoaderForWebapps; + private DeploymentManager _deploymentManager; + private OSGiAppProvider _provider; + + private WebBundleDeployerHelper _webBundleDeployerHelper; + + + public ServerInstanceWrapper(String managedServerName) + { + _managedServerName = managedServerName; + } + + public String getManagedServerName() + { + return _managedServerName; + } + + /** + * The classloader that should be the parent classloader for + * each webapp deployed on this server. + * @return + */ + public ClassLoader getParentClassLoaderForWebapps() + { + return _commonParentClassLoaderForWebapps; + } + + /** + * @return The deployment manager registered on this server. + */ + public DeploymentManager getDeploymentManager() + { + return _deploymentManager; + } + + /** + * @return The app provider registered on this server. + */ + public OSGiAppProvider getOSGiAppProvider() + { + return _provider; + } + + + public Server getServer() + { + return _server; + } + + + public WebBundleDeployerHelper getWebBundleDeployerHelp() + { + return _webBundleDeployerHelper; + } + + /** + * @return The collection of context handlers + */ + public ContextHandlerCollection getContextHandlerCollection() + { + return _ctxtHandler; + } + + + public void start(Server server, Dictionary props) + { + _server = server; + ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); + try + { + // passing this bundle's classloader as the context classlaoder + // makes sure there is access to all the jetty's bundles + ClassLoader libExtClassLoader = null; + String sharedURLs = (String)props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS); + try + { + List<File> shared = sharedURLs != null ? extractFiles(sharedURLs) : null; + libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader( + shared, null, server, JettyBootstrapActivator.class.getClassLoader()); + } + catch (MalformedURLException e) + { + e.printStackTrace(); + } + + Thread.currentThread().setContextClassLoader(libExtClassLoader); + + configure(server, props); + + init(); + + //now that we have an app provider we can call the registration customizer. + try + { + URL[] jarsWithTlds = getJarsWithTlds(); + _commonParentClassLoaderForWebapps = jarsWithTlds == null + ? libExtClassLoader + :new TldLocatableURLClassloader(libExtClassLoader,jarsWithTlds); + } + catch (MalformedURLException e) + { + e.printStackTrace(); + } + + + server.start(); + } + catch (Throwable t) + { + t.printStackTrace(); + } + finally + { + Thread.currentThread().setContextClassLoader(contextCl); + } + _webBundleDeployerHelper = new WebBundleDeployerHelper(this); + } + + + public void stop() + { + try { + if (_server.isRunning()) + { + _server.stop(); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * TODO: right now only the jetty-jsp bundle is scanned for common taglibs. + * Should support a way to plug more bundles that contain taglibs. + * + * The jasper TldScanner expects a URLClassloader to parse a jar for the + * /META-INF/*.tld it may contain. We place the bundles that we know contain + * such tag-libraries. Please note that it will work if and only if the + * bundle is a jar (!) Currently we just hardcode the bundle that contains + * the jstl implemenation. + * + * A workaround when the tld cannot be parsed with this method is to copy + * and paste it inside the WEB-INF of the webapplication where it is used. + * + * Support only 2 types of packaging for the bundle: - the bundle is a jar + * (recommended for runtime.) - the bundle is a folder and contain jars in + * the root and/or in the lib folder (nice for PDE developement situations) + * Unsupported: the bundle is a jar that embeds more jars. + * + * @return + * @throws Exception + */ + private URL[] getJarsWithTlds() throws Exception + { + ArrayList<URL> res = new ArrayList<URL>(); + WebBundleDeployerHelper.staticInit();//that is not looking great. + for (WebappRegistrationCustomizer regCustomizer : WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS) + { + URL[] urls = regCustomizer.getJarsWithTlds(_provider, WebBundleDeployerHelper.BUNDLE_FILE_LOCATOR_HELPER); + for (URL url : urls) + { + if (!res.contains(url)) + res.add(url); + } + } + if (!res.isEmpty()) + return res.toArray(new URL[res.size()]); + else + return null; + } + + private void configure(Server server, Dictionary props) throws Exception + { + String jettyConfigurationUrls = (String) props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS); + List<URL> jettyConfigurations = jettyConfigurationUrls != null + ? extractResources(jettyConfigurationUrls) : null; + if (jettyConfigurations == null || jettyConfigurations.isEmpty()) + { + return; + } + Map<Object,Object> id_map = new HashMap<Object,Object>(); + id_map.put("Server",server); + Map<Object,Object> properties = new HashMap<Object,Object>(); + Enumeration en = props.keys(); + while (en.hasMoreElements()) + { + Object key = en.nextElement(); + Object value = props.get(key); + properties.put(key, value); + } + + for (URL jettyConfiguration : jettyConfigurations) + { + InputStream is = null; + try + { + // Execute a Jetty configuration file + is = jettyConfiguration.openStream(); + XmlConfiguration config = new XmlConfiguration(is); + config.setIdMap(id_map); + config.setProperties(properties); + config.configure(); + id_map=config.getIdMap(); + } + catch (SAXParseException saxparse) + { + __logger.warn("Unable to configure the jetty/etc file " + jettyConfiguration,saxparse); + throw saxparse; + } + finally + { + IO.close(is); + } + } + + } + + + /** + * Must be called after the server is configured. + * + * Locate the actual instance of the ContextDeployer and WebAppDeployer that + * was created when configuring the server through jetty.xml. If there is no + * such thing it won't be possible to deploy webapps from a context and we + * throw IllegalStateExceptions. + */ + private void init() + { + // Get the context handler + _ctxtHandler = (ContextHandlerCollection)_server.getChildHandlerByClass(ContextHandlerCollection.class); + + // get a deployerManager + List<DeploymentManager> deployers = _server.getBeans(DeploymentManager.class); + if (deployers != null && !deployers.isEmpty()) + { + _deploymentManager = deployers.get(0); + + for (AppProvider provider : _deploymentManager.getAppProviders()) + { + if (provider instanceof OSGiAppProvider) + { + _provider=(OSGiAppProvider)provider; + break; + } + } + if (_provider == null) + { + //create it on the fly with reasonable default values. + try + { + _provider = new OSGiAppProvider(); + _provider.setMonitoredDir( + Resource.newResource(getDefaultOSGiContextsHome( + new File(System.getProperty("jetty.home"))).toURI())); + } catch (IOException e) { + e.printStackTrace(); + } + _deploymentManager.addAppProvider(_provider); + } + } + + if (_ctxtHandler == null || _provider==null) + throw new IllegalStateException("ERROR: No ContextHandlerCollection or OSGiAppProvider configured"); + + + } + + /** + * @return The default folder in which the context files of the osgi bundles + * are located and watched. Or null when the system property + * "jetty.osgi.contexts.home" is not defined. + * If the configuration file defines the OSGiAppProvider's context. + * This will not be taken into account. + */ + File getDefaultOSGiContextsHome(File jettyHome) + { + String jettyContextsHome = System.getProperty("jetty.osgi.contexts.home"); + if (jettyContextsHome != null) + { + File contextsHome = new File(jettyContextsHome); + if (!contextsHome.exists() || !contextsHome.isDirectory()) + { + throw new IllegalArgumentException("the ${jetty.osgi.contexts.home} '" + jettyContextsHome + " must exist and be a folder"); + } + return contextsHome; + } + return new File(jettyHome, "/contexts"); + } + + File getOSGiContextsHome() + { + return _provider.getContextXmlDirAsFile(); + } + + /** + * @return the urls in this string. + */ + private List<URL> extractResources(String propertyValue) + { + StringTokenizer tokenizer = new StringTokenizer(propertyValue, ",;", false); + List<URL> urls = new ArrayList<URL>(); + while (tokenizer.hasMoreTokens()) + { + String tok = tokenizer.nextToken(); + try + { + urls.add(((DefaultFileLocatorHelper) WebBundleDeployerHelper + .BUNDLE_FILE_LOCATOR_HELPER).getLocalURL(new URL(tok))); + } + catch (Throwable mfe) + { + + } + } + return urls; + } + + /** + * Get the folders that might contain jars for the legacy J2EE shared libraries + */ + private List<File> extractFiles(String propertyValue) + { + StringTokenizer tokenizer = new StringTokenizer(propertyValue, ",;", false); + List<File> files = new ArrayList<File>(); + while (tokenizer.hasMoreTokens()) + { + String tok = tokenizer.nextToken(); + try + { + URL url = new URL(tok); + url = ((DefaultFileLocatorHelper) WebBundleDeployerHelper + .BUNDLE_FILE_LOCATOR_HELPER).getFileURL(url); + if (url.getProtocol().equals("file")) + { + Resource res = Resource.newResource(url); + File folder = res.getFile(); + if (folder != null) + { + files.add(folder); + } + } + } + catch (Throwable mfe) + { + + } + } + return files; + } + + +} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/IWebBundleDeployerHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/IWebBundleDeployerHelper.java new file mode 100644 index 0000000000..8805561480 --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/IWebBundleDeployerHelper.java @@ -0,0 +1,84 @@ +// ======================================================================== +// Copyright (c) 2010 Intalio, Inc. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// Contributors: +// Hugues Malphettes - initial API and implementation +// ======================================================================== +package org.eclipse.jetty.osgi.boot.internal.webapp; + +import org.eclipse.jetty.deploy.ContextDeployer; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.webapp.WebAppContext; +import org.osgi.framework.Bundle; + +/** + * Internal interface for the class that deploys a webapp on a server. + * Used as we migrate from the single instance of the jety server to multiple jetty servers. + */ +public interface IWebBundleDeployerHelper { + + /** when this property is present, the type of context handler registered is not + * known in advance. */ + public static final String INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE = "unknownContextHandlerType"; + + + /** + * Deploy a new web application on the jetty server. + * + * @param bundle + * The bundle + * @param webappFolderPath + * The path to the root of the webapp. Must be a path relative to + * bundle; either an absolute path. + * @param contextPath + * The context path. Must start with "/" + * @param extraClasspath + * @param overrideBundleInstallLocation + * @param webXmlPath + * @param defaultWebXmlPath + * TODO: parameter description + * @return The contexthandler created and started + * @throws Exception + */ + public abstract WebAppContext registerWebapplication(Bundle bundle, + String webappFolderPath, String contextPath, String extraClasspath, + String overrideBundleInstallLocation, String webXmlPath, + String defaultWebXmlPath, WebAppContext webAppContext) throws Exception; + + /** + * Stop a ContextHandler and remove it from the collection. + * + * @see ContextDeployer#undeploy + * @param contextHandler + * @throws Exception + */ + public abstract void unregister(ContextHandler contextHandler) + throws Exception; + + /** + * This type of registration relies on jetty's complete context xml file. + * Context encompasses jndi and all other things. This makes the definition + * of the webapp a lot more self-contained. + * + * @param contributor + * @param contextFileRelativePath + * @param extraClasspath + * @param overrideBundleInstallLocation + * @param handler the context handler passed in the server + * reference that will be configured, deployed and started. + * @return The contexthandler created and started + * @throws Exception + */ + public abstract ContextHandler registerContext(Bundle contributor, + String contextFileRelativePath, String extraClasspath, + String overrideBundleInstallLocation, ContextHandler handler) throws Exception; + +}
\ No newline at end of file diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerServiceTracker.java index 153267b1d8..efb908239a 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerServiceTracker.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerServiceTracker.java @@ -13,12 +13,15 @@ package org.eclipse.jetty.osgi.boot.internal.webapp; import java.io.File; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator; +import org.eclipse.jetty.osgi.boot.OSGiServerConstants; import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; -import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.osgi.boot.internal.serverfactory.IManagedJettyServerRegistry; +import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.Scanner; import org.eclipse.jetty.webapp.WebAppContext; @@ -49,62 +52,26 @@ import org.osgi.framework.ServiceReference; public class JettyContextHandlerServiceTracker implements ServiceListener { - private final WebappRegistrationHelper _helper; + /** New style: ability to manage multiple jetty instances */ + private final IManagedJettyServerRegistry _registry; /** The context-handler to deactivate indexed by context handler */ private Map<ServiceReference, ContextHandler> _indexByServiceReference = new HashMap<ServiceReference, ContextHandler>(); /** - * The index is the bundle-symbolic-name/paht/to/context/file when there is - * such thing + * The index is the bundle-symbolic-name/path/to/context/file when there is such thing */ private Map<String, ServiceReference> _indexByContextFile = new HashMap<String, ServiceReference>(); - /** or null when */ - private String _osgiContextHomeFolderCanonicalPath; /** in charge of detecting changes in the osgi contexts home folder. */ private Scanner _scanner; /** - * @param context - * @param server + * @param registry */ - public JettyContextHandlerServiceTracker(BundleContext context, Server server) throws Exception + public JettyContextHandlerServiceTracker(IManagedJettyServerRegistry registry) throws Exception { - _helper = new WebappRegistrationHelper(server); - _helper.setup(context,new HashMap<String, String>()); - File contextHome = _helper.getOSGiContextsHome(); - if (contextHome != null) - { - _osgiContextHomeFolderCanonicalPath = contextHome.getCanonicalPath(); - _scanner = new Scanner(); - _scanner.setRecursive(true); - _scanner.setReportExistingFilesOnStartup(false); - _scanner.addListener(new Scanner.DiscreteListener() - { - public void fileAdded(String filename) throws Exception - { - // adding a file does not create a new app, - // it just reloads it with the new custom file. - // well, if the file does not define a context handler, - // then in fact it does remove it. - reloadJettyContextHandler(filename); - } - - public void fileChanged(String filename) throws Exception - { - reloadJettyContextHandler(filename); - } - - public void fileRemoved(String filename) throws Exception - { - // removing a file does not remove the app: - // it just goes back to the default embedded in the bundle. - // well, if there was no default then it does remove it. - reloadJettyContextHandler(filename); - } - }); - } + _registry = registry; } public void stop() @@ -117,6 +84,49 @@ public class JettyContextHandlerServiceTracker implements ServiceListener // nothing to stop in the WebappRegistrationHelper } + + /** + * @param contextHome Parent folder where the context files can override the context files + * defined in the web bundles: equivalent to the contexts folder in a traditional + * jetty installation. + * when null, just do nothing. + */ + protected void setupContextHomeScanner(File contextHome) throws IOException + { + if (contextHome == null) + { + return; + } + final String osgiContextHomeFolderCanonicalPath = contextHome.getCanonicalPath(); + _scanner = new Scanner(); + _scanner.setRecursive(true); + _scanner.setReportExistingFilesOnStartup(false); + _scanner.addListener(new Scanner.DiscreteListener() + { + public void fileAdded(String filename) throws Exception + { + // adding a file does not create a new app, + // it just reloads it with the new custom file. + // well, if the file does not define a context handler, + // then in fact it does remove it. + reloadJettyContextHandler(filename, osgiContextHomeFolderCanonicalPath); + } + + public void fileChanged(String filename) throws Exception + { + reloadJettyContextHandler(filename, osgiContextHomeFolderCanonicalPath); + } + + public void fileRemoved(String filename) throws Exception + { + // removing a file does not remove the app: + // it just goes back to the default embedded in the bundle. + // well, if there was no default then it does remove it. + reloadJettyContextHandler(filename, osgiContextHomeFolderCanonicalPath); + } + }); + + } /** * Receives notification that a service has had a lifecycle change. @@ -137,7 +147,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener { try { - _helper.unregister(ctxtHandler); + getWebBundleDeployerHelp(sr).unregister(ctxtHandler); } catch (Exception e) { @@ -146,15 +156,15 @@ public class JettyContextHandlerServiceTracker implements ServiceListener } } } - if (ev.getType() == ServiceEvent.UNREGISTERING) - { - break; - } - else - { - // modified, meaning: we reload it. now that we stopped it; - // we can register it. - } + if (ev.getType() == ServiceEvent.UNREGISTERING) + { + break; + } + else + { + // modified, meaning: we reload it. now that we stopped it; + // we can register it. + } case ServiceEvent.REGISTERED: { Bundle contributor = sr.getBundle(); @@ -165,7 +175,11 @@ public class JettyContextHandlerServiceTracker implements ServiceListener // is configured elsewhere. return; } - if (contextHandler instanceof WebAppContext) + String contextFilePath = (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH); + if (contextHandler instanceof WebAppContext && contextFilePath == null) + //it could be a web-application that will in fact be configured via a context file. + //that case is identified by the fact that the contextFilePath is not null + //in that case we must use the register context methods. { WebAppContext webapp = (WebAppContext)contextHandler; String contextPath = (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH); @@ -186,13 +200,23 @@ public class JettyContextHandlerServiceTracker implements ServiceListener String war = (String)sr.getProperty("war"); try { - ContextHandler handler = _helper.registerWebapplication(contributor,war,contextPath,(String)sr + IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr); + if (deployerHelper == null) + { + + } + else + { + WebAppContext handler = deployerHelper + .registerWebapplication(contributor,war,contextPath,(String)sr .getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),(String)sr - .getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),webXmlPath,defaultWebXmlPath); - if (handler != null) - { - registerInIndex(handler,sr); - } + .getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE), + webXmlPath,defaultWebXmlPath,webapp); + if (handler != null) + { + registerInIndex(handler,sr); + } + } } catch (Throwable e) { @@ -202,20 +226,33 @@ public class JettyContextHandlerServiceTracker implements ServiceListener else { // consider this just an empty skeleton: - String contextFilePath = (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH); if (contextFilePath == null) { throw new IllegalArgumentException("the property contextFilePath is required"); } try { - ContextHandler handler = _helper.registerContext(contributor,contextFilePath,(String)sr - .getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),(String)sr - .getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE)); - if (handler != null) - { - registerInIndex(handler,sr); - } + IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr); + if (deployerHelper == null) + { + //more warnings? + } + else + { + if (Boolean.TRUE.toString().equals(sr.getProperty( + IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE))) + { + contextHandler = null; + } + ContextHandler handler = deployerHelper.registerContext(contributor,contextFilePath, + (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH), + (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE), + contextHandler); + if (handler != null) + { + registerInIndex(handler,sr); + } + } } catch (Throwable e) { @@ -279,9 +316,9 @@ public class JettyContextHandlerServiceTracker implements ServiceListener * * @param contextFileFully */ - void reloadJettyContextHandler(String canonicalNameOfFileChanged) + public void reloadJettyContextHandler(String canonicalNameOfFileChanged, String osgiContextHomeFolderCanonicalPath) { - String key = getNormalizedRelativePath(canonicalNameOfFileChanged); + String key = getNormalizedRelativePath(canonicalNameOfFileChanged, osgiContextHomeFolderCanonicalPath); if (key == null) { return; @@ -299,16 +336,45 @@ public class JettyContextHandlerServiceTracker implements ServiceListener * @param canFilename * @return */ - private String getNormalizedRelativePath(String canFilename) + private String getNormalizedRelativePath(String canFilename, String osgiContextHomeFolderCanonicalPath) { - if (!canFilename.startsWith(_osgiContextHomeFolderCanonicalPath)) + if (!canFilename.startsWith(osgiContextHomeFolderCanonicalPath)) { // why are we here: this does not look like a child of the osgi // contexts home. // warning? return null; } - return canFilename.substring(_osgiContextHomeFolderCanonicalPath.length()).replace('\\','/'); + return canFilename.substring(osgiContextHomeFolderCanonicalPath.length()).replace('\\','/'); } - + + /** + * @return The server on which this webapp is meant to be deployed + */ + private ServerInstanceWrapper getServerInstanceWrapper(String managedServerName) + { + if (_registry == null) + { + return null; + } + if (managedServerName == null) + { + managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME; + } + ServerInstanceWrapper wrapper = _registry.getServerInstanceWrapper(managedServerName); + System.err.println("Returning " + managedServerName + " = " + wrapper); + return wrapper; + } + + private IWebBundleDeployerHelper getWebBundleDeployerHelp(ServiceReference sr) + { + if (_registry == null) + { + return null; + } + String managedServerName = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME); + ServerInstanceWrapper wrapper = getServerInstanceWrapper(managedServerName); + return wrapper != null ? wrapper.getWebBundleDeployerHelp() : null; + } + } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyHomeHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyHomeHelper.java deleted file mode 100644 index c6f7c3db49..0000000000 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyHomeHelper.java +++ /dev/null @@ -1,272 +0,0 @@ -// ======================================================================== -// Copyright (c) 2009 Intalio, Inc. -// ------------------------------------------------------------------------ -// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.boot.internal.webapp; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.eclipse.jetty.util.URIUtil; - -/** - * <p> - * Magically extract the jettyhome folder from this bundle's jar place it - * somewhere in the file-system. Currently we do this only when we detect a - * system property 'jetty.magic.home.parent' or if we are inside the pde in dev - * mode. In dev mode we use the osgi.configuration.area folder. - * </p> - * <p> - * This work is done through the jetty launch configuration inside the - * "Jetty Config" tab. We could choose to remove this code at some point - * although it does not hurt and it helps for users who don't go through the - * jetty launch. - * </p> - */ -class JettyHomeHelper -{ - - /** only magically extract jettyhome if we are inside the pde. */ - static boolean magic_install_only_in_pde = Boolean.valueOf(System.getProperty("jetty.magic.home.pde.only","true")); - - /** - * Hack for eclipse-PDE. When no jetty.home was set, detect if we running - * inside eclipse-PDE in development mode. In that case extract the - * jettyhome folder embedded inside this plugin inside the configuration - * area folder. It is specific to the workspace. Set the folder as - * jetty.home. If the folder already exist don't extract it again. - * <p> - * If we are not pde dev mode, the same but look in the installation folder - * of eclipse itself. - * </p> - * - * @return - * @throws URISyntaxException - */ - static String setupJettyHomeInEclipsePDE(File thisbundlejar) - { - File ecFolder = getParentFolderOfMagicHome(); - if (ecFolder == null || !ecFolder.exists()) - { - return null; - } - File jettyhome = new File(ecFolder,"jettyhome"); - String path; - try - { - path = jettyhome.getCanonicalPath(); - if (jettyhome.exists()) - { - System.setProperty("jetty.home",path); - return path; - } - else - { - // now grab the jar and unzip the relevant portion - unzipJettyHomeIntoDirectory(thisbundlejar,ecFolder); - System.setProperty("jetty.home",path); - return path; - } - } - catch (IOException e) - { - e.printStackTrace(); - } - return null; - } - - /** - * @return true when we are currently being run by the pde in development - * mode. - */ - private static boolean isPDEDevelopment() - { - String eclipseCommands = System.getProperty("eclipse.commands"); - // detect if we are being run from the pde: ie during development. - return eclipseCommands != null && eclipseCommands.indexOf("-dev") != -1 - && (eclipseCommands.indexOf("-dev\n") != -1 || eclipseCommands.indexOf("-dev\r") != -1 || eclipseCommands.indexOf("-dev ") != -1); - } - - /** - * @return - */ - private static File getConfigurationAreaDirectory() - { - return getFile(System.getProperty("osgi.configuration.area")); - } - - /** - * @param zipFile - * The current jar file for this bundle. contains an archive of - * the default jettyhome - * @param parentOfMagicJettyHome - * The folder inside which jettyhome is created. - */ - private static void unzipJettyHomeIntoDirectory(File thisbundlejar, File parentOfMagicJettyHome) throws IOException - { - ZipFile zipFile = null; - try - { - zipFile = new ZipFile(thisbundlejar); - Enumeration<? extends ZipEntry> files = zipFile.entries(); - File f = null; - FileOutputStream fos = null; - - while (files.hasMoreElements()) - { - try - { - ZipEntry entry = files.nextElement(); - String entryName = entry.getName(); - if (!entryName.startsWith("jettyhome")) - { - continue; - } - - InputStream eis = zipFile.getInputStream(entry); - byte[] buffer = new byte[1024]; - int bytesRead = 0; - f = new File(parentOfMagicJettyHome,entry.getName()); - - if (entry.isDirectory()) - { - f.mkdirs(); - } - else - { - f.getParentFile().mkdirs(); - f.createNewFile(); - fos = new FileOutputStream(f); - while ((bytesRead = eis.read(buffer)) != -1) - { - fos.write(buffer,0,bytesRead); - } - } - } - catch (IOException e) - { - e.printStackTrace(); - continue; - } - finally - { - if (fos != null) - { - try - { - fos.close(); - } - catch (IOException e) - { - } - fos = null; - } - } - } - } - finally - { - if (zipFile != null) - try - { - zipFile.close(); - } - catch (Throwable t) - { - } - } - } - - /** - * Look for the parent folder that contains jettyhome. Can be specified by - * the sys property jetty.magic.home.parent or if inside the pde will - * default on the configuration area. Otherwise returns null. - * - * @return The folder inside which jettyhome should be placed. - */ - private static File getParentFolderOfMagicHome() - { - // for (java.util.Map.Entry<Object, Object> e : - // System.getProperties().entrySet()) { - // System.err.println(e.getKey() + " -> " + e.getValue()); - // } - String magicParent = WebappRegistrationHelper.stripQuotesIfPresent(System.getProperty("jetty.magic.home.parent")); - String magicParentValue = magicParent != null?System.getProperty(magicParent):null; - File specifiedMagicParent = magicParentValue != null?getFile(magicParentValue) // in - // that - // case - // it - // was - // pointing - // to - // another - // system - // property. - :getFile(magicParent); // in that case it was directly a file. - if (specifiedMagicParent != null && specifiedMagicParent.exists()) - { - return specifiedMagicParent; - } - if (isPDEDevelopment()) - { - return getConfigurationAreaDirectory(); - } - return null; - } - - /** - * Be flexible with the url/uri/path that can be the value of the various - * system properties. - * - * @param file - * @return a file. might not exist. - */ - private static File getFile(String file) - { - if (file == null) - { - return null; - } - file = WebappRegistrationHelper.stripQuotesIfPresent(file); - try - { - if (file.startsWith("file:/")) - { - if (!file.startsWith("file://")) - { - return new File(new URI(URIUtil.encodePath(file))); - } - else - { - return new File(new URL(file).toURI()); - } - } - else - { - return new File(file); - } - } - catch (Throwable t) - { - t.printStackTrace(); - return new File(file); - } - - } -} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java index e93585277d..ee5e3c97de 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java @@ -19,6 +19,7 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -91,9 +92,13 @@ public class LibExtClassLoaderHelper * is the JettyBootStrapper (an osgi classloader. * @throws MalformedURLException */ - public static URLClassLoader createLibEtcClassLoaderHelper(File jettyHome, Server server, ClassLoader parentClassLoader) throws MalformedURLException + public static ClassLoader createLibEtcClassLoader(File jettyHome, Server server, + ClassLoader parentClassLoader) throws MalformedURLException { - + if (jettyHome == null) + { + return parentClassLoader; + } ArrayList<URL> urls = new ArrayList<URL>(); File jettyResources = new File(jettyHome,"resources"); if (jettyResources.exists()) @@ -139,6 +144,52 @@ public class LibExtClassLoaderHelper } /** + * @param server + * @return a url classloader with the jars of resources, lib/ext and the + * jars passed in the other argument. The parent classloader usually + * is the JettyBootStrapper (an osgi classloader). + * If there was no extra jars to insert, then just return the parentClassLoader. + * @throws MalformedURLException + */ + public static ClassLoader createLibExtClassLoader(List<File> jarsContainerOrJars, + List<URL> otherJarsOrFolder, Server server, + ClassLoader parentClassLoader) throws MalformedURLException + { + if (jarsContainerOrJars == null && otherJarsOrFolder == null) + { + return parentClassLoader; + } + List<URL> urls = new ArrayList<URL>(); + if (otherJarsOrFolder != null) + { + urls.addAll(otherJarsOrFolder); + } + if (jarsContainerOrJars != null) + { + for (File libExt : jarsContainerOrJars) + { + if (libExt.isDirectory()) + { + for (File f : libExt.listFiles()) + { + if (f.getName().endsWith(".jar")) + { + // cheap to tolerate folders so let's do it. + URL url = f.toURI().toURL(); + if (f.isFile()) + {// is this necessary anyways? + url = new URL("jar:" + url.toString() + "!/"); + } + urls.add(url); + } + } + } + } + } + return new URLClassLoader(urls.toArray(new URL[urls.size()]),parentClassLoader); + } + + /** * When we find files typically used for central logging configuration we do * what it takes in this method to do what the user expects. Without * depending too much directly on a particular logging framework. diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java index 50cec93fda..13c097e85e 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java @@ -29,18 +29,20 @@ import java.util.jar.JarFile; import javax.servlet.http.HttpServlet; +import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppClassLoader; import org.eclipse.jetty.webapp.WebAppContext; import org.osgi.framework.Bundle; +import org.osgi.framework.BundleReference; /** * Extends the webappclassloader to insert the classloader provided by the osgi * bundle at the same level than any other jars palced in the webappclassloader. */ -public class OSGiWebappClassLoader extends WebAppClassLoader +public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleReference { private Logger __logger = Log.getLogger(OSGiWebappClassLoader.class.getName().toString()); @@ -67,14 +69,34 @@ public class OSGiWebappClassLoader extends WebAppClassLoader } private ClassLoader _osgiBundleClassLoader; + private Bundle _contributor; private boolean _lookInOsgiFirst = true; private Set<String> _libsAlreadyInManifest = new HashSet<String>(); - public OSGiWebappClassLoader(ClassLoader parent, WebAppContext context, Bundle contributor) throws IOException + /** + * @param parent The parent classloader. In this case + * @param context The WebAppContext + * @param contributor The bundle that defines this web-application. + * @throws IOException + */ + public OSGiWebappClassLoader(ClassLoader parent, WebAppContext context, Bundle contributor, + BundleClassLoaderHelper bundleClassLoaderHelper) throws IOException { super(parent,context); - _osgiBundleClassLoader = WebappRegistrationHelper.BUNDLE_CLASS_LOADER_HELPER.getBundleClassLoader(contributor); + _contributor = contributor; + _osgiBundleClassLoader = bundleClassLoaderHelper.getBundleClassLoader(contributor); } + + /** + * Returns the <code>Bundle</code> that defined this web-application. + * + * @return The <code>Bundle</code> object associated with this + * <code>BundleReference</code>. + */ + public Bundle getBundle() + { + return _contributor; + } /** * Reads the manifest. If the manifest is already configured to loads a few diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleDeployerHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleDeployerHelper.java new file mode 100644 index 0000000000..f43dbb31df --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleDeployerHelper.java @@ -0,0 +1,619 @@ +// ======================================================================== +// Copyright (c) 2009 Intalio, Inc. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// Contributors: +// Hugues Malphettes - initial API and implementation +// ======================================================================== +package org.eclipse.jetty.osgi.boot.internal.webapp; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; + +import org.eclipse.jetty.deploy.ContextDeployer; +import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; +import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper; +import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper; +import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper; +import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer; +import org.eclipse.jetty.osgi.boot.utils.internal.DefaultBundleClassLoaderHelper; +import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.xml.XmlConfiguration; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.xml.sax.SAXException; + +/** + * Bridges the jetty deployers with the OSGi lifecycle where applications are + * managed inside OSGi-bundles. + * <p> + * This class should be called as a consequence of the activation of a new + * service that is a ContextHandler.<br/> + * This way the new webapps are exposed as OSGi services. + * </p> + * <p> + * Helper methods to register a bundle that is a web-application or a context. + * </p> + * Limitations: + * <ul> + * <li>support for jarred webapps is somewhat limited.</li> + * </ul> + */ +public class WebBundleDeployerHelper implements IWebBundleDeployerHelper +{ + + private static Logger __logger = Log.getLogger(WebBundleDeployerHelper.class.getName()); + + private static boolean INITIALIZED = false; + + /** + * By default set to: {@link DefaultBundleClassLoaderHelper}. It supports + * equinox and apache-felix fragment bundles that are specific to an OSGi + * implementation should set a different implementation. + */ + public static BundleClassLoaderHelper BUNDLE_CLASS_LOADER_HELPER = null; + /** + * By default set to: {@link DefaultBundleClassLoaderHelper}. It supports + * equinox and apache-felix fragment bundles that are specific to an OSGi + * implementation should set a different implementation. + */ + public static BundleFileLocatorHelper BUNDLE_FILE_LOCATOR_HELPER = null; + + /** + * By default set to: {@link DefaultBundleClassLoaderHelper}. It supports + * equinox and apache-felix fragment bundles that are specific to an OSGi + * implementation should set a different implementation. + * <p> + * Several of those objects can be added here: For example we could have an optional fragment that setups + * a specific implementation of JSF for the whole of jetty-osgi. + * </p> + */ + public static Collection<WebappRegistrationCustomizer> JSP_REGISTRATION_HELPERS = new ArrayList<WebappRegistrationCustomizer>(); + + /** + * this class loader loads the jars inside {$jetty.home}/lib/ext it is meant + * as a migration path and for jars that are not OSGi ready. also gives + * access to the jsp jars. + */ + // private URLClassLoader _libExtClassLoader; + + private ServerInstanceWrapper _wrapper; + + public WebBundleDeployerHelper(ServerInstanceWrapper wrapper) + { + staticInit(); + _wrapper = wrapper; + } + + // Inject the customizing classes that might be defined in fragment bundles. + public static synchronized void staticInit() + { + if (!INITIALIZED) + { + INITIALIZED = true; + // setup the custom BundleClassLoaderHelper + try + { + BUNDLE_CLASS_LOADER_HELPER = (BundleClassLoaderHelper)Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance(); + } + catch (Throwable t) + { + // System.err.println("support for equinox and felix"); + BUNDLE_CLASS_LOADER_HELPER = new DefaultBundleClassLoaderHelper(); + } + // setup the custom FileLocatorHelper + try + { + BUNDLE_FILE_LOCATOR_HELPER = (BundleFileLocatorHelper)Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance(); + } + catch (Throwable t) + { + // System.err.println("no jsp/jasper support"); + BUNDLE_FILE_LOCATOR_HELPER = new DefaultFileLocatorHelper(); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#registerWebapplication(org.osgi.framework.Bundle, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public WebAppContext registerWebapplication(Bundle bundle, String webappFolderPath, String contextPath, String extraClasspath, + String overrideBundleInstallLocation, String webXmlPath, String defaultWebXmlPath, WebAppContext webAppContext) throws Exception + { + File bundleInstall = overrideBundleInstallLocation == null?BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle):new File( + overrideBundleInstallLocation); + File webapp = null; + URL baseWebappInstallURL = null; + if (webappFolderPath != null && webappFolderPath.length() != 0 && !webappFolderPath.equals(".")) + { + if (webappFolderPath.startsWith("/") || webappFolderPath.startsWith("file:")) + { + webapp = new File(webappFolderPath); + } + else if (bundleInstall != null && bundleInstall.isDirectory()) + { + webapp = new File(bundleInstall,webappFolderPath); + } + else if (bundleInstall != null) + { + Enumeration<URL> urls = BUNDLE_FILE_LOCATOR_HELPER.findEntries(bundle, webappFolderPath); + if (urls != null && urls.hasMoreElements()) + { + baseWebappInstallURL = urls.nextElement(); + } + } + } + else + { + webapp = bundleInstall; + } + if (baseWebappInstallURL == null && (webapp == null || !webapp.exists())) + { + throw new IllegalArgumentException("Unable to locate " + webappFolderPath + " inside " + + (bundleInstall != null?bundleInstall.getAbsolutePath():"unlocated bundle '" + bundle.getSymbolicName() + "'")); + } + if (baseWebappInstallURL == null && webapp != null) + { + baseWebappInstallURL = webapp.toURI().toURL(); + } + return registerWebapplication(bundle,webappFolderPath,baseWebappInstallURL,contextPath, + extraClasspath,bundleInstall,webXmlPath,defaultWebXmlPath,webAppContext); + } + + /* (non-Javadoc) + * @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#registerWebapplication(org.osgi.framework.Bundle, java.lang.String, java.io.File, java.lang.String, java.lang.String, java.io.File, java.lang.String, java.lang.String) + */ + private WebAppContext registerWebapplication(Bundle contributor, String pathInBundleToWebApp, + URL baseWebappInstallURL, String contextPath, String extraClasspath, File bundleInstall, + String webXmlPath, String defaultWebXmlPath, WebAppContext context) throws Exception + { + + ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); + String[] oldServerClasses = null; + + try + { + // make sure we provide access to all the jetty bundles by going + // through this bundle. + OSGiWebappClassLoader composite = createWebappClassLoader(contributor); + // configure with access to all jetty classes and also all the classes + // that the contributor gives access to. + Thread.currentThread().setContextClassLoader(composite); + + context.setWar(baseWebappInstallURL.toString()); + context.setContextPath(contextPath); + context.setExtraClasspath(extraClasspath); + + if (webXmlPath != null && webXmlPath.length() != 0) + { + File webXml = null; + if (webXmlPath.startsWith("/") || webXmlPath.startsWith("file:/")) + { + webXml = new File(webXmlPath); + } + else + { + webXml = new File(bundleInstall,webXmlPath); + } + if (webXml.exists()) + { + context.setDescriptor(webXml.getAbsolutePath()); + } + } + + if (defaultWebXmlPath == null || defaultWebXmlPath.length() == 0) + { + //use the one defined by the OSGiAppProvider. + defaultWebXmlPath = _wrapper.getOSGiAppProvider().getDefaultsDescriptor(); + } + if (defaultWebXmlPath != null && defaultWebXmlPath.length() != 0) + { + File defaultWebXml = null; + if (defaultWebXmlPath.startsWith("/") || defaultWebXmlPath.startsWith("file:/")) + { + defaultWebXml = new File(webXmlPath); + } + else + { + defaultWebXml = new File(bundleInstall,defaultWebXmlPath); + } + if (defaultWebXml.exists()) + { + context.setDefaultsDescriptor(defaultWebXml.getAbsolutePath()); + } + } + + //other parameters that might be defines on the OSGiAppProvider: + context.setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority()); + + configureWebAppContext(context,contributor); + configureWebappClassLoader(contributor,context,composite); + + // @see + // org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext) + // during initialization of the webapp all the jetty packages are + // visible + // through the webapp classloader. + oldServerClasses = context.getServerClasses(); + context.setServerClasses(null); + + _wrapper.getOSGiAppProvider().addContext(contributor,pathInBundleToWebApp,context); + + return context; + } + finally + { + if (context != null && oldServerClasses != null) + { + context.setServerClasses(oldServerClasses); + } + Thread.currentThread().setContextClassLoader(contextCl); + } + + } + + /* (non-Javadoc) + * @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#unregister(org.eclipse.jetty.server.handler.ContextHandler) + */ + public void unregister(ContextHandler contextHandler) throws Exception + { + _wrapper.getOSGiAppProvider().removeContext(contextHandler); + } + + /* (non-Javadoc) + * @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#registerContext(org.osgi.framework.Bundle, java.lang.String, java.lang.String, java.lang.String) + */ + public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath, + String overrideBundleInstallLocation, ContextHandler handler) + throws Exception + { + File contextsHome = _wrapper.getOSGiAppProvider().getContextXmlDirAsFile(); + if (contextsHome != null) + { + File prodContextFile = new File(contextsHome,contributor.getSymbolicName() + "/" + contextFileRelativePath); + if (prodContextFile.exists()) + { + return registerContext(contributor,contextFileRelativePath,prodContextFile,extraClasspath, + overrideBundleInstallLocation,handler); + } + } + File rootFolder = overrideBundleInstallLocation != null + ? Resource.newResource(overrideBundleInstallLocation).getFile() + : BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor); + File contextFile = rootFolder != null?new File(rootFolder,contextFileRelativePath):null; + if (contextFile != null && contextFile.exists()) + { + return registerContext(contributor,contextFileRelativePath,contextFile,extraClasspath,overrideBundleInstallLocation,handler); + } + else + { + if (contextFileRelativePath.startsWith("./")) + { + contextFileRelativePath = contextFileRelativePath.substring(1); + } + if (!contextFileRelativePath.startsWith("/")) + { + contextFileRelativePath = "/" + contextFileRelativePath; + } + + URL contextURL = contributor.getEntry(contextFileRelativePath); + if (contextURL != null) + { + return registerContext(contributor,contextFileRelativePath,contextURL.openStream(),extraClasspath,overrideBundleInstallLocation,handler); + } + throw new IllegalArgumentException("Could not find the context " + "file " + contextFileRelativePath + " for the bundle " + + contributor.getSymbolicName() + (overrideBundleInstallLocation != null?" using the install location " + overrideBundleInstallLocation:"")); + } + } + + /** + * This type of registration relies on jetty's complete context xml file. + * Context encompasses jndi and all other things. This makes the definition + * of the webapp a lot more self-contained. + * + * @param webapp + * @param contextPath + * @param classInBundle + * @throws Exception + */ + private ContextHandler registerContext(Bundle contributor, String pathInBundle, File contextFile, + String extraClasspath, String overrideBundleInstallLocation, ContextHandler handler) throws Exception + { + InputStream contextFileInputStream = null; + try + { + contextFileInputStream = new BufferedInputStream(new FileInputStream(contextFile)); + return registerContext(contributor, pathInBundle, contextFileInputStream,extraClasspath,overrideBundleInstallLocation, handler); + } + finally + { + IO.close(contextFileInputStream); + } + } + + /** + * @param contributor + * @param contextFileInputStream + * @return The ContextHandler created and registered or null if it did not + * happen. + * @throws Exception + */ + private ContextHandler registerContext(Bundle contributor, String pathInsideBundle, InputStream contextFileInputStream, + String extraClasspath, String overrideBundleInstallLocation, ContextHandler handler) + throws Exception + { + ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); + String[] oldServerClasses = null; + WebAppContext webAppContext = null; + try + { + // make sure we provide access to all the jetty bundles by going + // through this bundle. + OSGiWebappClassLoader composite = createWebappClassLoader(contributor); + // configure with access to all jetty classes and also all the + // classes + // that the contributor gives access to. + Thread.currentThread().setContextClassLoader(composite); + ContextHandler context = createContextHandler(handler, contributor,contextFileInputStream,extraClasspath,overrideBundleInstallLocation); + if (context == null) + { + return null;// did not happen + } + + // ok now register this webapp. we checked when we started jetty + // that there + // was at least one such handler for webapps. + //the actual registration must happen via the new Deployment API. +// _ctxtHandler.addHandler(context); + + configureWebappClassLoader(contributor,context,composite); + if (context instanceof WebAppContext) + { + webAppContext = (WebAppContext)context; + // @see + // org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext) + oldServerClasses = webAppContext.getServerClasses(); + webAppContext.setServerClasses(null); + } + _wrapper.getOSGiAppProvider().addContext(contributor, pathInsideBundle, context); + return context; + } + finally + { + if (webAppContext != null) + { + webAppContext.setServerClasses(oldServerClasses); + } + Thread.currentThread().setContextClassLoader(contextCl); + } + + } + + /** + * Applies the properties of WebAppDeployer as defined in jetty.xml. + * + * @see {WebAppDeployer#scan} around the comment + * <code>// configure it</code> + */ + protected void configureWebAppContext(WebAppContext wah, Bundle contributor) + { + // rfc66 + wah.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT,contributor.getBundleContext()); + + //spring-dm-1.2.1 looks for the BundleContext as a different attribute. + //not a spec... but if we want to support + //org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext + //then we need to do this to: + wah.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), + contributor.getBundleContext()); + + } + + /** + * @See {@link ContextDeployer#scan} + * @param contextFile + * @return + */ + protected ContextHandler createContextHandler(ContextHandler handlerToConfigure, + Bundle bundle, File contextFile, String extraClasspath, String overrideBundleInstallLocation) + { + try + { + return createContextHandler(handlerToConfigure,bundle,new BufferedInputStream(new FileInputStream(contextFile)),extraClasspath,overrideBundleInstallLocation); + } + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + return null; + } + + /** + * @See {@link ContextDeployer#scan} + * @param contextFile + * @return + */ + @SuppressWarnings("unchecked") + protected ContextHandler createContextHandler(ContextHandler handlerToConfigure, + Bundle bundle, InputStream contextInputStream, String extraClasspath, String overrideBundleInstallLocation) + { + /* + * Do something identical to what the ContextProvider would have done: + * XmlConfiguration xmlConfiguration=new + * XmlConfiguration(resource.getURL()); HashMap properties = new + * HashMap(); properties.put("Server", _contexts.getServer()); if + * (_configMgr!=null) properties.putAll(_configMgr.getProperties()); + * + * xmlConfiguration.setProperties(properties); ContextHandler + * context=(ContextHandler)xmlConfiguration.configure(); + * context.setAttributes(new AttributesMap(_contextAttributes)); + */ + try + { + XmlConfiguration xmlConfiguration = new XmlConfiguration(contextInputStream); + HashMap properties = new HashMap(); + properties.put("Server",_wrapper.getServer()); + + // insert the bundle's location as a property. + setThisBundleHomeProperty(bundle,properties,overrideBundleInstallLocation); + xmlConfiguration.setProperties(properties); + + ContextHandler context = null; + if (handlerToConfigure == null) + { + context = (ContextHandler)xmlConfiguration.configure(); + } + else + { + xmlConfiguration.configure(handlerToConfigure); + context = handlerToConfigure; + } + + if (context instanceof WebAppContext) + { + ((WebAppContext)context).setExtraClasspath(extraClasspath); + ((WebAppContext)context).setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority()); + if (_wrapper.getOSGiAppProvider().getDefaultsDescriptor() != null && _wrapper.getOSGiAppProvider().getDefaultsDescriptor().length() != 0) + { + ((WebAppContext)context).setDefaultsDescriptor(_wrapper.getOSGiAppProvider().getDefaultsDescriptor()); + } + } + + // rfc-66: + context.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT,bundle.getBundleContext()); + + //spring-dm-1.2.1 looks for the BundleContext as a different attribute. + //not a spec... but if we want to support + //org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext + //then we need to do this to: + context.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), + bundle.getBundleContext()); + return context; + } + catch (FileNotFoundException e) + { + return null; + } + catch (SAXException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + catch (Throwable e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + finally + { + IO.close(contextInputStream); + } + return null; + } + + /** + * Configure a classloader onto the context. If the context is a + * WebAppContext, build a WebAppClassLoader that has access to all the jetty + * classes thanks to the classloader of the JettyBootStrapper bundle and + * also has access to the classloader of the bundle that defines this + * context. + * <p> + * If the context is not a WebAppContext, same but with a simpler + * URLClassLoader. Note that the URLClassLoader is pretty much fake: it + * delegate all actual classloading to the parent classloaders. + * </p> + * <p> + * The URL[] returned by the URLClassLoader create contained specifically + * the jars that some j2ee tools expect and look into. For example the jars + * that contain tld files for jasper's jstl support. + * </p> + * <p> + * Also as the jars in the lib folder and the classes in the classes folder + * might already be in the OSGi classloader we filter them out of the + * WebAppClassLoader + * </p> + * + * @param context + * @param contributor + * @param webapp + * @param contextPath + * @param classInBundle + * @throws Exception + */ + protected void configureWebappClassLoader(Bundle contributor, ContextHandler context, OSGiWebappClassLoader webappClassLoader) throws Exception + { + if (context instanceof WebAppContext) + { + WebAppContext webappCtxt = (WebAppContext)context; + context.setClassLoader(webappClassLoader); + webappClassLoader.setWebappContext(webappCtxt); + } + else + { + context.setClassLoader(webappClassLoader); + } + } + + /** + * No matter what the type of webapp, we create a WebappClassLoader. + */ + protected OSGiWebappClassLoader createWebappClassLoader(Bundle contributor) throws Exception + { + // we use a temporary WebAppContext object. + // if this is a real webapp we will set it on it a bit later: once we + // know. + OSGiWebappClassLoader webappClassLoader = new OSGiWebappClassLoader( + _wrapper.getParentClassLoaderForWebapps(),new WebAppContext(),contributor,BUNDLE_CLASS_LOADER_HELPER); + return webappClassLoader; + } + + /** + * Set the property "this.bundle.install" to point to the location + * of the bundle. Useful when <SystemProperty name="this.bundle.home"/> is + * used. + */ + private void setThisBundleHomeProperty(Bundle bundle, HashMap<String, Object> properties, String overrideBundleInstallLocation) + { + try + { + File location = overrideBundleInstallLocation != null?new File(overrideBundleInstallLocation):BUNDLE_FILE_LOCATOR_HELPER + .getBundleInstallLocation(bundle); + properties.put("this.bundle.install",location.getCanonicalPath()); + properties.put("this.bundle.install.url",bundle.getEntry("/").toString()); + } + catch (Throwable t) + { + System.err.println("Unable to set 'this.bundle.install' " + " for the bundle " + bundle.getSymbolicName()); + t.printStackTrace(); + } + } + + +} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerExtender.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java index b82bd29050..df257839fd 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerExtender.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) 2009 Intalio, Inc. +// Copyright (c) 2009-2010 Intalio, Inc. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,10 @@ import java.util.Dictionary; import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator; import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; -import org.osgi.framework.BundleListener; +import org.osgi.util.tracker.BundleTracker; +import org.osgi.util.tracker.BundleTrackerCustomizer; + /** * Support bundles that declare the webapp directly through headers in their @@ -46,44 +47,102 @@ import org.osgi.framework.BundleListener; * * @author hmalphettes */ -public class JettyContextHandlerExtender implements BundleListener -{ +public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer { + - /** - * Receives notification that a bundle has had a lifecycle change. - * - * @param event - * The <code>BundleEvent</code>. - */ - public void bundleChanged(BundleEvent event) - { - switch (event.getType()) - { - case BundleEvent.STARTED: - register(event.getBundle()); - break; - case BundleEvent.STOPPING: - unregister(event.getBundle()); - break; - } - } + /** + * A bundle is being added to the <code>BundleTracker</code>. + * + * <p> + * This method is called before a bundle which matched the search parameters + * of the <code>BundleTracker</code> is added to the + * <code>BundleTracker</code>. This method should return the object to be + * tracked for the specified <code>Bundle</code>. The returned object is + * stored in the <code>BundleTracker</code> and is available from the + * {@link BundleTracker#getObject(Bundle) getObject} method. + * + * @param bundle The <code>Bundle</code> being added to the + * <code>BundleTracker</code>. + * @param event The bundle event which caused this customizer method to be + * called or <code>null</code> if there is no bundle event associated + * with the call to this method. + * @return The object to be tracked for the specified <code>Bundle</code> + * object or <code>null</code> if the specified <code>Bundle</code> + * object should not be tracked. + */ + public Object addingBundle(Bundle bundle, BundleEvent event) + { + if (bundle.getState() == Bundle.ACTIVE) + { + boolean isWebBundle = register(bundle); + return isWebBundle ? bundle : null; + } + else if (bundle.getState() == Bundle.STOPPING) + { + unregister(bundle); + } + else + { + //we should not be called in that state as + //we are registered only for ACTIVE and STOPPING + } + return null; + } - /** + /** + * A bundle tracked by the <code>BundleTracker</code> has been modified. * + * <p> + * This method is called when a bundle being tracked by the + * <code>BundleTracker</code> has had its state modified. + * + * @param bundle The <code>Bundle</code> whose state has been modified. + * @param event The bundle event which caused this customizer method to be + * called or <code>null</code> if there is no bundle event associated + * with the call to this method. + * @param object The tracked object for the specified bundle. */ - public void init(BundleContext context) - { - Bundle bundles[] = context.getBundles(); - for (int i = 0; i < bundles.length; i++) - { - if ((bundles[i].getState() & (Bundle.STARTING | Bundle.ACTIVE)) != 0) - { - register(bundles[i]); - } - } - } + public void modifiedBundle(Bundle bundle, BundleEvent event, + Object object) + { + //nothing the web-bundle was already track. something changed. + //we only reload the webapps if the bundle is stopped and restarted. +// System.err.println(bundle.getSymbolicName()); + if (bundle.getState() == Bundle.STOPPING || bundle.getState() == Bundle.ACTIVE) + { + unregister(bundle); + } + if (bundle.getState() == Bundle.ACTIVE) + { + register(bundle); + } + } - private void register(Bundle bundle) + /** + * A bundle tracked by the <code>BundleTracker</code> has been removed. + * + * <p> + * This method is called after a bundle is no longer being tracked by the + * <code>BundleTracker</code>. + * + * @param bundle The <code>Bundle</code> that has been removed. + * @param event The bundle event which caused this customizer method to be + * called or <code>null</code> if there is no bundle event associated + * with the call to this method. + * @param object The tracked object for the specified bundle. + */ + public void removedBundle(Bundle bundle, BundleEvent event, + Object object) + { + unregister(bundle); + } + + + /** + * @param bundle + * @return true if this bundle in indeed a web-bundle. + */ + private boolean register(Bundle bundle) { Dictionary<?, ?> dic = bundle.getHeaders(); String warFolderRelativePath = (String)dic.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH); @@ -99,11 +158,13 @@ public class JettyContextHandlerExtender implements BundleListener try { JettyBootstrapActivator.registerWebapplication(bundle,warFolderRelativePath,contextPath); + return true; } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); + return true;//maybe it did not work maybe it did. safer to track this bundle. } } else if (dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH) != null) @@ -112,7 +173,7 @@ public class JettyContextHandlerExtender implements BundleListener if (contextFileRelativePath == null) { // nothing to register here. - return; + return false; } // support for multiple webapps in the same bundle: String[] pathes = contextFileRelativePath.split(",;"); @@ -128,6 +189,7 @@ public class JettyContextHandlerExtender implements BundleListener e.printStackTrace(); } } + return true; } else { @@ -137,7 +199,7 @@ public class JettyContextHandlerExtender implements BundleListener URL rfc66Webxml = bundle.getEntry("/WEB-INF/web.xml"); if (rfc66Webxml == null) { - return;// no webapp in here + return false;// no webapp in here } // this is risky: should we make sure that there is no classes and // jars directly available @@ -151,11 +213,13 @@ public class JettyContextHandlerExtender implements BundleListener try { JettyBootstrapActivator.registerWebapplication(bundle,".",rfc66ContextPath); + return true; } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); + return true;//maybe it did not work maybe it did. safer to track this bundle. } } } @@ -195,4 +259,7 @@ public class JettyContextHandlerExtender implements BundleListener // webapps registered in that bundle. } + + + } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebappRegistrationHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebappRegistrationHelper.java deleted file mode 100644 index 447893d315..0000000000 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebappRegistrationHelper.java +++ /dev/null @@ -1,979 +0,0 @@ -// ======================================================================== -// Copyright (c) 2009 Intalio, Inc. -// ------------------------------------------------------------------------ -// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// Contributors: -// Hugues Malphettes - initial API and implementation -// ======================================================================== -package org.eclipse.jetty.osgi.boot.internal.webapp; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.jar.JarFile; -import java.util.zip.ZipEntry; - -import org.eclipse.jetty.deploy.AppProvider; -import org.eclipse.jetty.deploy.ContextDeployer; -import org.eclipse.jetty.deploy.DeploymentManager; -import org.eclipse.jetty.deploy.WebAppDeployer; -import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator; -import org.eclipse.jetty.osgi.boot.OSGiAppProvider; -import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; -import org.eclipse.jetty.osgi.boot.internal.jsp.TldLocatableURLClassloader; -import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper; -import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper; -import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer; -import org.eclipse.jetty.osgi.boot.utils.internal.DefaultBundleClassLoaderHelper; -import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.server.handler.DefaultHandler; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.RequestLogHandler; -import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.xml.XmlConfiguration; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -/** - * Bridges the jetty deployers with the OSGi lifecycle where applications are - * managed inside OSGi-bundles. - * <p> - * This class should be called as a consequence of the activation of a new - * service that is a ContextHandler.<br/> - * This way the new webapps are exposed as OSGi services. - * </p> - * <p> - * Helper methods to register a bundle that is a web-application or a context. - * </p> - * Limitations: - * <ul> - * <li>support for jarred webapps is somewhat limited.</li> - * </ul> - */ -public class WebappRegistrationHelper -{ - - private static Logger __logger = Log.getLogger(WebappRegistrationHelper.class.getName()); - - private static boolean INITIALIZED = false; - - /** - * By default set to: {@link DefaultBundleClassLoaderHelper}. It supports - * equinox and apache-felix fragment bundles that are specific to an OSGi - * implementation should set a different implementation. - */ - public static BundleClassLoaderHelper BUNDLE_CLASS_LOADER_HELPER = null; - /** - * By default set to: {@link DefaultBundleClassLoaderHelper}. It supports - * equinox and apache-felix fragment bundles that are specific to an OSGi - * implementation should set a different implementation. - */ - public static BundleFileLocatorHelper BUNDLE_FILE_LOCATOR_HELPER = null; - - /** - * By default set to: {@link DefaultBundleClassLoaderHelper}. It supports - * equinox and apache-felix fragment bundles that are specific to an OSGi - * implementation should set a different implementation. - * <p> - * Several of those objects can be added here: For example we could have an optional fragment that setups - * a specific implementation of JSF for the whole of jetty-osgi. - * </p> - */ - public static Collection<WebappRegistrationCustomizer> JSP_REGISTRATION_HELPERS = new ArrayList<WebappRegistrationCustomizer>(); - - private Server _server; - private ContextHandlerCollection _ctxtHandler; - - /** - * this class loader loads the jars inside {$jetty.home}/lib/ext it is meant - * as a migration path and for jars that are not OSGi ready. also gives - * access to the jsp jars. - */ - // private URLClassLoader _libExtClassLoader; - - /** - * This is the class loader that should be the parent classloader of any - * webapp classloader. It is in fact the _libExtClassLoader with a trick to - * let the TldScanner find the jars where the tld files are. - */ - private URLClassLoader _commonParentClassLoaderForWebapps; - - private DeploymentManager _deploymentManager; - - private OSGiAppProvider _provider; - - public WebappRegistrationHelper(Server server) - { - _server = server; - staticInit(); - } - - // Inject the customizing classes that might be defined in fragment bundles. - private static synchronized void staticInit() - { - if (!INITIALIZED) - { - INITIALIZED = true; - // setup the custom BundleClassLoaderHelper - try - { - BUNDLE_CLASS_LOADER_HELPER = (BundleClassLoaderHelper)Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance(); - } - catch (Throwable t) - { - // System.err.println("support for equinox and felix"); - BUNDLE_CLASS_LOADER_HELPER = new DefaultBundleClassLoaderHelper(); - } - // setup the custom FileLocatorHelper - try - { - BUNDLE_FILE_LOCATOR_HELPER = (BundleFileLocatorHelper)Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance(); - } - catch (Throwable t) - { - // System.err.println("no jsp/jasper support"); - BUNDLE_FILE_LOCATOR_HELPER = new DefaultFileLocatorHelper(); - } - } - } - - /** - * Removes quotes around system property values before we try to make them - * into file pathes. - */ - public static String stripQuotesIfPresent(String filePath) - { - if (filePath == null) - return null; - - if ((filePath.startsWith("\"") || filePath.startsWith("'")) && (filePath.endsWith("\"") || filePath.endsWith("'"))) - return filePath.substring(1,filePath.length() - 1); - return filePath; - } - - /** - * Look for the home directory of jetty as defined by the system property - * 'jetty.home'. If undefined, look at the current bundle and uses its own - * jettyhome folder for this feature. - * <p> - * Special case: inside eclipse-SDK:<br/> - * If the bundle is jarred, see if we are inside eclipse-PDE itself. In that - * case, look for the installation directory of eclipse-PDE, try to create a - * jettyhome folder there and install the sample jettyhome folder at that - * location. This makes the installation in eclipse-SDK easier. <br/> - * This is a bit redundant with the work done by the jetty configuration - * launcher. - * </p> - * - * @param context - * @throws Exception - */ - public void setup(BundleContext context, Map<String, String> configProperties) throws Exception - { - File _installLocation = BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(context.getBundle()); - // debug: - // new File("~/proj/eclipse-install/eclipse-3.5.1-SDK-jetty7/" + - // "dropins/jetty7/plugins/org.eclipse.jetty.osgi.boot_0.0.1.001-SNAPSHOT.jar"); - boolean bootBundleCanBeJarred = true; - String jettyHome = stripQuotesIfPresent(System.getProperty("jetty.home")); - - if (jettyHome == null || jettyHome.length() == 0) - { - if (_installLocation.getName().endsWith(".jar")) - { - jettyHome = JettyHomeHelper.setupJettyHomeInEclipsePDE(_installLocation); - } - if (jettyHome == null) - { - jettyHome = _installLocation.getAbsolutePath() + "/jettyhome"; - bootBundleCanBeJarred = false; - } - } - // in case we stripped the quotes. - System.setProperty("jetty.home",jettyHome); - - String jettyLogs = stripQuotesIfPresent(System.getProperty("jetty.logs")); - if (jettyLogs == null || jettyLogs.length() == 0) - { - System.setProperty("jetty.logs",jettyHome + "/logs"); - } - - if (!bootBundleCanBeJarred && !_installLocation.isDirectory()) - { - String install = _installLocation != null?_installLocation.getCanonicalPath():" unresolved_install_location"; - throw new IllegalArgumentException("The system property -Djetty.home" + " must be set to a directory or the bundle " - + context.getBundle().getSymbolicName() + " installed here " + install + " must be unjarred."); - - } - try - { - System.err.println("JETTY_HOME set to " + new File(jettyHome).getCanonicalPath()); - } - catch (Throwable t) - { - System.err.println("JETTY_HOME _set to " + new File(jettyHome).getAbsolutePath()); - } - - ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); - try - { - - // passing this bundle's classloader as the context classlaoder - // makes sure there is access to all the jetty's bundles - - File jettyHomeF = new File(jettyHome); - URLClassLoader libExtClassLoader = null; - try - { - libExtClassLoader = LibExtClassLoaderHelper.createLibEtcClassLoaderHelper(jettyHomeF,_server, - JettyBootstrapActivator.class.getClassLoader()); - } - catch (MalformedURLException e) - { - e.printStackTrace(); - } - - Thread.currentThread().setContextClassLoader(libExtClassLoader); - - String jettyetc = System.getProperty(OSGiWebappConstants.SYS_PROP_JETTY_ETC_FILES,"etc/jetty.xml"); - StringTokenizer tokenizer = new StringTokenizer(jettyetc,";,"); - - Map<Object,Object> id_map = new HashMap<Object,Object>(); - id_map.put("Server",_server); - Map<Object,Object> properties = new HashMap<Object,Object>(); - properties.put("jetty.home",jettyHome); - properties.put("jetty.host",System.getProperty("jetty.host","")); - properties.put("jetty.port",System.getProperty("jetty.port","8080")); - properties.put("jetty.port.ssl",System.getProperty("jetty.port.ssl","8443")); - - while (tokenizer.hasMoreTokens()) - { - String etcFile = tokenizer.nextToken().trim(); - File conffile = etcFile.startsWith("/")?new File(etcFile):new File(jettyHomeF,etcFile); - if (!conffile.exists()) - { - __logger.warn("Unable to resolve the jetty/etc file " + etcFile); - - if ("etc/jetty.xml".equals(etcFile)) - { - // Missing jetty.xml file, so create a minimal Jetty configuration - __logger.info("Configuring default server on 8080"); - SelectChannelConnector connector = new SelectChannelConnector(); - connector.setPort(8080); - _server.addConnector(connector); - - HandlerCollection handlers = new HandlerCollection(); - ContextHandlerCollection contexts = new ContextHandlerCollection(); - RequestLogHandler requestLogHandler = new RequestLogHandler(); - handlers.setHandlers(new Handler[] { contexts, new DefaultHandler(), requestLogHandler }); - _server.setHandler(handlers); - } - } - else - { - try - { - // Execute a Jetty configuration file - XmlConfiguration config = new XmlConfiguration(new FileInputStream(conffile)); - config.setIdMap(id_map); - config.setProperties(properties); - config.configure(); - id_map=config.getIdMap(); - } - catch (SAXParseException saxparse) - { - Log.getLogger(WebappRegistrationHelper.class.getName()).warn("Unable to configure the jetty/etc file " + etcFile,saxparse); - throw saxparse; - } - } - } - - init(); - - //now that we have an app provider we can call the registration customizer. - try - { - URL[] jarsWithTlds = getJarsWithTlds(); - _commonParentClassLoaderForWebapps = jarsWithTlds == null?libExtClassLoader:new TldLocatableURLClassloader(libExtClassLoader,getJarsWithTlds()); - } - catch (MalformedURLException e) - { - e.printStackTrace(); - } - - - _server.start(); - } - catch (Throwable t) - { - t.printStackTrace(); - } - finally - { - Thread.currentThread().setContextClassLoader(contextCl); - } - - } - - /** - * Must be called after the server is configured. - * - * Locate the actual instance of the ContextDeployer and WebAppDeployer that - * was created when configuring the server through jetty.xml. If there is no - * such thing it won't be possible to deploy webapps from a context and we - * throw IllegalStateExceptions. - */ - private void init() - { - // Get the context handler - _ctxtHandler = (ContextHandlerCollection)_server.getChildHandlerByClass(ContextHandlerCollection.class); - - // get a deployerManager - List<DeploymentManager> deployers = _server.getBeans(DeploymentManager.class); - if (deployers != null && !deployers.isEmpty()) - { - _deploymentManager = deployers.get(0); - - for (AppProvider provider : _deploymentManager.getAppProviders()) - { - if (provider instanceof OSGiAppProvider) - { - _provider=(OSGiAppProvider)provider; - break; - } - } - if (_provider == null) - { - //create it on the fly with reasonable default values. - try - { - _provider = new OSGiAppProvider(); - _provider.setMonitoredDir( - Resource.newResource(getDefaultOSGiContextsHome( - new File(System.getProperty("jetty.home"))).toURI())); - } catch (IOException e) { - e.printStackTrace(); - } - _deploymentManager.addAppProvider(_provider); - } - } - - if (_ctxtHandler == null || _provider==null) - throw new IllegalStateException("ERROR: No ContextHandlerCollection or OSGiAppProvider configured"); - - - } - - /** - * Deploy a new web application on the jetty server. - * - * @param context - * The current bundle context - * @param webappFolderPath - * The path to the root of the webapp. Must be a path relative to - * bundle; either an absolute path. - * @param contextPath - * The context path. Must start with "/" - * @param classInBundle - * A class that belongs to the current bundle to inherit from the - * osgi classloader. Null to not have access to the OSGI - * classloader. - * @throws Exception - */ - public ContextHandler registerWebapplication(Bundle bundle, String webappFolderPath, String contextPath, String extraClasspath, - String overrideBundleInstallLocation, String webXmlPath, String defaultWebXmlPath) throws Exception - { - File bundleInstall = overrideBundleInstallLocation == null?BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle):new File( - overrideBundleInstallLocation); - File webapp = null; - if (webappFolderPath != null && webappFolderPath.length() != 0 && !webappFolderPath.equals(".")) - { - if (webappFolderPath.startsWith("/") || webappFolderPath.startsWith("file:/")) - { - webapp = new File(webappFolderPath); - } - else - { - webapp = new File(bundleInstall,webappFolderPath); - } - } - else - { - webapp = bundleInstall; - } - if (!webapp.exists()) - { - throw new IllegalArgumentException("Unable to locate " + webappFolderPath + " inside " - + (bundleInstall != null?bundleInstall.getAbsolutePath():"unlocated bundle '" + bundle.getSymbolicName() + "'")); - } - return registerWebapplication(bundle,webapp,contextPath,extraClasspath,bundleInstall,webXmlPath,defaultWebXmlPath); - } - - /** - * @See {@link WebAppDeployer#scan()} - * TODO: refacotr this into the createContext method of OSGiAppProvider. - * - * @param webapp - * @param contextPath - * @param classInBundle - * @return The contexthandler created and started - * @throws Exception - */ - public ContextHandler registerWebapplication(Bundle contributor, File webapp, String contextPath, String extraClasspath, File bundleInstall, - String webXmlPath, String defaultWebXmlPath) throws Exception - { - - ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); - String[] oldServerClasses = null; - WebAppContext context = null; - try - { - // make sure we provide access to all the jetty bundles by going - // through this bundle. - OSGiWebappClassLoader composite = createWebappClassLoader(contributor); - // configure with access to all jetty classes and also all the classes - // that the contributor gives access to. - Thread.currentThread().setContextClassLoader(composite); - - context = new WebAppContext(webapp.getAbsolutePath(),contextPath); - context.setExtraClasspath(extraClasspath); - - if (webXmlPath != null && webXmlPath.length() != 0) - { - File webXml = null; - if (webXmlPath.startsWith("/") || webXmlPath.startsWith("file:/")) - { - webXml = new File(webXmlPath); - } - else - { - webXml = new File(bundleInstall,webXmlPath); - } - if (webXml.exists()) - { - context.setDescriptor(webXml.getAbsolutePath()); - } - } - - if (defaultWebXmlPath == null || defaultWebXmlPath.length() == 0) - { - //use the one defined by the OSGiAppProvider. - defaultWebXmlPath = _provider.getDefaultsDescriptor(); - } - if (defaultWebXmlPath != null && defaultWebXmlPath.length() != 0) - { - File defaultWebXml = null; - if (defaultWebXmlPath.startsWith("/") || defaultWebXmlPath.startsWith("file:/")) - { - defaultWebXml = new File(webXmlPath); - } - else - { - defaultWebXml = new File(bundleInstall,defaultWebXmlPath); - } - if (defaultWebXml.exists()) - { - context.setDefaultsDescriptor(defaultWebXml.getAbsolutePath()); - } - } - - //other parameters that might be defines on the OSGiAppProvider: - context.setParentLoaderPriority(_provider.isParentLoaderPriority()); - - configureWebAppContext(context,contributor); - configureWebappClassLoader(contributor,context,composite); - - // @see - // org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext) - // during initialization of the webapp all the jetty packages are - // visible - // through the webapp classloader. - oldServerClasses = context.getServerClasses(); - context.setServerClasses(null); - _provider.addContext(context); - - return context; - } - finally - { - if (context != null && oldServerClasses != null) - { - context.setServerClasses(oldServerClasses); - } - Thread.currentThread().setContextClassLoader(contextCl); - } - - } - - /** - * Stop a ContextHandler and remove it from the collection. - * - * @See ContextDeployer#undeploy - * @param contextHandler - * @throws Exception - */ - public void unregister(ContextHandler contextHandler) throws Exception - { - contextHandler.stop(); - _ctxtHandler.removeHandler(contextHandler); - } - - /** - * @return The default folder in which the context files of the osgi bundles - * are located and watched. Or null when the system property - * "jetty.osgi.contexts.home" is not defined. - * If the configuration file defines the OSGiAppProvider's context. - * This will not be taken into account. - */ - File getDefaultOSGiContextsHome(File jettyHome) - { - String jettyContextsHome = System.getProperty("jetty.osgi.contexts.home"); - if (jettyContextsHome != null) - { - File contextsHome = new File(jettyContextsHome); - if (!contextsHome.exists() || !contextsHome.isDirectory()) - { - throw new IllegalArgumentException("the ${jetty.osgi.contexts.home} '" + jettyContextsHome + " must exist and be a folder"); - } - return contextsHome; - } - return new File(jettyHome, "/contexts"); - } - - File getOSGiContextsHome() - { - return _provider.getContextXmlDirAsFile(); - } - - /** - * This type of registration relies on jetty's complete context xml file. - * Context encompasses jndi and all other things. This makes the definition - * of the webapp a lot more self-contained. - * - * @param webapp - * @param contextPath - * @param classInBundle - * @throws Exception - */ - public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath, String overrideBundleInstallLocation) - throws Exception - { - File contextsHome = _provider.getContextXmlDirAsFile(); - if (contextsHome != null) - { - File prodContextFile = new File(contextsHome,contributor.getSymbolicName() + "/" + contextFileRelativePath); - if (prodContextFile.exists()) - { - return registerContext(contributor,prodContextFile,extraClasspath,overrideBundleInstallLocation); - } - } - File contextFile = overrideBundleInstallLocation != null?new File(overrideBundleInstallLocation,contextFileRelativePath):new File( - BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor),contextFileRelativePath); - if (contextFile.exists()) - { - return registerContext(contributor,contextFile,extraClasspath,overrideBundleInstallLocation); - } - else - { - if (contextFileRelativePath.startsWith("./")) - { - contextFileRelativePath = contextFileRelativePath.substring(1); - } - if (!contextFileRelativePath.startsWith("/")) - { - contextFileRelativePath = "/" + contextFileRelativePath; - } - if (overrideBundleInstallLocation == null) - { - URL contextURL = contributor.getEntry(contextFileRelativePath); - if (contextURL != null) - { - return registerContext(contributor,contextURL.openStream(),extraClasspath,overrideBundleInstallLocation); - } - } - else - { - JarFile zipFile = null; - try - { - zipFile = new JarFile(overrideBundleInstallLocation); - ZipEntry entry = zipFile.getEntry(contextFileRelativePath.substring(1)); - return registerContext(contributor,zipFile.getInputStream(entry),extraClasspath,overrideBundleInstallLocation); - } - catch (Throwable t) - { - - } - finally - { - if (zipFile != null) - try - { - zipFile.close(); - } - catch (IOException ioe) - { - } - } - } - throw new IllegalArgumentException("Could not find the context " + "file " + contextFileRelativePath + " for the bundle " - + contributor.getSymbolicName() + (overrideBundleInstallLocation != null?" using the install location " + overrideBundleInstallLocation:"")); - } - } - - /** - * This type of registration relies on jetty's complete context xml file. - * Context encompasses jndi and all other things. This makes the definition - * of the webapp a lot more self-contained. - * - * @param webapp - * @param contextPath - * @param classInBundle - * @throws Exception - */ - private ContextHandler registerContext(Bundle contributor, File contextFile, String extraClasspath, String overrideBundleInstallLocation) throws Exception - { - InputStream contextFileInputStream = null; - try - { - contextFileInputStream = new BufferedInputStream(new FileInputStream(contextFile)); - return registerContext(contributor,contextFileInputStream,extraClasspath,overrideBundleInstallLocation); - } - finally - { - if (contextFileInputStream != null) - try - { - contextFileInputStream.close(); - } - catch (IOException ioe) - { - } - } - } - - /** - * @param contributor - * @param contextFileInputStream - * @return The ContextHandler created and registered or null if it did not - * happen. - * @throws Exception - */ - private ContextHandler registerContext(Bundle contributor, InputStream contextFileInputStream, String extraClasspath, String overrideBundleInstallLocation) - throws Exception - { - ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); - String[] oldServerClasses = null; - WebAppContext webAppContext = null; - try - { - // make sure we provide access to all the jetty bundles by going - // through this bundle. - OSGiWebappClassLoader composite = createWebappClassLoader(contributor); - // configure with access to all jetty classes and also all the - // classes - // that the contributor gives access to. - Thread.currentThread().setContextClassLoader(composite); - ContextHandler context = createContextHandler(contributor,contextFileInputStream,extraClasspath,overrideBundleInstallLocation); - if (context == null) - { - return null;// did not happen - } - - // ok now register this webapp. we checked when we started jetty - // that there - // was at least one such handler for webapps. - //the actual registration must happen via the new Deployment API. -// _ctxtHandler.addHandler(context); - - configureWebappClassLoader(contributor,context,composite); - if (context instanceof WebAppContext) - { - webAppContext = (WebAppContext)context; - // @see - // org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext) - oldServerClasses = webAppContext.getServerClasses(); - webAppContext.setServerClasses(null); - } - - context.start(); - return context; - } - finally - { - if (webAppContext != null) - { - webAppContext.setServerClasses(oldServerClasses); - } - Thread.currentThread().setContextClassLoader(contextCl); - } - - } - - /** - * TODO: right now only the jetty-jsp bundle is scanned for common taglibs. - * Should support a way to plug more bundles that contain taglibs. - * - * The jasper TldScanner expects a URLClassloader to parse a jar for the - * /META-INF/*.tld it may contain. We place the bundles that we know contain - * such tag-libraries. Please note that it will work if and only if the - * bundle is a jar (!) Currently we just hardcode the bundle that contains - * the jstl implemenation. - * - * A workaround when the tld cannot be parsed with this method is to copy - * and paste it inside the WEB-INF of the webapplication where it is used. - * - * Support only 2 types of packaging for the bundle: - the bundle is a jar - * (recommended for runtime.) - the bundle is a folder and contain jars in - * the root and/or in the lib folder (nice for PDE developement situations) - * Unsupported: the bundle is a jar that embeds more jars. - * - * @return - * @throws Exception - */ - private URL[] getJarsWithTlds() throws Exception - { - ArrayList<URL> res = new ArrayList<URL>(); - for (WebappRegistrationCustomizer regCustomizer : JSP_REGISTRATION_HELPERS) - { - URL[] urls = regCustomizer.getJarsWithTlds(_provider, BUNDLE_FILE_LOCATOR_HELPER); - for (URL url : urls) - { - if (!res.contains(url)) - res.add(url); - } - } - if (!res.isEmpty()) - return res.toArray(new URL[res.size()]); - else - return null; - } - - /** - * Applies the properties of WebAppDeployer as defined in jetty.xml. - * - * @see {WebAppDeployer#scan} around the comment - * <code>// configure it</code> - */ - protected void configureWebAppContext(WebAppContext wah, Bundle contributor) - { - // rfc66 - wah.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT,contributor.getBundleContext()); - - //spring-dm-1.2.1 looks for the BundleContext as a different attribute. - //not a spec... but if we want to support - //org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext - //then we need to do this to: - wah.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), - contributor.getBundleContext()); - - } - - /** - * @See {@link ContextDeployer#scan} - * @param contextFile - * @return - */ - protected ContextHandler createContextHandler(Bundle bundle, File contextFile, String extraClasspath, String overrideBundleInstallLocation) - { - try - { - return createContextHandler(bundle,new BufferedInputStream(new FileInputStream(contextFile)),extraClasspath,overrideBundleInstallLocation); - } - catch (FileNotFoundException e) - { - e.printStackTrace(); - } - return null; - } - - /** - * @See {@link ContextDeployer#scan} - * @param contextFile - * @return - */ - @SuppressWarnings("unchecked") - protected ContextHandler createContextHandler(Bundle bundle, InputStream contextInputStream, String extraClasspath, String overrideBundleInstallLocation) - { - /* - * Do something identical to what the ContextProvider would have done: - * XmlConfiguration xmlConfiguration=new - * XmlConfiguration(resource.getURL()); HashMap properties = new - * HashMap(); properties.put("Server", _contexts.getServer()); if - * (_configMgr!=null) properties.putAll(_configMgr.getProperties()); - * - * xmlConfiguration.setProperties(properties); ContextHandler - * context=(ContextHandler)xmlConfiguration.configure(); - * context.setAttributes(new AttributesMap(_contextAttributes)); - */ - try - { - XmlConfiguration xmlConfiguration = new XmlConfiguration(contextInputStream); - HashMap properties = new HashMap(); - properties.put("Server",_server); - - // insert the bundle's location as a property. - setThisBundleHomeProperty(bundle,properties,overrideBundleInstallLocation); - xmlConfiguration.setProperties(properties); - - ContextHandler context = (ContextHandler)xmlConfiguration.configure(); - if (context instanceof WebAppContext) - { - ((WebAppContext)context).setExtraClasspath(extraClasspath); - ((WebAppContext)context).setParentLoaderPriority(_provider.isParentLoaderPriority()); - if (_provider.getDefaultsDescriptor() != null && _provider.getDefaultsDescriptor().length() != 0) - { - ((WebAppContext)context).setDefaultsDescriptor(_provider.getDefaultsDescriptor()); - } - } - - // rfc-66: - context.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT,bundle.getBundleContext()); - - //spring-dm-1.2.1 looks for the BundleContext as a different attribute. - //not a spec... but if we want to support - //org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext - //then we need to do this to: - context.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), - bundle.getBundleContext()); - return context; - } - catch (FileNotFoundException e) - { - return null; - } - catch (SAXException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - catch (IOException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - catch (Throwable e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - finally - { - if (contextInputStream != null) - try - { - contextInputStream.close(); - } - catch (IOException ioe) - { - } - } - return null; - } - - /** - * Configure a classloader onto the context. If the context is a - * WebAppContext, build a WebAppClassLoader that has access to all the jetty - * classes thanks to the classloader of the JettyBootStrapper bundle and - * also has access to the classloader of the bundle that defines this - * context. - * <p> - * If the context is not a WebAppContext, same but with a simpler - * URLClassLoader. Note that the URLClassLoader is pretty much fake: it - * delegate all actual classloading to the parent classloaders. - * </p> - * <p> - * The URL[] returned by the URLClassLoader create contained specifically - * the jars that some j2ee tools expect and look into. For example the jars - * that contain tld files for jasper's jstl support. - * </p> - * <p> - * Also as the jars in the lib folder and the classes in the classes folder - * might already be in the OSGi classloader we filter them out of the - * WebAppClassLoader - * </p> - * - * @param context - * @param contributor - * @param webapp - * @param contextPath - * @param classInBundle - * @throws Exception - */ - protected void configureWebappClassLoader(Bundle contributor, ContextHandler context, OSGiWebappClassLoader webappClassLoader) throws Exception - { - if (context instanceof WebAppContext) - { - WebAppContext webappCtxt = (WebAppContext)context; - context.setClassLoader(webappClassLoader); - webappClassLoader.setWebappContext(webappCtxt); - } - else - { - context.setClassLoader(webappClassLoader); - } - } - - /** - * No matter what the type of webapp, we create a WebappClassLoader. - */ - protected OSGiWebappClassLoader createWebappClassLoader(Bundle contributor) throws Exception - { - // we use a temporary WebAppContext object. - // if this is a real webapp we will set it on it a bit later: once we - // know. - OSGiWebappClassLoader webappClassLoader = new OSGiWebappClassLoader(_commonParentClassLoaderForWebapps,new WebAppContext(),contributor); - return webappClassLoader; - } - - /** - * Set the property "this.bundle.install" to point to the location - * of the bundle. Useful when <SystemProperty name="this.bundle.home"/> is - * used. - */ - private void setThisBundleHomeProperty(Bundle bundle, HashMap<String, Object> properties, String overrideBundleInstallLocation) - { - try - { - File location = overrideBundleInstallLocation != null?new File(overrideBundleInstallLocation):BUNDLE_FILE_LOCATOR_HELPER - .getBundleInstallLocation(bundle); - properties.put("this.bundle.install",location.getCanonicalPath()); - } - catch (Throwable t) - { - System.err.println("Unable to set 'this.bundle.install' " + " for the bundle " + bundle.getSymbolicName()); - t.printStackTrace(); - } - } - - -} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java index 8aef238472..820a627e1f 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java @@ -13,6 +13,8 @@ package org.eclipse.jetty.osgi.boot.utils; import java.io.File; +import java.net.URL; +import java.util.Enumeration; import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper; import org.osgi.framework.Bundle; @@ -53,7 +55,7 @@ public interface BundleFileLocatorHelper * * @param bundle * @param path - * @return + * @return file object * @throws Exception */ public File getFileInBundle(Bundle bundle, String path) throws Exception; @@ -73,5 +75,16 @@ public interface BundleFileLocatorHelper * embedded inside it. */ public File[] locateJarsInsideBundle(Bundle bundle) throws Exception; + + + /** + * Helper method equivalent to Bundle#getEntry(String entryPath) except that + * it searches for entries in the fragments by using the findEntries method. + * + * @param bundle + * @param entryPath + * @return null or all the entries found for that path. + */ + public Enumeration<URL> findEntries(Bundle bundle, String entryPath); } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java index 5db0a2f4de..1a37a046c6 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java @@ -46,7 +46,7 @@ public interface WebappRegistrationCustomizer * the root and/or in the lib folder (nice for PDE developement situations) * Unsupported: the bundle is a jar that embeds more jars. * - * @return + * @return array of URLs * @throws Exception */ URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper fileLocator) throws Exception; diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java index a3541b60ac..a918cd7706 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java @@ -14,6 +14,8 @@ package org.eclipse.jetty.osgi.boot.utils.internal; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLConnection; import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper; import org.osgi.framework.Bundle; @@ -59,7 +61,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper * Assuming the bundle is started. * * @param bundle - * @return + * @return classloader object */ public ClassLoader getBundleClassLoader(Bundle bundle) { @@ -180,4 +182,5 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper } return null; } + } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java index 5dfc3676df..ec8f997d69 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java @@ -14,10 +14,13 @@ package org.eclipse.jetty.osgi.boot.utils.internal; import java.io.File; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.net.URI; import java.net.URL; import java.net.URLConnection; +import java.net.URLDecoder; import java.util.ArrayList; +import java.util.Enumeration; import java.util.zip.ZipFile; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper; @@ -66,8 +69,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper // grab the MANIFEST.MF's url // and then do what it takes. URL url = bundle.getEntry("/META-INF/MANIFEST.MF"); - // System.err.println(url.toString() + " " + url.toURI() + " " + - // url.getProtocol()); +// System.err.println(url.toString() + " " + url.toURI() + " " + url.getProtocol()); if (url.getProtocol().equals("file")) { // some osgi frameworks do use the file protocole directly in some @@ -130,11 +132,36 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper { // observed this on felix-2.0.0 String location = bundle.getLocation(); +// System.err.println("location " + location); if (location.startsWith("file:/")) { URI uri = new URI(URIUtil.encodePath(location)); return new File(uri); } + else if (location.startsWith("file:")) + { + //location defined in the BundleArchive m_bundleArchive + //it is relative to relative to the BundleArchive's m_archiveRootDir + File res = new File(location.substring("file:".length())); + if (!res.exists()) + { + return null; +// Object bundleArchive = getFelixBundleArchive(bundle); +// File archiveRoot = getFelixBundleArchiveRootDir(bundleArchive); +// String currentLocation = getFelixBundleArchiveCurrentLocation(bundleArchive); +// System.err.println("Got the archive root " + archiveRoot.getAbsolutePath() +// + " current location " + currentLocation + " is directory ?"); +// res = new File(archiveRoot, currentLocation != null +// ? currentLocation : location.substring("file:".length())); + } + return res; + } + else if (location.startsWith("reference:file:")) + { + location = URLDecoder.decode(location.substring("reference:".length()), "UTF-8"); + File file = new File(location.substring("file:".length())); + return file; + } } return null; } @@ -144,7 +171,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper * * @param bundle * @param path - * @return + * @return file object * @throws Exception */ public File getFileInBundle(Bundle bundle, String path) throws Exception @@ -162,6 +189,29 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper } return webapp; } + + /** + * Helper method equivalent to Bundle#getEntry(String entryPath) except that + * it searches for entries in the fragments by using the Bundle#findEntries method. + * + * @param bundle + * @param entryPath + * @return null or all the entries found for that path. + */ + public Enumeration<URL> findEntries(Bundle bundle, String entryPath) + { + int last = entryPath.lastIndexOf('/'); + String path = last != -1 && last < entryPath.length() -2 + ? entryPath.substring(0, last) : "/"; + if (!path.startsWith("/")) + { + path = "/" + path; + } + String pattern = last != -1 && last < entryPath.length() -2 + ? entryPath.substring(last+1) : entryPath; + Enumeration<URL> enUrls = bundle.findEntries(path, pattern, false); + return enUrls; + } /** * If the bundle is a jar, returns the jar. If the bundle is a folder, look @@ -205,9 +255,78 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper } else { - return new File[] - { jasperLocation }; + return new File[] { jasperLocation }; } } + + + //introspection on equinox to invoke the getLocalURL method on BundleURLConnection + //equivalent to using the FileLocator without depending on an equinox class. + private static Method BUNDLE_URL_CONNECTION_getLocalURL = null; + private static Method BUNDLE_URL_CONNECTION_getFileURL = null; + /** + * Only useful for equinox: on felix we get the file:// or jar:// url already. + * Other OSGi implementations have not been tested + * <p> + * Get a URL to the bundle entry that uses a common protocol (i.e. file: + * jar: or http: etc.). + * </p> + * @return a URL to the bundle entry that uses a common protocol + */ + public static URL getLocalURL(URL url) { + if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol())) { + try { + URLConnection conn = url.openConnection(); + if (BUNDLE_URL_CONNECTION_getLocalURL == null && + conn.getClass().getName().equals( + "org.eclipse.osgi.framework.internal.core.BundleURLConnection")) { + BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL", null); + BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true); + } + if (BUNDLE_URL_CONNECTION_getLocalURL != null) { + return (URL)BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn, null); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + return url; + } + /** + * Only useful for equinox: on felix we get the file:// url already. + * Other OSGi implementations have not been tested + * <p> + * Get a URL to the content of the bundle entry that uses the file: protocol. + * The content of the bundle entry may be downloaded or extracted to the local + * file system in order to create a file: URL. + * @return a URL to the content of the bundle entry that uses the file: protocol + * </p> + */ + public static URL getFileURL(URL url) + { + if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol())) + { + try + { + URLConnection conn = url.openConnection(); + if (BUNDLE_URL_CONNECTION_getFileURL == null && + conn.getClass().getName().equals( + "org.eclipse.osgi.framework.internal.core.BundleURLConnection")) + { + BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL", null); + BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true); + } + if (BUNDLE_URL_CONNECTION_getFileURL != null) + { + return (URL)BUNDLE_URL_CONNECTION_getFileURL.invoke(conn, null); + } + } + catch (Throwable t) + { + t.printStackTrace(); + } + } + return url; + } } diff --git a/jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF index c71a82e4c4..6cc44e2155 100644 --- a/jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF +++ b/jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: OSGi HttpService provided by equinox HttpServiceServlet deployed on jetty Bundle-SymbolicName: org.eclipse.jetty.osgi.httpservice -Bundle-Version: 8.0.0.M0.qualifier +Bundle-Version: 8.0.0.qualifier Bundle-Vendor: Mort Bay Consulting Bundle-RequiredExecutionEnvironment: J2SE-1.6 Import-Package: javax.servlet;version="3.0", diff --git a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml index caf77ba90d..b4a931d492 100644 --- a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml +++ b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml @@ -19,5 +19,6 @@ <Call name="addServlet"> <Arg>org.eclipse.jetty.osgi.httpservice.HttpServiceServletX</Arg> <Arg>/*</Arg> + <Set name="InitOrder">0</Set> </Call> </Configure>
\ No newline at end of file diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml index f74c49fa0e..be3a6ea356 100644 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml +++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml @@ -2,7 +2,7 @@ <parent> <groupId>org.eclipse.jetty.osgi</groupId> <artifactId>jetty-osgi-project</artifactId> - <version>8.0.0.M1</version> + <version>8.0.0.M1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> @@ -72,11 +72,12 @@ </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.osgi.httpservice.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml.tycho b/jetty-osgi/jetty-osgi-httpservice/pom.xml.tycho deleted file mode 100644 index c6efbeb50f..0000000000 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml.tycho +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <modelVersion>4.0.0</modelVersion> - <parent> - <artifactId>jetty-osgi</artifactId> - <groupId>org.eclipse.jetty.osgi</groupId> - <version>7.0.1-SNAPSHOT</version> - </parent> - <artifactId>org.eclipse.jetty.osgi.httpservice</artifactId> - <packaging>eclipse-plugin</packaging> -</project> diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index 4db0740817..c5e67f39b3 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-project</artifactId> - <version>8.0.0.M1</version> + <version>8.0.0.M1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <groupId>org.eclipse.jetty.osgi</groupId> @@ -19,10 +19,8 @@ </properties> <modules> <module>jetty-osgi-boot</module> - <!-- remove until jsp jars available in main maven repo --> + <!-- remove until we update the code to make it work with the jsp-2.2 jars --> <!-- module>jetty-osgi-boot-jsp</module --> - <!-- logback is currently under CQs --> - <module>jetty-osgi-boot-logback</module> <module>jetty-osgi-boot-warurl</module> <module>jetty-osgi-httpservice</module> <!-- module>example-jetty-osgi</module --> @@ -56,19 +54,6 @@ </resources> <plugins> <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <version>1.3</version> - <executions> - <execution> - <id>parse-version</id> - <goals> - <goal>parse-version</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-eclipse-plugin</artifactId> <configuration> @@ -88,67 +73,56 @@ <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> <version>${project.version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-webapp</artifactId> <version>${project.version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-deploy</artifactId> <version>${project.version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse</groupId> <artifactId>osgi</artifactId> <version>${osgi-version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.osgi</groupId> <artifactId>services</artifactId> <version>${osgi-services-version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.equinox.http</groupId> <artifactId>servlet</artifactId> <version>${equinox-http-servlet-version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j-version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j-version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>${slf4j-version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback-version}</version> - <scope>provided</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback-version}</version> - <scope>provided</scope> </dependency> </dependencies> </dependencyManagement> diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index 1abf83079a..2a6c9ff77e 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -13,7 +13,7 @@ </properties> <build> <plugins> -<!-- +<!-- COMMENTED OUT UNTIL CORRECT CONFIG IS FOUND FOR Export uses clauses --> <plugin> @@ -39,16 +39,11 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include sources since jetty-xbean makes use of them --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> @@ -72,6 +67,13 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.plus.*</onlyAnalyze> + </configuration> + </plugin> </plugins> </build> <dependencies> @@ -84,6 +86,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-plus/src/main/config/etc/jetty-plus.xml b/jetty-plus/src/main/config/etc/jetty-plus.xml index c9352f5526..fd6cca33bf 100644 --- a/jetty-plus/src/main/config/etc/jetty-plus.xml +++ b/jetty-plus/src/main/config/etc/jetty-plus.xml @@ -47,6 +47,7 @@ <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item> <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item> <Item>org.eclipse.jetty.plus.webapp.Configuration</Item> + <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item> <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item> <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item> </Array> @@ -57,13 +58,12 @@ <!-- Uncomment the following to set up a deployer that will --> <!-- deploy webapps from a directory called webapps-plus. Note --> <!-- that you will need to create this directory first! --> - <!-- <Ref id="DeploymentManager"> <Call name="addAppProvider"> <Arg> <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> <Set name="monitoredDir"><Property name="jetty.home" default="." />/webapps-plus</Set> - <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set> + <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set> <Set name="scanInterval">5</Set> <Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set> <Set name="parentLoaderPriority">false</Set> @@ -73,6 +73,5 @@ </Arg> </Call> </Ref> - --> </Configure> diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java index 20728938e2..79a80e264f 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java @@ -161,7 +161,6 @@ public class Injection /** * Inject a value for a Resource from JNDI into an object * @param injectable - * @throws Exception */ public void inject (Object injectable) { @@ -179,8 +178,8 @@ public class Injection /** * The Resource must already exist in the ENC of this webapp. - * @return - * @throws Exception + * @return the injected valud + * @throws NamingException */ public Object lookupInjectedValue () throws NamingException diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/InjectionCollection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/InjectionCollection.java index 089e2ce292..7d87b80e77 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/InjectionCollection.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/InjectionCollection.java @@ -32,6 +32,7 @@ public class InjectionCollection public static final String INJECTION_COLLECTION = "org.eclipse.jetty.injectionCollection"; private HashMap<String, List<Injection>> _injectionMap = new HashMap<String, List<Injection>>();//map of classname to injections + public void add (Injection injection) { if ((injection==null) || injection.getTargetClass()==null) @@ -47,7 +48,6 @@ public class InjectionCollection injections = new ArrayList<Injection>(); _injectionMap.put(injection.getTargetClass().getCanonicalName(), injections); } - injections.add(injection); } @@ -59,6 +59,7 @@ public class InjectionCollection return _injectionMap.get(className); } + public Injection getInjection (String jndiName, Class clazz, Field field) diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java index edb930c887..fc75dd4b3f 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java @@ -123,7 +123,7 @@ public abstract class LifeCycleCallback * @param clazz the class under inspection * @param methodName the method to find * @param checkInheritance false on first entry, true if a superclass is being introspected - * @return + * @return the method */ public Method findMethod (Package pack, Class clazz, String methodName, boolean checkInheritance) { diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java index b531f7cc02..dc6cd9975e 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/AbstractLoginModule.java @@ -165,7 +165,7 @@ public abstract class AbstractLoginModule implements LoginModule /** * @see javax.security.auth.spi.LoginModule#commit() - * @return + * @return true if committed, false if not (likely not authenticated) * @throws LoginException */ public boolean commit() throws LoginException @@ -201,7 +201,7 @@ public abstract class AbstractLoginModule implements LoginModule /** * @see javax.security.auth.spi.LoginModule#login() - * @return + * @return true if is authenticated, false otherwise * @throws LoginException */ public boolean login() throws LoginException @@ -252,7 +252,7 @@ public abstract class AbstractLoginModule implements LoginModule /** * @see javax.security.auth.spi.LoginModule#logout() - * @return + * @return true always * @throws LoginException */ public boolean logout() throws LoginException diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java index 668c01916f..95926c30a2 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/DataSourceLoginModule.java @@ -27,8 +27,7 @@ import javax.sql.DataSource; * A LoginModule that uses a DataSource to retrieve user authentication * and authorisation information. * - * @see org.eclipse.jetty.server.server.plus.jaas.spi.JDBCLoginModule - * + * @see JDBCLoginModule */ public class DataSourceLoginModule extends AbstractDatabaseLoginModule { @@ -68,8 +67,8 @@ public class DataSourceLoginModule extends AbstractDatabaseLoginModule /** * Get a connection from the DataSource - * @see org.eclipse.jetty.server.server.plus.jaas.spi.AbstractDatabaseLoginModule#getConnection() - * @return + * @see AbstractDatabaseLoginModule#getConnection() + * @return the connection for the datasource * @throws Exception */ public Connection getConnection () diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java index 5242148654..31a799861d 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/JDBCLoginModule.java @@ -36,13 +36,9 @@ import org.eclipse.jetty.util.log.Log; * * <p><h4>Usage</h4> * <pre> - */ -/* * </pre> * - * @see * @version 1.0 Tue Apr 15 2003 - * */ public class JDBCLoginModule extends AbstractDatabaseLoginModule { @@ -52,14 +48,10 @@ public class JDBCLoginModule extends AbstractDatabaseLoginModule private String dbPassword; - - - - /** * Get a connection from the DriverManager - * @see org.eclipse.jetty.server.server.plus.jaas.spi.AbstractDatabaseLoginModule#getConnection() - * @return + * @see AbstractDatabaseLoginModule#getConnection() + * @return the connection for this datasource * @throws Exception */ public Connection getConnection () diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java index ca009978e9..586862384e 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/LdapLoginModule.java @@ -182,7 +182,7 @@ public class LdapLoginModule extends AbstractLoginModule * roles are also an optional concept if required * * @param username - * @return + * @return the userinfo for the username * @throws Exception */ public UserInfo getUserInfo(String username) throws Exception @@ -367,7 +367,7 @@ public class LdapLoginModule extends AbstractLoginModule * then we try a binding authentication check, otherwise if we have the users encoded password then * we can try authentication via that mechanic * - * @return + * @return true if authenticated, false otherwise * @throws LoginException */ public boolean login() throws LoginException @@ -440,7 +440,7 @@ public class LdapLoginModule extends AbstractLoginModule * password supplied authentication check * * @param webCredential - * @return + * @return true if authenticated * @throws LoginException */ protected boolean credentialLogin(Object webCredential) throws LoginException @@ -451,13 +451,13 @@ public class LdapLoginModule extends AbstractLoginModule /** * binding authentication check - * This methode of authentication works only if the user branch of the DIT (ldap tree) - * has an ACI (acces control instruction) that allow the access to any user or at least + * This method of authentication works only if the user branch of the DIT (ldap tree) + * has an ACI (access control instruction) that allow the access to any user or at least * for the user that logs in. * * @param username * @param password - * @return + * @return true always * @throws LoginException */ public boolean bindingLogin(String username, Object password) throws LoginException, NamingException @@ -610,7 +610,7 @@ public class LdapLoginModule extends AbstractLoginModule /** * get the context for connection * - * @return + * @return the environment details for the context */ public Hashtable<Object, Object> getEnvironment() { diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java index c2f4ee935d..d99db19a4e 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jaas/spi/PropertyFileLoginModule.java @@ -141,7 +141,6 @@ public class PropertyFileLoginModule extends AbstractLoginModule /** * Don't implement this as we want to pre-fetch all of the * users. - * @see org.eclipse.jetty.plus.jaas.spi.AbstractLoginModule#lazyLoadUser(java.lang.String) * @param username * @throws Exception */ diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java index 2fd2bcd884..9c2d7f9952 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java @@ -134,7 +134,7 @@ public abstract class NamingEntry /** * Get the unique name of the object * relative to the scope - * @return + * @return the unique jndi name of the object */ public String getJndiName () { @@ -143,7 +143,7 @@ public abstract class NamingEntry /** * Get the object that is to be bound - * @return + * @return the object that is to be bound */ public Object getObjectToBind() throws NamingException @@ -155,7 +155,7 @@ public abstract class NamingEntry /** * Get the name of the object, fully * qualified with the scope - * @return + * @return the name of the object, fully qualified with the scope */ public String getJndiNameInScope () { diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java index 444fa68d42..fa4f8416e2 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java @@ -40,10 +40,10 @@ public class NamingEntryUtil * resource. The pre-existing resource can be either in the webapp's * naming environment, or in the container's naming environment. Webapp's * environment takes precedence over the server's namespace. - * + * + * @param scope the scope of the lookup * @param asName the name to bind as * @param mappedName the name from the environment to link to asName - * @param namingEntryType * @throws NamingException */ public static boolean bindToENC (Object scope, String asName, String mappedName) @@ -72,7 +72,7 @@ public class NamingEntryUtil * * @param scope * @param jndiName - * @return + * @return the naming entry for the given scope * @throws NamingException */ public static NamingEntry lookupNamingEntry (Object scope, String jndiName) @@ -115,7 +115,7 @@ public class NamingEntryUtil * * @param scope * @param clazz the type of the entry - * @return + * @return all NameEntries of a certain type in the given naming environment scope (server-wide names or context-specific names) * @throws NamingException */ public static List lookupNamingEntries (Object scope, Class clazz) diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/Transaction.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/Transaction.java index 39cefe456e..397cad0fce 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/Transaction.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/Transaction.java @@ -27,13 +27,6 @@ import org.eclipse.jetty.util.log.Log; * Transaction * * Class to represent a JTA UserTransaction impl. - * - * - */ -/** - * Transaction - * - * */ public class Transaction extends NamingEntry { @@ -68,7 +61,7 @@ public class Transaction extends NamingEntry * Allow other bindings of UserTransaction. * * These should be in ADDITION to java:comp/UserTransaction - * @see org.eclipse.jetty.server.server.plus.jndi.NamingEntry#bindToENC(java.lang.String) + * @see NamingEntry#bindToENC(java.lang.String) */ public void bindToENC (String localName) throws NamingException diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java index 79728c1d8f..8d0d6ae3e8 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java @@ -277,7 +277,7 @@ public class DataSourceLoginService extends MappedLoginService /* ------------------------------------------------------------ */ /** Load user's info from database. * - * @param user + * @param userName */ @Override protected UserIdentity loadUser (String userName) diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/Configuration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/Configuration.java index 1a59c7f930..b767c5e78b 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/Configuration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/Configuration.java @@ -24,9 +24,9 @@ import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; import org.eclipse.jetty.plus.annotation.RunAsCollection; import org.eclipse.jetty.plus.jndi.Transaction; import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.webapp.Fragment; +import org.eclipse.jetty.webapp.FragmentDescriptor; import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.webapp.WebXmlProcessor; +import org.eclipse.jetty.webapp.MetaData; /** @@ -59,23 +59,29 @@ public class Configuration implements org.eclipse.jetty.webapp.Configuration { bindUserTransaction(context); - WebXmlProcessor webXmlProcessor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (webXmlProcessor == null) - throw new IllegalStateException ("No processor for web xml"); + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException ("No metadata"); - PlusDescriptorProcessor plusProcessor = new PlusDescriptorProcessor(webXmlProcessor); - webXmlProcessor.process(webXmlProcessor.getWebDefault(), plusProcessor); - webXmlProcessor.process(webXmlProcessor.getWebXml(), plusProcessor); + metaData.addDescriptorProcessor(new PlusDescriptorProcessor()); + + /* + * THE PROCESSING IS NOW DONE IN metadata.resolve () + + PlusDescriptorProcessor plusProcessor = new PlusDescriptorProcessor(metaData); + plusProcessor.process(metaData.getWebDefault()); + plusProcessor.process(metaData.getWebXml()); //Process plus-elements of each descriptor - for (Fragment frag: webXmlProcessor.getFragments()) + for (FragmentDescriptor frag: metaData.getOrderedFragments()) { - webXmlProcessor.process(frag, plusProcessor); + plusProcessor.process(frag); } //process the override-web.xml descriptor - webXmlProcessor.process(webXmlProcessor.getOverrideWeb(), plusProcessor); + plusProcessor.process(metaData.getOverrideWeb()); + */ } public void postConfigure(WebAppContext context) throws Exception diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java index d226a38429..6500b1eab1 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java @@ -53,7 +53,7 @@ public class EnvConfiguration implements Configuration /** - * @see org.eclipse.jetty.webapp.Configuration#configureDefaults() + * @see Configuration#configure(WebAppContext) * @throws Exception */ public void preConfigure (WebAppContext context) throws Exception @@ -108,7 +108,7 @@ public class EnvConfiguration implements Configuration /** * Remove all jndi setup - * @see org.eclipse.jetty.webapp.Configuration#deconfigureWebApp() + * @see Configuration#deconfigure(WebAppContext) * @throws Exception */ public void deconfigure (WebAppContext context) throws Exception diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java index 9261784b23..bd39d05e4b 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java @@ -33,11 +33,11 @@ import org.eclipse.jetty.plus.jndi.NamingEntryUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.webapp.Descriptor; -import org.eclipse.jetty.webapp.Fragment; +import org.eclipse.jetty.webapp.FragmentDescriptor; import org.eclipse.jetty.webapp.IterativeDescriptorProcessor; import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.webapp.WebXmlProcessor; -import org.eclipse.jetty.webapp.WebXmlProcessor.Origin; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.MetaData.Origin; import org.eclipse.jetty.xml.XmlParser; /** @@ -49,12 +49,10 @@ import org.eclipse.jetty.xml.XmlParser; public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { protected WebAppContext _context; - protected WebXmlProcessor _processor; + protected MetaData _metaData; - public PlusDescriptorProcessor (WebXmlProcessor processor) + public PlusDescriptorProcessor () { - _processor = processor; - _context = _processor.getContext(); try { registerVisitor("env-entry", getClass().getDeclaredMethod("visitEnvEntry", __signature)); @@ -71,19 +69,26 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } /** - * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start() + * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start(org.eclipse.jetty.webapp.Descriptor) */ - public void start() - { + public void start(Descriptor descriptor) + { + _metaData = descriptor.getMetaData(); + _context = _metaData.getContext(); } - + + /** - * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#end() + * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#end(org.eclipse.jetty.webapp.Descriptor) */ - public void end() + public void end(Descriptor descriptor) { + _metaData = null; + _context = null; } + + /** * JavaEE 5.4.1.3 @@ -106,19 +111,19 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor return; } - Origin o = _processor.getOrigin("env-entry."+name); + Origin o = _metaData.getOrigin("env-entry."+name); switch (o) { case NotSet: { //no descriptor has configured an env-entry of this name previously - _processor.setOrigin("env-entry."+name, descriptor); + _metaData.setOrigin("env-entry."+name, descriptor); //the javaee_5.xsd says that the env-entry-type is optional //if there is an <injection> element, because you can get //type from the element, but what to do if there is more //than one <injection> element, do you just pick the type //of the first one? - addInjection (descriptor, node, name, TypeUtil.fromName(type)); + addInjections (descriptor, node, name, TypeUtil.fromName(type)); Object value = TypeUtil.valueOf(type,valueStr); bindEnvEntry(name, value); break; @@ -130,12 +135,12 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor //ServletSpec 3.0 p75. web.xml (or web-override/web-defaults) declared //the env-entry. A fragment is not allowed to change that, except unless //the web.xml did not declare any injections. - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { //We're processing web-defaults, web.xml or web-override. Any of them can //set or change the env-entry. - _processor.setOrigin("env-entry."+name, descriptor); - addInjection (descriptor, node, name, TypeUtil.fromName(type)); + _metaData.setOrigin("env-entry."+name, descriptor); + addInjections (descriptor, node, name, TypeUtil.fromName(type)); Object value = TypeUtil.valueOf(type,valueStr); bindEnvEntry(name, value); } @@ -144,9 +149,9 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor //A web.xml declared the env-entry. Check to see if any injections have been //declared for it. If it was declared in web.xml then don't merge any injections. //If it was declared in a web-fragment, then we can keep merging fragments. - Descriptor d = _processor.getOriginDescriptor("env-entry."+name+".injection"); - if (d==null || d instanceof Fragment) - addInjection(descriptor, node, name, TypeUtil.fromName(type)); + Descriptor d = _metaData.getOriginDescriptor("env-entry."+name+".injection"); + if (d==null || d instanceof FragmentDescriptor) + addInjections(descriptor, node, name, TypeUtil.fromName(type)); } break; } @@ -196,19 +201,19 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor String auth = node.getString("res-auth", false, true); String shared = node.getString("res-sharing-scope", false, true); - Origin o = _processor.getOrigin("resource-ref."+jndiName); + Origin o = _metaData.getOrigin("resource-ref."+jndiName); switch (o) { case NotSet: { - //No descriptor previously declared a resource-ref of this name. - _processor.setOrigin("resource-ref."+jndiName, descriptor); + //No descriptor or annotation previously declared a resource-ref of this name. + _metaData.setOrigin("resource-ref."+jndiName, descriptor); //check for <injection> elements Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection (descriptor, node, jndiName, typeClass); + addInjections(descriptor, node, jndiName, typeClass); bindResourceRef(jndiName, typeClass); break; } @@ -217,33 +222,35 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //A web xml previously declared the resource-ref. - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { //We're processing web-defaults, web.xml or web-override. Any of them can //set or change the resource-ref. - _processor.setOrigin("resource-ref."+jndiName, descriptor); + _metaData.setOrigin("resource-ref."+jndiName, descriptor); //check for <injection> elements Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection (descriptor, node, jndiName, typeClass); + + addInjections(descriptor, node, jndiName, typeClass); //bind the entry into jndi bindResourceRef(jndiName, typeClass); } else { - //A web xml declared the resource-ref. Check to see if any injections have been - //declared for it. If an injection was declared in web.xml then don't merge any injections. + //A web xml declared the resource-ref and we're processing a + //web-fragment. Check to see if any injections were declared for it by web.xml. + //If any injection was declared in web.xml then don't merge any injections. //If it was declared in a web-fragment, then we can keep merging fragments. - Descriptor d = _processor.getOriginDescriptor("resource-ref."+jndiName+".injection"); - if (d==null || d instanceof Fragment) + Descriptor d = _metaData.getOriginDescriptor("resource-ref."+jndiName+".injection"); + if (d==null || d instanceof FragmentDescriptor) { Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection(descriptor, node, jndiName, TypeUtil.fromName(type)); + addInjections(descriptor, node, jndiName, TypeUtil.fromName(type)); } } break; @@ -274,7 +281,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor String jndiName = node.getString("resource-env-ref-name",false,true); String type = node.getString("resource-env-ref-type", false, true); - Origin o = _processor.getOrigin("resource-env-ref."+jndiName); + Origin o = _metaData.getOrigin("resource-env-ref."+jndiName); switch (o) { case NotSet: @@ -285,7 +292,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection (descriptor, node, jndiName, typeClass); + addInjections (descriptor, node, jndiName, typeClass); bindResourceEnvRef(jndiName, typeClass); break; } @@ -295,28 +302,28 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { //A resource-env-ref of this name has been declared first in a web xml. //Only allow other web-default, web.xml, web-override to change it. - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { //We're processing web-defaults, web.xml or web-override. Any of them can //set or change the resource-env-ref. - _processor.setOrigin("resource-env-ref."+jndiName, descriptor); + _metaData.setOrigin("resource-env-ref."+jndiName, descriptor); Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection (descriptor, node, jndiName, typeClass); + addInjections (descriptor, node, jndiName, typeClass); bindResourceEnvRef(jndiName, typeClass); } else { //We're processing a web-fragment. It can only contribute injections if the //there haven't been any injections declared yet, or they weren't declared in a WebXml file. - Descriptor d = _processor.getOriginDescriptor("resource-env-ref."+jndiName+".injection"); - if (d == null || d instanceof Fragment) + Descriptor d = _metaData.getOriginDescriptor("resource-env-ref."+jndiName+".injection"); + if (d == null || d instanceof FragmentDescriptor) { Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection (descriptor, node, jndiName, typeClass); + addInjections (descriptor, node, jndiName, typeClass); } } break; @@ -345,7 +352,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor String type = node.getString("message-destination-type",false,true); String usage = node.getString("message-destination-usage",false,true); - Origin o = _processor.getOrigin("message-destination-ref."+jndiName); + Origin o = _metaData.getOrigin("message-destination-ref."+jndiName); switch (o) { case NotSet: @@ -354,9 +361,9 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection(descriptor, node, jndiName, typeClass); + addInjections(descriptor, node, jndiName, typeClass); bindMessageDestinationRef(jndiName, typeClass); - _processor.setOrigin("message-destination-ref."+jndiName, descriptor); + _metaData.setOrigin("message-destination-ref."+jndiName, descriptor); break; } case WebXml: @@ -365,26 +372,26 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { //A message-destination-ref of this name has been declared first in a web xml. //Only allow other web-default, web.xml, web-override to change it. - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection(descriptor, node, jndiName, typeClass); + addInjections(descriptor, node, jndiName, typeClass); bindMessageDestinationRef(jndiName, typeClass); - _processor.setOrigin("message-destination-ref."+jndiName, descriptor); + _metaData.setOrigin("message-destination-ref."+jndiName, descriptor); } else { //A web-fragment has declared a message-destination-ref with the same name as a web xml. //It can only contribute injections, and only if the web xml didn't declare any. - Descriptor d = _processor.getOriginDescriptor("message-destination-ref."+jndiName+".injection"); - if (d == null || d instanceof Fragment) + Descriptor d = _metaData.getOriginDescriptor("message-destination-ref."+jndiName+".injection"); + if (d == null || d instanceof FragmentDescriptor) { Class typeClass = TypeUtil.fromName(type); if (typeClass==null) typeClass = _context.loadClass(type); - addInjection(descriptor, node, jndiName, typeClass); + addInjections(descriptor, node, jndiName, typeClass); } } break; @@ -427,13 +434,13 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); //ServletSpec 3.0 p80 If web.xml declares a post-construct then all post-constructs //in fragments must be ignored. Otherwise, they are additive. - Origin o = _processor.getOrigin("post-construct"); + Origin o = _metaData.getOrigin("post-construct"); switch (o) { case NotSet: { //No post-constructs have been declared previously. - _processor.setOrigin("post-construct", descriptor); + _metaData.setOrigin("post-construct", descriptor); try { @@ -454,7 +461,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { //A web xml first declared a post-construct. Only allow other web xml files (web-defaults, web-overrides etc) //to add to it - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { try { @@ -513,14 +520,14 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); - Origin o = _processor.getOrigin("pre-destroy"); + Origin o = _metaData.getOrigin("pre-destroy"); switch(o) { case NotSet: { //No pre-destroys have been declared previously. Record this descriptor //as the first declarer. - _processor.setOrigin("pre-destroy", descriptor); + _metaData.setOrigin("pre-destroy", descriptor); try { Class clazz = _context.loadClass(className); @@ -540,7 +547,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor { //A web xml file previously declared a pre-destroy. Only allow other web xml files //(not web-fragments) to add to them. - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { try { @@ -585,7 +592,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor * @param valueClass * @return */ - public void addInjection (Descriptor descriptor, XmlParser.Node node, String jndiName, Class valueClass) + public void addInjections (Descriptor descriptor, XmlParser.Node node, String jndiName, Class valueClass) { Iterator itor = node.iterator("injection-target"); @@ -615,9 +622,10 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor injection.setJndiName(jndiName); injection.setTarget(clazz, targetName, valueClass); injections.add(injection); + //Record which was the first descriptor to declare an injection for this name - if (_processor.getOriginDescriptor(node.getTag()+"."+jndiName+".injection") == null) - _processor.setOrigin(node.getTag()+"."+jndiName+".injection", descriptor); + if (_metaData.getOriginDescriptor(node.getTag()+"."+jndiName+".injection") == null) + _metaData.setOrigin(node.getTag()+"."+jndiName+".injection", descriptor); } catch (ClassNotFoundException e) { @@ -625,6 +633,8 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor } } } + + /** @@ -763,4 +773,6 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor else throw new IllegalStateException("Nothing to bind for name "+nameInEnvironment); } + + } diff --git a/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java b/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java index a83f1dd71f..d18998b5b2 100644 --- a/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java +++ b/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java @@ -4,19 +4,17 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.plus.jndi; - import java.util.Hashtable; import java.util.List; - import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; @@ -27,138 +25,110 @@ import javax.naming.Referenceable; import javax.naming.StringRefAddr; import javax.naming.spi.ObjectFactory; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** - * TestEnvEntry - * * */ -public class TestNamingEntries extends TestCase +public class TestNamingEntries { - public class ScopeA extends Object + public class ScopeA { public String toString() { return this.getClass().getName()+"@"+super.hashCode(); } } - + public class ScopeB extends ScopeA - {} - - - + { + } + public static class SomeObject { private int value; public SomeObject (int value) {this.value = value;} - + public int getValue () { return this.value; } } - + public static class SomeObjectFactory implements ObjectFactory { - public SomeObjectFactory() { - } - /** - * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable) - * @param arg0 - * @param arg1 - * @param arg2 - * @param arg3 - * @return - * @throws Exception - */ + public Object getObjectInstance(Object arg0, Name arg1, Context arg2, Hashtable arg3) throws Exception { Reference ref = (Reference)arg0; - + RefAddr refAddr = ref.get(0); String valueName = refAddr.getType(); if (!valueName.equalsIgnoreCase("val")) throw new RuntimeException("Unrecognized refaddr type = "+valueName); - + String value = (String)refAddr.getContent(); - + return new SomeObject(Integer.parseInt(value.trim())); - } - } - + public static class SomeOtherObject extends SomeObject implements Referenceable { - - private String svalue; public SomeOtherObject (String value) { super(Integer.parseInt(value.trim())); - } - - /** - * @see javax.naming.Referenceable#getReference() - * @return - * @throws NamingException - */ + public Reference getReference() throws NamingException { RefAddr refAddr = new StringRefAddr("val", String.valueOf(getValue())); - Reference ref = new Reference(SomeOtherObject.class.getName(), refAddr, SomeOtherObjectFactory.class.getName(), null); - return ref; + return new Reference(SomeOtherObject.class.getName(), refAddr, SomeOtherObjectFactory.class.getName(), null); } } - + public static class SomeOtherObjectFactory implements ObjectFactory { - public SomeOtherObjectFactory() { - } - /** - * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable) - * @param arg0 - * @param arg1 - * @param arg2 - * @param arg3 - * @return - * @throws Exception - */ + public Object getObjectInstance(Object arg0, Name arg1, Context arg2, Hashtable arg3) throws Exception { - Reference ref = (Reference)arg0; - + Reference ref = (Reference)arg0; + RefAddr refAddr = ref.get(0); String valueName = refAddr.getType(); if (!valueName.equalsIgnoreCase("val")) throw new RuntimeException("Unrecognized refaddr type = "+valueName); - + String value = (String)refAddr.getContent(); - + return new SomeOtherObject(value.trim()); } - } - - public SomeObject someObject; - - public void setUp () + private SomeObject someObject; + + @Before + public void init() { this.someObject = new SomeObject(4); } - public void testEnvEntryNoScope () - throws Exception + @Test + public void testEnvEntryNoScope() throws Exception { EnvEntry ee = new EnvEntry("nameZ", "zstring", true); List list = NamingEntryUtil.lookupNamingEntries(null, EnvEntry.class); @@ -170,10 +140,10 @@ public class TestNamingEntries extends TestCase EnvEntry eo = (EnvEntry)o; assertEquals ("nameZ", eo.getJndiName()); } - - public void testEnvEntryOverride () - throws Exception - { + + @Test + public void testEnvEntryOverride() throws Exception + { ScopeA scope = new ScopeA(); EnvEntry ee = new EnvEntry (scope, "nameA", someObject, true); @@ -188,10 +158,9 @@ public class TestNamingEntries extends TestCase assertNotNull(namingEntriesContext); assertEquals(someObject, scopeContext.lookup("nameA")); } - - public void testEnvEntryNonOverride () - throws Exception + @Test + public void testEnvEntryNonOverride() throws Exception { ScopeA scope = new ScopeA(); EnvEntry ee = new EnvEntry (scope, "nameA", someObject, false); @@ -208,34 +177,32 @@ public class TestNamingEntries extends TestCase assertEquals(someObject, scopeContext.lookup("nameA")); } - - public void testResource () - throws Exception + @Test + public void testResource () throws Exception { InitialContext icontext = new InitialContext(); - + Resource resource = new Resource (null, "resourceA/b/c", someObject); NamingEntry ne = NamingEntryUtil.lookupNamingEntry(null, "resourceA/b/c"); assertNotNull(ne); assertTrue(ne instanceof Resource); assertEquals(icontext.lookup("resourceA/b/c"), someObject); - + Object scope = new ScopeA(); Resource resource2 = new Resource (scope, "resourceB", someObject); ne = NamingEntryUtil.lookupNamingEntry(scope, "resourceB"); assertNotNull(ne); assertTrue(ne instanceof Resource); - + ne = NamingEntryUtil.lookupNamingEntry(null, "resourceB"); assertNull(ne); - + ne = NamingEntryUtil.lookupNamingEntry(new ScopeB(), "resourceB"); assertNull(ne); } - - - public void testLink () - throws Exception + + @Test + public void testLink () throws Exception { ScopeA scope = new ScopeA(); InitialContext icontext = new InitialContext(); @@ -246,15 +213,13 @@ public class TestNamingEntries extends TestCase assertEquals(icontext.lookup("resourceA"), "resourceB"); link = new Link (scope, "jdbc/resourceX", "jdbc/resourceY"); - ne = NamingEntryUtil.lookupNamingEntry(scope, "jdbc/resourceX"); + ne = NamingEntryUtil.lookupNamingEntry(scope, "jdbc/resourceX"); assertNotNull(ne); assertTrue(ne instanceof Link); } - - - - public void testResourceReferenceable () - throws Exception + + @Test + public void testResourceReferenceable() throws Exception { SomeOtherObject someOtherObj = new SomeOtherObject("100"); InitialContext icontext = new InitialContext(); @@ -263,25 +228,24 @@ public class TestNamingEntries extends TestCase assertNotNull(o); assertTrue (o instanceof SomeOtherObject); assertEquals(((SomeOtherObject)o).getValue(), 100); - } - - public void testResourceReference () - throws Exception + + @Test + public void testResourceReference () throws Exception { RefAddr refAddr = new StringRefAddr("val", "10"); Reference ref = new Reference(SomeObject.class.getName(), refAddr, SomeObjectFactory.class.getName(), null); - + InitialContext icontext = new InitialContext(); Resource resource = new Resource (null, "resourceByRef", ref); NamingEntry ne = NamingEntryUtil.lookupNamingEntry(null, "resourceByRef"); assertNotNull(ne); assertTrue (ne instanceof Resource); - + Object o = icontext.lookup("resourceByRef"); assertNotNull (o); assertTrue (o instanceof SomeObject); - + assertEquals(((SomeObject)o).getValue(), 10); } } diff --git a/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntryUtil.java b/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntryUtil.java index af407897f3..ad56aa295d 100644 --- a/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntryUtil.java +++ b/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntryUtil.java @@ -4,25 +4,30 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.plus.jndi; import java.util.List; - import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NameNotFoundException; import javax.naming.NamingException; -import junit.framework.TestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -public class TestNamingEntryUtil extends TestCase +public class TestNamingEntryUtil { public class MyNamingEntry extends NamingEntry { @@ -33,24 +38,25 @@ public class TestNamingEntryUtil extends TestCase } } - public class ScopeA extends Object + public class ScopeA { public String toString() { return this.getClass().getName()+"@"+super.hashCode(); } } - public void testGetNameForScope () - throws Exception + + @Test + public void testGetNameForScope () throws Exception { ScopeA scope = new ScopeA(); Name name = NamingEntryUtil.getNameForScope(scope); assertNotNull(name); assertEquals(scope.toString(), name.toString()); } - - public void testGetContextForScope() - throws Exception + + @Test + public void testGetContextForScope() throws Exception { ScopeA scope = new ScopeA(); try @@ -62,11 +68,11 @@ public class TestNamingEntryUtil extends TestCase { //expected } - + InitialContext ic = new InitialContext(); Context scopeContext = ic.createSubcontext(NamingEntryUtil.getNameForScope(scope)); assertNotNull(scopeContext); - + try { Context c = NamingEntryUtil.getContextForScope(scope); @@ -77,50 +83,49 @@ public class TestNamingEntryUtil extends TestCase fail(e.getMessage()); } } - - public void testMakeNamingEntryName () - throws Exception + + @Test + public void testMakeNamingEntryName() throws Exception { Name name = NamingEntryUtil.makeNamingEntryName(null, "fee/fi/fo/fum"); assertNotNull(name); assertEquals(NamingEntry.__contextName+"/fee/fi/fo/fum", name.toString()); } - - public void testLookupNamingEntry () - throws Exception + + @Test + public void testLookupNamingEntry() throws Exception { ScopeA scope = new ScopeA(); NamingEntry ne = NamingEntryUtil.lookupNamingEntry(scope, "foo"); assertNull(ne); - - MyNamingEntry mne = new MyNamingEntry(scope, "foo", new Integer(9)); - + + MyNamingEntry mne = new MyNamingEntry(scope, "foo", 9); + ne = NamingEntryUtil.lookupNamingEntry(scope, "foo"); assertNotNull(ne); assertEquals(ne, mne); } - - public void testLookupNamingEntries () - throws Exception + + @Test + public void testLookupNamingEntries() throws Exception { ScopeA scope = new ScopeA(); List list = NamingEntryUtil.lookupNamingEntries(scope, MyNamingEntry.class); assertTrue(list.isEmpty()); - - MyNamingEntry mne1 = new MyNamingEntry(scope, "a/b", new Integer(1)); - MyNamingEntry mne2 = new MyNamingEntry(scope, "a/c", new Integer(2)); - + + MyNamingEntry mne1 = new MyNamingEntry(scope, "a/b", 1); + MyNamingEntry mne2 = new MyNamingEntry(scope, "a/c", 2); + ScopeA scope2 = new ScopeA(); - MyNamingEntry mne3 = new MyNamingEntry(scope2, "a/b", new Integer(3)); - + MyNamingEntry mne3 = new MyNamingEntry(scope2, "a/b", 3); + list = NamingEntryUtil.lookupNamingEntries(scope, MyNamingEntry.class); assertEquals(2, list.size()); assertTrue (list.contains(mne1)); assertTrue (list.contains(mne2)); - + list = NamingEntryUtil.lookupNamingEntries(scope2, MyNamingEntry.class); assertEquals(1, list.size()); assertTrue(list.contains(mne3)); - } } diff --git a/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/TestConfiguration.java b/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/TestConfiguration.java index 663972a4b0..e96b69008d 100644 --- a/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/TestConfiguration.java +++ b/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/TestConfiguration.java @@ -4,30 +4,31 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.plus.webapp; import javax.naming.Context; import javax.naming.InitialContext; -import junit.framework.TestCase; - import org.eclipse.jetty.plus.jndi.EnvEntry; import org.eclipse.jetty.plus.jndi.NamingEntry; import org.eclipse.jetty.plus.jndi.NamingEntryUtil; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.webapp.WebAppClassLoader; import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.webapp.WebXmlProcessor; +import org.eclipse.jetty.webapp.MetaData; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; -public class TestConfiguration extends TestCase +public class TestConfiguration { - public class MyWebAppContext extends WebAppContext { public String toString() @@ -35,9 +36,9 @@ public class TestConfiguration extends TestCase return this.getClass().getName()+"@"+super.hashCode(); } } - - public void testIt () - throws Exception + + @Test + public void testIt () throws Exception { ClassLoader old_loader = Thread.currentThread().getContextClassLoader(); @@ -51,18 +52,18 @@ public class TestConfiguration extends TestCase wac.setServer(server); wac.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), wac)); - WebXmlProcessor processor = new WebXmlProcessor(wac); + MetaData metaData = new MetaData(wac); - PlusDescriptorProcessor plusProcessor = new PlusDescriptorProcessor(processor); + PlusDescriptorProcessor plusProcessor = new PlusDescriptorProcessor(); - //bind some EnvEntrys at the server level + //bind some EnvEntrys at the server level EnvEntry ee1 = new EnvEntry(server, "xxx/a", "100", true); EnvEntry ee2 = new EnvEntry(server, "yyy/b", "200", false); EnvEntry ee3 = new EnvEntry(server, "zzz/c", "300", false); EnvEntry ee4 = new EnvEntry(server, "zzz/d", "400", false); EnvEntry ee5 = new EnvEntry(server, "zzz/f", "500", true); - //bind some EnvEntrys at the webapp level + //bind some EnvEntrys at the webapp level EnvEntry ee6 = new EnvEntry(wac, "xxx/a", "900", true); EnvEntry ee7 = new EnvEntry(wac, "yyy/b", "910", true); EnvEntry ee8 = new EnvEntry(wac, "zzz/c", "920", false); @@ -74,11 +75,10 @@ public class TestConfiguration extends TestCase assertNotNull(NamingEntryUtil.lookupNamingEntry(server, "zzz/d")); assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "xxx/a")); assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "yyy/b")); - assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/c")); + assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/c")); assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/e")); - Configuration config = new Configuration(); - + //make a new env configuration EnvConfiguration envConfig = new EnvConfiguration(); diff --git a/jetty-policy/pom.xml b/jetty-policy/pom.xml index 50bd19706e..ffb3bd233d 100644 --- a/jetty-policy/pom.xml +++ b/jetty-policy/pom.xml @@ -42,7 +42,7 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> @@ -95,7 +95,7 @@ <goal>copy</goal> </goals> <configuration> - <artifactItems> + <artifactItems> <artifactItem> <groupId>org.eclipse.jetty.toolchain</groupId> <artifactId>jetty-test-policy</artifactId> @@ -103,23 +103,24 @@ <type>jar</type> <overWrite>true</overWrite> <includes>**</includes> - <outputDirectory>${jetty.test.policy.loc}</outputDirectory> + <outputDirectory>${jetty.test.policy.loc}</outputDirectory> <destFileName>jetty-test-policy.jar</destFileName> </artifactItem> </artifactItems> </configuration> </execution> - </executions> + </executions> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.policy.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> - <dependencies> + <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> @@ -128,6 +129,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/jetty-policy/src/main/config/etc/jetty-policy.xml b/jetty-policy/src/main/config/etc/jetty-policy.xml index 6d8848cc4b..2a9c393f34 100644 --- a/jetty-policy/src/main/config/etc/jetty-policy.xml +++ b/jetty-policy/src/main/config/etc/jetty-policy.xml @@ -11,12 +11,12 @@ <Configure id="Policy" class="org.eclipse.jetty.policy.JettyPolicyConfigurator"> <Call name="addPolicy"> - <Arg><SystemProperty name="jetty.home"/>/lib/policy/jetty.policy</Arg> + <Arg><Property name="jetty.home"/>/lib/policy/jetty.policy</Arg> </Call> <Call name="addProperty"> <Arg>jetty.home</Arg> - <Arg><SystemProperty name="jetty.home"/></Arg> + <Arg><Property name="jetty.home"/></Arg> </Call> <Call name="initialize"/> diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/PolicyFileScanner.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/PolicyFileScanner.java index 3b2a67be78..0322f4b956 100644 --- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/PolicyFileScanner.java +++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/PolicyFileScanner.java @@ -56,8 +56,8 @@ import org.eclipse.jetty.policy.entry.PrincipalEntry; * * </pre> * - * For semantical details of this format, see the {@link org.apache.harmony.security.DefaultPolicy default policy - * description}. <br> + * For semantical details of this format, see org.apache.harmony.security.DefaultPolicy javadoc. <br> + * * Keywords are case-insensitive in contrast to quoted string literals. Comma-separation rule is quite forgiving, most * commas may be just omitted. Whitespaces, line- and block comments are ignored. Symbol-level tokenization is delegated * to java.io.StreamTokenizer. <br> @@ -65,6 +65,7 @@ import org.eclipse.jetty.policy.entry.PrincipalEntry; * This implementation is effectively thread-safe, as it has no field references to data being processed (that is, * passes all the data as method parameters). * + * This implementation is a bit more strict in enforcing format then the default policy scanner as implemented in the sun jdk. */ public class PolicyFileScanner { diff --git a/jetty-policy/src/test/java/org/eclipse/jetty/policy/JettyPolicyRuntimeTest.java b/jetty-policy/src/test/java/org/eclipse/jetty/policy/JettyPolicyRuntimeTest.java index 17e91680fe..eb893e925c 100644 --- a/jetty-policy/src/test/java/org/eclipse/jetty/policy/JettyPolicyRuntimeTest.java +++ b/jetty-policy/src/test/java/org/eclipse/jetty/policy/JettyPolicyRuntimeTest.java @@ -1,17 +1,17 @@ -package org.eclipse.jetty.policy; //======================================================================== //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 +//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.opensource.org/licenses/apache2.0.php -//You may elect to redistribute this code under either of these licenses. +//You may elect to redistribute this code under either of these licenses. //======================================================================== +package org.eclipse.jetty.policy; import java.io.File; import java.lang.reflect.InvocationTargetException; @@ -24,65 +24,61 @@ import java.util.Collections; import java.util.HashMap; import java.util.Set; -import junit.framework.TestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class JettyPolicyRuntimeTest extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class JettyPolicyRuntimeTest { - HashMap<String, String> evaluator = new HashMap<String, String>(); - + private HashMap<String, String> evaluator = new HashMap<String, String>(); private boolean _runningOnWindows; - - - @Override - protected void setUp() throws Exception + + @Before + public void init() throws Exception { System.setSecurityManager(null); Policy.setPolicy(null); _runningOnWindows = System.getProperty( "os.name" ).startsWith( "Windows" ); - - super.setUp(); - + evaluator.put("jetty.home",MavenTestingUtils.getBaseURI().toASCIIString()); evaluator.put("basedir",MavenTestingUtils.getBaseURI().toASCIIString()); } - - @Override - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { - super.tearDown(); - - System.setSecurityManager( null ); - Policy.setPolicy( null ); + System.setSecurityManager(null); + Policy.setPolicy(null); } + @Test public void testSimplePolicyReplacement() throws Exception - { - - JettyPolicy ap = new JettyPolicy(getSinglePolicy("global-all-permission.policy"),evaluator); - + { + JettyPolicy ap = new JettyPolicy(getSinglePolicy("global-all-permission.policy"), evaluator); ap.refresh(); - - Policy.setPolicy( ap ); + + Policy.setPolicy( ap ); System.setSecurityManager( new SecurityManager() ); - + File test = new File( "/tmp" ); - - assertTrue ( test.canRead() ); - + + assertTrue( test.canRead() ); } - + + @Test public void testRepeatedPolicyReplacement() throws Exception - { + { JettyPolicy ap = new JettyPolicy(getSinglePolicy("global-all-permission.policy"),evaluator); - ap.refresh(); - + Policy.setPolicy( ap ); - System.setSecurityManager( new SecurityManager() ); - + // Test that the all permission policy allows us to do this try { @@ -95,11 +91,10 @@ public class JettyPolicyRuntimeTest extends TestCase ace.printStackTrace(System.err); fail("Should NOT have thrown an AccessControlException"); } - + JettyPolicy ap2 = new JettyPolicy(getSinglePolicy("global-file-read-only-tmp-permission.policy"),evaluator); - ap2.refresh(); - + Policy.setPolicy( ap2 ); // Test that the new policy does replace the old one and we are now not allowed @@ -114,9 +109,9 @@ public class JettyPolicyRuntimeTest extends TestCase { // Expected Path } - } + @Test public void testPolicyRestrictive() throws Exception { // TODO - temporary, create alternate file to load for windows @@ -127,20 +122,18 @@ public class JettyPolicyRuntimeTest extends TestCase } JettyPolicy ap = new JettyPolicy(getSinglePolicy("global-file-read-only-tmp-permission.policy"),evaluator); - ap.refresh(); - + Policy.setPolicy( ap ); - System.setSecurityManager( new SecurityManager() ); - + File test = new File( "/tmp" ); - + assertTrue ( test.canRead() ); - + File test2 = new File( "/tmp/foo" ); assertTrue ( test2.canRead() ); - + try { File test3 = new File("/tmp/foo/bar/do"); @@ -153,9 +146,9 @@ public class JettyPolicyRuntimeTest extends TestCase // Expected Path } } - - public void testCertificateLoader() - throws Exception + + @Test + public void testCertificateLoader() throws Exception { // TODO - temporary, create alternate file to load for windows if (_runningOnWindows) @@ -165,51 +158,47 @@ public class JettyPolicyRuntimeTest extends TestCase } JettyPolicy ap = new JettyPolicy(getSinglePolicy("jetty-certificate.policy"),evaluator); - ap.refresh(); - + Policy.setPolicy( ap ); - System.setSecurityManager( new SecurityManager() ); - + URL url = MavenTestingUtils.toTargetURL("test-policy/jetty-test-policy.jar"); - + URLClassLoader loader ; if (Thread.currentThread().getContextClassLoader() != null ) { - loader = new URLClassLoader( new URL[]{ url }, Thread.currentThread().getContextClassLoader() ); + loader = new URLClassLoader( new URL[]{ url }, Thread.currentThread().getContextClassLoader() ); } else { - loader = new URLClassLoader( new URL[]{ url }, ClassLoader.getSystemClassLoader() ); + loader = new URLClassLoader( new URL[]{ url }, ClassLoader.getSystemClassLoader() ); } - + Thread.currentThread().setContextClassLoader(loader); - + ap.refresh(); - + Class<?> clazz = loader.loadClass("org.eclipse.jetty.toolchain.test.policy.Tester"); Method m = clazz.getMethod("testEcho",new Class[] { String.class }); - String foo = (String)m.invoke(clazz.newInstance(),new Object[] - { "foo" }); + String foo = (String)m.invoke(clazz.newInstance(), "foo"); assertEquals("foo",foo); Method m2 = clazz.getMethod("testReadSystemProperty",new Class[] { String.class }); - m2.invoke(clazz.newInstance(),new Object[] - { "foo" }); + m2.invoke(clazz.newInstance(), "foo"); assertTrue("system property access was granted",true); // ap.dump(System.out); } - - + + @Test public void testBadCertificateLoader() throws Exception { @@ -221,43 +210,40 @@ public class JettyPolicyRuntimeTest extends TestCase } JettyPolicy ap = new JettyPolicy(getSinglePolicy("jetty-bad-certificate.policy"),evaluator); - ap.refresh(); - + Policy.setPolicy( ap ); - System.setSecurityManager( new SecurityManager() ); - + URL url = MavenTestingUtils.toTargetURL("test-policy/jetty-test-policy.jar"); - + URLClassLoader loader ; if (Thread.currentThread().getContextClassLoader() != null ) { - loader = new URLClassLoader( new URL[]{ url }, Thread.currentThread().getContextClassLoader() ); + loader = new URLClassLoader( new URL[]{ url }, Thread.currentThread().getContextClassLoader() ); } else { - loader = new URLClassLoader( new URL[]{ url }, ClassLoader.getSystemClassLoader() ); + loader = new URLClassLoader( new URL[]{ url }, ClassLoader.getSystemClassLoader() ); } - + Thread.currentThread().setContextClassLoader(loader); - + ap.refresh(); - + try { Class<?> clazz = loader.loadClass("org.eclipse.jetty.toolchain.test.policy.Tester"); - + Method m = clazz.getMethod( "testEcho", new Class[] {String.class} ); - - String foo = (String)m.invoke( clazz.newInstance(), new Object[] {"foo"} ); - + + String foo = (String)m.invoke( clazz.newInstance(), "foo"); + assertEquals("foo", foo ); - + Method m2 = clazz.getMethod( "testReadSystemProperty", new Class[] {String.class} ); - - m2.invoke(clazz.newInstance(),new Object[] - { "foobar" }); + + m2.invoke(clazz.newInstance(), "foobar"); fail("Should have thrown an InvocationTargetException"); } diff --git a/jetty-policy/src/test/java/org/eclipse/jetty/policy/JettyPolicyTest.java b/jetty-policy/src/test/java/org/eclipse/jetty/policy/JettyPolicyTest.java index 182e09d36c..f5be38d151 100644 --- a/jetty-policy/src/test/java/org/eclipse/jetty/policy/JettyPolicyTest.java +++ b/jetty-policy/src/test/java/org/eclipse/jetty/policy/JettyPolicyTest.java @@ -1,4 +1,3 @@ -package org.eclipse.jetty.policy; //======================================================================== //Copyright (c) Webtide LLC //------------------------------------------------------------------------ @@ -15,6 +14,8 @@ package org.eclipse.jetty.policy; //You may elect to redistribute this code under either of these licenses. //======================================================================== +package org.eclipse.jetty.policy; + import java.io.FilePermission; import java.net.URL; import java.security.CodeSource; @@ -28,98 +29,92 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Set; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; -public class JettyPolicyTest extends TestCase +public class JettyPolicyTest { - HashMap<String, String> evaluator = new HashMap<String, String>(); - + private HashMap<String, String> evaluator = new HashMap<String, String>(); - @Override - protected void setUp() - throws Exception + @Before + public void setUp() throws Exception { - super.setUp(); - evaluator.put("jetty.home",MavenTestingUtils.getBaseURI().toASCIIString()); evaluator.put("basedir",MavenTestingUtils.getBaseURI().toASCIIString()); } - public void testGlobalAllPermissionLoader() - throws Exception + @Test + public void testGlobalAllPermissionLoader() throws Exception { - - JettyPolicy ap = - new JettyPolicy( Collections.singleton( MavenTestingUtils.getBasedir().getAbsolutePath() + "/src/test/resources/global-all-permission.policy" ), evaluator ); + JettyPolicy ap = new JettyPolicy( Collections.singleton( MavenTestingUtils.getBasedir().getAbsolutePath() + "/src/test/resources/global-all-permission.policy" ), evaluator ); ap.refresh(); - PermissionCollection pc = ap.getPermissions( new ProtectionDomain( null, null ) ); - + assertNotNull( pc ); - + Permission testPerm = new FilePermission( "/tmp", "read" ); - + assertTrue( pc.implies( testPerm ) ); - - for ( Enumeration<Permission> e = pc.elements(); e.hasMoreElements(); ) + + for ( Enumeration<Permission> e = pc.elements(); e.hasMoreElements(); ) { System.out.println( "Permission: " + e.nextElement().getClass().getName() ); } - } - public void testSingleCodebaseFilePermissionLoader() - throws Exception + @Test + public void testSingleCodebaseFilePermissionLoader() throws Exception { JettyPolicy ap = new JettyPolicy( Collections.singleton( MavenTestingUtils.getBasedir().getAbsolutePath() + "/src/test/resources/single-codebase-file-permission.policy" ), evaluator ); - ap.refresh(); - - URL url = new URL( "file:///foo.jar" ); + + URL url = new URL( "file:///foo.jar" ); CodeSource cs = new CodeSource( url, new Certificate[0]); - + PermissionCollection pc = ap.getPermissions( cs ); - + assertNotNull( pc ); - + Permission testPerm = new FilePermission( "/tmp/*", "read" ); - + assertTrue( pc.implies( testPerm ) ); - } - public void testMultipleCodebaseFilePermissionLoader() - throws Exception + @Test + public void testMultipleCodebaseFilePermissionLoader() throws Exception { JettyPolicy ap = new JettyPolicy( Collections.singleton( MavenTestingUtils.getBasedir().getAbsolutePath() + "/src/test/resources/multiple-codebase-file-permission.policy" ), evaluator ); ap.refresh(); - + // ap.dump(System.out); - URL url = new URL( "file:///bar.jar" ); + URL url = new URL( "file:///bar.jar" ); CodeSource cs = new CodeSource( url, new Certificate[0]); - + PermissionCollection pc = ap.getPermissions( cs ); - + assertNotNull( pc ); - + Permission testPerm = new FilePermission( "/tmp/*", "read,write" ); Permission testPerm2 = new FilePermission( "/usr/*", "write" ); // only read was granted - + assertTrue( pc.implies( testPerm ) ); assertFalse( pc.implies( testPerm2 ) ); - } - public void testMultipleCodebaseMixedPermissionLoader() - throws Exception + @Test + public void testMultipleCodebaseMixedPermissionLoader() throws Exception { JettyPolicy ap = new JettyPolicy( Collections.singleton( MavenTestingUtils.getBasedir().getAbsolutePath() @@ -129,7 +124,8 @@ public class JettyPolicyTest extends TestCase // ap.dump(System.out); } - + + @Test public void testSCLoader() throws Exception { JettyPolicy ap = new JettyPolicy(Collections.singleton(MavenTestingUtils.getBasedir().getAbsolutePath() + "/src/main/config/lib/policy/jetty.policy"),evaluator); @@ -138,30 +134,29 @@ public class JettyPolicyTest extends TestCase ap.dump(System.out); } - public void testMultipleFilePermissionLoader() - throws Exception + @Test + public void testMultipleFilePermissionLoader() throws Exception { Set<String> files = new HashSet<String>(); - + files.add( MavenTestingUtils.getBasedir().getAbsolutePath() + "/src/test/resources/single-codebase-file-permission.policy" ); files.add( MavenTestingUtils.getBasedir().getAbsolutePath() + "/src/test/resources/single-codebase-file-permission-2.policy" ); - + JettyPolicy ap = new JettyPolicy( files, evaluator ); ap.refresh(); - - URL url = new URL( "file:///bar.jar" ); + + URL url = new URL( "file:///bar.jar" ); CodeSource cs = new CodeSource( url, new Certificate[0]); - + PermissionCollection pc = ap.getPermissions( cs ); - + assertNotNull( pc ); - + Permission testPerm = new FilePermission( "/tmp/*", "read" ); - Permission testPerm2 = new FilePermission( "/usr/*", "write" ); // - + Permission testPerm2 = new FilePermission( "/usr/*", "write" ); // + assertTrue( pc.implies( testPerm ) ); assertFalse( pc.implies( testPerm2 ) ); } - } diff --git a/jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyContextTest.java b/jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyContextTest.java index 4e8ad3e291..fdcf2b12ab 100644 --- a/jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyContextTest.java +++ b/jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyContextTest.java @@ -1,4 +1,3 @@ -package org.eclipse.jetty.policy; //======================================================================== //Copyright (c) Webtide LLC //------------------------------------------------------------------------ @@ -15,120 +14,110 @@ package org.eclipse.jetty.policy; //You may elect to redistribute this code under either of these licenses. //======================================================================== +package org.eclipse.jetty.policy; + import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.security.Permission; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import junit.framework.TestCase; - import org.eclipse.jetty.policy.entry.GrantEntry; import org.eclipse.jetty.policy.entry.KeystoreEntry; import org.eclipse.jetty.policy.loader.PolicyFileScanner; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; public class PolicyContextTest - extends TestCase { public static final String __PRINCIPAL = "javax.security.auth.x500.X500Principal \"CN=Jetty Policy,OU=Artifact,O=Jetty Project,L=Earth,ST=Internet,C=US\""; - private boolean _runningOnWindows; - - - @Override - protected void setUp() - throws Exception + + @Before + public void init() throws Exception { _runningOnWindows = System.getProperty( "os.name" ).startsWith( "Windows" ); - System.setProperty( "basedir", MavenTestingUtils.getBaseURI().toASCIIString() ); - - super.setUp(); } + @Test public void testSelfPropertyExpansion() throws Exception { - - PolicyContext context = new PolicyContext(); - PolicyFileScanner loader = new PolicyFileScanner(); + PolicyContext context = new PolicyContext(); + PolicyFileScanner loader = new PolicyFileScanner(); List<GrantEntry> grantEntries = new ArrayList<GrantEntry>(); List<KeystoreEntry> keystoreEntries = new ArrayList<KeystoreEntry>(); - - File policyFile = new File( getWorkingDirectory() + "/src/test/resources/context/jetty-certificate.policy" ); - + + File policyFile = new File( getWorkingDirectory() + "/src/test/resources/context/jetty-certificate.policy" ); + loader.scanStream( new InputStreamReader( new FileInputStream( policyFile ) ), grantEntries, keystoreEntries ); - + if ( !_runningOnWindows ) //temporary, create alternate file to load for windows { - - for ( Iterator<KeystoreEntry> i = keystoreEntries.iterator(); i.hasNext();) - { - KeystoreEntry node = i.next(); - node.expand( context ); - - context.setKeystore( node.toKeyStore() ); - } - - GrantEntry grant = grantEntries.get( 0 ); - grant.expand( context ); - - Permission perm = grant.getPermissions().elements().nextElement(); - - - assertEquals( __PRINCIPAL, perm.getName() ); + for (KeystoreEntry node : keystoreEntries) + { + node.expand(context); + + context.setKeystore(node.toKeyStore()); + } + + GrantEntry grant = grantEntries.get( 0 ); + grant.expand( context ); + + Permission perm = grant.getPermissions().elements().nextElement(); + + assertEquals( __PRINCIPAL, perm.getName() ); } } - + + @Test public void testAliasPropertyExpansion() throws Exception { - - PolicyContext context = new PolicyContext(); - PolicyFileScanner loader = new PolicyFileScanner(); + PolicyContext context = new PolicyContext(); + PolicyFileScanner loader = new PolicyFileScanner(); List<GrantEntry> grantEntries = new ArrayList<GrantEntry>(); List<KeystoreEntry> keystoreEntries = new ArrayList<KeystoreEntry>(); - - File policyFile = new File( getWorkingDirectory() + "/src/test/resources/context/jetty-certificate-alias.policy" ); - + + File policyFile = new File( getWorkingDirectory() + "/src/test/resources/context/jetty-certificate-alias.policy" ); + loader.scanStream( new InputStreamReader( new FileInputStream( policyFile ) ), grantEntries, keystoreEntries ); - + if ( !_runningOnWindows ) //temporary, create alternate file to load for windows { - - for ( Iterator<KeystoreEntry> i = keystoreEntries.iterator(); i.hasNext();) - { - KeystoreEntry node = i.next(); - node.expand( context ); - - context.setKeystore( node.toKeyStore() ); - } - - GrantEntry grant = grantEntries.get( 0 ); - grant.expand( context ); - - Permission perm = grant.getPermissions().elements().nextElement(); - - assertEquals( __PRINCIPAL, perm.getName() ); + for (KeystoreEntry node : keystoreEntries) + { + node.expand(context); + + context.setKeystore(node.toKeyStore()); + } + + GrantEntry grant = grantEntries.get( 0 ); + grant.expand( context ); + + Permission perm = grant.getPermissions().elements().nextElement(); + + assertEquals( __PRINCIPAL, perm.getName() ); } } - + + @Test public void testFileSeparatorExpansion() throws Exception { - PolicyContext context = new PolicyContext(); + PolicyContext context = new PolicyContext(); context.addProperty( "foo", "bar" ); - + assertEquals(File.separator, context.evaluate( "${/}" ) ); assertEquals(File.separator + "bar" + File.separator, context.evaluate( "${/}${foo}${/}" ) ); - assertEquals(File.separator + File.separator, context.evaluate( "${/}${/}" ) ); } - + private String getWorkingDirectory() { return MavenTestingUtils.getBasedir().getAbsolutePath(); } - } diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index b52c851fd1..adb0b0b2b9 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -55,11 +55,12 @@ </execution> </executions> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.rewrite.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> @@ -67,6 +68,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.java index b0fbbcaf76..cd2bfb4042 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.java @@ -72,7 +72,7 @@ public class HeaderPatternRule extends PatternRule * the new value overwrites the previous one. Otherwise, it adds the new * header name and value. * - *@see org.eclipse.jetty.server.server.rewrite.handler.Rule#matchAndApply(String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + *@see org.eclipse.jetty.rewrite.handler.Rule#matchAndApply(String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ public String apply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException { diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java index 57d1572a5d..5723fb7ca4 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java @@ -26,35 +26,32 @@ import org.eclipse.jetty.server.handler.HandlerWrapper; /* ------------------------------------------------------------ */ /** *<p> Rewrite handler is responsible for managing the rules. Its capabilities - * is not only limited for url rewrites such as RewritePatternRule or RewriteRegexRule. + * is not only limited for URL rewrites such as RewritePatternRule or RewriteRegexRule. * There is also handling for cookies, headers, redirection, setting status or error codes * whenever the rule finds a match. * - * <p> The rules can be matched by the ff. options: pattern matching of PathMap - * (class PatternRule), regular expressions (class RegexRule) or certain conditions set - * (e.g. MsieSslRule - the requests must be in SSL mode). + * <p> The rules can be matched by the either: pattern matching of PathMap + * (eg {@link PatternRule}), regular expressions (eg {@link RegexRule}) or certain conditions set + * (eg {@link MsieSslRule} - the requests must be in SSL mode). * - * Here are the list of rules: - * <ul> - * <li> CookiePatternRule - adds a new cookie in response. </li> - * <li> HeaderPatternRule - adds/modifies the HTTP headers in response. </li> - * <li> RedirectPatternRule - sets the redirect location. </li> - * <li> ResponsePatternRule - sets the status/error codes. </li> - * <li> RewritePatternRule - rewrites the requested URI. </li> - * <li> RewriteRegexRule - rewrites the requested URI using regular expression for pattern matching. </li> - * <li> MsieSslRule - disables the keep alive on SSL for IE5 and IE6. </li> - * <li> LegacyRule - the old version of rewrite. </li> - * <li> ForwardedSchemeHeaderRule - set the scheme according to the headers present. </li> - * </ul> - * - * <p> The rules can be grouped into rule containers (class RuleContainerRule), and will only + * <p> The rules can be grouped into rule containers (class {@link RuleContainer}), and will only * be applied if the request matches the conditions for their container * (e.g., by virtual host name) - * - * Here are a list of rule containers: + * + * <p>The list of predefined rules is: * <ul> - * <li> VirtualHostRuleContainerRule - checks whether the request matches one of a set of virtual host names.</li> + * <li> {@link CookiePatternRule} - adds a new cookie in response. </li> + * <li> {@link HeaderPatternRule} - adds/modifies the HTTP headers in response. </li> + * <li> {@link RedirectPatternRule} - sets the redirect location. </li> + * <li> {@link ResponsePatternRule} - sets the status/error codes. </li> + * <li> {@link RewritePatternRule} - rewrites the requested URI. </li> + * <li> {@link RewriteRegexRule} - rewrites the requested URI using regular expression for pattern matching. </li> + * <li> {@link MsieSslRule} - disables the keep alive on SSL for IE5 and IE6. </li> + * <li> {@link LegacyRule} - the old version of rewrite. </li> + * <li> {@link ForwardedSchemeHeaderRule} - set the scheme according to the headers present. </li> + * <li> {@link VirtualHostRuleContainer} - checks whether the request matches one of a set of virtual host names.</li> * </ul> + * * * Here is a typical jetty.xml configuration would be: <pre> * @@ -283,7 +280,7 @@ public class RewriteHandler extends HandlerWrapper /* ------------------------------------------------------------ */ /** - * @param originalPathAttribte If non null, this string will be used + * @param originalPathAttribute If non null, this string will be used * as the attribute name to store the original request path. */ public void setOriginalPathAttribute(String originalPathAttribute) diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainer.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainer.java index eabb07837e..8b3c023be3 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainer.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainer.java @@ -52,7 +52,7 @@ public class VirtualHostRuleContainer extends RuleContainer /* ------------------------------------------------------------ */ /** Get the virtual hosts that the rules within this container will apply to - * @param virtualHosts Array of virtual hosts that the rules within this container are applied to. + * @return Array of virtual hosts that the rules within this container are applied to. * A null hostname or null/empty array means any hostname is acceptable. */ public String[] getVirtualHosts() diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/AbstractRuleTestCase.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/AbstractRuleTestCase.java index b2b818d95e..7907fb04ab 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/AbstractRuleTestCase.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/AbstractRuleTestCase.java @@ -4,16 +4,14 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; -import junit.framework.TestCase; - import org.eclipse.jetty.io.bio.StringEndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConnection; @@ -21,56 +19,51 @@ import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Server; +import org.junit.After; -public abstract class AbstractRuleTestCase extends TestCase +public abstract class AbstractRuleTestCase { - protected Server _server=new Server(); + protected Server _server = new Server(); protected LocalConnector _connector; - protected StringEndPoint _endpoint=new StringEndPoint(); + protected StringEndPoint _endpoint = new StringEndPoint(); protected HttpConnection _connection; - protected Request _request; protected Response _response; - protected boolean _isSecure = false; - - public void setUp() throws Exception - { - start(); - } - - public void tearDown() throws Exception + + @After + public void stopServer() throws Exception { stop(); } - - public void start() throws Exception + + protected void start(final boolean isSecure) throws Exception { - _connector = new LocalConnector() { + _connector = new LocalConnector() + { public boolean isConfidential(Request request) { - return _isSecure; + return isSecure; } }; - _server.setConnectors(new Connector[]{_connector}); _server.start(); reset(); } - - public void stop() throws Exception + + protected void stop() throws Exception { _server.stop(); + _server.join(); _request = null; _response = null; } - - public void reset() + + protected void reset() { - _connection = new HttpConnection(_connector,_endpoint,_server); + _connection = new HttpConnection(_connector, _endpoint, _server); _request = new Request(_connection); _response = new Response(_connection); - _request.setRequestURI("/test/"); } } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/CookiePatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/CookiePatternRuleTest.java index 4eed73b6ac..a423b29ee9 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/CookiePatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/CookiePatternRuleTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; @@ -17,24 +17,29 @@ import java.util.Enumeration; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeaders; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; public class CookiePatternRuleTest extends AbstractRuleTestCase -{ - public void setUp() throws Exception +{ + @Before + public void init() throws Exception { - super.setUp(); + start(false); } - + + @Test public void testSingleCookie() throws IOException { String[][] cookie = { {"cookie", "value"} }; - assertCookies(cookie); } - + + @Test public void testMultipleCookies() throws IOException { String[][] cookies = { @@ -42,16 +47,13 @@ public class CookiePatternRuleTest extends AbstractRuleTestCase {"name", "wolfgangpuck"}, {"age", "28"} }; - assertCookies(cookies); } - + private void assertCookies(String[][] cookies) throws IOException { - for (int i = 0; i < cookies.length; i++) + for (String[] cookie : cookies) { - String[] cookie = cookies[i]; - // set cookie pattern CookiePatternRule rule = new CookiePatternRule(); rule.setPattern("*"); @@ -62,7 +64,7 @@ public class CookiePatternRuleTest extends AbstractRuleTestCase // apply cookie pattern rule.apply(_request.getRequestURI(), _request, _response); - + // verify HttpFields httpFields = _response.getHttpFields(); Enumeration e = httpFields.getValues(HttpHeaders.SET_COOKIE_BUFFER); @@ -72,7 +74,7 @@ public class CookiePatternRuleTest extends AbstractRuleTestCase String[] result = ((String)e.nextElement()).split("="); assertEquals(cookies[index][0], result[0]); assertEquals(cookies[index][1], result[1]); - + // +1 cookies index index++; } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java index 97bd9175a6..49623b27a9 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java @@ -4,84 +4,84 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import org.eclipse.jetty.http.HttpFields; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; public class ForwardedSchemeHeaderRuleTest extends AbstractRuleTestCase { private ForwardedSchemeHeaderRule _rule; private HttpFields _requestHeaderFields; - public void setUp() throws Exception + @Before + public void init() throws Exception { - super.setUp(); + start(false); _rule = new ForwardedSchemeHeaderRule(); _requestHeaderFields = _connection.getRequestFields(); _request.setScheme(null); } - + + @Test public void testDefaultScheme() throws Exception { setRequestHeader("X-Forwarded-Scheme", "https"); _rule.setHeader("X-Forwarded-Scheme"); _rule.setHeaderValue("https"); - _rule.matchAndApply("/", _request, _response); assertEquals("https", _request.getScheme()); } + @Test public void testScheme() throws Exception { setRequestHeader("X-Forwarded-Scheme", "https"); _rule.setHeader("X-Forwarded-Scheme"); _rule.setHeaderValue("https"); _rule.setScheme("https"); - _rule.matchAndApply("/", _request, _response); assertEquals("https", _request.getScheme()); - - + _rule.setScheme("http"); _rule.matchAndApply("/", _request, _response); assertEquals("http", _request.getScheme()); } - + + @Test public void testHeaderValue() throws Exception { setRequestHeader("Front-End-Https", "on"); _rule.setHeader("Front-End-Https"); _rule.setHeaderValue("on"); _rule.setScheme("https"); - _rule.matchAndApply("/",_request,_response); assertEquals("https",_request.getScheme()); + _request.setScheme(null); - - // header value doesn't match rule's value setRequestHeader("Front-End-Https", "off"); - _rule.matchAndApply("/",_request,_response); assertEquals(null,_request.getScheme()); - _request.setScheme(null); - + _request.setScheme(null); // header value can be any value setRequestHeader("Front-End-Https", "any"); _rule.setHeaderValue(null); - _rule.matchAndApply("/",_request,_response); assertEquals("https",_request.getScheme()); } - + private void setRequestHeader(String header, String headerValue) { _requestHeaderFields.put(header, headerValue); diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java index 2c19ec404d..6559d03c69 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java @@ -4,59 +4,64 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import java.io.IOException; import java.util.Iterator; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; public class HeaderPatternRuleTest extends AbstractRuleTestCase { private HeaderPatternRule _rule; - - public void setUp() throws Exception - { - super.setUp(); + @Before + public void init() throws Exception + { + start(false); _rule = new HeaderPatternRule(); _rule.setPattern("*"); } + @Test public void testHeaderWithTextValues() throws IOException { // different keys - String headers[][] = { - { "hnum#1", "test1" }, + String headers[][] = { + { "hnum#1", "test1" }, { "hnum#2", "2test2" }, - { "hnum#3", "test3" } + { "hnum#3", "test3" } }; - assertHeaders(headers); } + @Test public void testHeaderWithNumberValues() throws IOException { - String headers[][] = { - { "hello", "1" }, + String headers[][] = { + { "hello", "1" }, { "hello", "-1" }, { "hello", "100" }, { "hello", "100" }, { "hello", "100" }, { "hello", "100" }, { "hello", "100" }, - + { "hello1", "200" } }; - assertHeaders(headers); } - + + @Test public void testHeaderOverwriteValues() throws IOException { String headers[][] = { @@ -73,9 +78,8 @@ public class HeaderPatternRuleTest extends AbstractRuleTestCase { "title1", "abba" }, { "title1", "abba1" } }; - assertHeaders(headers); - + Iterator<String> e = _response.getHeaders("size").iterator(); int count = 0; while (e.hasNext()) @@ -83,7 +87,7 @@ public class HeaderPatternRuleTest extends AbstractRuleTestCase e.next(); count++; } - + assertEquals(1, count); assertEquals("500", _response.getHeader("size")); assertEquals("cba", _response.getHeader("title")); @@ -92,14 +96,14 @@ public class HeaderPatternRuleTest extends AbstractRuleTestCase private void assertHeaders(String headers[][]) throws IOException { - for (int i = 0; i < headers.length; i++) + for (String[] header : headers) { - _rule.setName(headers[i][0]); - _rule.setValue(headers[i][1]); + _rule.setName(header[0]); + _rule.setValue(header[1]); _rule.apply(null, _request, _response); - assertEquals(headers[i][1], _response.getHeader(headers[i][0])); + assertEquals(header[1], _response.getHeader(header[0])); } } } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/LegacyRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/LegacyRuleTest.java index 314fa08e08..00a550757b 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/LegacyRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/LegacyRuleTest.java @@ -4,59 +4,58 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; public class LegacyRuleTest extends AbstractRuleTestCase { - private LegacyRule _rule; - - String[][] _tests= + private String[][] _tests= { {"/foo/bar","/*","/replace/foo/bar"}, {"/foo/bar","/foo/*","/replace/bar"}, {"/foo/bar","/foo/bar","/replace"} }; - - public void setUp() throws Exception + private LegacyRule _rule; + + @Before + public void init() throws Exception { - super.setUp(); + start(false); _rule = new LegacyRule(); } - - public void tearDown() + + @After + public void destroy() { _rule = null; } - + + @Test public void testMatchAndApply() throws Exception { - for (int i=0;i<_tests.length;i++) + for (String[] _test : _tests) { - _rule.addRewriteRule(_tests[i][1], "/replace"); - - String result = _rule.matchAndApply(_tests[i][0], _request, _response); - - assertEquals(_tests[i][1], _tests[i][2], result); + _rule.addRewriteRule(_test[1], "/replace"); + String result = _rule.matchAndApply(_test[0], _request, _response); + assertEquals(_test[1], _test[2], result); } } - + + @Test(expected = IllegalArgumentException.class) public void testAddRewrite() { - try - { - _rule.addRewriteRule("*.txt", "/replace"); - fail(); - } - catch (IllegalArgumentException e) - { - } + _rule.addRewriteRule("*.txt", "/replace"); } } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/MsieSslRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/MsieSslRuleTest.java index fab8cc28e0..9bc3444995 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/MsieSslRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/MsieSslRuleTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; @@ -16,206 +16,220 @@ package org.eclipse.jetty.rewrite.handler; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeaderValues; import org.eclipse.jetty.http.HttpHeaders; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; public class MsieSslRuleTest extends AbstractRuleTestCase -{ +{ private MsieSslRule _rule; - - public void setUp() throws Exception + + @Before + public void init() throws Exception { - // enable SSL - _isSecure = true; - - super.setUp(); + // enable SSL + start(true); _rule = new MsieSslRule(); } - + + @Test public void testWin2kWithIE5() throws Exception { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); - - + + fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"); result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); assertEquals(_request.getRequestURI(), result); - assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION));; - + assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); + fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"); result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); assertEquals(_request.getRequestURI(), result); - assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION));; + assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWin2kWithIE6() throws Exception - { + { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWin2kWithIE7() throws Exception - { + { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.0)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(null, result); assertEquals(null, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWin2kSP1WithIE5() throws Exception { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.01)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); - + fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.01)"); result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); - + fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.01)"); result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWin2kSP1WithIE6() throws Exception - { + { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.01)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWin2kSP1WithIE7() throws Exception - { + { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.01)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(null, result); assertEquals(null, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWinXpWithIE5() throws Exception { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); - + fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.1)"); result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); - + fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.1)"); result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWinXpWithIE6() throws Exception { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(null, result); assertEquals(null, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWinXpWithIE7() throws Exception { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(null, result); assertEquals(null, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWinVistaWithIE5() throws Exception { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 6.0)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); - + fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 6.0)"); result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); - + fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 6.0)"); result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); assertEquals(_request.getRequestURI(), result); assertEquals(HttpHeaderValues.CLOSE, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWinVistaWithIE6() throws Exception { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 6.0)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(null, result); assertEquals(null, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWinVistaWithIE7() throws Exception { HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(null, result); assertEquals(null, _response.getHeader(HttpHeaders.CONNECTION)); } - + + @Test public void testWithoutSsl() throws Exception { // disable SSL - _isSecure = false; super.stop(); - super.start(); - + super.start(false); + HttpFields fields = _connection.getRequestFields(); fields.add("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0)"); - + String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response); - + assertEquals(null, result); assertEquals(null, _response.getHeader(HttpHeaders.CONNECTION)); } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java index fa6baebeb5..80dbff2316 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java @@ -4,49 +4,54 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import java.io.IOException; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.Request; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class PatternRuleTest extends TestCase +import static org.junit.Assert.assertEquals; + +public class PatternRuleTest { private PatternRule _rule; - public void setUp() + @Before + public void init() { _rule = new TestPatternRule(); } - - public void tearDown() + + @After + public void destroy() { _rule = null; } - + + @Test public void testTrueMatch() throws IOException { String[][] matchCases = { // index 0 - pattern // index 1 - URI to match - + {"/abc", "/abc"}, {"/abc/", "/abc/"}, - + {"/abc/path/longer", "/abc/path/longer"}, {"/abc/path/longer/", "/abc/path/longer/"}, - + {"/abc/*", "/abc/hello.jsp"}, {"/abc/*", "/abc/a"}, {"/abc/*", "/abc/a/hello.jsp"}, @@ -54,70 +59,69 @@ public class PatternRuleTest extends TestCase {"/abc/*", "/abc/a/b/hello.jsp"}, {"/abc/*", "/abc/a/b/c"}, {"/abc/*", "/abc/a/b/c/hello.jsp"}, - + {"/abc/def/*", "/abc/def/gf"}, {"/abc/def/*", "/abc/def/gf.html"}, {"/abc/def/*", "/abc/def/ghi"}, {"/abc/def/*", "/abc/def/ghi/"}, {"/abc/def/*", "/abc/def/ghi/hello.html"}, - + {"*.do", "/abc.do"}, {"*.do", "/abc/hello.do"}, {"*.do", "/abc/def/hello.do"}, {"*.do", "/abc/def/ghi/hello.do"}, - + {"*.jsp", "/abc.jsp"}, {"*.jsp", "/abc/hello.jsp"}, {"*.jsp", "/abc/def/hello.jsp"}, {"*.jsp", "/abc/def/ghi/hello.jsp"}, - + {"/", "/Other"}, {"/", "/Other/hello.do"}, {"/", "/Other/path"}, {"/", "/Other/path/hello.do"}, {"/", "/abc/def"}, - + {"/abc:/def", "/abc:/def"} }; - - for (int i = 0; i < matchCases.length; i++) + + for (String[] matchCase : matchCases) { - String[] matchCase = matchCases[i]; assertMatch(true, matchCase); } } - + + @Test public void testFalseMatch() throws IOException { String[][] matchCases = { - + {"/abc", "/abcd"}, {"/abc/", "/abcd/"}, - + {"/abc/path/longer", "/abc/path/longer/"}, {"/abc/path/longer", "/abc/path/longer1"}, {"/abc/path/longer/", "/abc/path/longer"}, {"/abc/path/longer/", "/abc/path/longer1/"}, - + {"/*.jsp", "/hello.jsp"}, {"/abc/*.jsp", "/abc/hello.jsp"}, - + {"*.jsp", "/hello.1jsp"}, {"*.jsp", "/hello.jsp1"}, {"*.jsp", "/hello.do"}, - + {"*.jsp", "/abc/hello.do"}, {"*.jsp", "/abc/def/hello.do"}, {"*.jsp", "/abc.do"} }; - - for (int i = 0; i < matchCases.length; i++) + + for (String[] matchCase : matchCases) { - String[] matchCase = matchCases[i]; assertMatch(false, matchCase); } } - + private void assertMatch(boolean flag, String[] matchCase) throws IOException { _rule.setPattern(matchCase[0]); @@ -130,11 +134,10 @@ public class PatternRuleTest extends TestCase } }, null ); - + assertEquals("pattern: " + matchCase[0] + " uri: " + matchCase[1], flag, result!=null); } - - + private class TestPatternRule extends PatternRule { @Override @@ -143,6 +146,6 @@ public class PatternRuleTest extends TestCase { return target; } - + } } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRuleTest.java index 5512fd8d28..7cfa9e5bb8 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRuleTest.java @@ -4,43 +4,47 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import java.io.IOException; import org.eclipse.jetty.http.HttpHeaders; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; public class RedirectPatternRuleTest extends AbstractRuleTestCase { private RedirectPatternRule _rule; - - public void setUp() throws Exception + + @Before + public void init() throws Exception { - super.setUp(); + start(false); _rule = new RedirectPatternRule(); _rule.setPattern("*"); } - - public void tearDown() + + @After + public void destroy() { _rule = null; } - + + @Test public void testLocation() throws IOException { String location = "http://eclipse.com"; - _rule.setLocation(location); _rule.apply(null, _request, _response); - assertEquals(location, _response.getHeader(HttpHeaders.LOCATION)); } - } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRuleTest.java index b19fa4687e..43f9a1babc 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRuleTest.java @@ -5,13 +5,13 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; @@ -19,22 +19,30 @@ package org.eclipse.jetty.rewrite.handler; import java.io.IOException; import org.eclipse.jetty.http.HttpHeaders; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; public class RedirectRegexRuleTest extends AbstractRuleTestCase { private RedirectRegexRule _rule; - - public void setUp() throws Exception + + @Before + public void init() throws Exception { - super.setUp(); + start(false); _rule = new RedirectRegexRule(); } - - public void tearDown() + + @After + public void destroy() { _rule = null; } - + + @Test public void testLocationWithReplacementGroupEmpty() throws IOException { _rule.setRegex("/my/dir/file/(.*)$"); @@ -44,7 +52,8 @@ public class RedirectRegexRuleTest extends AbstractRuleTestCase _rule.matchAndApply("/my/dir/file/", _request, _response); assertEquals("http://www.mortbay.org/", _response.getHeader(HttpHeaders.LOCATION)); } - + + @Test public void testLocationWithReplacmentGroupSimple() throws IOException { _rule.setRegex("/my/dir/file/(.*)$"); @@ -54,7 +63,8 @@ public class RedirectRegexRuleTest extends AbstractRuleTestCase _rule.matchAndApply("/my/dir/file/image.png", _request, _response); assertEquals("http://www.mortbay.org/image.png", _response.getHeader(HttpHeaders.LOCATION)); } - + + @Test public void testLocationWithReplacementGroupDeepWithParams() throws IOException { _rule.setRegex("/my/dir/file/(.*)$"); @@ -64,5 +74,4 @@ public class RedirectRegexRuleTest extends AbstractRuleTestCase _rule.matchAndApply("/my/dir/file/api/rest/foo?id=100&sort=date", _request, _response); assertEquals("http://www.mortbay.org/api/rest/foo?id=100&sort=date", _response.getHeader(HttpHeaders.LOCATION)); } - } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RegexRuleTest.java index ef5d20025f..55f1ac4d80 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RegexRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RegexRuleTest.java @@ -4,85 +4,88 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import java.io.IOException; import java.util.regex.Matcher; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.Request; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class RegexRuleTest extends TestCase +import static org.junit.Assert.assertEquals; + +public class RegexRuleTest { private RegexRule _rule; - - public void setUp() + + @Before + public void init() { _rule = new TestRegexRule(); - } - - public void tearDown() + + @After + public void destroy() { _rule = null; } - + + @Test public void testTrueMatch() throws IOException { String[][] matchCases = { // regex: *.jsp {"/.*.jsp", "/hello.jsp"}, {"/.*.jsp", "/abc/hello.jsp"}, - + // regex: /abc or /def {"/abc|/def", "/abc"}, {"/abc|/def", "/def"}, - + // regex: *.do or *.jsp {".*\\.do|.*\\.jsp", "/hello.do"}, {".*\\.do|.*\\.jsp", "/hello.jsp"}, {".*\\.do|.*\\.jsp", "/abc/hello.do"}, {".*\\.do|.*\\.jsp", "/abc/hello.jsp"}, - + {"/abc/.*.htm|/def/.*.htm", "/abc/hello.htm"}, {"/abc/.*.htm|/def/.*.htm", "/abc/def/hello.htm"}, - + // regex: /abc/*.jsp {"/abc/.*.jsp", "/abc/hello.jsp"}, {"/abc/.*.jsp", "/abc/def/hello.jsp"} }; - - for (int i = 0; i < matchCases.length; i++) + + for (String[] matchCase : matchCases) { - String[] matchCase = matchCases[i]; assertMatch(true, matchCase); } } - + + @Test public void testFalseMatch() throws IOException { String[][] matchCases = { {"/abc/.*.jsp", "/hello.jsp"} }; - - for (int i = 0; i < matchCases.length; i++) + + for (String[] matchCase : matchCases) { - String[] matchCase = matchCases[i]; assertMatch(false, matchCase); } } - + private void assertMatch(boolean flag, String[] matchCase) throws IOException { _rule.setRegex(matchCase[0]); @@ -96,10 +99,10 @@ public class RegexRuleTest extends TestCase } }, null ); - + assertEquals("regex: " + matchCase[0] + " uri: " + matchCase[1], flag, result!=null); } - + private class TestRegexRule extends RegexRule { public String apply(String target,HttpServletRequest request,HttpServletResponse response, Matcher matcher) throws IOException diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ResponsePatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ResponsePatternRuleTest.java index 0770c141ff..319b8dc18e 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ResponsePatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ResponsePatternRuleTest.java @@ -4,38 +4,46 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import java.io.IOException; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + public class ResponsePatternRuleTest extends AbstractRuleTestCase { private ResponsePatternRule _rule; - - public void setUp() throws Exception + + @Before + public void init() throws Exception { - super.setUp(); + start(false); _rule = new ResponsePatternRule(); _rule.setPattern("/test"); } - + + @Test public void testStatusCodeNoReason() throws IOException { for (int i = 1; i < 400; i++) { _rule.setCode("" + i); _rule.apply(null, _request, _response); - + assertEquals(i, _response.getStatus()); } } - + + @Test public void testStatusCodeWithReason() throws IOException { for (int i = 1; i < 400; i++) @@ -43,25 +51,27 @@ public class ResponsePatternRuleTest extends AbstractRuleTestCase _rule.setCode("" + i); _rule.setReason("reason" + i); _rule.apply(null, _request, _response); - + assertEquals(i, _response.getStatus()); assertEquals(null, _response.getReason()); } } - + + @Test public void testErrorStatusNoReason() throws IOException { for (int i = 400; i < 600; i++) { _rule.setCode("" + i); _rule.apply(null, _request, _response); - + assertEquals(i, _response.getStatus()); assertEquals("", _response.getReason()); super.reset(); } } - + + @Test public void testErrorStatusWithReason() throws IOException { for (int i = 400; i < 600; i++) @@ -69,7 +79,7 @@ public class ResponsePatternRuleTest extends AbstractRuleTestCase _rule.setCode("" + i); _rule.setReason("reason-" + i); _rule.apply(null, _request, _response); - + assertEquals(i, _response.getStatus()); assertEquals("reason-" + i, _response.getReason()); super.reset(); diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java index 386e2ffe1d..be50988ca4 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java @@ -4,33 +4,36 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class RewriteHandlerTest extends AbstractRuleTestCase -{ - RewriteHandler _handler; - RewritePatternRule _rule1; - RewritePatternRule _rule2; - RewritePatternRule _rule3; - - - public void setUp() throws Exception +{ + private RewriteHandler _handler; + private RewritePatternRule _rule1; + private RewritePatternRule _rule2; + private RewritePatternRule _rule3; + + @Before + public void init() throws Exception { _handler=new RewriteHandler(); _server.setHandler(_handler); @@ -43,9 +46,9 @@ public class RewriteHandlerTest extends AbstractRuleTestCase request.setAttribute("URI",request.getRequestURI()); request.setAttribute("info",request.getPathInfo()); } - + }); - + _rule1 = new RewritePatternRule(); _rule1.setPattern("/aaa/*"); _rule1.setReplacement("/bbb"); @@ -55,13 +58,13 @@ public class RewriteHandlerTest extends AbstractRuleTestCase _rule3 = new RewritePatternRule(); _rule3.setPattern("/ccc/*"); _rule3.setReplacement("/ddd"); - + _handler.setRules(new Rule[]{_rule1,_rule2,_rule3}); - - super.setUp(); - } - - + + start(false); + } + + @Test public void test() throws Exception { _response.setStatus(200); @@ -77,7 +80,6 @@ public class RewriteHandlerTest extends AbstractRuleTestCase assertEquals("/foo/bar",_request.getAttribute("URI")); assertEquals("/foo/bar",_request.getAttribute("info")); assertEquals(null,_request.getAttribute("before")); - _response.setStatus(200); _request.setHandled(false); @@ -90,7 +92,6 @@ public class RewriteHandlerTest extends AbstractRuleTestCase assertEquals("/aaa/bar",_request.getAttribute("URI")); assertEquals("/aaa/bar",_request.getAttribute("info")); assertEquals(null,_request.getAttribute("before")); - _response.setStatus(200); _request.setHandled(false); @@ -105,7 +106,6 @@ public class RewriteHandlerTest extends AbstractRuleTestCase assertEquals("/ddd/bar",_request.getAttribute("URI")); assertEquals("/ddd/bar",_request.getAttribute("info")); assertEquals("/aaa/bar",_request.getAttribute("before")); - _response.setStatus(200); _request.setHandled(false); @@ -135,8 +135,5 @@ public class RewriteHandlerTest extends AbstractRuleTestCase assertEquals(null,_request.getAttribute("info")); assertEquals("/aaa/bar",_request.getAttribute("before")); assertTrue(_request.isHandled()); - - - } } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java index dfecfc0279..c939b89bcc 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java @@ -4,22 +4,24 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import java.io.IOException; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; public class RewritePatternRuleTest extends AbstractRuleTestCase { - private RewritePatternRule _rule; - - String[][] _tests= + private String[][] _tests= { {"/foo/bar","/","/replace"}, {"/foo/bar","/*","/replace/foo/bar"}, @@ -27,25 +29,24 @@ public class RewritePatternRuleTest extends AbstractRuleTestCase {"/foo/bar","/foo/bar","/replace"}, {"/foo/bar.txt","*.txt","/replace"}, }; - - public void setUp() throws Exception + private RewritePatternRule _rule; + + @Before + public void init() throws Exception { - super.setUp(); + start(false); _rule = new RewritePatternRule(); _rule.setReplacement("/replace"); - } - - + } + + @Test public void testRequestUriEnabled() throws IOException { - for (int i=0;i<_tests.length;i++) + for (String[] test : _tests) { - _rule.setPattern(_tests[i][1]); - - String result = _rule.matchAndApply(_tests[i][0], _request, _response); - - assertEquals(_tests[i][1],_tests[i][2], result); + _rule.setPattern(test[1]); + String result = _rule.matchAndApply(test[0], _request, _response); + assertEquals(test[1], test[2], result); } } - } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java index 7372b6bbb4..7d05946d1e 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java @@ -4,44 +4,47 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; import java.io.IOException; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + public class RewriteRegexRuleTest extends AbstractRuleTestCase { - private RewriteRegexRule _rule; - - String[][] _tests= - { + private String[][] _tests= + { {"/foo/bar",".*","/replace","/replace"}, - {"/foo/bar","/xxx.*","/replace",null}, + {"/foo/bar","/xxx.*","/replace",null}, {"/foo/bar","/(.*)/(.*)","/$2/$1/xxx","/bar/foo/xxx"}, }; - - public void setUp() throws Exception + private RewriteRegexRule _rule; + + @Before + public void init() throws Exception { - super.setUp(); + start(false); _rule=new RewriteRegexRule(); } - + + @Test public void testRequestUriEnabled() throws IOException { - for (int i=0;i<_tests.length;i++) + for (String[] test : _tests) { - _rule.setRegex(_tests[i][1]); - _rule.setReplacement(_tests[i][2]); - - String result = _rule.matchAndApply(_tests[i][0], _request, _response); - - assertEquals(_tests[i][1],_tests[i][3], result); + _rule.setRegex(test[1]); + _rule.setReplacement(test[2]); + String result = _rule.matchAndApply(test[0], _request, _response); + assertEquals(test[1], test[3], result); } } - } diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java index 208d94f1d4..210be241db 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java @@ -4,26 +4,29 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; public class VirtualHostRuleContainerTest extends AbstractRuleTestCase { - RewriteHandler _handler; + private RewriteHandler _handler; + private RewritePatternRule _rule; + private RewritePatternRule _fooRule; + private VirtualHostRuleContainer _fooContainerRule; - RewritePatternRule _rule; - RewritePatternRule _fooRule; - VirtualHostRuleContainer _fooContainerRule; - - public void setUp() throws Exception + @Before + public void init() throws Exception { _handler = new RewriteHandler(); _handler.setRewriteRequestURI(true); @@ -35,17 +38,18 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase _fooRule = new RewritePatternRule(); _fooRule.setPattern("/cheese/bar/*"); _fooRule.setReplacement("/cheese/fooRule"); - + _fooContainerRule = new VirtualHostRuleContainer(); _fooContainerRule.setVirtualHosts(new String[] {"foo.com"}); _fooContainerRule.setRules(new Rule[] { _fooRule }); - + _server.setHandler(_handler); - super.setUp(); + start(false); _request.setRequestURI("/cheese/bar"); } + @Test public void testArbitraryHost() throws Exception { _request.setServerName("cheese.com"); @@ -54,6 +58,7 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase assertEquals("{_rule, _fooContainerRule, Host: cheese.com}: applied _rule", "/rule/bar", _request.getRequestURI()); } + @Test public void testVirtualHost() throws Exception { _request.setServerName("foo.com"); @@ -62,84 +67,89 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase assertEquals("{_fooContainerRule, Host: foo.com}: applied _fooRule", "/cheese/fooRule", _request.getRequestURI()); } + @Test public void testCascadingRules() throws Exception { _request.setServerName("foo.com"); _request.setRequestURI("/cheese/bar"); - + _rule.setTerminating(false); _fooRule.setTerminating(false); _fooContainerRule.setTerminating(false); - + _handler.setRules(new Rule[]{_rule, _fooContainerRule}); handleRequest(); assertEquals("{_rule, _fooContainerRule}: applied _rule, didn't match _fooRule", "/rule/bar", _request.getRequestURI()); - + _request.setRequestURI("/cheese/bar"); _handler.setRules(new Rule[] { _fooContainerRule, _rule }); handleRequest(); assertEquals("{_fooContainerRule, _rule}: applied _fooRule, _rule","/rule/fooRule", _request.getRequestURI()); - + _request.setRequestURI("/cheese/bar"); _fooRule.setTerminating(true); handleRequest(); assertEquals("{_fooContainerRule, _rule}: (_fooRule is terminating); applied _fooRule, _rule", "/rule/fooRule", _request.getRequestURI()); - + _request.setRequestURI("/cheese/bar"); _fooRule.setTerminating(false); _fooContainerRule.setTerminating(true); handleRequest(); assertEquals("{_fooContainerRule, _rule}: (_fooContainerRule is terminating); applied _fooRule, terminated before _rule", "/cheese/fooRule", _request.getRequestURI()); } - - public void testCaseInsensitiveHostname() throws Exception + + @Test + public void testCaseInsensitiveHostname() throws Exception { _request.setServerName("Foo.com"); _fooContainerRule.setVirtualHosts(new String[] {"foo.com"} ); - + _handler.setRules(new Rule[]{ _fooContainerRule }); handleRequest(); assertEquals("Foo.com and foo.com are equivalent", "/cheese/fooRule", _request.getRequestURI()); } - - public void testEmptyVirtualHost() throws Exception + + @Test + public void testEmptyVirtualHost() throws Exception { _request.setServerName("cheese.com"); - + _handler.setRules(new Rule[] { _fooContainerRule }); _fooContainerRule.setVirtualHosts(null); handleRequest(); assertEquals("{_fooContainerRule: virtual hosts array is null, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); - + _request.setRequestURI("/cheese/bar"); _request.setRequestURI("/cheese/bar"); _fooContainerRule.setVirtualHosts(new String[] {}); handleRequest(); assertEquals("{_fooContainerRule: virtual hosts array is empty, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); - + _request.setRequestURI("/cheese/bar"); _request.setRequestURI("/cheese/bar"); _fooContainerRule.setVirtualHosts(new String[] {null}); handleRequest(); assertEquals("{_fooContainerRule: virtual host is null, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); - + } - - public void testMultipleVirtualHosts() throws Exception + + @Test + public void testMultipleVirtualHosts() throws Exception { _request.setServerName("foo.com"); _handler.setRules(new Rule[] {_fooContainerRule }); - + _fooContainerRule.setVirtualHosts(new String[]{ "cheese.com" }); handleRequest(); assertEquals("{_fooContainerRule: vhosts[cheese.com], Host: foo.com}: no effect", "/cheese/bar", _request.getRequestURI()); - + _request.setRequestURI("/cheese/bar"); _fooContainerRule.addVirtualHost( "foo.com" ); handleRequest(); assertEquals("{_fooContainerRule: vhosts[cheese.com, foo.com], Host: foo.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI()); } - + + @Test public void testWildcardVirtualHosts() throws Exception { checkWildcardHost(true,null,new String[] {"foo.com", ".foo.com", "vhost.foo.com"}); @@ -147,18 +157,18 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase checkWildcardHost(true,new String[] {"foo.com", "*.foo.com"}, new String[] {"foo.com", ".foo.com", "vhost.foo.com"}); checkWildcardHost(false,new String[] {"foo.com", "*.foo.com"}, new String[] {"badfoo.com", ".badfoo.com", "vhost.badfoo.com"}); - + checkWildcardHost(false,new String[] {"*."}, new String[] {"anything.anything"}); - + checkWildcardHost(true,new String[] {"*.foo.com"}, new String[] {"vhost.foo.com", ".foo.com"}); checkWildcardHost(false,new String[] {"*.foo.com"}, new String[] {"vhost.www.foo.com", "foo.com", "www.vhost.foo.com"}); checkWildcardHost(true,new String[] {"*.sub.foo.com"}, new String[] {"vhost.sub.foo.com", ".sub.foo.com"}); checkWildcardHost(false,new String[] {"*.sub.foo.com"}, new String[] {".foo.com", "sub.foo.com", "vhost.foo.com"}); - - checkWildcardHost(false,new String[] {"foo.*.com","foo.com.*"}, new String[] {"foo.vhost.com", "foo.com.vhost", "foo.com"}); + + checkWildcardHost(false,new String[] {"foo.*.com","foo.com.*"}, new String[] {"foo.vhost.com", "foo.com.vhost", "foo.com"}); } - + private void checkWildcardHost(boolean succeed, String[] ruleHosts, String[] requestHosts) throws Exception { _fooContainerRule.setVirtualHosts(ruleHosts); @@ -181,4 +191,3 @@ public class VirtualHostRuleContainerTest extends AbstractRuleTestCase _server.handle("/cheese/bar", _request, _request, _response); } } - diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index c8ec49057d..fdeed8779d 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -39,15 +39,17 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include sources since jetty-xbean makes use of them --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.security.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> @@ -60,6 +62,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java index 271fa933d8..0852bf5f9b 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java @@ -53,10 +53,10 @@ public interface Authenticator * @param request The request * @param response The response * @param mandatory True if authentication is mandatory. - * @return An Authentication. If Authentication is successful, this will be a {@link Authentication.User}. If a response has + * @return An Authentication. If Authentication is successful, this will be a {@link org.eclipse.jetty.server.Authentication.User}. If a response has * been sent by the Authenticator (which can be done for both successful and unsuccessful authentications), then the result will - * implement {@link Authentication.ResponseSent}. If Authentication is not manditory, then a {@link Authentication.Deferred} - * may be returned. + * implement {@link org.eclipse.jetty.server.Authentication.ResponseSent}. If Authentication is not manditory, then a + * {@link org.eclipse.jetty.server.Authentication.Deferred} may be returned. * * @throws ServerAuthException */ @@ -68,7 +68,7 @@ public interface Authenticator * @param response * @param mandatory * @param validatedUser - * @return + * @return true if response is secure * @throws ServerAuthException */ boolean secureResponse(ServletRequest request, ServletResponse response, boolean mandatory, User validatedUser) throws ServerAuthException; diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java index 1135aa7591..2ec8d8db01 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.security; +import java.util.List; import java.util.Set; /** @@ -20,9 +21,29 @@ import java.util.Set; */ public interface ConstraintAware { - ConstraintMapping[] getConstraintMappings(); - + List<ConstraintMapping> getConstraintMappings(); Set<String> getRoles(); - - void setConstraintMappings(ConstraintMapping[] constraintMappings, Set<String> roles); + + /* ------------------------------------------------------------ */ + /** Set Constraint Mappings and roles. + * Can only be called during initialization. + * @param constraintMappings + * @param roles + */ + void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles); + + /* ------------------------------------------------------------ */ + /** Add a Constraint Mapping. + * May be called for running webapplication as an annotated servlet is instantiated. + * @param mapping + */ + void addConstraintMapping(ConstraintMapping mapping); + + + /* ------------------------------------------------------------ */ + /** Add a Role definition. + * May be called on running webapplication as an annotated servlet is instantiated. + * @param role + */ + void addRole(String role); } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java index c8daed4c99..3996a0df6e 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java @@ -14,9 +14,14 @@ package org.eclipse.jetty.security; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.http.security.Constraint; @@ -36,9 +41,9 @@ import org.eclipse.jetty.util.StringMap; */ public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware { - private ConstraintMapping[] _constraintMappings; - private Set<String> _roles; - private PathMap _constraintMap = new PathMap(); + private final List<ConstraintMapping> _constraintMappings= new CopyOnWriteArrayList<ConstraintMapping>(); + private final Set<String> _roles = new CopyOnWriteArraySet<String>(); + private final PathMap _constraintMap = new PathMap(); private boolean _strict = true; @@ -76,7 +81,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr /** * @return Returns the contraintMappings. */ - public ConstraintMapping[] getConstraintMappings() + public List<ConstraintMapping> getConstraintMappings() { return _constraintMappings; } @@ -86,7 +91,14 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr { return _roles; } - + + /* ------------------------------------------------------------ */ + @Deprecated + public void setConstraintMappings(ConstraintMapping[] constraintMappings) + { + setConstraintMappings(Arrays.asList(constraintMappings),null); + } + /* ------------------------------------------------------------ */ /** * Process the constraints following the combining rules in Servlet 3.0 EA @@ -96,11 +108,19 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr * The contraintMappings to set, from which the set of known roles * is determined. */ - public void setConstraintMappings(ConstraintMapping[] constraintMappings) + public void setConstraintMappings(List<ConstraintMapping> constraintMappings) { setConstraintMappings(constraintMappings,null); } - + + + /* ------------------------------------------------------------ */ + @Deprecated + public void setConstraintMappings(ConstraintMapping[] constraintMappings, Set<String> roles) + { + setConstraintMappings(Arrays.asList(constraintMappings),roles); + } + /* ------------------------------------------------------------ */ /** * Process the constraints following the combining rules in Servlet 3.0 EA @@ -110,11 +130,12 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr * The contraintMappings to set. * @param roles The known roles (or null to determine them from the mappings) */ - public void setConstraintMappings(ConstraintMapping[] constraintMappings, Set<String> roles) + public void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles) { if (isStarted()) throw new IllegalStateException("Started"); - _constraintMappings = constraintMappings; + _constraintMappings.clear(); + _constraintMappings.addAll(constraintMappings); if (roles==null) { @@ -146,7 +167,48 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr if (isStarted()) throw new IllegalStateException("Started"); - this._roles = roles; + _roles.clear(); + _roles.addAll(roles); + } + + + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.security.ConstraintAware#addConstraintMapping(org.eclipse.jetty.security.ConstraintMapping) + */ + public void addConstraintMapping(ConstraintMapping mapping) + { + _constraintMappings.add(mapping); + if (mapping.getConstraint()!=null && mapping.getConstraint().getRoles()!=null) + for (String role : mapping.getConstraint().getRoles()) + addRole(role); + + if (isStarted()) + { + processContraintMapping(mapping); + } + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.security.ConstraintAware#addRole(java.lang.String) + */ + public void addRole(String role) + { + boolean modified = _roles.add(role); + if (isStarted() && modified && _strict) + { + // Add the new role to currently defined any role role infos + for (Map<String,RoleInfo> map : (Collection<Map<String,RoleInfo>>)_constraintMap.values()) + { + for (RoleInfo info : map.values()) + { + if (info.isAnyRole()) + info.addRole(role); + } + } + } } /* ------------------------------------------------------------ */ @@ -161,92 +223,95 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr { for (ConstraintMapping mapping : _constraintMappings) { - Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.get(mapping.getPathSpec()); - if (mappings == null) - { - mappings = new StringMap(); - _constraintMap.put(mapping.getPathSpec(),mappings); - } - RoleInfo allMethodsRoleInfo = mappings.get(null); - if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden()) - { - continue; - } - String httpMethod = mapping.getMethod(); - RoleInfo roleInfo = mappings.get(httpMethod); - if (roleInfo == null) + processContraintMapping(mapping); + } + } + super.doStart(); + } + + protected void processContraintMapping(ConstraintMapping mapping) + { + Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.get(mapping.getPathSpec()); + if (mappings == null) + { + mappings = new StringMap(); + _constraintMap.put(mapping.getPathSpec(),mappings); + } + RoleInfo allMethodsRoleInfo = mappings.get(null); + if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden()) + return; + + String httpMethod = mapping.getMethod(); + RoleInfo roleInfo = mappings.get(httpMethod); + if (roleInfo == null) + { + roleInfo = new RoleInfo(); + mappings.put(httpMethod,roleInfo); + if (allMethodsRoleInfo != null) + { + roleInfo.combine(allMethodsRoleInfo); + } + } + if (roleInfo.isForbidden()) + return; + + Constraint constraint = mapping.getConstraint(); + boolean forbidden = constraint.isForbidden(); + roleInfo.setForbidden(forbidden); + if (forbidden) + { + if (httpMethod == null) + { + mappings.clear(); + mappings.put(null,roleInfo); + } + } + else + { + UserDataConstraint userDataConstraint = UserDataConstraint.get(constraint.getDataConstraint()); + roleInfo.setUserDataConstraint(userDataConstraint); + + boolean checked = constraint.getAuthenticate(); + roleInfo.setChecked(checked); + if (roleInfo.isChecked()) + { + if (constraint.isAnyRole()) { - roleInfo = new RoleInfo(); - mappings.put(httpMethod,roleInfo); - if (allMethodsRoleInfo != null) + if (_strict) { - roleInfo.combine(allMethodsRoleInfo); + // * means "all defined roles" + for (String role : _roles) + roleInfo.addRole(role); } + else + // * means any role + roleInfo.setAnyRole(true); } - if (roleInfo.isForbidden()) - { - continue; - } - Constraint constraint = mapping.getConstraint(); - boolean forbidden = constraint.isForbidden(); - roleInfo.setForbidden(forbidden); - if (forbidden) + else { - if (httpMethod == null) + String[] newRoles = constraint.getRoles(); + for (String role : newRoles) { - mappings.clear(); - mappings.put(null,roleInfo); + if (_strict &&!_roles.contains(role)) + throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles); + roleInfo.addRole(role); } } - else + } + if (httpMethod == null) + { + for (Map.Entry<String, RoleInfo> entry : mappings.entrySet()) { - UserDataConstraint userDataConstraint = UserDataConstraint.get(constraint.getDataConstraint()); - roleInfo.setUserDataConstraint(userDataConstraint); - - boolean checked = constraint.getAuthenticate(); - roleInfo.setChecked(checked); - if (roleInfo.isChecked()) + if (entry.getKey() != null) { - if (constraint.isAnyRole()) - { - if (_strict) - { - // * means "all defined roles" - for (String role : _roles) - roleInfo.addRole(role); - } - else - // * means any role - roleInfo.setAnyRole(true); - } - else - { - String[] newRoles = constraint.getRoles(); - for (String role : newRoles) - { - if (_strict &&!_roles.contains(role)) - throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles); - roleInfo.addRole(role); - } - } - } - if (httpMethod == null) - { - for (Map.Entry<String, RoleInfo> entry : mappings.entrySet()) - { - if (entry.getKey() != null) - { - RoleInfo specific = entry.getValue(); - specific.combine(roleInfo); - } - } + RoleInfo specific = entry.getValue(); + specific.combine(roleInfo); } } } } - super.doStart(); } - + protected Object prepareConstraintInfo(String pathInContext, Request request) { Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext); @@ -353,8 +418,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr if (roleInfo.isAnyRole() && request.getAuthType()!=null) return true; - String[] roles = roleInfo.getRoles(); - for (String role : roles) + for (String role : roleInfo.getRoles()) { if (userIdentity.isUserInRole(role, null)) return true; diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java index 290ae6b0d1..bec4b347c1 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java @@ -27,13 +27,17 @@ import org.eclipse.jetty.server.Server; /** * The Default Authenticator Factory. * Uses the {@link Configuration#getAuthMethod()} to select an {@link Authenticator} from: <ul> - * <li>{@link BasicAuthenticator}</li> - * <li>{@link DigestAuthenticator}</li> - * <li>{@link FormAuthenticator}</li> - * <li>{@link ClientCertAuthenticator}</li> + * <li>{@link org.eclipse.jetty.security.authentication.BasicAuthenticator}</li> + * <li>{@link org.eclipse.jetty.security.authentication.DigestAuthenticator}</li> + * <li>{@link org.eclipse.jetty.security.authentication.FormAuthenticator}</li> + * <li>{@link org.eclipse.jetty.security.authentication.ClientCertAuthenticator}</li> * </ul> - * If {@link Configuration#isLazy()} is true, the Authenticator is wrapped with a {@link DeferredAuthenticator} - * instance. The FormAuthenticator is always wrapped in a {@link SessionCachingAuthenticator}. + * All authenticators derived from {@link org.eclipse.jetty.security.authentication.LoginAuthenticator} are + * wrapped with a {@link org.eclipse.jetty.security.authentication.DeferredAuthentication} + * instance, which is used if authentication is not mandatory. + * + * The Authentications from the {@link org.eclipse.jetty.security.authentication.FormAuthenticator} are always wrapped in a + * {@link org.eclipse.jetty.security.authentication.SessionAuthentication} * <p> * If a {@link LoginService} has not been set on this factory, then * the service is selected by searching the {@link Server#getBeans(Class)} results for @@ -61,7 +65,6 @@ public class DefaultAuthenticatorFactory implements Authenticator.Factory return authenticator; } - /* ------------------------------------------------------------ */ /** * @return the loginService diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java index e5f3335a64..2b2b746276 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java @@ -24,9 +24,10 @@ import org.eclipse.jetty.server.UserIdentity; /** * Default Identity Service implementation. * This service handles only role reference maps passed in an - * associated {@link UserIdentity.Scope}. If there are roles + * associated {@link org.eclipse.jetty.server.UserIdentity.Scope}. If there are roles * refs present, then associate will wrap the UserIdentity with one - * that uses the role references in the {@link UserIdentity#isUserInRole(String)} + * that uses the role references in the + * {@link org.eclipse.jetty.server.UserIdentity#isUserInRole(String, org.eclipse.jetty.server.UserIdentity.Scope)} * implementation. All other operations are effectively noops. * */ @@ -40,7 +41,7 @@ public class DefaultIdentityService implements IdentityService /* ------------------------------------------------------------ */ /** * If there are roles refs present in the scope, then wrap the UserIdentity - * with one that uses the role references in the {@link UserIdentity#isUserInRole(String)} + * with one that uses the role references in the {@link UserIdentity#isUserInRole(String, org.eclipse.jetty.server.UserIdentity.Scope)} */ public Object associate(UserIdentity user) { diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java index 31e21af15a..eb3946bd0d 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java @@ -51,9 +51,6 @@ import org.eclipse.jetty.util.resource.Resource; * * If DIGEST Authentication is used, the password must be in a recoverable * format, either plain text or OBF:. - * - * @see org.eclipse.jetty.security.Password - * */ public class HashLoginService extends MappedLoginService { @@ -105,8 +102,6 @@ public class HashLoginService extends MappedLoginService * names. * * @param config Filename or url of user properties file. - * @exception java.io.IOException if user properties file could not be - * loaded */ public void setConfig(String config) { diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java index 06e51c8136..7075cc9792 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; -import org.eclipse.jetty.http.security.Password; +import org.eclipse.jetty.http.security.Credential; import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; @@ -168,7 +168,6 @@ public class JDBCLoginService extends MappedLoginService * Load JDBC connection configuration from properties file. * * @param config Filename or url of user properties file. - * @exception java.io.IOException */ public void setConfig(String config) { @@ -249,7 +248,7 @@ public class JDBCLoginService extends MappedLoginService roles.add(rs.getString(_roleTableRoleField)); stat.close(); - return putUser(username, new Password(credentials),roles.toArray(new String[roles.size()])); + return putUser(username, Credential.getCredential(credentials),roles.toArray(new String[roles.size()])); } } catch (SQLException e) diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/RoleInfo.java b/jetty-security/src/main/java/org/eclipse/jetty/security/RoleInfo.java index b58558f70d..35df88ce8f 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/RoleInfo.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/RoleInfo.java @@ -13,9 +13,8 @@ package org.eclipse.jetty.security; -import java.util.Arrays; - -import org.eclipse.jetty.util.LazyList; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; /** * @@ -27,13 +26,12 @@ import org.eclipse.jetty.util.LazyList; */ public class RoleInfo { - private final static String[] NO_ROLES={}; private boolean _isAnyRole; private boolean _checked; private boolean _forbidden; private UserDataConstraint _userDataConstraint; - private String[] _roles = NO_ROLES; + private final Set<String> _roles = new CopyOnWriteArraySet<String>(); public RoleInfo() { @@ -50,7 +48,7 @@ public class RoleInfo if (!checked) { _forbidden=false; - _roles=NO_ROLES; + _roles.clear(); _isAnyRole=false; } } @@ -68,7 +66,7 @@ public class RoleInfo _checked = true; _userDataConstraint = null; _isAnyRole=false; - _roles=NO_ROLES; + _roles.clear(); } } @@ -83,7 +81,7 @@ public class RoleInfo if (anyRole) { _checked = true; - _roles=NO_ROLES; + _roles.clear(); } } @@ -105,14 +103,14 @@ public class RoleInfo } } - public String[] getRoles() + public Set<String> getRoles() { return _roles; } public void addRole(String role) { - _roles=(String[])LazyList.addToArray(_roles,role,String.class); + _roles.add(role); } public void combine(RoleInfo other) @@ -126,14 +124,15 @@ public class RoleInfo else if (!_isAnyRole) { for (String r : other._roles) - _roles=(String[])LazyList.addToArray(_roles,r,String.class); + _roles.add(r); } setUserDataConstraint(other._userDataConstraint); } + @Override public String toString() { - return "{RoleInfo"+(_forbidden?",F":"")+(_checked?",C":"")+(_isAnyRole?",*":Arrays.asList(_roles).toString())+"}"; + return "{RoleInfo"+(_forbidden?",F":"")+(_checked?",C":"")+(_isAnyRole?",*":_roles)+"}"; } } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index b3f9e8ac7a..0d78853666 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -256,15 +256,13 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti /* ------------------------------------------------------------ */ protected IdentityService findIdentityService() { - List<IdentityService> services = getServer().getBeans(IdentityService.class); - if (services!=null && services.size()>0) - return services.get(0); - return null; + return getServer().getBean(IdentityService.class); } /* ------------------------------------------------------------ */ /** */ + @Override protected void doStart() throws Exception { @@ -354,6 +352,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti } + /* ------------------------------------------------------------ */ protected boolean checkSecurity(Request request) { switch(request.getDispatcherType()) diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java index 44f9ff3bf3..212b4ef104 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java @@ -36,9 +36,6 @@ import org.eclipse.jetty.util.StringUtil; public class BasicAuthenticator extends LoginAuthenticator { /* ------------------------------------------------------------ */ - /** - * @param loginService - */ public BasicAuthenticator() { } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java index a344b7c0bf..f40b7e66e8 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java @@ -46,7 +46,7 @@ public class ClientCertAuthenticator extends LoginAuthenticator } /** - * @return + * @return Authentication for request * @throws ServerAuthException */ public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java index b4a900f141..a22fdb5c88 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java @@ -67,7 +67,7 @@ public class DeferredAuthentication implements Authentication.Deferred /* ------------------------------------------------------------ */ /** - * @see org.eclipse.jetty.server.Authentication.Deferred#authenticate() + * @see org.eclipse.jetty.server.Authentication.Deferred#authenticate(ServletRequest) */ public Authentication authenticate(ServletRequest request) { diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java index 7a624ddc7f..96833e1613 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java @@ -42,15 +42,16 @@ import org.eclipse.jetty.util.log.Log; /** * FORM Authenticator. * - * The form authenticator redirects unauthenticated requests to a log page + * <p>This authenticator implements form authentication will use dispatchers to + * the login page if the {@link #__FORM_DISPATCH} init parameter is set to true. + * Otherwise it will redirect.</p> + * + * <p>The form authenticator redirects unauthenticated requests to a log page * which should use a form to gather username/password from the user and send them - * to the /j_security_check URI within the context. FormAuthentication is intended - * to be used together with the {@link SessionCachingAuthenticator} so that the - * auth results may be associated with the session. + * to the /j_security_check URI within the context. FormAuthentication uses + * {@link SessionAuthentication} to wrap Authentication results so that they + * are associated with the session.</p> * - * This authenticator implements form authentication will use dispatchers to - * the login page if the {@link #__FORM_DISPATCH} init parameter is set to true. - * Otherwise it will redirect. * */ public class FormAuthenticator extends LoginAuthenticator diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java index 5790677b01..ec20115ee5 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.security.Authenticator; import org.eclipse.jetty.security.UserAuthentication; import org.eclipse.jetty.server.UserIdentity; -class SessionAuthentication extends UserAuthentication implements HttpSessionAttributeListener, Serializable +public class SessionAuthentication extends UserAuthentication implements HttpSessionAttributeListener, Serializable { private static final long serialVersionUID = -4643200685888258706L; diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java index 184cffb9c0..de8aa34809 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java @@ -13,7 +13,11 @@ package org.eclipse.jetty.security; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -23,8 +27,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.http.security.B64Code; import org.eclipse.jetty.http.security.Constraint; import org.eclipse.jetty.http.security.Password; @@ -39,40 +41,52 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.session.SessionHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; /** - * + * @version $Revision: 1441 $ $Date: 2010-04-02 12:28:17 +0200 (Fri, 02 Apr 2010) $ */ -public class ConstraintTest extends TestCase +public class ConstraintTest { private static final String TEST_REALM = "TestRealm"; + private static Server _server; + private static LocalConnector _connector; + private static SessionHandler _session; + private ConstraintSecurityHandler _security; - Server _server = new Server(); - LocalConnector _connector = new LocalConnector(); - ContextHandler _context = new ContextHandler(); - SessionHandler _session = new SessionHandler(); - ConstraintSecurityHandler _security = new ConstraintSecurityHandler(); - HashLoginService _loginService = new HashLoginService(TEST_REALM); - - RequestHandler _handler = new RequestHandler(); - + @BeforeClass + public static void startServer() { + _server = new Server(); + _connector = new LocalConnector(); _server.setConnectors(new Connector[]{_connector}); - _context.setContextPath("/ctx"); - _server.setHandler(_context); - _context.setHandler(_session); - _session.setHandler(_security); - _security.setHandler(_handler); + ContextHandler _context = new ContextHandler(); + _session = new SessionHandler(); + + HashLoginService _loginService = new HashLoginService(TEST_REALM); _loginService.putUser("user",new Password("password")); _loginService.putUser("user2",new Password("password"), new String[] {"user"}); _loginService.putUser("admin",new Password("password"), new String[] {"user","administrator"}); + + _context.setContextPath("/ctx"); + _server.setHandler(_context); + _context.setHandler(_session); + _server.addBean(_loginService); } - public ConstraintTest(String arg0) + @Before + public void setupSecurity() { - super(arg0); + _security = new ConstraintSecurityHandler(); + _session.setHandler(_security); + RequestHandler _handler = new RequestHandler(); + _security.setHandler(_handler); + Constraint constraint0 = new Constraint(); constraint0.setAuthenticate(true); constraint0.setName("forbid"); @@ -111,41 +125,31 @@ public class ConstraintTest extends TestCase ConstraintMapping mapping4 = new ConstraintMapping(); mapping4.setPathSpec("/testLoginPage"); mapping4.setConstraint(constraint4); - + Set<String> knownRoles=new HashSet<String>(); knownRoles.add("user"); knownRoles.add("administrator"); - _security.setConstraintMappings(new ConstraintMapping[] + _security.setConstraintMappings(Arrays.asList(new ConstraintMapping[] { mapping0, mapping1, mapping2, mapping3, mapping4 - },knownRoles); + }), knownRoles); } - /* - * @see TestCase#setUp() - */ - protected void setUp() throws Exception + @After + public void stopServer() throws Exception { - super.setUp(); - - } - - /* - * @see TestCase#tearDown() - */ - protected void tearDown() throws Exception - { - super.tearDown(); - _server.stop(); + if (_server.isRunning()) + { + _server.stop(); + _server.join(); + } } - - - public void testConstraints() - throws Exception + @Test + public void testConstraints() throws Exception { - ConstraintMapping[] mappings =_security.getConstraintMappings(); + ConstraintMapping[] mappings =_security.getConstraintMappings().toArray(new ConstraintMapping[0]); assertTrue (mappings[0].getConstraint().isForbidden()); assertFalse(mappings[1].getConstraint().isForbidden()); @@ -168,9 +172,8 @@ public class ConstraintTest extends TestCase assertFalse(mappings[3].getConstraint().getAuthenticate()); } - - public void testBasic() - throws Exception + @Test + public void testBasic() throws Exception { _security.setAuthenticator(new BasicAuthenticator()); _security.setStrict(false); @@ -226,8 +229,8 @@ public class ConstraintTest extends TestCase assertTrue(response.startsWith("HTTP/1.1 200 OK")); } - public void testFormDispatch() - throws Exception + @Test + public void testFormDispatch() throws Exception { _security.setAuthenticator(new FormAuthenticator("/testLoginPage","/testErrorPage",true)); _security.setStrict(false); @@ -278,8 +281,8 @@ public class ConstraintTest extends TestCase assertTrue(response.indexOf("!role") > 0); } - public void testFormRedirect() - throws Exception + @Test + public void testFormRedirect() throws Exception { _security.setAuthenticator(new FormAuthenticator("/testLoginPage","/testErrorPage",false)); _security.setStrict(false); @@ -303,7 +306,7 @@ public class ConstraintTest extends TestCase "\r\n"); assertTrue(response.indexOf(" 200 OK") > 0); assertTrue(response.indexOf("URI=/ctx/testLoginPage") > 0); - + response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" + "Cookie: JSESSIONID=" + session + "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + @@ -334,8 +337,8 @@ public class ConstraintTest extends TestCase assertTrue(response.indexOf("!role") > 0); } - public void testFormNoCookies() - throws Exception + @Test + public void testFormNoCookies() throws Exception { _security.setAuthenticator(new FormAuthenticator("/testLoginPage","/testErrorPage",false)); _security.setStrict(false); @@ -354,12 +357,12 @@ public class ConstraintTest extends TestCase assertTrue(response.indexOf("/ctx/testLoginPage") > 0); int jsession=response.indexOf(";jsessionid="); String session = response.substring(jsession + 12, response.indexOf("\r\n",jsession)); - + response = _connector.getResponses("GET /ctx/testLoginPage;jsessionid="+session+";other HTTP/1.0\r\n"+ "\r\n"); assertTrue(response.indexOf(" 200 OK") > 0); assertTrue(response.indexOf("URI=/ctx/testLoginPage") > 0); - + response = _connector.getResponses("POST /ctx/j_security_check;jsessionid="+session+";other HTTP/1.0\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 31\r\n" + @@ -386,8 +389,8 @@ public class ConstraintTest extends TestCase assertTrue(response.indexOf("!role") > 0); } - public void testStrictBasic() - throws Exception + @Test + public void testStrictBasic() throws Exception { _security.setAuthenticator(new BasicAuthenticator()); _server.start(); @@ -448,11 +451,11 @@ public class ConstraintTest extends TestCase assertTrue(response.startsWith("HTTP/1.1 200 OK")); } + @Test public void testStrictFormDispatch() throws Exception { _security.setAuthenticator(new FormAuthenticator("/testLoginPage","/testErrorPage",true)); - _server.start(); String response; @@ -561,11 +564,10 @@ public class ConstraintTest extends TestCase assertTrue(response.startsWith("HTTP/1.1 200 OK")); } - public void testStrictFormRedirect() - throws Exception + @Test + public void testStrictFormRedirect() throws Exception { _security.setAuthenticator(new FormAuthenticator("/testLoginPage","/testErrorPage",false)); - _server.start(); String response; @@ -672,8 +674,8 @@ public class ConstraintTest extends TestCase assertTrue(response.startsWith("HTTP/1.1 200 OK")); } - public void testRoleRef() - throws Exception + @Test + public void testRoleRef() throws Exception { RoleCheckHandler check=new RoleCheckHandler(); _security.setHandler(check); @@ -704,9 +706,8 @@ public class ConstraintTest extends TestCase assertTrue(response.startsWith("HTTP/1.1 200 OK")); } - - public void testDeferredBasic() - throws Exception + @Test + public void testDeferredBasic() throws Exception { _security.setAuthenticator(new BasicAuthenticator()); _security.setStrict(false); @@ -732,7 +733,7 @@ public class ConstraintTest extends TestCase assertTrue(response.indexOf("user=admin") > 0); } - class RequestHandler extends AbstractHandler + private class RequestHandler extends AbstractHandler { public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException { @@ -750,7 +751,7 @@ public class ConstraintTest extends TestCase } } - class RoleRefHandler extends HandlerWrapper + private class RoleRefHandler extends HandlerWrapper { /* ------------------------------------------------------------ */ /** @@ -794,7 +795,7 @@ public class ConstraintTest extends TestCase } } - class RoleCheckHandler extends AbstractHandler + private class RoleCheckHandler extends AbstractHandler { public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException { diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index 20c164823a..3afcea2c4f 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -51,16 +51,11 @@ </execution> </executions> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include sources since jetty-xbean makes use of them --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> @@ -79,12 +74,20 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.server.*</onlyAnalyze> + </configuration> + </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-server/src/main/config/etc/jetty-bio-ssl.xml b/jetty-server/src/main/config/etc/jetty-bio-ssl.xml index 0b0c6fc16f..9c075e46cb 100644 --- a/jetty-server/src/main/config/etc/jetty-bio-ssl.xml +++ b/jetty-server/src/main/config/etc/jetty-bio-ssl.xml @@ -14,10 +14,10 @@ <New class="org.eclipse.jetty.server.ssl.SslSocketConnector"> <Set name="Port">9443</Set> <Set name="maxIdleTime">30000</Set> - <Set name="Keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> + <Set name="Keystore"><Property name="jetty.home" default="." />/etc/keystore</Set> <Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> <Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - <Set name="truststore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> + <Set name="truststore"><Property name="jetty.home" default="." />/etc/keystore</Set> <Set name="trustPassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> </New> </Arg> diff --git a/jetty-server/src/main/config/etc/jetty-bio.xml b/jetty-server/src/main/config/etc/jetty-bio.xml index 3c4c8a6b80..66950eee55 100644 --- a/jetty-server/src/main/config/etc/jetty-bio.xml +++ b/jetty-server/src/main/config/etc/jetty-bio.xml @@ -13,7 +13,7 @@ <Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.bio.SocketConnector"> - <Set name="port"><SystemProperty name="jetty.bio.port" default="8081"/></Set> + <Set name="port"><Property name="jetty.bio.port" default="8081"/></Set> <Set name="maxIdleTime">50000</Set> <Set name="lowResourceMaxIdleTime">1500</Set> </New> diff --git a/jetty-server/src/main/config/etc/jetty-debug.xml b/jetty-server/src/main/config/etc/jetty-debug.xml index afc972e5ab..0ffccb69bf 100644 --- a/jetty-server/src/main/config/etc/jetty-debug.xml +++ b/jetty-server/src/main/config/etc/jetty-debug.xml @@ -13,7 +13,7 @@ <Set name="handler"><Ref id="oldhandler"/></Set> <Set name="outputStream"> <New class="org.eclipse.jetty.util.RolloverFileOutputStream"> - <Arg type="String"><SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg> + <Arg type="String"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg> <Arg type="boolean">true</Arg> <!-- append --> <Arg type="int">90</Arg> <!-- retain days --> </New> diff --git a/jetty-server/src/main/config/etc/jetty-proxy.xml b/jetty-server/src/main/config/etc/jetty-proxy.xml index 9fe82f1429..5bc46c389d 100644 --- a/jetty-server/src/main/config/etc/jetty-proxy.xml +++ b/jetty-server/src/main/config/etc/jetty-proxy.xml @@ -32,8 +32,8 @@ <Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> - <Set name="host"><SystemProperty name="jetty.host" /></Set> - <Set name="port"><SystemProperty name="jetty.port" default="8888"/></Set> + <Set name="host"><Property name="jetty.host" /></Set> + <Set name="port"><Property name="jetty.port" default="8888"/></Set> <Set name="maxIdleTime">300000</Set> <Set name="Acceptors">2</Set> <Set name="statsOn">false</Set> diff --git a/jetty-server/src/main/config/etc/jetty-requestlog.xml b/jetty-server/src/main/config/etc/jetty-requestlog.xml new file mode 100644 index 0000000000..622fd84208 --- /dev/null +++ b/jetty-server/src/main/config/etc/jetty-requestlog.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> + +<!-- =============================================================== --> +<!-- Configure the Jetty Request Log --> +<!-- =============================================================== --> + +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <!-- =========================================================== --> + <!-- Configure Request Log --> + <!-- =========================================================== --> + <Ref id="Handlers"> + <Call name="addHandler"> + <Arg> + <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"> + <Set name="requestLog"> + <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> + <Set name="filename"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Set> + <Set name="filenameDateFormat">yyyy_MM_dd</Set> + <Set name="retainDays">90</Set> + <Set name="append">true</Set> + <Set name="extended">false</Set> + <Set name="logCookies">false</Set> + <Set name="LogTimeZone">GMT</Set> + </New> + </Set> + </New> + </Arg> + </Call> + </Ref> + +</Configure> diff --git a/jetty-server/src/main/config/etc/jetty-ssl.xml b/jetty-server/src/main/config/etc/jetty-ssl.xml index 955053101a..7a0d500aee 100644 --- a/jetty-server/src/main/config/etc/jetty-ssl.xml +++ b/jetty-server/src/main/config/etc/jetty-ssl.xml @@ -18,10 +18,10 @@ <Set name="maxIdleTime">30000</Set> <Set name="Acceptors">2</Set> <Set name="AcceptQueueSize">100</Set> - <Set name="Keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> + <Set name="Keystore"><Property name="jetty.home" default="." />/etc/keystore</Set> <Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> <Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - <Set name="truststore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set> + <Set name="truststore"><Property name="jetty.home" default="." />/etc/keystore</Set> <Set name="trustPassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> </New> </Arg> diff --git a/jetty-server/src/main/config/etc/jetty-xinetd.xml b/jetty-server/src/main/config/etc/jetty-xinetd.xml index 0b6582572b..c2fbaa285e 100644 --- a/jetty-server/src/main/config/etc/jetty-xinetd.xml +++ b/jetty-server/src/main/config/etc/jetty-xinetd.xml @@ -40,7 +40,7 @@ service jetty <!-- Optional. Fallback in case System.inheritedChannel() does not give a ServerSocketChannel - <Set name="port"><SystemProperty name="jetty.service.port" default="8082"/></Set> + <Set name="port"><Property name="jetty.service.port" default="8082"/></Set> --> <!-- sane defaults --> diff --git a/jetty-server/src/main/config/etc/jetty.xml b/jetty-server/src/main/config/etc/jetty.xml index cfb371118c..f2de6a0cc8 100644 --- a/jetty-server/src/main/config/etc/jetty.xml +++ b/jetty-server/src/main/config/etc/jetty.xml @@ -5,8 +5,13 @@ <!-- Configure the Jetty Server --> <!-- --> <!-- Documentation of this file format can be found at: --> -<!-- http://docs.codehaus.org/display/JETTY/jetty.xml --> +<!-- http://wiki.eclipse.org/Jetty/Reference/jetty.xml_syntax --> <!-- --> +<!-- Additional configuration files are available in $JETTY_HOME/etc --> +<!-- and can be mixed in. For example: --> +<!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml --> +<!-- --> +<!-- See start.ini file for the default configuraton files --> <!-- =============================================================== --> @@ -23,8 +28,6 @@ </New> </Set> - - <!-- =========================================================== --> <!-- Set connectors --> <!-- =========================================================== --> @@ -32,8 +35,8 @@ <Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> - <Set name="host"><SystemProperty name="jetty.host" /></Set> - <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set> + <Set name="host"><Property name="jetty.host" /></Set> + <Set name="port"><Property name="jetty.port" default="8080"/></Set> <Set name="maxIdleTime">300000</Set> <Set name="Acceptors">2</Set> <Set name="statsOn">false</Set> @@ -44,26 +47,6 @@ </Arg> </Call> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- To add a HTTPS SSL connector --> - <!-- mixin jetty-ssl.xml: --> - <!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- To add a HTTP blocking connector --> - <!-- mixin jetty-bio.xml: --> - <!-- java -jar start.jar etc/jetty.xml etc/jetty-bio.xml --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- To allow Jetty to be started from xinetd --> - <!-- mixin jetty-xinetd.xml: --> - <!-- java -jar start.jar etc/jetty.xml etc/jetty-xinetd.xml --> - <!-- --> - <!-- See jetty-xinetd.xml for further instructions. --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- =========================================================== --> <!-- Set handler Collection Structure --> <!-- =========================================================== --> @@ -77,97 +60,12 @@ <Item> <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/> </Item> - <Item> - <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/> - </Item> </Array> </Set> </New> </Set> <!-- =========================================================== --> - <!-- Configure the deployment manager --> - <!-- --> - <!-- Sets up 2 monitored dir app providers that are configured --> - <!-- to behave in a similaraly to the legacy ContextDeployer --> - <!-- and WebAppDeployer from previous versions of Jetty. --> - <!-- =========================================================== --> - <Call name="addBean"> - <Arg> - <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager"> - <Set name="contexts"> - <Ref id="Contexts" /> - </Set> - <Call name="setContextAttribute"> - <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg> - <Arg>.*/servlet-api-[^/]*\.jar$</Arg> - </Call> - <!-- Providers of Apps via Context XML files. - Configured to behave similar to the legacy ContextDeployer --> - <Call name="addAppProvider"> - <Arg> - <New class="org.eclipse.jetty.deploy.providers.ContextProvider"> - <Set name="monitoredDir"><Property name="jetty.home" default="." />/contexts</Set> - <Set name="scanInterval">5</Set> - </New> - </Arg> - </Call> - <!-- Providers of Apps via WAR file existence. - Configured to behave similar to the legacy WebAppDeployer --> - <Call name="addAppProvider"> - <Arg> - <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> - <Set name="monitoredDir"><Property name="jetty.home" default="." />/webapps</Set> - <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set> - <Set name="scanInterval">5</Set> - <Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set> - </New> - </Arg> - </Call> - </New> - </Arg> - </Call> - - - <!-- =========================================================== --> - <!-- Configure Authentication Login Service --> - <!-- Realms may be configured for the entire server here, or --> - <!-- they can be configured for a specific web app in a context --> - <!-- configuration (see $(jetty.home)/contexts/test.xml for an --> - <!-- example). --> - <!-- =========================================================== --> - <Call name="addBean"> - <Arg> - <New class="org.eclipse.jetty.security.HashLoginService"> - <Set name="name">Test Realm</Set> - <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set> - <Set name="refreshInterval">0</Set> - </New> - </Arg> - </Call> - - <!-- =========================================================== --> - <!-- Configure Request Log --> - <!-- Request logs may be configured for the entire server here, --> - <!-- or they can be configured for a specific web app in a --> - <!-- contexts configuration (see $(jetty.home)/contexts/test.xml --> - <!-- for an example). --> - <!-- =========================================================== --> - <Ref id="RequestLog"> - <Set name="requestLog"> - <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> - <Set name="filename"><SystemProperty name="jetty.home" default="."/>/logs/yyyy_mm_dd.request.log</Set> - <Set name="filenameDateFormat">yyyy_MM_dd</Set> - <Set name="retainDays">90</Set> - <Set name="append">true</Set> - <Set name="extended">false</Set> - <Set name="logCookies">false</Set> - <Set name="LogTimeZone">GMT</Set> - </New> - </Set> - </Ref> - - <!-- =========================================================== --> <!-- extra options --> <!-- =========================================================== --> <Set name="stopAtShutdown">true</Set> diff --git a/jetty-server/src/main/config/etc/realm.properties b/jetty-server/src/main/config/etc/realm.properties deleted file mode 100644 index cbf905de9f..0000000000 --- a/jetty-server/src/main/config/etc/realm.properties +++ /dev/null @@ -1,21 +0,0 @@ -# -# This file defines users passwords and roles for a HashUserRealm -# -# The format is -# <username>: <password>[,<rolename> ...] -# -# Passwords may be clear text, obfuscated or checksummed. The class -# org.eclipse.util.Password should be used to generate obfuscated -# passwords or password checksums -# -# If DIGEST Authentication is used, the password must be in a recoverable -# format, either plain text or OBF:. -# -jetty: MD5:164c88b302622e17050af52c89945d44,user -admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin -other: OBF:1xmk1w261u9r1w1c1xmq,user -plain: plain,user -user: password,user - -# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password -digest: MD5:6e120743ad67abfbc385bc2bb754e297,user diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 76064c4656..7fed43a9a1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -68,15 +68,10 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector private boolean _useDNS; private boolean _forwarded; private String _hostHeader; - private String _forwardedHostHeader = "X-Forwarded-Host"; // default to - // mod_proxy_http - // header - private String _forwardedServerHeader = "X-Forwarded-Server"; // default to - // mod_proxy_http - // header - private String _forwardedForHeader = "X-Forwarded-For"; // default to - // mod_proxy_http - // header + + private String _forwardedHostHeader = "X-Forwarded-Host"; + private String _forwardedServerHeader = "X-Forwarded-Server"; + private String _forwardedForHeader = "X-Forwarded-For"; private boolean _reuseAddress = true; protected int _maxIdleTime = 200000; @@ -87,101 +82,70 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector private final AtomicLong _statsStartedAt = new AtomicLong(-1L); - private final CounterStatistic _connectionStats = new CounterStatistic(); // connections - // to - // server - private final SampleStatistic _requestStats = new SampleStatistic(); // requests - // per - // connection - private final SampleStatistic _connectionDurationStats = new SampleStatistic(); // duration - // of - // a - // connection + /** connections to server */ + private final CounterStatistic _connectionStats = new CounterStatistic(); + /** requests per connection */ + private final SampleStatistic _requestStats = new SampleStatistic(); + /** duration of a connection */ + private final SampleStatistic _connectionDurationStats = new SampleStatistic(); - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /** */ public AbstractConnector() { } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ public final Buffer newBuffer(int size) { // TODO remove once no overrides established return null; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override public Buffer newRequestBuffer(int size) { return new ByteArrayBuffer(size); } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override public Buffer newRequestHeader(int size) { return new ByteArrayBuffer(size); } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override public Buffer newResponseBuffer(int size) { return new ByteArrayBuffer(size); } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override public Buffer newResponseHeader(int size) { return new ByteArrayBuffer(size); } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override protected boolean isRequestHeader(Buffer buffer) { return true; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override protected boolean isResponseHeader(Buffer buffer) { return true; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* */ public Server getServer() @@ -189,19 +153,13 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector return _server; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ public void setServer(Server server) { _server = server; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.http.HttpListener#getHttpServer() */ @@ -210,19 +168,13 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector return _threadPool; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ public void setThreadPool(ThreadPool pool) { _threadPool = pool; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /** */ public void setHost(String host) @@ -230,10 +182,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector _host = host; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* */ public String getHost() @@ -241,10 +190,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector return _host; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.server.server.HttpListener#setPort(int) */ @@ -253,10 +199,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector _port = port; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.server.server.HttpListener#getPort() */ @@ -490,8 +433,6 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector try { socket.setTcpNoDelay(true); - if (_maxIdleTime >= 0) - socket.setSoTimeout(_maxIdleTime); if (_soLingerTime >= 0) socket.setSoLinger(true,_soLingerTime / 1000); else @@ -777,7 +718,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector /* ------------------------------------------------------------ */ /** - * @param forwardedHostHeader + * @param forwardedServerHeader * The header name for forwarded server (default * x-forwarded-server) */ @@ -794,12 +735,12 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector /* ------------------------------------------------------------ */ /** - * @param forwardedHostHeader + * @param forwardedRemoteAddressHeader * The header name for forwarded for (default x-forwarded-for) */ - public void setForwardedForHeader(String forwardedRemoteAddressHeade) + public void setForwardedForHeader(String forwardedRemoteAddressHeader) { - _forwardedForHeader = forwardedRemoteAddressHeade; + _forwardedForHeader = forwardedRemoteAddressHeader; } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java index b4ead4ad3b..5aad13129a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java @@ -672,7 +672,7 @@ public class AsyncContinuation implements AsyncContext, Continuation { _expireAt = System.currentTimeMillis()+_timeoutMs; long wait=_timeoutMs; - while (_expireAt>0 && wait>0) + while (_expireAt>0 && wait>0 && _connection.getServer().isRunning()) { try { @@ -685,7 +685,7 @@ public class AsyncContinuation implements AsyncContext, Continuation wait=_expireAt-System.currentTimeMillis(); } - if (_expireAt>0 && wait<=0) + if (_expireAt>0 && wait<=0 && _connection.getServer().isRunning()) { expired(); } @@ -823,11 +823,19 @@ public class AsyncContinuation implements AsyncContext, Continuation } /* ------------------------------------------------------------ */ - public void start(Runnable run) + public void start(final Runnable run) { final AsyncEventState event=_event; if (event!=null) - ((Context)event.getServletContext()).getContextHandler().handle(run); + { + _connection.getServer().getThreadPool().dispatch(new Runnable() + { + public void run() + { + ((Context)event.getServletContext()).getContextHandler().handle(run); + } + }); + } } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java index 5328a1a143..5a77634e0a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java @@ -131,14 +131,14 @@ public interface Connector extends LifeCycle /* ------------------------------------------------------------ */ /** * @return The port to use when redirecting a request if a data constraint of integral is - * required. See {@link org.eclipse.jetty.server.server.security.Constraint#getDataConstraint()} + * required. See {@link org.eclipse.jetty.http.security.Constraint#getDataConstraint()} */ int getIntegralPort(); /* ------------------------------------------------------------ */ /** * @return The schema to use when redirecting a request if a data constraint of integral is - * required. See {@link org.eclipse.jetty.server.server.security.Constraint#getDataConstraint()} + * required. See {@link org.eclipse.jetty.http.security.Constraint#getDataConstraint()} */ String getIntegralScheme(); @@ -152,7 +152,7 @@ public interface Connector extends LifeCycle /* ------------------------------------------------------------ */ /** * @return The port to use when redirecting a request if a data constraint of confidential is - * required. See {@link org.eclipse.jetty.server.server.security.Constraint#getDataConstraint()} + * required. See {@link org.eclipse.jetty.http.security.Constraint#getDataConstraint()} */ int getConfidentialPort(); @@ -160,7 +160,7 @@ public interface Connector extends LifeCycle /* ------------------------------------------------------------ */ /** * @return The schema to use when redirecting a request if a data constraint of confidential is - * required. See {@link org.eclipse.jetty.server.server.security.Constraint#getDataConstraint()} + * required. See {@link org.eclipse.jetty.http.security.Constraint#getDataConstraint()} */ String getConfidentialScheme(); @@ -185,15 +185,23 @@ public interface Connector extends LifeCycle /** Persist an endpoint. * Called after every request if the connection is to remain open. * @param endpoint - * @param request * @throws IOException */ void persist(EndPoint endpoint) throws IOException; /* ------------------------------------------------------------ */ + /** + * @return The hostname representing the interface to which + * this connector will bind, or null for all interfaces. + */ String getHost(); /* ------------------------------------------------------------ */ + /** + * Set the hostname of the interface to bind to. + * @param hostname The hostname representing the interface to which + * this connector will bind, or null for all interfaces. + */ void setHost(String hostname); /* ------------------------------------------------------------ */ @@ -212,8 +220,8 @@ public interface Connector extends LifeCycle /* ------------------------------------------------------------ */ /** - * @return The actual port the connector is listening on or -1 if there - * is no port or the connector is not open. + * @return The actual port the connector is listening on or + * -1 if it has not been opened, or -2 if it has been closed. */ int getLocalPort(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HandlerContainer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HandlerContainer.java index a64c0f8d0b..32406ce3f4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HandlerContainer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HandlerContainer.java @@ -18,8 +18,8 @@ import org.eclipse.jetty.util.component.LifeCycle; /** * A Handler that contains other Handlers. * <p> - * The contained handlers may be one (see @{link {@link org.eclipse.jetty.server.server.handler.HandlerWrapper}) - * or many (see {@link org.eclipse.jetty.server.server.handler.HandlerList} or {@link org.eclipse.jetty.server.server.handler.HandlerCollection}. + * The contained handlers may be one (see @{link {@link org.eclipse.jetty.server.handler.HandlerWrapper}) + * or many (see {@link org.eclipse.jetty.server.handler.HandlerList} or {@link org.eclipse.jetty.server.handler.HandlerCollection}. * */ public interface HandlerContainer extends LifeCycle diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index c85638b9cc..8c71df016c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -16,7 +16,6 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; - import javax.servlet.DispatcherType; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; @@ -42,13 +41,12 @@ import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.Parser; import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.UncheckedIOException; import org.eclipse.jetty.io.UncheckedPrintWriter; -import org.eclipse.jetty.io.BufferCache.CachedBuffer; -import org.eclipse.jetty.io.nio.SelectChannelEndPoint; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; @@ -69,7 +67,7 @@ import org.eclipse.jetty.util.thread.Timeout; * with the connection via the parser and/or generator. * </p> * <p> - * The connection state is held by 3 separate state machines: The request state, the + * The connection state is held by 3 separate state machines: The request state, the * response state and the continuation state. All three state machines must be driven * to completion for every request, and all three can complete in any order. * </p> @@ -77,12 +75,12 @@ import org.eclipse.jetty.util.thread.Timeout; * The HttpConnection support protocol upgrade. If on completion of a request, the * response code is 101 (switch protocols), then the org.eclipse.jetty.io.Connection * request attribute is checked to see if there is a new Connection instance. If so, - * the new connection is returned from {@link #handle()} and is used for future + * the new connection is returned from {@link #handle()} and is used for future * handling of the underlying connection. Note that for switching protocols that * don't use 101 responses (eg CONNECT), the response should be sent and then the - * status code changed to 101 before returning from the handler. Implementors + * status code changed to 101 before returning from the handler. Implementors * of new Connection types should be careful to extract any buffered data from - * (HttpParser)http.getParser()).getHeaderBuffer() and + * (HttpParser)http.getParser()).getHeaderBuffer() and * (HttpParser)http.getParser()).getBodyBuffer() to initialise their new connection. * </p> * @@ -150,7 +148,7 @@ public class HttpConnection implements Connection HttpBuffers ab = (HttpBuffers)_connector; _parser = new HttpParser(ab.getRequestBuffers(), endpoint, new RequestHandler()); _requestFields = new HttpFields(); - _responseFields = new HttpFields(); + _responseFields = new HttpFields(server.getMaxCookieVersion()); _request = new Request(this); _response = new Response(this); _generator = new HttpGenerator(ab.getResponseBuffers(), _endp); @@ -167,7 +165,7 @@ public class HttpConnection implements Connection _endp = endpoint; _parser = parser; _requestFields = new HttpFields(); - _responseFields = new HttpFields(); + _responseFields = new HttpFields(server.getMaxCookieVersion()); _request = request; _response = new Response(this); _generator = generator; @@ -192,7 +190,13 @@ public class HttpConnection implements Connection { return _requests; } - + + /* ------------------------------------------------------------ */ + public Server getServer() + { + return _server; + } + /* ------------------------------------------------------------ */ /** * @return The time this connection was established. @@ -378,6 +382,8 @@ public class HttpConnection implements Connection /* ------------------------------------------------------------ */ public Connection handle() throws IOException { + Connection connection = this; + // Loop while more in buffer boolean more_in_buffer =true; // assume true until proven otherwise boolean progress=true; @@ -389,12 +395,15 @@ public class HttpConnection implements Connection _handling=true; setCurrentConnection(this); - while (more_in_buffer) + while (more_in_buffer && _endp.isOpen()) { try { if (_request._async.isAsync()) { + // TODO - handle the case of input being read for a + // suspended request. + Log.debug("async request",_request); if (!_request._async.isComplete()) handleRequest(); @@ -454,38 +463,44 @@ public class HttpConnection implements Connection _parser.reset(true); _endp.close(); - throw e; } finally { more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput(); + // Is this request/response round complete? if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput()) { - if (_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101) + // look for a switched connection instance? + Connection switched=(_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101) + ?(Connection)_request.getAttribute("org.eclipse.jetty.io.Connection"):null; + + // have we switched? + if (switched!=null) { - Connection connection = (Connection)_request.getAttribute("org.eclipse.jetty.io.Connection"); - if (connection!=null) + _parser.reset(true); + _generator.reset(true); + connection=switched; + } + else + { + // No switch, so cleanup and reset + if (!_generator.isPersistent()) { _parser.reset(true); - return connection; + more_in_buffer=false; + _endp.close(); } - } - - if (!_generator.isPersistent()) - { - _parser.reset(true); - more_in_buffer=false; - } - if (more_in_buffer) - { - reset(false); - more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput(); + if (more_in_buffer) + { + reset(false); + more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput(); + } + else + reset(true); + progress=true; } - else - reset(true); - progress=true; } if (_request.isAsyncStarted()) @@ -493,7 +508,7 @@ public class HttpConnection implements Connection Log.debug("return with suspended request"); more_in_buffer=false; } - else if (_generator.isCommitted() && !_generator.isComplete() && _endp instanceof AsyncEndPoint) + else if (_generator.isCommitted() && !_generator.isComplete() && _endp instanceof AsyncEndPoint) ((AsyncEndPoint)_endp).setWritable(false); } } @@ -503,7 +518,7 @@ public class HttpConnection implements Connection setCurrentConnection(null); _handling=false; } - return this; + return connection; } /* ------------------------------------------------------------ */ @@ -567,7 +582,7 @@ public class HttpConnection implements Connection { _uri.getPort(); info=URIUtil.canonicalPath(_uri.getDecodedPath()); - if (info==null) + if (info==null && !_request.getMethod().equals(HttpMethods.CONNECT)) throw new HttpException(400); _request.setPathInfo(info); @@ -623,7 +638,6 @@ public class HttpConnection implements Connection Log.debug(e); _request.setHandled(true); _generator.sendError(info==null?400:500, null, null, true); - } finally { @@ -683,6 +697,10 @@ public class HttpConnection implements Connection _generator.setResponse(_response.getStatus(), _response.getReason()); try { + // If the client was expecting 100 continues, but we sent something + // else, then we need to close the connection + if (_expect100Continue && _response.getStatus()!=100) + _generator.setPersistent(false); _generator.completeHeader(_responseFields, last); } catch(IOException io) @@ -832,7 +850,20 @@ public class HttpConnection implements Connection try { - _uri.parse(uri.array(), uri.getIndex(), uri.length()); + switch (HttpMethods.CACHE.getOrdinal(method)) + { + case HttpMethods.CONNECT_ORDINAL: + _uri.parseConnect(uri.array(), uri.getIndex(), uri.length()); + break; + + case HttpMethods.HEAD_ORDINAL: + _head=true; + // fall through + + default: + _uri.parse(uri.array(), uri.getIndex(), uri.length()); + } + _request.setUri(_uri); if (version==null) @@ -847,8 +878,6 @@ public class HttpConnection implements Connection if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL; _request.setProtocol(version.toString()); } - - _head = method == HttpMethods.HEAD_BUFFER; // depends on method being decached. } catch (Exception e) { @@ -968,6 +997,8 @@ public class HttpConnection implements Connection @Override public void headerComplete() throws IOException { + if (_endp instanceof AsyncEndPoint) + ((AsyncEndPoint)_endp).scheduleIdle(); _requests++; _generator.setVersion(_version); switch (_version) @@ -976,6 +1007,10 @@ public class HttpConnection implements Connection break; case HttpVersions.HTTP_1_0_ORDINAL: _generator.setHead(_head); + + if (_server.getSendDateHeader()) + _generator.setDate(_request.getTimeStampBuffer()); + break; case HttpVersions.HTTP_1_1_ORDINAL: _generator.setHead(_head); @@ -994,7 +1029,10 @@ public class HttpConnection implements Connection if (_expect) { - _generator.sendError(HttpStatus.EXPECTATION_FAILED_417, null, null, true); + _generator.setResponse(HttpStatus.EXPECTATION_FAILED_417, null); + _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER); + _generator.completeHeader(_responseFields, true); + _generator.complete(); return; } @@ -1019,6 +1057,8 @@ public class HttpConnection implements Connection @Override public void content(Buffer ref) throws IOException { + if (_endp instanceof AsyncEndPoint) + ((AsyncEndPoint)_endp).scheduleIdle(); if (_delayedHandling) { _delayedHandling=false; @@ -1148,13 +1188,13 @@ public class HttpConnection implements Connection else { _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, - contentType+";charset="+QuotedStringTokenizer.quote(enc,";= ")); + contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= ")); } } else { _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, - contentType+";charset="+QuotedStringTokenizer.quote(enc,";= ")); + contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= ")); } } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index 403c29d803..e7190a7b19 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -28,7 +28,7 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2; /** Output. * * <p> - * Implements {@link javax.servlet.ServletOutputStream} from the {@link javax.servlet} package. + * Implements {@link javax.servlet.ServletOutputStream} from the <code>javax.servlet</code> package. * </p> * A {@link ServletOutputStream} implementation that writes content * to a {@link AbstractGenerator}. The class is designed to be reused diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java index 6385d2785a..30267c2a46 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java @@ -33,14 +33,6 @@ public class LocalConnector extends AbstractConnector return this; } - /** - * @deprecated Not needed anymore, as there is no need to reopen the connector to reset its state - */ - @Deprecated - public void reopen() - { - } - public String getResponses(String requests) throws Exception { return getResponses(requests, false); @@ -121,7 +113,7 @@ public class LocalConnector extends AbstractConnector boolean leaveOpen = keepOpen; try { - while (endPoint.getIn().length() > 0) + while (endPoint.getIn().length() > 0 && endPoint.isOpen()) { while (true) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java index 5a19545b10..f90e7818fc 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; @@ -20,7 +20,6 @@ import java.io.Writer; import java.util.ArrayList; import java.util.Locale; import java.util.TimeZone; - import javax.servlet.http.Cookie; import org.eclipse.jetty.http.HttpHeaders; @@ -28,7 +27,6 @@ import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.util.DateCache; import org.eclipse.jetty.util.RolloverFileOutputStream; import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; @@ -40,12 +38,13 @@ import org.eclipse.jetty.util.log.Log; * Format (single log format). This log format can be output by most web * servers, and almost all web log analysis software can understand these * formats. - * - * - * - * + * * @org.apache.xbean.XBean element="ncsaLog" */ + +/* ------------------------------------------------------------ */ +/** + */ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog { private String _filename; @@ -62,6 +61,7 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog private boolean _logLatency = false; private boolean _logCookies = false; private boolean _logServer = false; + private boolean _logDispatch = false; private transient OutputStream _out; private transient OutputStream _fileOut; @@ -71,6 +71,10 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog private transient ArrayList _buffers; private transient char[] _copy; + /* ------------------------------------------------------------ */ + /** + * Create request log object with default settings. + */ public NCSARequestLog() { _extended = true; @@ -80,9 +84,11 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog /* ------------------------------------------------------------ */ /** - * @param filename - * The filename for the request log. This may be in the - * format expected by {@link RolloverFileOutputStream} + * Create request log object with specified output file name. + * + * @param filename the file name for the request log. + * This may be in the format expected + * by {@link RolloverFileOutputStream} */ public NCSARequestLog(String filename) { @@ -94,9 +100,12 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog /* ------------------------------------------------------------ */ /** - * @param filename - * The filename for the request log. This may be in the - * format expected by {@link RolloverFileOutputStream} + * Set the output file name of the request log. + * The file name may be in the format expected by + * {@link RolloverFileOutputStream}. + * + * @param filename file name of the request log + * */ public void setFilename(String filename) { @@ -109,11 +118,25 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog _filename = filename; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the output file name of the request log. + * + * @return file name of the request log + */ public String getFilename() { return _filename; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the file name of the request log with the expanded + * date wildcard if the output is written to the disk using + * {@link RolloverFileOutputStream}. + * + * @return file name of the request log, or null if not applicable + */ public String getDatedFilename() { if (_fileOut instanceof RolloverFileOutputStream) @@ -123,116 +146,306 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog /* ------------------------------------------------------------ */ /** - * @param format - * Format for the timestamps in the log file. If not set, the - * pre-formated request timestamp is used. + * Set the timestamp format for request log entries in the file. + * If this is not set, the pre-formated request timestamp is used. + * + * @param format timestamp format string */ public void setLogDateFormat(String format) { _logDateFormat = format; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the timestamp format string for request log entries. + * + * @return timestamp format string. + */ public String getLogDateFormat() { return _logDateFormat; } - + + /* ------------------------------------------------------------ */ + /** + * Set the locale of the request log. + * + * @param logLocale locale object + */ public void setLogLocale(Locale logLocale) { _logLocale = logLocale; } - + + /* ------------------------------------------------------------ */ + /** + * Retrieve the locale of the request log. + * + * @return locale object + */ public Locale getLogLocale() { return _logLocale; } + /* ------------------------------------------------------------ */ + /** + * Set the timezone of the request log. + * + * @param tz timezone string + */ public void setLogTimeZone(String tz) { _logTimeZone = tz; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the timezone of the request log. + * + * @return timezone string + */ public String getLogTimeZone() { return _logTimeZone; } + /* ------------------------------------------------------------ */ + /** + * Set the number of days before rotated log files are deleted. + * + * @param retainDays number of days to keep a log file + */ public void setRetainDays(int retainDays) { _retainDays = retainDays; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the number of days before rotated log files are deleted. + * + * @return number of days to keep a log file + */ public int getRetainDays() { return _retainDays; } + /* ------------------------------------------------------------ */ + /** + * Set the extended request log format flag. + * + * @param extended true - log the extended request information, + * false - do not log the extended request information + */ public void setExtended(boolean extended) { _extended = extended; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the extended request log format flag. + * + * @return value of the flag + */ public boolean isExtended() { return _extended; } + /* ------------------------------------------------------------ */ + /** + * Set append to log flag. + * + * @param append true - request log file will be appended after restart, + * false - request log file will be overwritten after restart + */ public void setAppend(boolean append) { _append = append; } + /* ------------------------------------------------------------ */ + /** + * Retrieve append to log flag. + * + * @return value of the flag + */ public boolean isAppend() { return _append; } + /* ------------------------------------------------------------ */ + /** + * Set request paths that will not be logged. + * + * @param ignorePaths array of request paths + */ public void setIgnorePaths(String[] ignorePaths) { _ignorePaths = ignorePaths; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the request paths that will not be logged. + * + * @return array of request paths + */ public String[] getIgnorePaths() { return _ignorePaths; } + /* ------------------------------------------------------------ */ + /** + * Controls logging of the request cookies. + * + * @param logCookies true - values of request cookies will be logged, + * false - values of request cookies will not be logged + */ public void setLogCookies(boolean logCookies) { _logCookies = logCookies; } + /* ------------------------------------------------------------ */ + /** + * Retrieve log cookies flag + * + * @return value of the flag + */ public boolean getLogCookies() { return _logCookies; } - public boolean getLogServer() + /* ------------------------------------------------------------ */ + /** + * Controls logging of the request hostname. + * + * @param logServer true - request hostname will be logged, + * false - request hostname will not be logged + */ + public void setLogServer(boolean logServer) { - return _logServer; + _logServer = logServer; } - public void setLogServer(boolean logServer) + /* ------------------------------------------------------------ */ + /** + * Retrieve log hostname flag. + * + * @return value of the flag + */ + public boolean getLogServer() { - _logServer = logServer; + return _logServer; } + /* ------------------------------------------------------------ */ + /** + * Controls logging of request processing time. + * + * @param logLatency true - request processing time will be logged + * false - request processing time will not be logged + */ public void setLogLatency(boolean logLatency) { _logLatency = logLatency; } + /* ------------------------------------------------------------ */ + /** + * Retrieve log request processing time flag. + * + * @return value of the flag + */ public boolean getLogLatency() { return _logLatency; } + /* ------------------------------------------------------------ */ + /** + * Controls whether the actual IP address of the connection or + * the IP address from the X-Forwarded-For header will be logged. + * + * @param preferProxiedForAddress true - IP address from header will be logged, + * false - IP address from the connection will be logged + */ public void setPreferProxiedForAddress(boolean preferProxiedForAddress) { _preferProxiedForAddress = preferProxiedForAddress; } + + /* ------------------------------------------------------------ */ + /** + * Retrieved log X-Forwarded-For IP address flag. + * + * @return value of the flag + */ + public boolean getPreferProxiedForAddress() + { + return _preferProxiedForAddress; + } + + /* ------------------------------------------------------------ */ + /** + * Set the log file name date format. + * @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String) + * + * @param logFileDateFormat format string that is passed to {@link RolloverFileOutputStream} + */ + public void setFilenameDateFormat(String logFileDateFormat) + { + _filenameDateFormat = logFileDateFormat; + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve the file name date format string. + * + * @return the log File Date Format + */ + public String getFilenameDateFormat() + { + return _filenameDateFormat; + } + + /* ------------------------------------------------------------ */ + /** + * Controls logging of the request dispatch time + * + * @param value true - request dispatch time will be logged + * false - request dispatch time will not be logged + */ + public void setLogDispatch(boolean value) + { + _logDispatch = value; + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve request dispatch time logging flag + * + * @return value of the flag + */ + public boolean isLogDispatch() + { + return _logDispatch; + } /* ------------------------------------------------------------ */ + /** + * Writes the request and response information to the output stream. + * + * @see org.eclipse.jetty.server.RequestLog#log(org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response) + */ public void log(Request request, Response response) { if (!isStarted()) @@ -254,7 +467,7 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog u8buf = size==0?new Utf8StringBuilder(160):(Utf8StringBuilder)_buffers.remove(size-1); buf = u8buf.getStringBuilder(); } - + if (_logServer) { buf.append(request.getServerName()); @@ -277,7 +490,7 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog buf.append(((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName()); else buf.append(" - "); - + buf.append(" ["); if (_logDateCache != null) buf.append(_logDateCache.format(request.getTimeStamp())); @@ -335,12 +548,12 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog buf.append(StringUtil.__LINE_SEPARATOR); int l=buf.length(); if (l>_copy.length) - l=_copy.length; - buf.getChars(0,l,_copy,0); + l=_copy.length; + buf.getChars(0,l,_copy,0); _writer.write(_copy,0,l); _writer.flush(); u8buf.reset(); - _buffers.add(u8buf); + _buffers.add(u8buf); } } else @@ -349,11 +562,11 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog { int l=buf.length(); if (l>_copy.length) - l=_copy.length; - buf.getChars(0,l,_copy,0); + l=_copy.length; + buf.getChars(0,l,_copy,0); _writer.write(_copy,0,l); u8buf.reset(); - _buffers.add(u8buf); + _buffers.add(u8buf); // TODO do outside synchronized scope if (_extended) @@ -362,13 +575,13 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog // TODO do outside synchronized scope if (_logCookies) { - Cookie[] cookies = request.getCookies(); + Cookie[] cookies = request.getCookies(); if (cookies == null || cookies.length == 0) _writer.write(" -"); else { _writer.write(" \""); - for (int i = 0; i < cookies.length; i++) + for (int i = 0; i < cookies.length; i++) { if (i != 0) _writer.write(';'); @@ -379,11 +592,20 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog _writer.write('\"'); } } + + final long now = System.currentTimeMillis(); + final long start = request.getTimeStamp(); + final long dispatch = request.getDispatchTime(); + if (_logDispatch) + { + _writer.write(' '); + _writer.write(Long.toString(now - (dispatch==0 ? start:dispatch))); + } if (_logLatency) { _writer.write(' '); - _writer.write(TypeUtil.toString(System.currentTimeMillis() - request.getTimeStamp())); + _writer.write(Long.toString(now - start)); } _writer.write(StringUtil.__LINE_SEPARATOR); @@ -399,9 +621,17 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog } /* ------------------------------------------------------------ */ - protected void logExtended(Request request, - Response response, - Writer writer) throws IOException + /** + * Writes extended request and response information to the output stream. + * + * @param request request object + * @param response response object + * @param writer log file writer + * @throws IOException + */ + protected void logExtended(Request request, + Response response, + Writer writer) throws IOException { String referer = request.getHeader(HttpHeaders.REFERER); if (referer == null) @@ -425,6 +655,11 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog } /* ------------------------------------------------------------ */ + /** + * Set up request logging and open log file. + * + * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() + */ @Override protected void doStart() throws Exception { @@ -461,6 +696,11 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog } /* ------------------------------------------------------------ */ + /** + * Close the log file and perform cleanup. + * + * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() + */ @Override protected void doStop() throws Exception { @@ -492,28 +732,4 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog _buffers = null; _copy = null; } - - /* ------------------------------------------------------------ */ - /** - * @return the log File Date Format - */ - public String getFilenameDateFormat() - { - return _filenameDateFormat; - } - - /* ------------------------------------------------------------ */ - /** - * Set the log file date format. - * - * @see {@link RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String)} - * @param logFileDateFormat - * the logFileDateFormat to pass to - * {@link RolloverFileOutputStream} - */ - public void setFilenameDateFormat(String logFileDateFormat) - { - _filenameDateFormat = logFileDateFormat; - } - } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 6a06cc8ffa..a1c5599fc6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -82,26 +82,26 @@ import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ /** Jetty Request. * <p> - * Implements {@link javax.servlet.http.HttpServletRequest} from the {@link javax.servlet.http} package. + * Implements {@link javax.servlet.http.HttpServletRequest} from the <code>javax.servlet.http</code> package. * </p> * <p> * The standard interface of mostly getters, * is extended with setters so that the request is mutable by the handlers that it is * passed to. This allows the request object to be as lightweight as possible and not - * actually implement any significant behaviour. For example<ul> + * actually implement any significant behavior. For example<ul> * - * <li>The {@link Request#getContextPath} method will return null, until the requeset has been - * passed to a {@link ContextHandler} which matches the {@link Request#getPathInfo} with a context - * path and calls {@link Request#setContextPath} as a result.</li> + * <li>The {@link Request#getContextPath()} method will return null, until the request has been + * passed to a {@link ContextHandler} which matches the {@link Request#getPathInfo()} with a context + * path and calls {@link Request#setContextPath(String)} as a result.</li> * * <li>the HTTP session methods * will all return null sessions until such time as a request has been passed to - * a {@link org.eclipse.jetty.servlet.SessionHandler} which checks for session cookies + * a {@link org.eclipse.jetty.server.session.SessionHandler} which checks for session cookies * and enables the ability to create new sessions.</li> * - * <li>The {@link Request#getServletPath} method will return null until the request has been - * passed to a {@link org.eclipse.jetty.servlet.ServletHandler} and the pathInfo matched - * against the servlet URL patterns and {@link Request#setServletPath} called as a result.</li> + * <li>The {@link Request#getServletPath()} method will return null until the request has been + * passed to a <code>org.eclipse.jetty.servlet.ServletHandler</code> and the pathInfo matched + * against the servlet URL patterns and {@link Request#setServletPath(String)} called as a result.</li> * </ul> * * A request instance is created for each {@link HttpConnection} accepted by the server @@ -166,7 +166,8 @@ public class Request implements HttpServletRequest private HttpSession _session; private SessionManager _sessionManager; private long _timeStamp; - + private long _dispatchTime; + private Buffer _timeStampBuffer; private HttpURI _uri; @@ -1225,6 +1226,16 @@ public class Request implements HttpServletRequest } /* ------------------------------------------------------------ */ + /** Get timestamp of the request dispatch + * + * @return timestamp + */ + public long getDispatchTime() + { + return _dispatchTime; + } + + /* ------------------------------------------------------------ */ public boolean isAsyncStarted() { return _async.isAsyncStarted(); @@ -1565,7 +1576,9 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ /** - * @param context + * Set request context + * + * @param context context object */ public void setContext(Context context) { @@ -1575,7 +1588,8 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ /** - * @return True if this is the first call of takeNewContext() since the last {@link #setContext(Context)} call. + * @return True if this is the first call of {@link #takeNewContext()} + * since the last {@link #setContext(org.eclipse.jetty.server.handler.ContextHandler.Context)} call. */ public boolean takeNewContext() { @@ -1587,7 +1601,7 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ /** * Sets the "context path" for this request - * @see HttpServletRequest#getContextPath + * @see HttpServletRequest#getContextPath() */ public void setContextPath(String contextPath) { @@ -1801,6 +1815,16 @@ public class Request implements HttpServletRequest } /* ------------------------------------------------------------ */ + /** Set timetstamp of request dispatch + * + * @param value timestamp + */ + public void setDispatchTime(long value) + { + _dispatchTime = value; + } + + /* ------------------------------------------------------------ */ public AsyncContext startAsync() throws IllegalStateException { if (!_asyncSupported) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java index 2e95bbc0e0..a2b7a9b36c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java @@ -16,9 +16,8 @@ package org.eclipse.jetty.server; import org.eclipse.jetty.util.component.LifeCycle; /** - * A <code>RequestLog</code> can be attached to a {@link org.eclipse.jetty.server.server.handler.RequestLogHandler} to enable logging of requests/responses. - * - * @see Server#setRequestLog + * A <code>RequestLog</code> can be attached to a {@link org.eclipse.jetty.server.handler.RequestLogHandler} to enable + * logging of requests/responses. */ public interface RequestLog extends LifeCycle { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 0230f90665..37ed17efca 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -17,6 +17,8 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Collection; import java.util.Collections; +import java.util.List; +import java.util.List; import java.util.Locale; import javax.servlet.ServletOutputStream; @@ -29,6 +31,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpHeaderValues; import org.eclipse.jetty.http.HttpHeaders; +import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersions; @@ -43,14 +46,10 @@ import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; -/* ------------------------------------------------------------ */ /** Response. * <p> - * Implements {@link javax.servlet.HttpServletResponse} from the {@link javax.servlet} package. + * Implements {@link javax.servlet.http.HttpServletResponse} from the <code>javax.servlet.http</code> package. * </p> - * - * - * */ public class Response implements HttpServletResponse { @@ -156,16 +155,30 @@ public class Response implements HttpServletResponse */ public String encodeURL(String url) { - Request request=_connection.getRequest(); + final Request request=_connection.getRequest(); SessionManager sessionManager = request.getSessionManager(); if (sessionManager==null) return url; + + if (sessionManager.isCheckingRemoteSessionIdEncoding() && URIUtil.hasScheme(url)) + { + HttpURI uri = new HttpURI(url); + int port=uri.getPort(); + if (port<0) + port = HttpSchemes.HTTPS.equalsIgnoreCase(uri.getScheme())?443:80; + if (!request.getServerName().equalsIgnoreCase(uri.getHost()) || + request.getServerPort()!=port || + !uri.getPath().startsWith(request.getContextPath())) + return url; + } + String sessionURLPrefix = sessionManager.getSessionIdPathParameterNamePrefix(); if (sessionURLPrefix==null) return url; if (url==null) return null; + // should not encode if cookies in evidence if (request.isRequestedSessionIdFromCookie()) { @@ -190,15 +203,12 @@ public class Response implements HttpServletResponse if (session == null) return url; - // invalid session if (!sessionManager.isValid(session)) return url; String id=sessionManager.getNodeId(session); - - // TODO Check host and port are for this server // Already encoded int prefix=url.indexOf(sessionURLPrefix); if (prefix!=-1) @@ -224,7 +234,7 @@ public class Response implements HttpServletResponse } /* ------------------------------------------------------------ */ - /* + /** * @see javax.servlet.http.HttpServletResponse#encodeRedirectURL(java.lang.String) */ public String encodeRedirectURL(String url) @@ -233,21 +243,17 @@ public class Response implements HttpServletResponse } /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#encodeUrl(java.lang.String) - */ + @Deprecated public String encodeUrl(String url) { return encodeURL(url); } /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#encodeRedirectUrl(java.lang.String) - */ + @Deprecated public String encodeRedirectUrl(String url) { - return encodeURL(url); + return encodeRedirectURL(url); } /* ------------------------------------------------------------ */ @@ -288,14 +294,14 @@ public class Response implements HttpServletResponse ContextHandler.Context context = request.getContext(); if (context!=null) error_handler=context.getContextHandler().getErrorHandler(); + if (error_handler==null) + error_handler = _connection.getConnector().getServer().getBean(ErrorHandler.class); if (error_handler!=null) { - // TODO - probably should reset these after the request? request.setAttribute(Dispatcher.ERROR_STATUS_CODE,new Integer(code)); request.setAttribute(Dispatcher.ERROR_MESSAGE, message); request.setAttribute(Dispatcher.ERROR_REQUEST_URI, request.getRequestURI()); request.setAttribute(Dispatcher.ERROR_SERVLET_NAME,request.getServletName()); - error_handler.handle(null,_connection.getRequest(),_connection.getRequest(),this ); } else @@ -715,7 +721,7 @@ public class Response implements HttpServletResponse if (_contentType==null) { - _contentType = _mimeType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType = _mimeType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } @@ -724,16 +730,16 @@ public class Response implements HttpServletResponse int i1=_contentType.indexOf("charset=",i0); if (i1<0) { - _contentType = _contentType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType = _contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); } else { int i8=i1+8; int i2=_contentType.indexOf(" ",i8); if (i2<0) - _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); else - _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quote(_characterEncoding,";= ")+_contentType.substring(i2); + _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ")+_contentType.substring(i2); } _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } @@ -861,12 +867,12 @@ public class Response implements HttpServletResponse } else if (i2<0) { - _contentType=contentType.substring(0,i1)+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=contentType.substring(0,i1)+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } else { - _contentType=contentType.substring(0,i1)+contentType.substring(i2)+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=contentType.substring(0,i1)+contentType.substring(i2)+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } @@ -912,7 +918,7 @@ public class Response implements HttpServletResponse else // No encoding in the params. { _cachedMimeType=null; - _contentType=_characterEncoding==null?contentType:contentType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=_characterEncoding==null?contentType:contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } @@ -933,13 +939,13 @@ public class Response implements HttpServletResponse } else { - _contentType=_mimeType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=_mimeType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } else { - _contentType=contentType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index 297e81f538..9ab0a6151d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -14,15 +14,12 @@ package org.eclipse.jetty.server; import java.io.IOException; -import java.lang.reflect.Method; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.ListIterator; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -30,7 +27,6 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.server.bio.SocketConnector; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.util.Attributes; @@ -74,7 +70,9 @@ public class Server extends HandlerWrapper implements Attributes private boolean _sendDateHeader = false; //send Date: header private int _graceful=0; private boolean _stopAtShutdown; + private int _maxCookieVersion=1; + /* ------------------------------------------------------------ */ public Server() { @@ -83,7 +81,7 @@ public class Server extends HandlerWrapper implements Attributes /* ------------------------------------------------------------ */ /** Convenience constructor - * Creates server and a {@link SocketConnector} at the passed port. + * Creates server and a {@link SelectChannelConnector} at the passed port. */ public Server(int port) { @@ -93,6 +91,20 @@ public class Server extends HandlerWrapper implements Attributes connector.setPort(port); setConnectors(new Connector[]{connector}); } + + /* ------------------------------------------------------------ */ + /** Convenience constructor + * Creates server and a {@link SelectChannelConnector} at the passed address. + */ + public Server(InetSocketAddress addr) + { + setServer(this); + + Connector connector=new SelectChannelConnector(); + connector.setHost(addr.getHostName()); + connector.setPort(addr.getPort()); + setConnectors(new Connector[]{connector}); + } /* ------------------------------------------------------------ */ @@ -198,7 +210,13 @@ public class Server extends HandlerWrapper implements Attributes HttpGenerator.setServerVersion(_version); MultiException mex=new MultiException(); - Iterator itor = _dependentBeans.iterator(); + if (_threadPool==null) + { + QueuedThreadPool tp=new QueuedThreadPool(); + setThreadPool(tp); + } + + Iterator<Object> itor = _dependentBeans.iterator(); while (itor.hasNext()) { try @@ -210,12 +228,6 @@ public class Server extends HandlerWrapper implements Attributes catch (Throwable e) {mex.add(e);} } - if (_threadPool==null) - { - QueuedThreadPool tp=new QueuedThreadPool(); - setThreadPool(tp); - } - if (_sessionIdManager!=null) _sessionIdManager.start(); @@ -299,7 +311,7 @@ public class Server extends HandlerWrapper implements Attributes if (!_dependentBeans.isEmpty()) { - ListIterator itor = _dependentBeans.listIterator(_dependentBeans.size()); + ListIterator<Object> itor = _dependentBeans.listIterator(_dependentBeans.size()); while (itor.hasPrevious()) { try @@ -313,7 +325,9 @@ public class Server extends HandlerWrapper implements Attributes } mex.ifExceptionThrow(); - ShutdownThread.deregister(this); + + if (getStopAtShutdown()) + ShutdownThread.deregister(this); } /* ------------------------------------------------------------ */ @@ -436,13 +450,30 @@ public class Server extends HandlerWrapper implements Attributes { return _sendDateHeader; } - + + /* ------------------------------------------------------------ */ + /** Get the maximum cookie version. + * @return the maximum set-cookie version sent by this server + */ + public int getMaxCookieVersion() + { + return _maxCookieVersion; + } + + /* ------------------------------------------------------------ */ + /** Set the maximum cookie version. + * @param maxCookieVersion the maximum set-cookie version sent by this server + */ + public void setMaxCookieVersion(int maxCookieVersion) + { + _maxCookieVersion = maxCookieVersion; + } /* ------------------------------------------------------------ */ /** * Add a LifeCycle object to be started/stopped * along with the Server. - * @deprecated Use {@link #addBean(LifeCycle)} + * @deprecated Use {@link #addBean(Object)} * @param c */ @Deprecated @@ -457,7 +488,7 @@ public class Server extends HandlerWrapper implements Attributes * The bean will be added to the servers {@link Container} * and if it is a {@link LifeCycle} instance, it will be * started/stopped along with the Server. - * @param c + * @param o the bean object to add */ public void addBean(Object o) { @@ -500,6 +531,34 @@ public class Server extends HandlerWrapper implements Attributes return beans; } + /* ------------------------------------------------------------ */ + /** Get dependent bean of a specific class. + * If more than one bean of the type exist, the first is returned. + * @see #addBean(Object) + * @param clazz + * @return bean or null + */ + public <T> T getBean(Class<T> clazz) + { + Iterator<?> iter = _dependentBeans.iterator(); + T t=null; + int count=0; + while (iter.hasNext()) + { + Object o = iter.next(); + if (clazz.isInstance(o)) + { + count++; + if (t==null) + t=(T)o; + } + } + if (count>1) + Log.debug("getBean({}) 1 of {}",clazz.getName(),count); + + return t; + } + /** * Remove a LifeCycle object to be started/stopped * along with the Server @@ -578,7 +637,7 @@ public class Server extends HandlerWrapper implements Attributes /* ------------------------------------------------------------ */ /** - * Set graceful shutdown timeout. If set, the {@link #doStop()} method will not immediately stop the + * Set graceful shutdown timeout. If set, the internal <code>doStop()</code> method will not immediately stop the * server. Instead, all {@link Connector}s will be closed so that new connections will not be accepted * and all handlers that implement {@link Graceful} will be put into the shutdown mode so that no new requests * will be accepted, but existing requests can complete. The server will then wait the configured timeout diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionIdManager.java index 1d76581822..cca2783673 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionIdManager.java @@ -20,13 +20,6 @@ import org.eclipse.jetty.util.component.LifeCycle; /** Session ID Manager. * Manages session IDs across multiple contexts. - * - * - */ -/* ------------------------------------------------------------ */ -/** - * - * */ public interface SessionIdManager extends LifeCycle { @@ -57,7 +50,7 @@ public interface SessionIdManager extends LifeCycle /** * @param request * @param created - * @return + * @return the new session id */ public String newSessionId(HttpServletRequest request,long created); @@ -68,7 +61,7 @@ public interface SessionIdManager extends LifeCycle /** Get a cluster ID from a node ID. * Strip node identifier from a located session ID. * @param nodeId - * @return + * @return the cluster id */ public String getClusterId(String nodeId); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java index 3d11dd554a..7d8ea58284 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java @@ -30,14 +30,15 @@ import org.eclipse.jetty.util.component.LifeCycle; /** * Session Manager. * The API required to manage sessions for a servlet context. + * */ public interface SessionManager extends LifeCycle { /* ------------------------------------------------------------ */ /** * Session cookie name. - * Defaults to JSESSIONID, but can be set with the - * org.eclipse.jetty.servlet.SessionCookie context init parameter. + * Defaults to <code>JSESSIONID</code>, but can be set with the + * <code>org.eclipse.jetty.servlet.SessionCookie</code> context init parameter. */ public final static String __SessionCookieProperty = "org.eclipse.jetty.servlet.SessionCookie"; public final static String __DefaultSessionCookie = "JSESSIONID"; @@ -46,12 +47,13 @@ public interface SessionManager extends LifeCycle /* ------------------------------------------------------------ */ /** * Session id path parameter name. - * Defaults to jsessionid, but can be set with the - * org.eclipse.jetty.servlet.SessionIdPathParameterName context init parameter. + * Defaults to <code>jsessionid</code>, but can be set with the + * <code>org.eclipse.jetty.servlet.SessionIdPathParameterName</code> context init parameter. * If set to null or "none" no URL rewriting will be done. */ public final static String __SessionIdPathParameterNameProperty = "org.eclipse.jetty.servlet.SessionIdPathParameterName"; public final static String __DefaultSessionIdPathParameterName = "jsessionid"; + public final static String __CheckRemoteSessionEncoding = "org.eclipse.jetty.servlet.CheckingRemoteSessionIdEncoding"; /* ------------------------------------------------------------ */ @@ -101,6 +103,14 @@ public interface SessionManager extends LifeCycle */ public HttpSession newHttpSession(HttpServletRequest request); + + /* ------------------------------------------------------------ */ + /** + * @return true if session cookies should be HTTP-only (Microsoft extension) + * @see org.eclipse.jetty.http.HttpCookie#isHttpOnly() + */ + public boolean getHttpOnly(); + /* ------------------------------------------------------------ */ /** * @return the max period of inactivity, after which the session is invalidated, in seconds. @@ -267,4 +277,15 @@ public interface SessionManager extends LifeCycle public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes); public SessionCookieConfig getSessionCookieConfig(); + + /** + * @return True if absolute URLs are check for remoteness before being session encoded. + */ + public boolean isCheckingRemoteSessionIdEncoding(); + + /** + * @param remote True if absolute URLs are check for remoteness before being session encoded. + */ + public void setCheckingRemoteSessionIdEncoding(boolean remote); + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/UserIdentity.java b/jetty-server/src/main/java/org/eclipse/jetty/server/UserIdentity.java index 0c849bd593..8422e85dc3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/UserIdentity.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/UserIdentity.java @@ -51,14 +51,11 @@ public interface UserIdentity /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ /** * A UserIdentity Scope. * A scope is the environment in which a User Identity is to * be interpreted. Typically it is set by the target servlet of * a request. - * @see org.eclipse.jetty.servlet.ServletHolder */ interface Scope { @@ -83,15 +80,11 @@ public interface UserIdentity } /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ public interface UnauthenticatedUserIdentity extends UserIdentity { } /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ public static final UserIdentity UNAUTHENTICATED_IDENTITY = new UnauthenticatedUserIdentity() { public Subject getSubject() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/bio/SocketConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/bio/SocketConnector.java index 5a39e71f38..e3104dbb8d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/bio/SocketConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/bio/SocketConnector.java @@ -4,13 +4,13 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== - + package org.eclipse.jetty.server.bio; import java.io.IOException; @@ -39,21 +39,22 @@ import org.eclipse.jetty.util.log.Log; * This connector implements a traditional blocking IO and threading model. * Normal JRE sockets are used and a thread is allocated per connection. * Buffers are managed so that large buffers are only allocated to active connections. - * + * * This Connector should only be used if NIO is not available. - * + * * @org.apache.xbean.XBean element="bioConnector" description="Creates a BIO based socket connector" - * - * + * + * */ public class SocketConnector extends AbstractConnector { protected ServerSocket _serverSocket; protected final Set<EndPoint> _connections; - + protected volatile int _localPort=-1; + /* ------------------------------------------------------------ */ /** Constructor. - * + * */ public SocketConnector() { @@ -65,7 +66,7 @@ public class SocketConnector extends AbstractConnector { return _serverSocket; } - + /* ------------------------------------------------------------ */ public void open() throws IOException { @@ -73,6 +74,10 @@ public class SocketConnector extends AbstractConnector if (_serverSocket==null || _serverSocket.isClosed()) _serverSocket= newServerSocket(getHost(),getPort(),getAcceptQueueSize()); _serverSocket.setReuseAddress(getReuseAddress()); + _localPort=_serverSocket.getLocalPort(); + if (_localPort<=0) + throw new IllegalStateException("port not allocated for "+this); + } /* ------------------------------------------------------------ */ @@ -81,26 +86,27 @@ public class SocketConnector extends AbstractConnector ServerSocket ss= host==null? new ServerSocket(port,backlog): new ServerSocket(port,backlog,InetAddress.getByName(host)); - + return ss; } - + /* ------------------------------------------------------------ */ public void close() throws IOException { if (_serverSocket!=null) _serverSocket.close(); _serverSocket=null; + _localPort=-2; } /* ------------------------------------------------------------ */ @Override public void accept(int acceptorID) throws IOException, InterruptedException - { + { Socket socket = _serverSocket.accept(); configure(socket); - + ConnectorEndPoint connection=new ConnectorEndPoint(socket); connection.dispatch(); } @@ -109,7 +115,7 @@ public class SocketConnector extends AbstractConnector /** * Allows subclass to override Conection if required. */ - protected HttpConnection newHttpConnection(EndPoint endpoint) + protected Connection newConnection(EndPoint endpoint) { return new HttpConnection(this, endpoint, getServer()); } @@ -121,21 +127,15 @@ public class SocketConnector extends AbstractConnector { ConnectorEndPoint connection = (ConnectorEndPoint)endpoint; int lrmit = isLowResources()?_lowResourceMaxIdleTime:_maxIdleTime; - if (connection._sotimeout!=lrmit) - { - connection._sotimeout=lrmit; - ((Socket)endpoint.getTransport()).setSoTimeout(lrmit); - } - + connection.setMaxIdleTime(lrmit); + super.customize(endpoint, request); } /* ------------------------------------------------------------------------------- */ public int getLocalPort() { - if (_serverSocket==null || _serverSocket.isClosed()) - return -1; - return _serverSocket.getLocalPort(); + return _localPort; } /* ------------------------------------------------------------------------------- */ @@ -157,7 +157,7 @@ public class SocketConnector extends AbstractConnector { set= new HashSet(_connections); } - + Iterator iter=set.iterator(); while(iter.hasNext()) { @@ -173,14 +173,12 @@ public class SocketConnector extends AbstractConnector { boolean _dispatched=false; volatile Connection _connection; - int _sotimeout; protected final Socket _socket; - + public ConnectorEndPoint(Socket socket) throws IOException { - super(socket); - _connection = newHttpConnection(this); - _sotimeout=socket.getSoTimeout(); + super(socket,_maxIdleTime); + _connection = newConnection(this); _socket=socket; } @@ -195,7 +193,7 @@ public class SocketConnector extends AbstractConnector connectionUpgraded(_connection,connection); _connection=connection; } - + public void dispatch() throws IOException { if (getThreadPool()==null || !getThreadPool().dispatch(this)) @@ -204,7 +202,7 @@ public class SocketConnector extends AbstractConnector close(); } } - + @Override public int fill(Buffer buffer) throws IOException { @@ -212,8 +210,8 @@ public class SocketConnector extends AbstractConnector if (l<0) close(); return l; - } - + } + @Override public void close() throws IOException { @@ -231,21 +229,14 @@ public class SocketConnector extends AbstractConnector { _connections.add(this); } - + while (isStarted() && !isClosed()) { if (_connection.isIdle()) { if (isLowResources()) - { - int lrmit = getLowResourcesMaxIdleTime(); - if (lrmit>=0 && _sotimeout!= lrmit) - { - _sotimeout=lrmit; - _socket.setSoTimeout(_sotimeout); - } - } - } + setMaxIdleTime(getLowResourcesMaxIdleTime()); + } _connection=_connection.handle(); } @@ -269,7 +260,7 @@ public class SocketConnector extends AbstractConnector catch(IOException e2){Log.ignore(e2);} } finally - { + { connectionClosed(_connection); synchronized(_connections) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java index fbaa3513d2..91a65a19b1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java @@ -94,6 +94,8 @@ public abstract class AbstractHandlerContainer extends AbstractHandler implement int last=handlers.length-1; for (int h=0;h<=last;h++) { + if (handlers[h]==null) + continue; b.append(indent); b.append(" +-"); if (handlers[h] instanceof AbstractHandler) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 4938021beb..114a5076b3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server.handler; @@ -73,31 +73,35 @@ import org.eclipse.jetty.util.resource.Resource; /* ------------------------------------------------------------ */ /** ContextHandler. - * + * * This handler wraps a call to handle by setting the context and * servlet path, plus setting the context classloader. - * + * * <p> * If the context init parameter "org.eclipse.jetty.server.context.ManagedAttributes" * is set to a comma separated list of names, then they are treated as context * attribute names, which if set as attributes are passed to the servers Container * so that they may be managed with JMX. - * - * @org.apache.xbean.XBean description="Creates a basic HTTP context" - * - * * + * @org.apache.xbean.XBean description="Creates a basic HTTP context" */ public class ContextHandler extends ScopedHandler implements Attributes, Server.Graceful { private static final ThreadLocal<Context> __context=new ThreadLocal<Context>(); - public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes"; + /** + * If a context attribute with this name is set, it is interpreted as a + * comma separated list of attribute name. Any other context attributes that + * are set with a name from this list will result in a call to {@link #setManagedAttribute(String, Object)}, + * which typically initiates the creation of a JMX MBean for the attribute value. + */ + public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes"; + /* ------------------------------------------------------------ */ /** Get the current ServletContext implementation. * This call is only valid during a call to doStart and is available to * nested handlers to access the context. - * + * * @return ServletContext implementation */ public static Context getCurrentContext() @@ -106,14 +110,14 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } protected Context _scontext; - - private AttributesMap _attributes; - private AttributesMap _contextAttributes; + + private final AttributesMap _attributes; + private final AttributesMap _contextAttributes; + private final Map<String,String> _initParams; private ClassLoader _classLoader; private String _contextPath="/"; - private Map<String,String> _initParams; private String _displayName; - private Resource _baseResource; + private Resource _baseResource; private MimeTypes _mimeTypes; private Map<String,String> _localeEncodingMap; private String[] _welcomeFiles; @@ -134,49 +138,51 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. private Map<String,Object> _managedAttributes; private boolean _shutdown=false; - private boolean _available=true; + private boolean _available=true; private volatile int _availability; // 0=STOPPED, 1=AVAILABLE, 2=SHUTDOWN, 3=UNAVAILABLE - + private final static int __STOPPED=0,__AVAILABLE=1,__SHUTDOWN=2,__UNAVAILABLE=3; - - + + /* ------------------------------------------------------------ */ /** - * + * */ public ContextHandler() { super(); _scontext=new Context(); _attributes=new AttributesMap(); + _contextAttributes=new AttributesMap(); _initParams=new HashMap<String,String>(); } - + /* ------------------------------------------------------------ */ /** - * + * */ protected ContextHandler(Context context) { super(); _scontext=context; _attributes=new AttributesMap(); + _contextAttributes=new AttributesMap(); _initParams=new HashMap<String,String>(); } - + /* ------------------------------------------------------------ */ /** - * + * */ public ContextHandler(String contextPath) { this(); setContextPath(contextPath); } - + /* ------------------------------------------------------------ */ /** - * + * */ public ContextHandler(HandlerContainer parent, String contextPath) { @@ -193,7 +199,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { return _scontext; } - + /* ------------------------------------------------------------ */ /** * @return the allowNullPathInfo true if /context is not redirected to /context/ @@ -221,13 +227,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. Server old_server=getServer(); if (old_server!=null && old_server!=server) old_server.getContainer().update(this, _errorHandler, null, "error",true); - super.setServer(server); + super.setServer(server); if (server!=null && server!=old_server) server.getContainer().update(this, null, _errorHandler, "error",true); - _errorHandler.setServer(server); + _errorHandler.setServer(server); } else - super.setServer(server); + super.setServer(server); } /* ------------------------------------------------------------ */ @@ -247,8 +253,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. if ( vhosts == null ) { _vhosts = vhosts; - } - else + } + else { _vhosts = new String[vhosts.length]; for ( int i = 0; i < vhosts.length; i++ ) @@ -274,8 +280,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /** - * @deprecated use {@link #setConnectorNames(String[])} + /** + * @deprecated use {@link #setConnectorNames(String[])} */ @Deprecated public void setHosts(String[] hosts) @@ -302,15 +308,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { if (_connectors==null || _connectors.size()==0) return null; - + return _connectors.toArray(new String[_connectors.size()]); } /* ------------------------------------------------------------ */ /** Set the names of accepted connectors. - * + * * Names are either "host:port" or a specific configured name for a connector. - * + * * @param connectors If non null, an array of connector names that this context * will accept a request from. */ @@ -321,9 +327,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. else _connectors= new HashSet<String>(Arrays.asList(connectors)); } - + /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getAttribute(java.lang.String) */ public Object getAttribute(String name) @@ -332,7 +338,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getAttributeNames() */ @SuppressWarnings("unchecked") @@ -340,7 +346,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { return AttributesMap.getAttributeNamesCopy(_attributes); } - + /* ------------------------------------------------------------ */ /** * @return Returns the attributes. @@ -349,7 +355,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { return _attributes; } - + /* ------------------------------------------------------------ */ /** * @return Returns the classLoader. @@ -402,9 +408,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { return _contextPath; } - + /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) */ public String getInitParameter(String name) @@ -413,7 +419,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getInitParameterNames() */ @SuppressWarnings("unchecked") @@ -421,7 +427,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { return Collections.enumeration(_initParams.keySet()); } - + /* ------------------------------------------------------------ */ /** * @return Returns the initParams. @@ -432,7 +438,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getServletContextName() */ public String getDisplayName() @@ -445,7 +451,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { return _eventListeners; } - + /* ------------------------------------------------------------ */ /** * Set the context event listeners. @@ -460,26 +466,26 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. _contextAttributeListeners=null; _requestListeners=null; _requestAttributeListeners=null; - + _eventListeners=eventListeners; - + for (int i=0; eventListeners!=null && i<eventListeners.length;i ++) { EventListener listener = _eventListeners[i]; - + if (listener instanceof ServletContextListener) _contextListeners= LazyList.add(_contextListeners, listener); - + if (listener instanceof ServletContextAttributeListener) _contextAttributeListeners= LazyList.add(_contextAttributeListeners, listener); - + if (listener instanceof ServletRequestListener) _requestListeners= LazyList.add(_requestListeners, listener); - + if (listener instanceof ServletRequestAttributeListener) _requestAttributeListeners= LazyList.add(_requestAttributeListeners, listener); } - } + } /* ------------------------------------------------------------ */ /** @@ -489,7 +495,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. * @see ServletRequestListener * @see ServletRequestAttributeListener */ - public void addEventListener(EventListener listener) + public void addEventListener(EventListener listener) { setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(), listener, EventListener.class)); } @@ -557,34 +563,34 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { return _logger; } - + /* ------------------------------------------------------------ */ public void setLogger(Logger logger) { _logger=logger; } - + /* ------------------------------------------------------------ */ - /* + /* * @see org.eclipse.thread.AbstractLifeCycle#doStart() */ @Override protected void doStart() throws Exception { _availability=__STOPPED; - + if (_contextPath==null) throw new IllegalStateException("Null contextPath"); - + _logger=Log.getLogger(getDisplayName()==null?getContextPath():getDisplayName()); ClassLoader old_classloader=null; Thread current_thread=null; Context old_context=null; - _contextAttributes=new AttributesMap(); + _contextAttributes.clearAttributes(); try { - + // Set the classloader if (_classLoader!=null) { @@ -592,46 +598,40 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. old_classloader=current_thread.getContextClassLoader(); current_thread.setContextClassLoader(_classLoader); } - + if (_mimeTypes==null) _mimeTypes=new MimeTypes(); - + old_context=__context.get(); __context.set(_scontext); - - if (_errorHandler==null) - setErrorHandler(new ErrorHandler()); - - + // defers the calling of super.doStart() startContext(); - _availability=_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE; } finally { __context.set(old_context); - + // reset the classloader if (_classLoader!=null) { current_thread.setContextClassLoader(old_classloader); } - + } } /* ------------------------------------------------------------ */ /** * Extensible startContext. - * this method is called from {@link ContextHandler#doStart()} instead of a + * this method is called from {@link ContextHandler#doStart()} instead of a * call to super.doStart(). This allows derived classes to insert additional * handling (Eg configuration) before the call to super.doStart by this method * will start contained handlers. - * @see org.eclipse.jetty.Scope.Context - * @see org.eclipse.jetty.webapp.WebAppContext + * @see org.eclipse.jetty.server.handler.ContextHandler.Context */ protected void startContext() throws Exception @@ -643,21 +643,21 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. String[] attributes = managedAttributes.split(","); for (String attribute : attributes) _managedAttributes.put(attribute,null); - + Enumeration e = _scontext.getAttributeNames(); while(e.hasMoreElements()) { String name = (String)e.nextElement(); Object value = _scontext.getAttribute(name); - setManagedAttribute(name,value); + checkManagedAttribute(name,value); } - } - + } + super.doStart(); if (_errorHandler!=null) _errorHandler.start(); - + // Context listeners if (_contextListeners != null ) { @@ -668,14 +668,14 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } } } - + public void callContextInitialized (ServletContextListener l, ServletContextEvent e) { l.contextInitialized(e); } - + public void callContextDestroyed (ServletContextListener l, ServletContextEvent e) { l.contextDestroyed(e); @@ -684,14 +684,14 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* ------------------------------------------------------------ */ - /* + /* * @see org.eclipse.thread.AbstractLifeCycle#doStop() */ @Override protected void doStop() throws Exception { _availability=__STOPPED; - + ClassLoader old_classloader=null; Thread current_thread=null; @@ -706,9 +706,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. old_classloader=current_thread.getContextClassLoader(); current_thread.setContextClassLoader(_classLoader); } - + super.doStop(); - + // Context listeners if (_contextListeners != null ) { @@ -721,12 +721,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. if (_errorHandler!=null) _errorHandler.stop(); - + Enumeration e = _scontext.getAttributeNames(); while(e.hasMoreElements()) { String name = (String)e.nextElement(); - setManagedAttribute(name,null); + checkManagedAttribute(name,null); } } finally @@ -737,20 +737,18 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. current_thread.setContextClassLoader(old_classloader); } - if (_contextAttributes!=null) - _contextAttributes.clearAttributes(); - _contextAttributes=null; + _contextAttributes.clearAttributes(); } /* ------------------------------------------------------------ */ - /* + /* * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException, ServletException - { + { DispatcherType dispatch=baseRequest.getDispatcherType(); - + switch(_availability) { case __STOPPED: @@ -763,14 +761,14 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. if((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled())) return false; } - + // Check the vhosts if (_vhosts!=null && _vhosts.length>0) { String vhost = normalizeHostname( baseRequest.getServerName()); boolean match=false; - + // TODO non-linear lookup for (int i=0;!match && i<_vhosts.length;i++) { @@ -785,7 +783,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. if (!match) return false; } - + // Check the connector if (_connectors!=null && _connectors.size()>0) { @@ -794,29 +792,31 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. return false; } - - if (target.startsWith(_contextPath)) + // Are we not the root context? + if (_contextPath.length()>1) { - if (_contextPath.length()==target.length() && _contextPath.length()>1 &&!_allowNullPathInfo) + // reject requests that are not for us + if (!target.startsWith(_contextPath)) + return false; + if (target.length()>_contextPath.length() && target.charAt(_contextPath.length())!='/') + return false; + + // redirect null path infos + if (!_allowNullPathInfo && _contextPath.length()==target.length()) { // context request must end with / baseRequest.setHandled(true); if (baseRequest.getQueryString()!=null) response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH)+"?"+baseRequest.getQueryString()); - else + else response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH)); return false; } } - else - { - // Not for this context! - return false; - } - + return true; - } - + } + /* ------------------------------------------------------------ */ @@ -825,7 +825,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. */ @Override public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { + { Context old_context=null; String old_context_path=null; String old_servlet_path=null; @@ -835,9 +835,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. String pathInfo=null; DispatcherType dispatch=baseRequest.getDispatcherType(); - + old_context=baseRequest.getContext(); - + // Are we already in this context? if (old_context!=_scontext) { @@ -848,7 +848,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. target=URIUtil.compactPath(target); if (!checkContext(target,baseRequest,response)) return; - + if (target.length()>_contextPath.length()) { if (_contextPath.length()>1) @@ -875,13 +875,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. current_thread.setContextClassLoader(_classLoader); } } - + try { old_context_path=baseRequest.getContextPath(); old_servlet_path=baseRequest.getServletPath(); old_path_info=baseRequest.getPathInfo(); - + // Update the paths baseRequest.setContext(_scontext); if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/")) @@ -893,16 +893,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. baseRequest.setServletPath(null); baseRequest.setPathInfo(pathInfo); } - + // start manual inline of nextScope(target,baseRequest,request,response); - //noinspection ConstantIfStatement - if (false) + if (never()) nextScope(target,baseRequest,request,response); else if (_nextScope!=null) _nextScope.doScope(target,baseRequest,request, response); else if (_outerScope!=null) _outerScope.doHandle(target,baseRequest,request, response); - else + else doHandle(target,baseRequest,request, response); // end manual inline (pathentic attempt to reduce stack depth) } @@ -915,16 +914,16 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { current_thread.setContextClassLoader(old_classloader); } - + // reset the context and servlet path. baseRequest.setContext(old_context); baseRequest.setContextPath(old_context_path); baseRequest.setServletPath(old_servlet_path); - baseRequest.setPathInfo(old_path_info); + baseRequest.setPathInfo(old_path_info); } } } - + /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.server.handler.ScopedHandler#doHandle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) @@ -954,13 +953,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestInitialized(sre); } } - + if (DispatcherType.REQUEST.equals(dispatch) && isProtectedTarget(target)) throw new HttpException(HttpServletResponse.SC_NOT_FOUND); - + // start manual inline of nextHandle(target,baseRequest,request,response); //noinspection ConstantIfStatement - if (false) + if (never()) nextHandle(target,baseRequest,request,response); else if (_nextScope!=null && _nextScope==_handler) _nextScope.doHandle(target,baseRequest,request, response); @@ -985,7 +984,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. for(int i=0;i<s;i++) ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestDestroyed(sre); } - + if (_requestAttributeListeners!=null) { for(int i=LazyList.size(_requestAttributeListeners);i-->0;) @@ -994,12 +993,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } } } - + /* ------------------------------------------------------------ */ /* Handle a runnable in this context */ public void handle(Runnable runnable) - { + { ClassLoader old_classloader=null; Thread current_thread=null; try @@ -1011,7 +1010,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. old_classloader=current_thread.getContextClassLoader(); current_thread.setContextClassLoader(_classLoader); } - + runnable.run(); } finally @@ -1028,64 +1027,49 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. * Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a * target within a context is determined. If the target is protected, 404 is returned. * The default implementation always returns false. - * @see org.eclipse.jetty.webapp.WebAppContext#isProtectedTarget(String) */ /* ------------------------------------------------------------ */ protected boolean isProtectedTarget(String target) - { + { return false; } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) */ public void removeAttribute(String name) { - setManagedAttribute(name,null); + checkManagedAttribute(name,null); _attributes.removeAttribute(name); } /* ------------------------------------------------------------ */ /* Set a context attribute. * Attributes set via this API cannot be overriden by the ServletContext.setAttribute API. - * Their lifecycle spans the stop/start of a context. No attribute listener events are + * Their lifecycle spans the stop/start of a context. No attribute listener events are * triggered by this API. * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object) */ public void setAttribute(String name, Object value) { - setManagedAttribute(name,value); + checkManagedAttribute(name,value); _attributes.setAttribute(name,value); } - + /* ------------------------------------------------------------ */ /** * @param attributes The attributes to set. */ public void setAttributes(Attributes attributes) { - if (attributes instanceof AttributesMap) - { - _attributes = (AttributesMap)attributes; - Enumeration e = _attributes.getAttributeNames(); - while (e.hasMoreElements()) - { - String name = (String)e.nextElement(); - setManagedAttribute(name,attributes.getAttribute(name)); - } - } - else + _attributes.clearAttributes(); + _attributes.addAll(attributes); + Enumeration e = _attributes.getAttributeNames(); + while (e.hasMoreElements()) { - _attributes=new AttributesMap(); - Enumeration e = attributes.getAttributeNames(); - while (e.hasMoreElements()) - { - String name = (String)e.nextElement(); - Object value=attributes.getAttribute(name); - setManagedAttribute(name,value); - _attributes.setAttribute(name,value); - } + String name = (String)e.nextElement(); + checkManagedAttribute(name,attributes.getAttribute(name)); } } @@ -1096,28 +1080,28 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. while (e.hasMoreElements()) { String name = (String)e.nextElement(); - setManagedAttribute(name,null); + checkManagedAttribute(name,null); } _attributes.clearAttributes(); } /* ------------------------------------------------------------ */ - private void setManagedAttribute(String name, Object value) - { + public void checkManagedAttribute(String name, Object value) + { if (_managedAttributes!=null && _managedAttributes.containsKey(name)) { - Object old =_managedAttributes.put(name,value); - if (old!=null) - getServer().getContainer().removeBean(old); - if (value!=null) - { - if (_logger.isDebugEnabled()) _logger.debug("Managing "+name); - getServer().getContainer().addBean(value); - } + setManagedAttribute(name,value); } } /* ------------------------------------------------------------ */ + public void setManagedAttribute(String name, Object value) + { + Object old =_managedAttributes.put(name,value); + getServer().getContainer().update(this,old,value,name); + } + + /* ------------------------------------------------------------ */ /** * @param classLoader The classLoader to set. */ @@ -1125,7 +1109,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { _classLoader = classLoader; } - + /* ------------------------------------------------------------ */ /** * @param contextPath The _contextPath to set. @@ -1135,7 +1119,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. if (contextPath!=null && contextPath.length()>1 && contextPath.endsWith("/")) throw new IllegalArgumentException("ends with /"); _contextPath = contextPath; - + if (getServer()!=null && (getServer().isStarting() || getServer().isStarted())) { Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class); @@ -1143,18 +1127,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. ((ContextHandlerCollection)contextCollections[h]).mapContexts(); } } - - /* ------------------------------------------------------------ */ - /** - * @param initParams The initParams to set. - */ - public void setInitParams(Map<String,String> initParams) - { - if (initParams == null) - return; - _initParams = new HashMap<String,String>(initParams); - } - + /* ------------------------------------------------------------ */ /** * @param servletContextName The servletContextName to set. @@ -1163,7 +1136,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { _displayName = servletContextName; } - + /* ------------------------------------------------------------ */ /** * @return Returns the resourceBase. @@ -1185,12 +1158,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. return null; return _baseResource.toString(); } - + /* ------------------------------------------------------------ */ /** * @param base The resourceBase to set. */ - public void setBaseResource(Resource base) + public void setBaseResource(Resource base) { _baseResource=base; } @@ -1199,7 +1172,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /** * @param resourceBase The base resource as a string. */ - public void setResourceBase(String resourceBase) + public void setResourceBase(String resourceBase) { try { @@ -1238,7 +1211,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { return _mimeTypes; } - + /* ------------------------------------------------------------ */ /** * @param mimeTypes The mimeTypes to set. @@ -1251,7 +1224,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* ------------------------------------------------------------ */ /** */ - public void setWelcomeFiles(String[] files) + public void setWelcomeFiles(String[] files) { _welcomeFiles=files; } @@ -1262,7 +1235,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a> * @see #setWelcomeFiles */ - public String[] getWelcomeFiles() + public String[] getWelcomeFiles() { return _welcomeFiles; } @@ -1288,13 +1261,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. getServer().getContainer().update(this, _errorHandler, errorHandler, "errorHandler",true); _errorHandler = errorHandler; } - + /* ------------------------------------------------------------ */ public int getMaxFormContentSize() { return _maxFormContentSize; } - + /* ------------------------------------------------------------ */ public void setMaxFormContentSize(int maxSize) { @@ -1324,7 +1297,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. @Override public String toString() { - + return super.toString()+"@"+Integer.toHexString(hashCode())+getContextPath()+","+getBaseResource(); } @@ -1334,13 +1307,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { if (className==null) return null; - + if (_classLoader==null) return Loader.loadClass(this.getClass(), className); return _classLoader.loadClass(className); } - + /* ------------------------------------------------------------ */ public void addLocaleEncoding(String locale,String encoding) @@ -1349,12 +1322,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. _localeEncodingMap=new HashMap<String,String>(); _localeEncodingMap.put(locale, encoding); } - + /* ------------------------------------------------------------ */ /** * Get the character encoding for a locale. The full locale name is first * looked up in the map of encodings. If no encoding is found, then the - * locale language is looked up. + * locale language is looked up. * * @param locale a <code>Locale</code> value * @return a <code>String</code> representing the character encoding for @@ -1369,7 +1342,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. encoding = _localeEncodingMap.get(locale.getLanguage()); return encoding; } - + public String getLocaleEncoding (String locale) { if (_localeEncodingMap==null) @@ -1379,13 +1352,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* */ public Resource getResource(String path) throws MalformedURLException { if (path==null || !path.startsWith(URIUtil.SLASH)) throw new MalformedURLException(path); - + if (_baseResource==null) return null; @@ -1393,7 +1366,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { path=URIUtil.canonicalPath(path); Resource resource=_baseResource.addPath(path); - + if (!_aliases && resource.getAlias()!=null) { if (resource.exists()) @@ -1402,20 +1375,20 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. Log.debug("Aliased resource: "+resource+"~="+resource.getAlias()); return null; } - + return resource; } catch(Exception e) { Log.ignore(e); } - + return null; } /* ------------------------------------------------------------ */ /** Convert URL to Resource - * wrapper for {@link Resource#newResource(URL)} enables extensions to + * wrapper for {@link Resource#newResource(URL)} enables extensions to * provide alternate resource implementations. */ public Resource newResource(URL url) throws IOException @@ -1425,7 +1398,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* ------------------------------------------------------------ */ /** Convert URL to Resource - * wrapper for {@link Resource#newResource(String)} enables extensions to + * wrapper for {@link Resource#newResource(String)} enables extensions to * provide alternate resource implementations. */ public Resource newResource(String url) throws IOException @@ -1434,20 +1407,20 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* */ public Set<String> getResourcePaths(String path) - { + { try { path=URIUtil.canonicalPath(path); Resource resource=getResource(path); - + if (resource!=null && resource.exists()) { if (!path.endsWith(URIUtil.SLASH)) path=path+URIUtil.SLASH; - + String[] l=resource.list(); if (l!=null) { @@ -1455,7 +1428,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. for(int i=0;i<l.length;i++) set.add(path+l[i]); return set; - } + } } } catch(Exception e) @@ -1472,20 +1445,20 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { if ( host == null ) return null; - + if ( host.endsWith( "." ) ) return host.substring( 0, host.length() -1); - + return host; } - + /* ------------------------------------------------------------ */ /** Context. * <p> * A partial implementation of {@link javax.servlet.ServletContext}. - * A complete implementation is provided by the derived {@link org.eclipse.jetty.servlet.ServletContextHandler.Context}. + * A complete implementation is provided by the derived {@link ContextHandler}. * </p> - * + * * */ public class Context implements ServletContext @@ -1507,14 +1480,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getContext(java.lang.String) */ @Override public ServletContext getContext(String uripath) { - // TODO this is a very poor implementation! - // TODO move this to Server ContextHandler context=null; Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class); for (int i=0;i<handlers.length;i++) @@ -1523,20 +1494,21 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. continue; ContextHandler ch = (ContextHandler)handlers[i]; String context_path=ch.getContextPath(); - if (uripath.equals(context_path) || (uripath.startsWith(context_path)&&uripath.charAt(context_path.length())=='/')) + + if (uripath.equals(context_path) || (uripath.startsWith(context_path)&&uripath.charAt(context_path.length())=='/') || "/".equals(context_path)) { if (context==null || context_path.length()>context.getContextPath().length()) context=ch; } } - + if (context!=null) return context._scontext; return null; } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getMajorVersion() */ @Override @@ -1547,7 +1519,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getMimeType(java.lang.String) */ @Override @@ -1562,7 +1534,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getMinorVersion() */ @Override @@ -1572,7 +1544,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String) */ @Override @@ -1582,7 +1554,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String) */ @Override @@ -1593,7 +1565,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. if (!uriInContext.startsWith("/")) return null; - + try { String query=null; @@ -1619,7 +1591,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getRealPath(java.lang.String) */ @Override @@ -1631,7 +1603,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. path = URIUtil.SLASH; else if(path.charAt(0)!='/') path = URIUtil.SLASH + path; - + try { Resource resource=ContextHandler.this.getResource(path); @@ -1646,7 +1618,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { Log.ignore(e); } - + return null; } @@ -1659,9 +1631,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. return resource.getURL(); return null; } - + /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String) */ @Override @@ -1682,17 +1654,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String) */ @Override public Set getResourcePaths(String path) - { + { return ContextHandler.this.getResourcePaths(path); } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getServerInfo() */ @Override @@ -1702,7 +1674,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getServlet(java.lang.String) */ @Override @@ -1713,7 +1685,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getServletNames() */ @SuppressWarnings("unchecked") @@ -1725,7 +1697,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getServlets() */ @SuppressWarnings("unchecked") @@ -1737,7 +1709,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String) */ @Override @@ -1747,7 +1719,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#log(java.lang.String) */ @Override @@ -1757,7 +1729,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable) */ @Override @@ -1767,7 +1739,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) */ @Override @@ -1777,7 +1749,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getInitParameterNames() */ @SuppressWarnings("unchecked") @@ -1788,7 +1760,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getAttribute(java.lang.String) */ @Override @@ -1801,7 +1773,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getAttributeNames() */ @SuppressWarnings("unchecked") @@ -1818,33 +1790,25 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. Enumeration<String> e = _attributes.getAttributeNames(); while(e.hasMoreElements()) set.add(e.nextElement()); - + return Collections.enumeration(set); } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object) */ @Override public synchronized void setAttribute(String name, Object value) { - - if (_contextAttributes==null) - { - // Set it on the handler - ContextHandler.this.setAttribute(name, value); - return; - } - - setManagedAttribute(name,value); + checkManagedAttribute(name,value); Object old_value=_contextAttributes.getAttribute(name); - + if (value==null) _contextAttributes.removeAttribute(name); else _contextAttributes.setAttribute(name,value); - + if (_contextAttributeListeners!=null) { ServletContextAttributeEvent event = @@ -1853,7 +1817,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. for(int i=0;i<LazyList.size(_contextAttributeListeners);i++) { ServletContextAttributeListener l = (ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i); - + if (old_value==null) l.attributeAdded(event); else if (value==null) @@ -1865,21 +1829,21 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) */ @Override public synchronized void removeAttribute(String name) { - setManagedAttribute(name,null); - + checkManagedAttribute(name,null); + if (_contextAttributes==null) { // Set it on the handler _attributes.removeAttribute(name); return; } - + Object old_value=_contextAttributes.getAttribute(name); _contextAttributes.removeAttribute(name); if (old_value!=null) @@ -1896,7 +1860,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.ServletContext#getServletContextName() */ @Override @@ -1914,7 +1878,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH)) return ""; - + return _contextPath; } @@ -2128,7 +2092,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. return _minorVersion; } - public void setEffectiveMajorVersion (int v) { _majorVersion = v; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java index c91e067ed3..4972bcf586 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java @@ -33,7 +33,7 @@ import org.eclipse.jetty.util.log.Log; /** ContextHandlerCollection. * * This {@link org.eclipse.jetty.server.handler.HandlerCollection} is creates a - * {@link org.eclipse.jetty.http.servlet.PathMap} to it's contained handlers based + * {@link org.eclipse.jetty.http.PathMap} to it's contained handlers based * on the context path and virtual hosts of any contained {@link org.eclipse.jetty.server.handler.ContextHandler}s. * The contexts do not need to be directly contained, only children of the contained handlers. * Multiple contexts may have the same context path and they are called in order until one @@ -265,9 +265,7 @@ public class ContextHandlerCollection extends HandlerCollection /* ------------------------------------------------------------ */ /** Add a context handler. * @param contextPath The context path to add - * @return - * @throws IllegalAccessException - * @throws InstantiationException + * @return the ContextHandler just added */ public ContextHandler addContext(String contextPath,String resourceBase) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java index 232aba637c..073c0dfde9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java @@ -50,6 +50,7 @@ public class DefaultHandler extends AbstractHandler final long _faviconModified=(System.currentTimeMillis()/1000)*1000; byte[] _favicon; boolean _serveIcon=true; + boolean _showContexts=true; public DefaultHandler() { @@ -114,44 +115,47 @@ public class DefaultHandler extends AbstractHandler writer.write("<HTML>\n<HEAD>\n<TITLE>Error 404 - Not Found"); writer.write("</TITLE>\n<BODY>\n<H2>Error 404 - Not Found.</H2>\n"); writer.write("No context on this server matched or handled this request.<BR>"); - writer.write("Contexts known to this server are: <ul>"); - - - Server server = getServer(); - Handler[] handlers = server==null?null:server.getChildHandlersByClass(ContextHandler.class); - - for (int i=0;handlers!=null && i<handlers.length;i++) + + if (_showContexts) { - ContextHandler context = (ContextHandler)handlers[i]; - if (context.isRunning()) - { - writer.write("<li><a href=\""); - if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) - writer.write("http://"+context.getVirtualHosts()[0]+":"+request.getLocalPort()); - writer.write(context.getContextPath()); - if (context.getContextPath().length()>1 && context.getContextPath().endsWith("/")) - writer.write("/"); - writer.write("\">"); - writer.write(context.getContextPath()); - if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) - writer.write(" @ "+context.getVirtualHosts()[0]+":"+request.getLocalPort()); - writer.write(" ---> "); - writer.write(context.toString()); - writer.write("</a></li>\n"); - } - else + writer.write("Contexts known to this server are: <ul>"); + + Server server = getServer(); + Handler[] handlers = server==null?null:server.getChildHandlersByClass(ContextHandler.class); + + for (int i=0;handlers!=null && i<handlers.length;i++) { - writer.write("<li>"); - writer.write(context.getContextPath()); - if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) - writer.write(" @ "+context.getVirtualHosts()[0]+":"+request.getLocalPort()); - writer.write(" ---> "); - writer.write(context.toString()); - if (context.isFailed()) - writer.write(" [failed]"); - if (context.isStopped()) - writer.write(" [stopped]"); - writer.write("</li>\n"); + ContextHandler context = (ContextHandler)handlers[i]; + if (context.isRunning()) + { + writer.write("<li><a href=\""); + if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) + writer.write("http://"+context.getVirtualHosts()[0]+":"+request.getLocalPort()); + writer.write(context.getContextPath()); + if (context.getContextPath().length()>1 && context.getContextPath().endsWith("/")) + writer.write("/"); + writer.write("\">"); + writer.write(context.getContextPath()); + if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) + writer.write(" @ "+context.getVirtualHosts()[0]+":"+request.getLocalPort()); + writer.write(" ---> "); + writer.write(context.toString()); + writer.write("</a></li>\n"); + } + else + { + writer.write("<li>"); + writer.write(context.getContextPath()); + if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) + writer.write(" @ "+context.getVirtualHosts()[0]+":"+request.getLocalPort()); + writer.write(" ---> "); + writer.write(context.toString()); + if (context.isFailed()) + writer.write(" [failed]"); + if (context.isStopped()) + writer.write(" [stopped]"); + writer.write("</li>\n"); + } } } @@ -183,6 +187,15 @@ public class DefaultHandler extends AbstractHandler { _serveIcon = serveIcon; } + + public boolean getShowContexts() + { + return _showContexts; + } + public void setShowContexts(boolean show) + { + _showContexts = show; + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java index a8dabdaf56..6a422e9be8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java @@ -27,13 +27,11 @@ import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.ByteArrayISO8859Writer; - /* ------------------------------------------------------------ */ /** Handler for Error pages - * A handler that is registered at the org.eclipse.http.ErrorHandler - * context attributed and called by the HttpResponse.sendError method to write a - * error page. - * + * An ErrorHandler is registered with {@link ContextHandler#setErrorHandler(ErrorHandler)} or + * {@link org.eclipse.jetty.server.Server#addBean(Object)}. + * It is called by the HttpResponse.sendError method to write a error page. * */ public class ErrorHandler extends AbstractHandler diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java index 7746bf5d75..fdb840030e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java @@ -109,8 +109,8 @@ public class HandlerCollection extends AbstractHandlerContainer } /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.server.EventHandler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + /** + * @see Handler#handle(String, Request, HttpServletRequest, HttpServletResponse) */ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerList.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerList.java index c25ab0e18e..35b067f508 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerList.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerList.java @@ -24,15 +24,15 @@ import org.eclipse.jetty.server.Request; /* ------------------------------------------------------------ */ /** HandlerList. - * This extension of {@link org.eclipse.jetty.server.server.handler.HandlerCollection} will call + * This extension of {@link HandlerCollection} will call * each contained handler in turn until either an exception is thrown, the response * is committed or a positive response status is set. */ public class HandlerList extends HandlerCollection { /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.server.EventHandler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + /** + * @see Handler#handle(String, Request, HttpServletRequest, HttpServletResponse) */ @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java index 6ed3d15fdd..ebcaadf9d0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java @@ -14,10 +14,9 @@ package org.eclipse.jetty.server.handler; import java.io.IOException; -import java.util.HashMap; +import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -28,78 +27,150 @@ import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.util.IPAddressMap; +import org.eclipse.jetty.util.log.Log; /** * IP Access Handler * <p> - * Control access to the wrapped handler by the real remote IP. - * The real IP of the connection is used (not the IP reported in the forwarded for headers), - * as this cannot be as easily forged. + * Controls access to the wrapped handler by the real remote IP. Control is provided + * by white/black lists that include both internet addresses and URIs. This handler + * uses the real internet address of the connection, not one reported in the forwarded + * for headers, as this cannot be as easily forged. * <p> - * Control is provided by white/black lists of both internet addresses and URIs. - * Internet addresses may be absolute (eg 10.1.2.3) or a prefix pattern (eg 10.1.3. ). - * URI patterns follow the servlet specification for simple prefix and suffix wild cards. + * Typically, the black/white lists will be used in one of three modes: + * <ul> + * <li>Blocking a few specific IPs/URLs by specifying several black list entries. + * <li>Allowing only some specific IPs/URLs by specifying several white lists entries. + * <li>Allowing a general range of IPs/URLs by specifying several general white list + * entries, that are then further refined by several specific black list exceptions + * </ul> * <p> - * An empty white list is treated as match all. If there is at least one entry in the - * white list, then a request must match a white list entry. Black list entries are always - * appied, so that even if an entry matches the white list, a black list entry will override. + * An empty white list is treated as match all. If there is at least one entry in + * the white list, then a request must match a white list entry. Black list entries + * are always applied, so that even if an entry matches the white list, a black list + * entry will override it. + * <p> + * Internet addresses may be specified as absolute address or as a combination of + * four octet wildcard specifications (a.b.c.d) that are defined as follows. * </p> + * <pre> + * nnn - an absolute value (0-255) + * mmm-nnn - an inclusive range of absolute values, + * with following shorthand notations: + * nnn- => nnn-255 + * -nnn => 0-nnn + * - => 0-255 + * a,b,... - a list of wildcard specifications + * </pre> + * <p> + * Internet address specification is separated from the URI pattern using the "|" (pipe) + * character. URI patterns follow the servlet specification for simple * prefix and + * suffix wild cards (e.g. /, /foo, /foo/bar, /foo/bar/*, *.baz). + * <p> + * Earlier versions of the handler used internet address prefix wildcard specification + * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.). + * They also used the first "/" character of the URI pattern to separate it from the + * internet address. Both of these features have been deprecated in the current version. * <p> - * Examples of match specifications are: + * Examples of the entry specifications are: * <ul> - * <li>10.1.2.3 - all requests from IP 10.1.2.3 - * <li>10.1.2.3/foo/bar - all requests from IP 10.1.2.3 to URI /foo/bar - * <li>10.1.2.3/foo/* - all requests from IP 10.1.2.3 to URIs starting with /foo/ - * <li>10.1.2.3/*.html - all requests from IP 10.1.2.3 to URIs ending with .html - * <li>10.1. - all requests from IPs starting with 10.1. - * <li>10.1./foo/bar - all requests from IPs starting with 10.1. to URI /foo/bar - * <li>10.1./foo/* - all requests from IPs starting with 10.1. to URIs starting with /foo/ + * <li>10.10.1.2 - all requests from IP 10.10.1.2 + * <li>10.10.1.2|/foo/bar - all requests from IP 10.10.1.2 to URI /foo/bar + * <li>10.10.1.2|/foo/* - all requests from IP 10.10.1.2 to URIs starting with /foo/ + * <li>10.10.1.2|*.html - all requests from IP 10.10.1.2 to URIs ending with .html + * <li>10.10.0-255.0-255 - all requests from IPs within 10.10.0.0/16 subnet + * <li>10.10.0-.-255|/foo/bar - all requests from IPs within 10.10.0.0/16 subnet to URI /foo/bar + * <li>10.10.0-3,1,3,7,15|/foo/* - all requests from IPs addresses with last octet equal + * to 1,3,7,15 in subnet 10.10.0.0/22 to URIs starting with /foo/ * </ul> * <p> - * Typically, the black/white lists will be used in one of three modes: - * <nl> - * <li>Blocking a few specific IPs/URLs by specifying several black list entries. - * <li>Allowing only some specific IPs/URLs by specifying several white lists entries. - * <li>Allowing a general range of IPs/URLs by specifying serveral general white list - * entries, that are then further refined by several specific black list exceptions - * </ul> - * + * Earlier versions of the handler used internet address prefix wildcard specification + * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.). + * They also used the first "/" character of the URI pattern to separate it from the + * internet address. Both of these features have been deprecated in the current version. */ public class IPAccessHandler extends HandlerWrapper { - Map<String,PathMap> _whiteAddr = new HashMap<String, PathMap>(); - List<String> _whitePattern = new CopyOnWriteArrayList<String>(); - Map<String,PathMap> _blackAddr = new HashMap<String, PathMap>(); - List<String> _blackPattern = new CopyOnWriteArrayList<String>(); - + IPAddressMap<PathMap> _white = new IPAddressMap<PathMap>(); + IPAddressMap<PathMap> _black = new IPAddressMap<PathMap>(); + + /* ------------------------------------------------------------ */ /** + * Creates new handler object */ public IPAccessHandler() { + super(); } - public void addBlack(String addrPath) + /* ------------------------------------------------------------ */ + /** + * Creates new handler object and initializes white- and black-list + * + * @param white array of whitelist entries + * @param black array of blacklist entries + */ + public IPAccessHandler(String[] white, String []black) { - add(addrPath, _blackAddr, _blackPattern); + super(); + + if (white != null && white.length > 0) + setWhite(white); + if (black != null && black.length > 0) + setBlack(black); } - public void addWhite(String addrPath) + /* ------------------------------------------------------------ */ + /** + * Add a whitelist entry to an existing handler configuration + * + * @param entry new whitelist entry + */ + public void addWhite(String entry) { - add(addrPath, _whiteAddr, _whitePattern); + add(entry, _white); } - public void setBlack(String[] addrPaths) + /* ------------------------------------------------------------ */ + /** + * Add a blacklist entry to an existing handler configuration + * + * @param entry new blacklist entry + */ + public void addBlack(String entry) + { + add(entry, _black); + } + + /* ------------------------------------------------------------ */ + /** + * Re-initialize the whitelist of existing handler object + * + * @param entries array of whitelist entries + */ + public void setWhite(String[] entries) { - set(addrPaths, _blackAddr, _blackPattern); + set(entries, _white); } - public void setWhite(String[] addrPaths) + /* ------------------------------------------------------------ */ + /** + * Re-initialize the blacklist of existing handler object + * + * @param entries array of blacklist entries + */ + public void setBlack(String[] entries) { - set(addrPaths, _whiteAddr, _whitePattern); + set(entries, _black); } + /* ------------------------------------------------------------ */ /** + * Checks the incoming request against the whitelist and blacklist + * + * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException @@ -123,78 +194,181 @@ public class IPAccessHandler extends HandlerWrapper getHandler().handle(target,baseRequest, request, response); } + - protected void add(String addrPath, Map<String,PathMap> addrMap, List<String> patternList) + /* ------------------------------------------------------------ */ + /** + * Helper method to parse the new entry and add it to + * the specified address pattern map. + * + * @param entry new entry + * @param patternMap target address pattern map + */ + protected void add(String entry, IPAddressMap<PathMap> patternMap) { - int idx = addrPath.indexOf('/'); - String addr = idx > 0 ? addrPath.substring(0,idx) : addrPath; - String path = idx > 0 ? addrPath.substring(idx) : null; - if (path!=null && path.length()>1 && path.charAt(1)=='*') - path=path.substring(1); - - PathMap map = addrMap.get(addr); - if (map==null) + if (entry != null && entry.length() > 0) { - map = new PathMap(true); - addrMap.put(addr,map); + boolean deprecated = false; + int idx; + if (entry.indexOf('|') > 0 ) + { + idx = entry.indexOf('|'); + } + else + { + idx = entry.indexOf('/'); + deprecated = (idx >= 0); + } + + String addr = idx > 0 ? entry.substring(0,idx) : entry; + String path = idx > 0 ? entry.substring(idx) : "/*"; + if (addr.endsWith(".")) - patternList.add(addr); + deprecated = true; + if (path!=null && (path.startsWith("|") || path.startsWith("/*."))) + path=path.substring(1); + + PathMap pathMap = patternMap.get(addr); + if (pathMap == null) + { + pathMap = new PathMap(true); + patternMap.put(addr,pathMap); + } + if (path != null) + pathMap.put(path,path); + + if (deprecated) + Log.debug(toString() +" - deprecated specification syntax: "+entry); } - - if (path != null) - map.put(path,path); } - protected void set(String[] addrPaths, Map<String,PathMap> addrMap, List<String> patternList) + /* ------------------------------------------------------------ */ + /** + * Helper method to process a list of new entries and replace + * the content of the specified address pattern map + * + * @param entries new entries + * @param patternMap target address pattern map + */ + protected void set(String[] entries, IPAddressMap<PathMap> patternMap) { - addrMap.clear(); - patternList.clear(); - for (String addrPath:addrPaths) - add(addrPath, addrMap, patternList); + patternMap.clear(); + + if (entries != null && entries.length > 0) + { + for (String addrPath:entries) + { + add(addrPath, patternMap); + } + } } + /* ------------------------------------------------------------ */ + /** + * Check if specified request is allowed by current IPAccess rules. + * + * @param addr internet address + * @param path context path + * @return true if request is allowed + * + */ protected boolean isAddrUriAllowed(String addr, String path) { - if (_whiteAddr.size()>0) + if (_white.size()>0) { - PathMap white=_whiteAddr.get(addr); + boolean match = false; - if (white==null || (white.size()>0 && white.match(path)==null)) + Object whiteObj = _white.getLazyMatches(addr); + if (whiteObj != null) { - boolean match=false; - for (String pattern:_whitePattern) + List whiteList = (whiteObj instanceof List) ? (List)whiteObj : Collections.singletonList(whiteObj); + + for (Object entry: whiteList) { - if (addr.startsWith(pattern)) - { - white=_whiteAddr.get(pattern); - if (white!=null && white.size()>0 && white.match(path)!=null) - { - match=true; - break; - } - } + PathMap pathMap = ((Map.Entry<String,PathMap>)entry).getValue(); + if (match = (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null))) + break; } - if (!match) - return false; } + + if (!match) + return false; } - PathMap black=_blackAddr.get(addr); - if (black!=null && (black.size()==0 || black.match(path)!=null)) - return false; - - for (String pattern:_blackPattern) + if (_black.size() > 0) { - if (addr.startsWith(pattern)) + Object blackObj = _black.getLazyMatches(addr); + if (blackObj != null) { - black=_blackAddr.get(pattern); - if (black!=null && black.match(path)!=null) - return false; - break; + List blackList = (blackObj instanceof List) ? (List)blackObj : Collections.singletonList(blackObj); + + for (Object entry: blackList) + { + PathMap pathMap = ((Map.Entry<String,PathMap>)entry).getValue(); + if (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null)) + return false; + } } } return true; } -} + /* ------------------------------------------------------------ */ + /** + * Dump the white- and black-list configurations when started + * + * @see org.eclipse.jetty.server.handler.HandlerWrapper#doStart() + */ + @Override + protected void doStart() + throws Exception + { + super.doStart(); + + if (Log.isDebugEnabled()) + { + System.err.println(dump()); + } + } + + /* ------------------------------------------------------------ */ + /** + * Dump the handler configuration + */ + public String dump() + { + StringBuilder buf = new StringBuilder(); + + buf.append(toString()); + buf.append(" WHITELIST:\n"); + dump(buf, _white); + buf.append(toString()); + buf.append(" BLACKLIST:\n"); + dump(buf, _black); + + return buf.toString(); + } + + /* ------------------------------------------------------------ */ + /** + * Dump a pattern map into a StringBuilder buffer + * + * @param buf buffer + * @param patternMap pattern map to dump + */ + protected void dump(StringBuilder buf, IPAddressMap<PathMap> patternMap) + { + for (String addr: patternMap.keySet()) + { + for (Object path: ((PathMap)patternMap.get(addr)).values()) + { + buf.append("# "); + buf.append(addr); + buf.append("|"); + buf.append(path); + buf.append("\n"); + } + } + } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ProxyHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ProxyHandler.java new file mode 100644 index 0000000000..60ad6d10de --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ProxyHandler.java @@ -0,0 +1,847 @@ +package org.eclipse.jetty.server.handler; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.http.HttpParser; +import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.ConnectedEndPoint; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.nio.IndirectNIOBuffer; +import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SelectorManager; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConnection; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.HostMap; +import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.ThreadPool; + +/** + * <p>Implementation of a tunneling proxy that supports HTTP CONNECT and transparent proxy.</p> + * <p>To work as CONNECT proxy, objects of this class must be instantiated using the no-arguments + * constructor, since the remote server information will be present in the CONNECT URI.</p> + * <p>To work as transparent proxy, objects of this class must be instantiated using the string + * argument constructor, passing the remote host address and port in the form {@code host:port}.</p> + * + * @version $Revision$ $Date$ + */ +public class ProxyHandler extends HandlerWrapper +{ + private final Logger _logger = Log.getLogger(getClass().getName()); + private final SelectorManager _selectorManager = new Manager(); + private volatile int _connectTimeout = 5000; + private volatile int _writeTimeout = 30000; + private volatile ThreadPool _threadPool; + private volatile boolean _privateThreadPool; + private HostMap<String> _white = new HostMap<String>(); + private HostMap<String> _black = new HostMap<String>(); + + public ProxyHandler() + { + this(null); + } + + public ProxyHandler(String[] white, String[] black) + { + this(null, white, black); + } + + public ProxyHandler(Handler handler) + { + setHandler(handler); + } + + public ProxyHandler(Handler handler, String[] white, String[] black) + { + setHandler(handler); + set(white, _white); + set(black, _black); + } + + /** + * @return the timeout, in milliseconds, to connect to the remote server + */ + public int getConnectTimeout() + { + return _connectTimeout; + } + + /** + * @param connectTimeout the timeout, in milliseconds, to connect to the remote server + */ + public void setConnectTimeout(int connectTimeout) + { + _connectTimeout = connectTimeout; + } + + /** + * @return the timeout, in milliseconds, to write data to a peer + */ + public int getWriteTimeout() + { + return _writeTimeout; + } + + /** + * @param writeTimeout the timeout, in milliseconds, to write data to a peer + */ + public void setWriteTimeout(int writeTimeout) + { + _writeTimeout = writeTimeout; + } + + @Override + public void setServer(Server server) + { + super.setServer(server); + + server.getContainer().update(this,null,_selectorManager,"selectManager"); + + if (_privateThreadPool) + server.getContainer().update(this,null,_privateThreadPool,"threadpool",true); + else + _threadPool=server.getThreadPool(); + } + + /** + * @return the thread pool + */ + public ThreadPool getThreadPool() + { + return _threadPool; + } + + /** + * @param threadPool the thread pool + */ + public void setThreadPool(ThreadPool threadPool) + { + if (getServer()!=null) + getServer().getContainer().update(this,_privateThreadPool?_threadPool:null,threadPool,"threadpool",true); + _privateThreadPool=threadPool!=null; + _threadPool=threadPool; + } + + @Override + protected void doStart() throws Exception + { + super.doStart(); + + if (_threadPool==null) + { + _threadPool=getServer().getThreadPool(); + _privateThreadPool=false; + } + if (_threadPool instanceof LifeCycle && !((LifeCycle)_threadPool).isRunning()) + ((LifeCycle)_threadPool).start(); + + _selectorManager.start(); + _threadPool.dispatch(new Runnable() + { + public void run() + { + while (isRunning()) + { + try + { + _selectorManager.doSelect(0); + } + catch (IOException x) + { + _logger.warn("Unexpected exception", x); + } + } + } + }); + } + + @Override + protected void doStop() throws Exception + { + _selectorManager.stop(); + + ThreadPool threadPool = _threadPool; + if (_privateThreadPool && _threadPool != null && threadPool instanceof LifeCycle) + ((LifeCycle)threadPool).stop(); + + super.doStop(); + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + if (HttpMethods.CONNECT.equalsIgnoreCase(request.getMethod())) + { + _logger.debug("CONNECT request for {}", request.getRequestURI()); + handleConnect(baseRequest, request, response, request.getRequestURI()); + } + else + { + super.handle(target, baseRequest, request, response); + } + } + + /** + * <p>Handles a CONNECT request.</p> + * <p>CONNECT requests may have authentication headers such as <code>Proxy-Authorization</code> + * that authenticate the client with the proxy.</p> + * + * @param baseRequest Jetty-specific http request + * @param request the http request + * @param response the http response + * @param serverAddress the remote server address in the form {@code host:port} + * @throws ServletException if an application error occurs + * @throws IOException if an I/O error occurs + */ + protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress) throws ServletException, IOException + { + boolean proceed = handleAuthentication(request, response, serverAddress); + if (!proceed) + return; + + String host = serverAddress; + int port = 80; + int colon = serverAddress.indexOf(':'); + if (colon > 0) + { + host = serverAddress.substring(0, colon); + port = Integer.parseInt(serverAddress.substring(colon + 1)); + } + + if (!validateDestination(host)) + { + Log.info("ProxyHandler: Forbidden destination "+host); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + baseRequest.setHandled(true); + return; + } + + SocketChannel channel = connectToServer(request, host, port); + + // Transfer unread data from old connection to new connection + // We need to copy the data to avoid races: + // 1. when this unread data is written and the server replies before the clientToProxy + // connection is installed (it is only installed after returning from this method) + // 2. when the client sends data before this unread data has been written. + HttpConnection httpConnection = HttpConnection.getCurrentConnection(); + Buffer headerBuffer = ((HttpParser)httpConnection.getParser()).getHeaderBuffer(); + Buffer bodyBuffer = ((HttpParser)httpConnection.getParser()).getBodyBuffer(); + int length = headerBuffer == null ? 0 : headerBuffer.length(); + length += bodyBuffer == null ? 0 : bodyBuffer.length(); + IndirectNIOBuffer buffer = null; + if (length > 0) + { + buffer = new IndirectNIOBuffer(length); + if (headerBuffer != null) + { + buffer.put(headerBuffer); + headerBuffer.clear(); + } + if (bodyBuffer != null) + { + buffer.put(bodyBuffer); + bodyBuffer.clear(); + } + } + + ConcurrentMap<String, Object> context = new ConcurrentHashMap<String, Object>(); + prepareContext(request, context); + + ClientToProxyConnection clientToProxy = prepareConnections(context, channel, buffer); + + // CONNECT expects a 200 response + response.setStatus(HttpServletResponse.SC_OK); + + // Prevent close + baseRequest.getConnection().getGenerator().setPersistent(true); + + // Close to force last flush it so that the client receives it + response.getOutputStream().close(); + + upgradeConnection(request, response, clientToProxy); + } + + private ClientToProxyConnection prepareConnections(ConcurrentMap<String, Object> context, SocketChannel channel, Buffer buffer) + { + HttpConnection httpConnection = HttpConnection.getCurrentConnection(); + ProxyToServerConnection proxyToServer = newProxyToServerConnection(context, buffer); + ClientToProxyConnection clientToProxy = newClientToProxyConnection(context, channel, httpConnection.getEndPoint(), httpConnection.getTimeStamp()); + clientToProxy.setConnection(proxyToServer); + proxyToServer.setConnection(clientToProxy); + return clientToProxy; + } + + /** + * <p>Handles the authentication before setting up the tunnel to the remote server.</p> + * <p>The default implementation returns true.</p> + * + * @param request the HTTP request + * @param response the HTTP response + * @param address the address of the remote server in the form {@code host:port}. + * @return true to allow to connect to the remote host, false otherwise + * @throws ServletException to report a server error to the caller + * @throws IOException to report a server error to the caller + */ + protected boolean handleAuthentication(HttpServletRequest request, HttpServletResponse response, String address) throws ServletException, IOException + { + return true; + } + + protected ClientToProxyConnection newClientToProxyConnection(ConcurrentMap<String, Object> context, SocketChannel channel, EndPoint endPoint, long timeStamp) + { + return new ClientToProxyConnection(context, channel, endPoint, timeStamp); + } + + protected ProxyToServerConnection newProxyToServerConnection(ConcurrentMap<String, Object> context, Buffer buffer) + { + return new ProxyToServerConnection(context, buffer); + } + + private SocketChannel connectToServer(HttpServletRequest request, String host, int port) throws IOException + { + SocketChannel channel = connect(request, host, port); + channel.configureBlocking(false); + return channel; + } + + /** + * <p>Establishes a connection to the remote server.</p> + * @param request the HTTP request that initiated the tunnel + * @param host the host to connect to + * @param port the port to connect to + * @return a {@link SocketChannel} connected to the remote server + * @throws IOException if the connection cannot be established + */ + protected SocketChannel connect(HttpServletRequest request, String host, int port) throws IOException + { + _logger.debug("Establishing connection to {}:{}", host, port); + // Connect to remote server + SocketChannel channel = SocketChannel.open(); + channel.socket().setTcpNoDelay(true); + channel.socket().connect(new InetSocketAddress(host, port), getConnectTimeout()); + _logger.debug("Established connection to {}:{}", host, port); + return channel; + } + + protected void prepareContext(HttpServletRequest request, ConcurrentMap<String, Object> context) + { + } + + private void upgradeConnection(HttpServletRequest request, HttpServletResponse response, Connection connection) throws IOException + { + // Set the new connection as request attribute and change the status to 101 + // so that Jetty understands that it has to upgrade the connection + request.setAttribute("org.eclipse.jetty.io.Connection", connection); + response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS); + _logger.debug("Upgraded connection to {}", connection); + } + + private void register(SocketChannel channel, ProxyToServerConnection proxyToServer) throws IOException + { + _selectorManager.register(channel, proxyToServer); + proxyToServer.waitReady(_connectTimeout); + } + + /** + * <p>Reads (with non-blocking semantic) into the given {@code buffer} from the given {@code endPoint}.</p> + * @param endPoint the endPoint to read from + * @param buffer the buffer to read data into + * @param context the context information related to the connection + * @return the number of bytes read (possibly 0 since the read is non-blocking) + * or -1 if the channel has been closed remotely + * @throws IOException if the endPoint cannot be read + */ + protected int read(EndPoint endPoint, Buffer buffer, ConcurrentMap<String, Object> context) throws IOException + { + return endPoint.fill(buffer); + } + + /** + * <p>Writes (with blocking semantic) the given buffer of data onto the given endPoint.</p> + * + * @param endPoint the endPoint to write to + * @param buffer the buffer to write + * @param context the context information related to the connection + * @throws IOException if the buffer cannot be written + * @return the number of bytes written + */ + protected int write(EndPoint endPoint, Buffer buffer, ConcurrentMap<String, Object> context) throws IOException + { + if (buffer == null) + return 0; + + int length = buffer.length(); + StringBuilder builder = new StringBuilder(); + int written = endPoint.flush(buffer); + builder.append(written); + buffer.compact(); + if (!endPoint.isBlocking()) + { + while (buffer.space() == 0) + { + boolean ready = endPoint.blockWritable(getWriteTimeout()); + if (!ready) + throw new IOException("Write timeout"); + + written = endPoint.flush(buffer); + builder.append("+").append(written); + buffer.compact(); + } + } + _logger.debug("Written {}/{} bytes {}", builder, length, endPoint); + return length; + } + + private class Manager extends SelectorManager + { + @Override + protected SocketChannel acceptChannel(SelectionKey key) throws IOException + { + // This is a client-side selector manager + throw new IllegalStateException(); + } + + @Override + protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey selectionKey) throws IOException + { + return new SelectChannelEndPoint(channel, selectSet, selectionKey); + } + + @Override + protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint) + { + ProxyToServerConnection proxyToServer = (ProxyToServerConnection)endpoint.getSelectionKey().attachment(); + proxyToServer.setTimeStamp(System.currentTimeMillis()); + proxyToServer.setEndPoint(endpoint); + return proxyToServer; + } + + @Override + protected void endPointOpened(SelectChannelEndPoint endpoint) + { + ProxyToServerConnection proxyToServer = (ProxyToServerConnection)endpoint.getSelectionKey().attachment(); + proxyToServer.ready(); + } + + @Override + public boolean dispatch(Runnable task) + { + return _threadPool.dispatch(task); + } + + @Override + protected void endPointClosed(SelectChannelEndPoint endpoint) + { + } + + @Override + protected void endPointUpgraded(ConnectedEndPoint endpoint, Connection oldConnection) + { + } + } + + public class ProxyToServerConnection implements Connection + { + private final CountDownLatch _ready = new CountDownLatch(1); + private final Buffer _buffer = new IndirectNIOBuffer(1024); + private final ConcurrentMap<String, Object> _context; + private volatile Buffer _data; + private volatile ClientToProxyConnection _toClient; + private volatile long _timestamp; + private volatile SelectChannelEndPoint _endPoint; + + public ProxyToServerConnection(ConcurrentMap<String, Object> context, Buffer data) + { + _context = context; + _data = data; + } + + public Connection handle() throws IOException + { + _logger.debug("ProxyToServer: begin reading from server"); + try + { + if (_data != null) + { + int written = write(_endPoint, _data, _context); + _logger.debug("ProxyToServer: written to server {} bytes", written); + _data = null; + } + + while (true) + { + int read = read(_endPoint, _buffer, _context); + + if (read == -1) + { + _logger.debug("ProxyToServer: server closed connection {}", _endPoint); + close(); + break; + } + + if (read == 0) + break; + + _logger.debug("ProxyToServer: read from server {} bytes {}", read, _endPoint); + int written = write(_toClient._endPoint, _buffer, _context); + _logger.debug("ProxyToServer: written to client {} bytes", written); + } + return this; + } + catch (IOException x) + { + _logger.warn("ProxyToServer: Unexpected exception", x); + close(); + throw x; + } + catch (RuntimeException x) + { + _logger.warn("ProxyToServer: Unexpected exception", x); + close(); + throw x; + } + finally + { + _logger.debug("ProxyToServer: end reading from server"); + } + } + + public void setConnection(ClientToProxyConnection connection) + { + _toClient = connection; + } + + public long getTimeStamp() + { + return _timestamp; + } + + public void setTimeStamp(long timestamp) + { + _timestamp = timestamp; + } + + public void setEndPoint(SelectChannelEndPoint endpoint) + { + _endPoint = endpoint; + _logger.debug("ProxyToServer: {}", _endPoint); + } + + public boolean isIdle() + { + return false; + } + + public boolean isSuspended() + { + return false; + } + + public void ready() + { + _ready.countDown(); + } + + public void waitReady(long timeout) throws IOException + { + try + { + _ready.await(timeout, TimeUnit.MILLISECONDS); + } + catch (final InterruptedException x) + { + throw new IOException(){{initCause(x);}}; + } + } + + public void closeClient() throws IOException + { + _toClient.closeClient(); + } + + public void closeServer() throws IOException + { + _endPoint.close(); + } + + public void close() + { + try + { + closeClient(); + } + catch (IOException x) + { + _logger.debug("ProxyToServer: Unexpected exception closing the client", x); + } + + try + { + closeServer(); + } + catch (IOException x) + { + _logger.debug("ProxyToServer: Unexpected exception closing the server", x); + } + } + } + + public class ClientToProxyConnection implements Connection + { + private final Buffer _buffer = new IndirectNIOBuffer(1024); + private final ConcurrentMap<String, Object> _context; + private final SocketChannel _channel; + private final EndPoint _endPoint; + private final long _timestamp; + private volatile ProxyToServerConnection _toServer; + private boolean _firstTime = true; + + public ClientToProxyConnection(ConcurrentMap<String, Object> context, SocketChannel channel, EndPoint endPoint, long timestamp) + { + _context = context; + _channel = channel; + _endPoint = endPoint; + _timestamp = timestamp; + _logger.debug("ClientToProxy: {}", _endPoint); + } + + public Connection handle() throws IOException + { + _logger.debug("ClientToProxy: begin reading from client"); + try + { + if (_firstTime) + { + _firstTime = false; + register(_channel, _toServer); + _logger.debug("ClientToProxy: registered channel {} with connection {}", _channel, _toServer); + } + + while (true) + { + int read = read(_endPoint, _buffer, _context); + + if (read == -1) + { + _logger.debug("ClientToProxy: client closed connection {}", _endPoint); + close(); + break; + } + + if (read == 0) + break; + + _logger.debug("ClientToProxy: read from client {} bytes {}", read, _endPoint); + int written = write(_toServer._endPoint, _buffer, _context); + _logger.debug("ClientToProxy: written to server {} bytes", written); + } + return this; + } + catch (ClosedChannelException x) + { + _logger.debug("ClientToProxy",x); + closeServer(); + throw x; + } + catch (IOException x) + { + _logger.warn("ClientToProxy", x); + close(); + throw x; + } + catch (RuntimeException x) + { + _logger.warn("ClientToProxy", x); + close(); + throw x; + } + finally + { + _logger.debug("ClientToProxy: end reading from client"); + } + } + + public long getTimeStamp() + { + return _timestamp; + } + + public boolean isIdle() + { + return false; + } + + public boolean isSuspended() + { + return false; + } + + public void setConnection(ProxyToServerConnection connection) + { + _toServer = connection; + } + + public void closeClient() throws IOException + { + _endPoint.close(); + } + + public void closeServer() throws IOException + { + _toServer.closeServer(); + } + + public void close() + { + try + { + closeClient(); + } + catch (IOException x) + { + _logger.debug("ClientToProxy: Unexpected exception closing the client", x); + } + + try + { + closeServer(); + } + catch (IOException x) + { + _logger.debug("ClientToProxy: Unexpected exception closing the server", x); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * Add a whitelist entry to an existing handler configuration + * + * @param entry new whitelist entry + */ + public void addWhite(String entry) + { + add(entry, _white); + } + + /* ------------------------------------------------------------ */ + /** + * Add a blacklist entry to an existing handler configuration + * + * @param entry new blacklist entry + */ + public void addBlack(String entry) + { + add(entry, _black); + } + + /* ------------------------------------------------------------ */ + /** + * Re-initialize the whitelist of existing handler object + * + * @param entries array of whitelist entries + */ + public void setWhite(String[] entries) + { + set(entries, _white); + } + + /* ------------------------------------------------------------ */ + /** + * Re-initialize the blacklist of existing handler object + * + * @param entries array of blacklist entries + */ + public void setBlack(String[] entries) + { + set(entries, _black); + } + + /* ------------------------------------------------------------ */ + /** + * Helper method to process a list of new entries and replace + * the content of the specified host map + * + * @param entries new entries + * @param patternMap target host map + */ + protected void set(String[] entries, HostMap<String> hostMap) + { + hostMap.clear(); + + if (entries != null && entries.length > 0) + { + for (String addrPath:entries) + { + add(addrPath, hostMap); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * Helper method to process the new entry and add it to + * the specified host map. + * + * @param entry new entry + * @param patternMap target host map + */ + private void add(String entry, HostMap<String> hostMap) + { + if (entry != null && entry.length() > 0) + { + entry = entry.trim(); + if (hostMap.get(entry) == null) + { + hostMap.put(entry,entry); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * Check the request hostname against white- and blacklist. + * + * @param host hostname to check + * @return true if hostname is allowed to be proxied + */ + public boolean validateDestination(String host) + { + if (_white.size()>0) + { + Object whiteObj = _white.getLazyMatches(host); + if (whiteObj == null) + { + return false; + } + } + + if (_black.size() > 0) + { + Object blackObj = _black.getLazyMatches(host); + if (blackObj != null) + { + return false; + } + } + + return true; + } +} diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java index 61d949da32..76ee4391a0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java @@ -20,6 +20,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.server.AsyncContinuation; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.Response; @@ -47,9 +48,24 @@ public class RequestLogHandler extends HandlerWrapper public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - super.handle(target, baseRequest, request, response); - if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType()) && _requestLog!=null) - _requestLog.log((Request)request, (Response)response); + AsyncContinuation continuation = baseRequest.getAsyncContinuation(); + if (!continuation.isInitial()) + { + baseRequest.setDispatchTime(System.currentTimeMillis()); + } + + try + { + super.handle(target, baseRequest, request, response); + } + finally + { + if (_requestLog != null && DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) + { + _requestLog.log(baseRequest, (Response)response); + } + + } } /* ------------------------------------------------------------ */ @@ -131,6 +147,5 @@ public class RequestLogHandler extends HandlerWrapper if (_requestLog!=null) _requestLog.stop(); } - } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java index 2bbc84f93d..51ba08e04a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server.handler; @@ -16,7 +16,6 @@ package org.eclipse.jetty.server.handler; import java.io.IOException; import java.io.OutputStream; import java.net.MalformedURLException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -33,7 +32,6 @@ import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.handler.ContextHandler.Context; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.FileResource; @@ -42,12 +40,12 @@ import org.eclipse.jetty.util.resource.Resource; /* ------------------------------------------------------------ */ /** Resource Handler. - * + * * This handle will serve static content and handle If-Modified-Since headers. * No caching is done. * Requests that cannot be handled are let pass (Eg no 404's) - * - * + * + * * @org.apache.xbean.XBean */ public class ResourceHandler extends AbstractHandler @@ -90,7 +88,7 @@ public class ResourceHandler extends AbstractHandler /** * Set if resource aliases (eg symlink, 8.3 names, case insensitivity) are allowed. * Allowing aliases can significantly increase security vulnerabilities. - * If this handler is deployed inside a ContextHandler, then the + * If this handler is deployed inside a ContextHandler, then the * {@link ContextHandler#isAliases()} takes precedent. * @param aliases True if aliases are supported. */ @@ -124,13 +122,13 @@ public class ResourceHandler extends AbstractHandler { Context scontext = ContextHandler.getCurrentContext(); _context = (scontext==null?null:scontext.getContextHandler()); - + if (_context!=null) _aliases=_context.isAliases(); - + if (!_aliases && !FileResource.getCheckAliases()) throw new IllegalStateException("Alias checking disabled"); - + super.doStart(); } @@ -156,12 +154,12 @@ public class ResourceHandler extends AbstractHandler return _baseResource.toString(); } - + /* ------------------------------------------------------------ */ /** * @param base The resourceBase to set. */ - public void setBaseResource(Resource base) + public void setBaseResource(Resource base) { _baseResource=base; } @@ -170,7 +168,7 @@ public class ResourceHandler extends AbstractHandler /** * @param resourceBase The base resource as a string. */ - public void setResourceBase(String resourceBase) + public void setResourceBase(String resourceBase) { try { @@ -203,18 +201,18 @@ public class ResourceHandler extends AbstractHandler } /* ------------------------------------------------------------ */ - /* + /* */ public Resource getResource(String path) throws MalformedURLException { if (path==null || !path.startsWith("/")) throw new MalformedURLException(path); - + Resource base = _baseResource; if (base==null) { if (_context==null) - return null; + return null; base=_context.getBaseResource(); if (base==null) return null; @@ -229,7 +227,7 @@ public class ResourceHandler extends AbstractHandler { Log.ignore(e); } - + return null; } @@ -254,7 +252,7 @@ public class ResourceHandler extends AbstractHandler { _welcomeFiles=welcomeFiles; } - + /* ------------------------------------------------------------ */ protected Resource getWelcome(Resource directory) throws MalformedURLException, IOException { @@ -269,14 +267,14 @@ public class ResourceHandler extends AbstractHandler } /* ------------------------------------------------------------ */ - /* + /* * @see org.eclipse.jetty.server.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int) */ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (baseRequest.isHandled()) return; - + boolean skipContentBody = false; if(!HttpMethods.GET.equals(request.getMethod())) { @@ -284,9 +282,9 @@ public class ResourceHandler extends AbstractHandler return; skipContentBody = true; } - + Resource resource=getResource(request); - + if (resource==null || !resource.exists()) return; if (!_aliases && resource.getAlias()!=null) @@ -297,7 +295,7 @@ public class ResourceHandler extends AbstractHandler // We are going to server something baseRequest.setHandled(true); - + if (resource.isDirectory()) { if (!request.getPathInfo().endsWith(URIUtil.SLASH)) @@ -305,7 +303,7 @@ public class ResourceHandler extends AbstractHandler response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH))); return; } - + Resource welcome=getWelcome(resource); if (welcome!=null && welcome.exists()) resource=welcome; @@ -316,7 +314,7 @@ public class ResourceHandler extends AbstractHandler return; } } - + // set some headers long last_modified=resource.lastModified(); if (last_modified>0) @@ -328,11 +326,11 @@ public class ResourceHandler extends AbstractHandler return; } } - + Buffer mime=_mimeTypes.getMimeByExtension(resource.toString()); if (mime==null) mime=_mimeTypes.getMimeByExtension(request.getPathInfo()); - + // set the headers doResponseHeaders(response,resource,mime!=null?mime.toString():null); response.setDateHeader(HttpHeaders.LAST_MODIFIED,last_modified); @@ -342,7 +340,7 @@ public class ResourceHandler extends AbstractHandler OutputStream out =null; try {out = response.getOutputStream();} catch(IllegalStateException e) {out = new WriterOutputStream(response.getWriter());} - + // See if a short direct method can be used? if (out instanceof HttpConnection.Output) { @@ -369,7 +367,7 @@ public class ResourceHandler extends AbstractHandler else response.sendError(HttpStatus.FORBIDDEN_403); } - + /* ------------------------------------------------------------ */ /** Set the response headers. * This method is called to set the response headers such as content type and content length. @@ -384,25 +382,25 @@ public class ResourceHandler extends AbstractHandler response.setContentType(mimeType); long length=resource.length(); - + if (response instanceof Response) { HttpFields fields = ((Response)response).getHttpFields(); if (length>0) fields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER,length); - + if (_cacheControl!=null) fields.put(HttpHeaders.CACHE_CONTROL_BUFFER,_cacheControl); } else { if (length>0) - response.setHeader(HttpHeaders.CONTENT_LENGTH,TypeUtil.toString(length)); - + response.setHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(length)); + if (_cacheControl!=null) response.setHeader(HttpHeaders.CACHE_CONTROL,_cacheControl.toString()); } - + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java index ae3154c3b7..d4ff318c7a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java @@ -134,7 +134,7 @@ public abstract class ScopedHandler extends HandlerWrapper throws IOException, ServletException { // this method has been manually inlined in several locations, but - // is called protected by an in(false), so your IDE can find those + // is called protected by an if(never()), so your IDE can find those // locations if this code is changed. if (_nextScope!=null) _nextScope.doScope(target,baseRequest,request, response); @@ -158,7 +158,7 @@ public abstract class ScopedHandler extends HandlerWrapper public final void nextHandle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // this method has been manually inlined in several locations, but - // is called protected by an in(false), so your IDE can find those + // is called protected by an if(never()), so your IDE can find those // locations if this code is changed. if (_nextScope!=null && _nextScope==_handler) _nextScope.doHandle(target,baseRequest,request, response); @@ -166,4 +166,10 @@ public abstract class ScopedHandler extends HandlerWrapper _handler.handle(target,baseRequest, request, response); } + /* ------------------------------------------------------------ */ + protected boolean never() + { + return false; + } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/nio/BlockingChannelConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/nio/BlockingChannelConnector.java index 1973e0a4d0..3927cb1caf 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/nio/BlockingChannelConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/nio/BlockingChannelConnector.java @@ -100,14 +100,8 @@ public class BlockingChannelConnector extends AbstractNIOConnector public void customize(EndPoint endpoint, Request request) throws IOException { - ConnectorEndPoint connection = (ConnectorEndPoint)endpoint; - if (connection._sotimeout!=_maxIdleTime) - { - connection._sotimeout=_maxIdleTime; - ((SocketChannel)endpoint.getTransport()).socket().setSoTimeout(_maxIdleTime); - } - super.customize(endpoint, request); + endpoint.setMaxIdleTime(_maxIdleTime); configure(((SocketChannel)endpoint.getTransport()).socket()); } @@ -130,12 +124,12 @@ public class BlockingChannelConnector extends AbstractNIOConnector int _sotimeout; ConnectorEndPoint(ByteChannel channel) + throws IOException { - super(channel); + super(channel,BlockingChannelConnector.this._maxIdleTime); _connection = new HttpConnection(BlockingChannelConnector.this,this,getServer()); } - /* ------------------------------------------------------------ */ /** Get the connection. * @return the connection diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/nio/SelectChannelConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/nio/SelectChannelConnector.java index 175bf6e176..40cb4f7fa0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/nio/SelectChannelConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/nio/SelectChannelConnector.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server.nio; @@ -20,6 +20,7 @@ import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.io.ConnectedEndPoint; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; @@ -44,27 +45,25 @@ import org.eclipse.jetty.util.thread.Timeout.Task; * This connector is best used when there are a many connections that have idle periods. * </p> * <p> - * When used with {@link org.eclipse.jetty.util.ajax.Continuation}, threadless waits are supported. When - * a filter or servlet calls getEvent on a Continuation, a {@link org.eclipse.jetty.server.RetryRequest} - * runtime exception is thrown to allow the thread to exit the current request handling. Jetty will - * catch this exception and will not send a response to the client. Instead the thread is released - * and the Continuation is placed on the timer queue. If the Continuation timeout expires, or it's + * When used with {@link org.eclipse.jetty.continuation.Continuation}, threadless waits are supported. + * If a filter or servlet returns after calling {@link Continuation#suspend()} or when a + * runtime exception is thrown from a call to {@link Continuation#undispatch()}, Jetty will + * will not send a response to the client. Instead the thread is released and the Continuation is + * placed on the timer queue. If the Continuation timeout expires, or it's * resume method is called, then the request is again allocated a thread and the request is retried. * The limitation of this approach is that request content is not available on the retried request, * thus if possible it should be read after the continuation or saved as a request attribute or as the * associated object of the Continuation instance. * </p> - * - * @org.apache.xbean.XBean element="nioConnector" description="Creates an NIO based socket connector" - * - * * + * @org.apache.xbean.XBean element="nioConnector" description="Creates an NIO based socket connector" */ -public class SelectChannelConnector extends AbstractNIOConnector +public class SelectChannelConnector extends AbstractNIOConnector { protected ServerSocketChannel _acceptChannel; private int _lowResourcesConnections; private int _lowResourcesMaxIdleTime; + private int _localPort=-1; private final SelectorManager _manager = new SelectorManager() { @@ -99,7 +98,7 @@ public class SelectChannelConnector extends AbstractNIOConnector // TODO handle max connections and low resources connectionOpened(endpoint.getConnection()); } - + @Override protected void endPointUpgraded(ConnectedEndPoint endpoint, Connection oldConnection) { @@ -118,23 +117,23 @@ public class SelectChannelConnector extends AbstractNIOConnector return SelectChannelConnector.this.newEndPoint(channel,selectSet,sKey); } }; - + /* ------------------------------------------------------------------------------- */ /** * Constructor. - * + * */ public SelectChannelConnector() { } - + /* ------------------------------------------------------------ */ @Override public void accept(int acceptorID) throws IOException { _manager.doSelect(acceptorID); } - + /* ------------------------------------------------------------ */ public void close() throws IOException { @@ -154,9 +153,10 @@ public class SelectChannelConnector extends AbstractNIOConnector if (_acceptChannel != null) _acceptChannel.close(); _acceptChannel = null; + _localPort=-2; } } - + /* ------------------------------------------------------------------------------- */ @Override public void customize(EndPoint endpoint, Request request) throws IOException @@ -166,7 +166,7 @@ public class SelectChannelConnector extends AbstractNIOConnector request.setTimeStamp(cep.getSelectSet().getNow()); super.customize(endpoint, request); } - + /* ------------------------------------------------------------------------------- */ @Override public void persist(EndPoint endpoint) throws IOException @@ -186,9 +186,7 @@ public class SelectChannelConnector extends AbstractNIOConnector { synchronized(this) { - if (_acceptChannel==null || !_acceptChannel.isOpen()) - return -1; - return _acceptChannel.socket().getLocalPort(); + return _localPort; } } @@ -209,12 +207,13 @@ public class SelectChannelConnector extends AbstractNIOConnector InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort()); _acceptChannel.socket().bind(addr,getAcceptQueueSize()); - if (_acceptChannel.socket().getLocalPort()==-1) + _localPort=_acceptChannel.socket().getLocalPort(); + if (_localPort<=0) throw new IOException("Server channel not bound"); - + // Set to non blocking mode _acceptChannel.configureBlocking(false); - + } } } @@ -241,7 +240,7 @@ public class SelectChannelConnector extends AbstractNIOConnector * Set the number of connections, which if exceeded places this manager in low resources state. * This is not an exact measure as the connection count is averaged over the select sets. * @param lowResourcesConnections the number of connections - * @see {@link #setLowResourcesMaxIdleTime(int)} + * @see #setLowResourcesMaxIdleTime(int) */ public void setLowResourcesConnections(int lowResourcesConnections) { @@ -264,16 +263,16 @@ public class SelectChannelConnector extends AbstractNIOConnector * than {@link #getLowResourcesConnections()} connections. This allows the server to rapidly close idle connections * in order to gracefully handle high load situations. * @param lowResourcesMaxIdleTime the period in ms that a connection is allowed to be idle when resources are low. - * @see {@link #setMaxIdleTime(long)} + * @see #setMaxIdleTime(int) */ @Override public void setLowResourcesMaxIdleTime(int lowResourcesMaxIdleTime) { _lowResourcesMaxIdleTime=lowResourcesMaxIdleTime; - super.setLowResourcesMaxIdleTime(lowResourcesMaxIdleTime); + super.setLowResourcesMaxIdleTime(lowResourcesMaxIdleTime); } - + /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.server.server.AbstractConnector#doStart() @@ -297,7 +296,7 @@ public class SelectChannelConnector extends AbstractNIOConnector */ @Override protected void doStop() throws Exception - { + { super.doStop(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java index f4a2ff6fff..0f7a305a0e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java @@ -56,12 +56,9 @@ import org.eclipse.jetty.util.statistic.SampleStatistic; * SessionManager interface provides the majority of the handling required to * implement a SessionManager. Concrete implementations of SessionManager based * on AbstractSessionManager need only implement the newSession method to return - * a specialized version of the Session inner class that provides an attribute + * a specialised version of the Session inner class that provides an attribute * Map. * <p> - * If the property - * org.eclipse.jetty.servlet.AbstractSessionManager.23Notifications is set to - * true, the 2.3 servlet spec notification style will be used. * */ public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager @@ -97,7 +94,8 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement protected int _maxCookieAge=-1; protected int _refreshCookieAge; protected boolean _nodeIdInSessionId; - + protected boolean _checkingRemoteSessionIdEncoding; + protected String _sessionComment; public Set<SessionTrackingMode> _sessionTrackingModes; @@ -128,7 +126,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement ) ) { - HttpCookie cookie=getSessionCookie(session,_context.getContextPath(),secure); + HttpCookie cookie=getSessionCookie(session,_context==null?"/":(_context.getContextPath()),secure); s.cookieSet(); s.setIdChanged(false); return cookie; @@ -209,6 +207,10 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement // set up the sessionPath if it isn't already if (_sessionPath==null) _sessionPath=_context.getInitParameter(SessionManager.__SessionPathProperty); + + tmp=_context.getInitParameter(SessionManager.__CheckRemoteSessionEncoding); + if (tmp!=null) + _checkingRemoteSessionIdEncoding=Boolean.parseBoolean(tmp); } super.doStart(); @@ -226,6 +228,15 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement } /* ------------------------------------------------------------ */ + /** + * @return Returns the httpOnly. + */ + public boolean getHttpOnly() + { + return _httpOnly; + } + + /* ------------------------------------------------------------ */ public HttpSession getHttpSession(String nodeId) { String cluster_id = getIdManager().getClusterId(nodeId); @@ -261,7 +272,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement /* ------------------------------------------------------------ */ /** - * @see getSessionsMax() + * @see #getSessionsMax() */ @Deprecated public int getMaxSessions() @@ -299,7 +310,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement /* ------------------------------------------------------------ */ /** - * @see getSessionsMin() + * @deprecated always returns 0. no replacement available. */ @Deprecated public int getMinSessions() @@ -318,16 +329,35 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement { if (isUsingCookies()) { + String sessionPath = (_sessionPath==null) ? contextPath : _sessionPath; + sessionPath = (sessionPath==null||sessionPath.length()==0) ? "/" : sessionPath; String id = getNodeId(session); - HttpCookie cookie=new HttpCookie( - _sessionCookie, - id, - _sessionDomain, - (contextPath==null||contextPath.length()==0)?"/":contextPath, - _cookieConfig.getMaxAge(), - _cookieConfig.isHttpOnly(), - requestIsSecure&&_cookieConfig.isSecure()); - + HttpCookie cookie = null; + if (_sessionComment == null) + { + cookie = new HttpCookie( + _sessionCookie, + id, + _sessionDomain, + sessionPath, + _cookieConfig.getMaxAge(), + _cookieConfig.isHttpOnly(), + _cookieConfig.isSecure()); + } + else + { + cookie = new HttpCookie( + _sessionCookie, + id, + _sessionDomain, + sessionPath, + _cookieConfig.getMaxAge(), + _cookieConfig.isHttpOnly(), + _cookieConfig.isSecure(), + _sessionComment, + 1); + } + return cookie; } return null; @@ -344,7 +374,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement /* ------------------------------------------------------------ */ /** - * @deprecated. Need to review if it is needed. + * @deprecated Need to review if it is needed. */ public abstract Map getSessionMap(); @@ -410,7 +440,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement /* ------------------------------------------------------------ */ /** - * @see statsReset() + * @see #statsReset() */ @Deprecated public void resetStats() @@ -530,7 +560,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement /** * Create a new session instance * @param request - * @return + * @return the new session */ protected abstract Session newSession(HttpServletRequest request); @@ -671,7 +701,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement @Override public String getComment() { - return null; + return _sessionComment; } @Override @@ -713,7 +743,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement @Override public void setComment(String comment) { - // TODO + _sessionComment = comment; } @Override @@ -784,6 +814,24 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement /* ------------------------------------------------------------ */ /** + * @see org.eclipse.jetty.server.SessionManager#isCheckingRemoteSessionIdEncoding() + */ + public boolean isCheckingRemoteSessionIdEncoding() + { + return _checkingRemoteSessionIdEncoding; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.server.SessionManager#setCheckingRemoteSessionIdEncoding(boolean) + */ + public void setCheckingRemoteSessionIdEncoding(boolean remote) + { + _checkingRemoteSessionIdEncoding=remote; + } + + /* ------------------------------------------------------------ */ + /** * Null returning implementation of HttpSessionContext * * @@ -830,12 +878,10 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement } /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ /** * * <p> - * Implements {@link javax.servlet.HttpSession} from the {@link javax.servlet} package. + * Implements {@link javax.servlet.http.HttpSession} from the <code>javax.servlet</code> package. * </p> * * @@ -1047,10 +1093,13 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement // Notify listeners and unbind values synchronized (this) { - if (_requests<=0) - doInvalidate(); - else - _doInvalidate=true; + if (!_invalid) + { + if (_requests<=0) + doInvalidate(); + else + _doInvalidate=true; + } } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java index bf227dd885..830cbfc7c5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java @@ -48,6 +48,7 @@ public class HashSessionIdManager extends AbstractSessionIdManager /* ------------------------------------------------------------ */ /** Get the session ID with any worker ID. * + * @param clusterId * @param request * @return sessionId plus any worker ID. */ @@ -66,7 +67,7 @@ public class HashSessionIdManager extends AbstractSessionIdManager /* ------------------------------------------------------------ */ /** Get the session ID without any worker ID. * - * @param request + * @param nodeId the node id * @return sessionId without any worker ID. */ public String getClusterId(String nodeId) @@ -94,8 +95,8 @@ public class HashSessionIdManager extends AbstractSessionIdManager } /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.server.SessionManager.MetaManager#idInUse(java.lang.String) + /** + * @see SessionIdManager#idInUse(String) */ public boolean idInUse(String id) { @@ -103,8 +104,8 @@ public class HashSessionIdManager extends AbstractSessionIdManager } /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.server.SessionManager.MetaManager#addSession(javax.servlet.http.HttpSession) + /** + * @see SessionIdManager#addSession(HttpSession) */ public void addSession(HttpSession session) { @@ -112,8 +113,8 @@ public class HashSessionIdManager extends AbstractSessionIdManager } /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.server.SessionManager.MetaManager#addSession(javax.servlet.http.HttpSession) + /** + * @see SessionIdManager#removeSession(HttpSession) */ public void removeSession(HttpSession session) { @@ -121,8 +122,8 @@ public class HashSessionIdManager extends AbstractSessionIdManager } /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.server.SessionManager.MetaManager#invalidateAll(java.lang.String) + /** + * @see SessionIdManager#invalidateAll(String) */ public void invalidateAll(String id) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java index 50633acbc4..5452362a4d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java @@ -112,7 +112,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager * depending on the way the db stores identifiers. * * @param identifier - * @return + * @return the converted identifier */ public String convertIdentifier (String identifier) { @@ -387,8 +387,6 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager * * Makes necessary database tables and starts a Session * scavenger thread. - * - * @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStart() */ @Override public void doStart() @@ -410,8 +408,6 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager /** * Stop the scavenger. - * - * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() */ @Override public void doStop () @@ -431,7 +427,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager /** * Get a connection from the driver or datasource. * - * @return + * @return the connection for the datasource * @throws SQLException */ protected Connection getConnection () diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java index 0ddfd131d8..ecb226fe9b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java @@ -52,15 +52,15 @@ import org.eclipse.jetty.util.log.Log; * contextPath (of the context owning the session) * sessionId (unique in a context) * lastNode (name of node last handled session) - * accessTime (time in ms session was accessed) - * lastAccessTime (previous time in ms session was accessed) - * createTime (time in ms session created) - * cookieTime (time in ms session cookie created) - * lastSavedTime (last time in ms session access times were saved) - * expiryTime (time in ms that the session is due to expire) + * accessTime (time in milliseconds session was accessed) + * lastAccessTime (previous time in milliseconds session was accessed) + * createTime (time in milliseconds session created) + * cookieTime (time in milliseconds session cookie created) + * lastSavedTime (last time in milliseconds session access times were saved) + * expiryTime (time in milliseconds that the session is due to expire) * map (attribute map) * - * As an optimisation, to prevent thrashing the database, we do not persist + * As an optimization, to prevent thrashing the database, we do not persist * the accessTime and lastAccessTime every time the session is accessed. Rather, * we write it out every so often. The frequency is controlled by the saveIntervalSec * field. @@ -274,7 +274,7 @@ public class JDBCSessionManager extends AbstractSessionManager /** * Session restored in database. - * @param row + * @param data */ protected Session (SessionData data) { @@ -442,7 +442,7 @@ public class JDBCSessionManager extends AbstractSessionManager * This could be used eg with a JMS backplane to notify nodes * that the session has changed and to delete the session from * the node's cache, and re-read it from the database. - * @param idInCluster + * @param session */ public void cacheInvalidate (Session session) { @@ -540,8 +540,6 @@ public class JDBCSessionManager extends AbstractSessionManager /** * Get all the sessions as a map of id to Session. - * - * @see org.eclipse.jetty.server.session.AbstractSessionManager#getSessionMap() */ @Override public Map getSessionMap() @@ -817,7 +815,7 @@ public class JDBCSessionManager extends AbstractSessionManager /** * Load a session from the database * @param id - * @return + * @return the session data that was loaded * @throws Exception */ protected SessionData loadSession (String id, String canonicalContextPath, String vhost) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index 746a2999d8..0272e8c11f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -35,9 +35,6 @@ import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ /** SessionHandler. - * - * - * */ public class SessionHandler extends ScopedHandler { @@ -224,8 +221,7 @@ public class SessionHandler extends ScopedHandler throws IOException, ServletException { // start manual inline of nextHandle(target,baseRequest,request,response); - //noinspection ConstantIfStatement - if (false) + if (never()) nextHandle(target,baseRequest,request,response); else if (_nextScope!=null && _nextScope==_handler) _nextScope.doHandle(target,baseRequest,request, response); @@ -236,8 +232,8 @@ public class SessionHandler extends ScopedHandler /* ------------------------------------------------------------ */ /** Look for a requested session ID in cookies and URI parameters + * @param baseRequest * @param request - * @param dispatch */ protected void setRequestedId(Request baseRequest, HttpServletRequest request) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslCertificates.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslCertificates.java index 94803ab856..25b1ac7dda 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslCertificates.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslCertificates.java @@ -10,9 +10,9 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import org.eclipse.jetty.http.HttpSchemes; -import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.bio.SocketEndPoint; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java index f40159f08a..71bb96de93 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java @@ -13,14 +13,12 @@ package org.eclipse.jetty.server.ssl; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.security.KeyStore; import java.security.SecureRandom; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -29,7 +27,6 @@ import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; @@ -38,7 +35,6 @@ import javax.net.ssl.TrustManagerFactory; import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.security.Password; -import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.Connection; @@ -47,11 +43,11 @@ import org.eclipse.jetty.io.ThreadLocalBuffers; import org.eclipse.jetty.io.bio.SocketEndPoint; import org.eclipse.jetty.io.nio.DirectNIOBuffer; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; import org.eclipse.jetty.io.nio.SelectorManager.SelectSet; import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; @@ -471,7 +467,6 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements /* ------------------------------------------------------------ */ /** - * @throws Exception * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext) */ public SSLContext getSslContext() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java index 0d7fb53bff..ca99861cd9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java @@ -137,7 +137,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector Socket socket = _serverSocket.accept(); configure(socket); - ConnectorEndPoint connection=new SslConnection(socket); + ConnectorEndPoint connection=new SslConnectorEndPoint(socket); connection.dispatch(); } @@ -205,14 +205,10 @@ public class SslSocketConnector extends SocketConnector implements SslConnector try { if (keystorePath!=null) - { keystoreInputStream = Resource.newResource(keystorePath).getInputStream(); - keystore=KeyStore.getInstance(keystoreType); - keystore.load(keystoreInputStream,keystorePassword==null?null:keystorePassword.toString().toCharArray()); - return keystore; - } - - return null; + keystore=KeyStore.getInstance(keystoreType); + keystore.load(keystoreInputStream,keystorePassword==null?null:keystorePassword.toString().toCharArray()); + return keystore; } finally { @@ -363,13 +359,13 @@ public class SslSocketConnector extends SocketConnector implements SslConnector /* ------------------------------------------------------------ */ /** - * @param addr The {@link SocketAddress address} that this server should listen on + * @param host The host name that this server should listen on + * @param port the port that this server should listen on * @param backlog See {@link ServerSocket#bind(java.net.SocketAddress, int)} * @return A new {@link ServerSocket socket object} bound to the supplied address with all other * settings as per the current configuration of this connector. - * @see #setWantClientAuth - * @see #setNeedClientAuth - * @see #setCipherSuites + * @see #setWantClientAuth(boolean) + * @see #setNeedClientAuth(boolean) * @exception IOException */ @@ -411,10 +407,10 @@ public class SslSocketConnector extends SocketConnector implements SslConnector excludedCSList = new ArrayList<String>(); } String[] enabledCipherSuites = socket.getEnabledCipherSuites(); - List<String> enabledCSList=Arrays.asList(enabledCipherSuites); + List<String> enabledCSList = new ArrayList<String>(Arrays.asList(enabledCipherSuites)); String[] supportedCipherSuites = socket.getSupportedCipherSuites(); - List<String> supportedCSList=Arrays.asList(supportedCipherSuites); + List<String> supportedCSList = Arrays.asList(supportedCipherSuites); for (String cipherName : includedCSList) { @@ -432,7 +428,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector enabledCSList.remove(cipherName); } } - enabledCipherSuites=enabledCSList.toArray(new String[0]); + enabledCipherSuites = enabledCSList.toArray(new String[enabledCSList.size()]); socket.setEnabledCipherSuites(enabledCipherSuites); } @@ -557,7 +553,6 @@ public class SslSocketConnector extends SocketConnector implements SslConnector /* ------------------------------------------------------------ */ /** - * @throws Exception * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext) */ public SSLContext getSslContext() @@ -577,10 +572,10 @@ public class SslSocketConnector extends SocketConnector implements SslConnector /* ------------------------------------------------------------ */ /** - * Set the value of the _wantClientAuth property. This property is used when - * {@link #newServerSocket(SocketAddress, int) opening server sockets}. + * Set the value of the _wantClientAuth property. This property is used + * internally when opening server sockets. * - * @param wantClientAuth true iff we want client certificate authentication. + * @param wantClientAuth true if we want client certificate authentication. * @see SSLServerSocket#setWantClientAuth */ public void setWantClientAuth(boolean wantClientAuth) @@ -607,14 +602,19 @@ public class SslSocketConnector extends SocketConnector implements SslConnector } /* ------------------------------------------------------------ */ - public class SslConnection extends ConnectorEndPoint + public class SslConnectorEndPoint extends ConnectorEndPoint { - public SslConnection(Socket socket) throws IOException + public SslConnectorEndPoint(Socket socket) throws IOException { super(socket); } @Override + public void shutdownOutput() throws IOException + { + } + + @Override public void run() { try @@ -667,7 +667,8 @@ public class SslSocketConnector extends SocketConnector implements SslConnector /* ------------------------------------------------------------ */ /** * Unsupported. - * @see org.eclipse.jetty.server.ssl.SslConnector#getAlgorithm() + * + * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) */ public String getAlgorithm() { @@ -677,7 +678,8 @@ public class SslSocketConnector extends SocketConnector implements SslConnector /* ------------------------------------------------------------ */ /** * Unsupported. - * @see org.eclipse.jetty.server.ssl.SslConnector#setAlgorithm(java.lang.String) + * + * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) */ public void setAlgorithm(String algorithm) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractConnectorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractConnectorTest.java index 5fe8d82a8a..bc782a162b 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractConnectorTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractConnectorTest.java @@ -20,184 +20,189 @@ import java.io.PrintWriter; import java.net.Socket; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.util.log.Log; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; -public class AbstractConnectorTest extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class AbstractConnectorTest { - private Server _server; - private Handler _handler; - private AbstractConnector _connector; - - private String _request = "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "\r\n"; + private static Server _server; + private static AbstractConnector _connector; + private static CyclicBarrier _connect; + private static CountDownLatch _closed; + private Socket[] _socket; private PrintWriter[] _out; private BufferedReader[] _in; - - private CyclicBarrier _connect; - private CountDownLatch _closed; - @Override - protected void setUp() throws Exception + @BeforeClass + public static void init() throws Exception { _connect = new CyclicBarrier(2); _server = new Server(); + _connector = new SelectChannelConnector() + { + public void connectionClosed(Connection connection) + { + super.connectionClosed(connection); + _closed.countDown(); + } - _connector = - new SelectChannelConnector() { - public void connectionClosed(Connection connection) - { - super.connectionClosed(connection); - _closed.countDown(); - } - - }; - _server.addConnector(_connector); + }; _connector.setStatsOn(true); + _server.addConnector(_connector); - HandlerWrapper wrapper = - new HandlerWrapper() { - public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException + HandlerWrapper wrapper = new HandlerWrapper() + { + public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException + { + try + { + _connect.await(); + } + catch (Exception ex) { - try - { - _connect.await(); - } - catch (Exception ex) - { - Log.debug(ex); - } - finally - { - super.handle(path, request, httpRequest, httpResponse); - } + Log.debug(ex); } - }; - _server.setHandler(wrapper); - - _handler = - new AbstractHandler() { - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException + finally { - baseRequest.setHandled(true); - - PrintWriter out = response.getWriter(); - out.write("Server response\n"); - out.close(); - - response.setStatus(HttpServletResponse.SC_OK); + super.handle(path, request, httpRequest, httpResponse); } - }; - wrapper.setHandler(_handler); - + } + }; + _server.setHandler(wrapper); + + Handler handler = new AbstractHandler() + { + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + baseRequest.setHandled(true); + + PrintWriter out = response.getWriter(); + out.write("Server response\n"); + out.close(); + + response.setStatus(HttpServletResponse.SC_OK); + } + }; + wrapper.setHandler(handler); + _server.start(); } - @Override - protected void tearDown() throws Exception + @AfterClass + public static void destroy() throws Exception { _server.stop(); _server.join(); } - public void testSingleRequest() - throws Exception + @Before + public void reset() { - doInit(1); + _connector.statsReset(); + } + + @Test + public void testSingleRequest() throws Exception + { + int connections = 1; + doInit(connections); sendRequest(1, 1); - - doClose(1); - - assertEquals(1, _connector.getConnections()); + + doClose(connections); + + assertEquals(connections, _connector.getConnections()); assertEquals(0, _connector.getConnectionsOpen()); - assertEquals(1, _connector.getConnectionsOpenMax()); + assertEquals(connections, _connector.getConnectionsOpenMax()); assertTrue(_connector.getConnectionsOpen() <= _connector.getConnectionsOpenMax()); - + assertTrue(_connector.getConnectionsDurationMean() > 0); assertTrue(_connector.getConnectionsDurationMax() > 0); assertTrue(_connector.getConnectionsDurationMean() <= _connector.getConnectionsDurationMax()); - + assertEquals(1, _connector.getRequests()); - assertEquals(1.0, _connector.getConnectionsRequestsMean()); + assertEquals(1.0, _connector.getConnectionsRequestsMean(), 0.01); assertEquals(1, _connector.getConnectionsRequestsMax()); assertTrue(_connector.getConnectionsRequestsMean() <= _connector.getConnectionsRequestsMax()); } - - public void testMultipleRequests() - throws Exception + + @Test + public void testMultipleRequests() throws Exception { doInit(1); - + sendRequest(1, 1); sendRequest(1, 1); doClose(1); - + assertEquals(1, _connector.getConnections()); assertEquals(0, _connector.getConnectionsOpen()); assertEquals(1, _connector.getConnectionsOpenMax()); assertTrue(_connector.getConnectionsOpen() <= _connector.getConnectionsOpenMax()); - + assertTrue(_connector.getConnectionsDurationMean() > 0); assertTrue(_connector.getConnectionsDurationMax() > 0); assertTrue(_connector.getConnectionsDurationMean() <= _connector.getConnectionsDurationMax()); - + assertEquals(2, _connector.getRequests()); - assertEquals(2.0, _connector.getConnectionsRequestsMean()); + assertEquals(2.0, _connector.getConnectionsRequestsMean(), 0.01); assertEquals(2, _connector.getConnectionsRequestsMax()); assertTrue(_connector.getConnectionsRequestsMean() <= _connector.getConnectionsRequestsMax()); } - - public void testMultipleConnections() - throws Exception + + @Test + public void testMultipleConnections() throws Exception { doInit(3); - + sendRequest(1, 1); // request 1 connection 1 - + sendRequest(2, 2); // request 1 connection 2 - + sendRequest(3, 3); // request 1 connection 3 - + sendRequest(2, 3); // request 2 connection 2 - + sendRequest(3, 3); // request 2 connection 3 - + sendRequest(3, 3); // request 3 connection 3 - + doClose(3); assertEquals(3, _connector.getConnections()); assertEquals(0, _connector.getConnectionsOpen()); assertEquals(3, _connector.getConnectionsOpenMax()); assertTrue(_connector.getConnectionsOpen() <= _connector.getConnectionsOpenMax()); - + assertTrue(_connector.getConnectionsDurationMean() > 0); assertTrue(_connector.getConnectionsDurationMax() > 0); assertTrue(_connector.getConnectionsDurationMean() <= _connector.getConnectionsDurationMax()); - + assertEquals(6, _connector.getRequests()); - assertEquals(2.0, _connector.getConnectionsRequestsMean()); + assertEquals(2.0, _connector.getConnectionsRequestsMean(), 0.01); assertEquals(3, _connector.getConnectionsRequestsMax()); assertTrue(_connector.getConnectionsRequestsMean() <= _connector.getConnectionsRequestsMax()); } - + protected void doInit(int count) { _socket = new Socket[count]; @@ -206,9 +211,8 @@ public class AbstractConnectorTest extends TestCase _closed = new CountDownLatch(count); } - - protected void doClose(int count) - throws Exception + + private void doClose(int count) throws Exception { for (int idx=0; idx < count; idx++) { @@ -217,35 +221,34 @@ public class AbstractConnectorTest extends TestCase if (_in[idx] != null) _in[idx].close(); - + if (_socket[idx] != null) _socket[idx].close(); } - + _closed.await(); } - - protected void sendRequest(int id, int count) - throws Exception + + private void sendRequest(int id, int count) throws Exception { int idx = id - 1; - + if (idx < 0) throw new IllegalArgumentException("Connection ID <= 0"); - + _socket[idx] = _socket[idx] == null ? new Socket("localhost", _connector.getLocalPort()) : _socket[idx]; _out[idx] = _out[idx] == null ? new PrintWriter(_socket[idx].getOutputStream(), true) : _out[idx]; _in[idx] = _in[idx] == null ? new BufferedReader(new InputStreamReader(_socket[idx].getInputStream())) : _in[idx]; - + _connect.reset(); - - _out[idx].write(_request); + + _out[idx].write("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"); _out[idx].flush(); - + _connect.await(); - + assertEquals(count, _connector.getConnectionsOpen()); - + while(_in[idx].ready()) { _in[idx].readLine(); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncContextTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncContextTest.java index 1fa5eab57e..22ddb943c2 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncContextTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncContextTest.java @@ -16,7 +16,6 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; @@ -25,40 +24,47 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - +import org.eclipse.jetty.continuation.Continuation; +import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.session.SessionHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class AsyncContextTest extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class AsyncContextTest { protected Server _server = new Server(); protected SuspendHandler _handler = new SuspendHandler(); protected LocalConnector _connector; - @Override - protected void setUp() throws Exception + @Before + public void init() throws Exception { _connector = new LocalConnector(); _server.setConnectors(new Connector[]{ _connector }); - + SessionHandler session = new SessionHandler(); session.setHandler(_handler); - + _server.setHandler(session); _server.start(); } - @Override - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { _server.stop(); + _server.join(); } - public void testOneCycle() throws Exception + @Test + public void testSuspendResume() throws Exception { String response; - __completed.set(0); __completed1.set(0); _handler.setRead(0); @@ -113,7 +119,6 @@ public class AsyncContextTest extends TestCase response=process("wibble"); check(response,"COMPLETED"); - _handler.setRead(6); _handler.setResumeAfter(0); @@ -171,7 +176,7 @@ public class AsyncContextTest extends TestCase } - public synchronized String process(String content) throws Exception + private synchronized String process(String content) throws Exception { String request = "GET / HTTP/1.1\r\n" + "Host: localhost\r\n"; @@ -194,8 +199,8 @@ public class AsyncContextTest extends TestCase private long _completeAfter2=-1; public SuspendHandler() - {} - + { + } public int getRead() { @@ -508,7 +513,6 @@ public class AsyncContextTest extends TestCase public void onError(AsyncEvent event) throws IOException { } - @Override public void onStartAsync(AsyncEvent event) throws IOException { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java index b4d5cafba6..8f51db579d 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java @@ -4,24 +4,22 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; import java.io.IOException; import java.io.InputStream; -import java.net.Inet4Address; import java.net.InetAddress; import java.net.Socket; import java.util.Random; import java.util.Timer; import java.util.TimerTask; - import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; @@ -30,8 +28,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.server.handler.HandlerWrapper; @@ -39,8 +35,13 @@ import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class AsyncStressTest extends TestCase +import static org.junit.Assert.assertEquals; + +public class AsyncStressTest { protected Server _server = new Server(); protected SuspendHandler _handler = new SuspendHandler(); @@ -50,9 +51,18 @@ public class AsyncStressTest extends TestCase protected Random _random = new Random(); protected QueuedThreadPool _threads=new QueuedThreadPool(); protected boolean _stress; + private final static String[][] __paths = + { + {"/path","NORMAL"}, + {"/path/info","NORMAL"}, + {"/path?sleep=<PERIOD>","SLEPT"}, + {"/path?suspend=<PERIOD>","TIMEOUT"}, + {"/path?suspend=60000&resume=<PERIOD>","RESUMED"}, + {"/path?suspend=60000&complete=<PERIOD>","COMPLETED"}, + }; - @Override - protected void setUp() throws Exception + @Before + public void init() throws Exception { _stress= Boolean.getBoolean("STRESS"); _threads.setMaxThreads(50); @@ -66,23 +76,28 @@ public class AsyncStressTest extends TestCase _addr=InetAddress.getLocalHost(); } - @Override - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { _server.stop(); + _server.join(); } - final static String[][] __paths = + @Test + public void testAsync() throws Throwable { - {"/path","NORMAL"}, - {"/path/info","NORMAL"}, - {"/path?sleep=<PERIOD>","SLEPT"}, - {"/path?suspend=<PERIOD>","TIMEOUT"}, - {"/path?suspend=60000&resume=<PERIOD>","RESUMED"}, - {"/path?suspend=60000&complete=<PERIOD>","COMPLETED"}, - }; - - public void doConnections(int connections,final int loops) throws Throwable + if (_stress) + { + System.err.println("STRESS!"); + doConnections(1600,240); + } + else + { + doConnections(80,80); + } + } + + private void doConnections(int connections,final int loops) throws Throwable { Socket[] socket = new Socket[connections]; int [][] path = new int[connections][loops]; @@ -109,13 +124,13 @@ public class AsyncStressTest extends TestCase String uri=__paths[p][0].replace("<PERIOD>",Integer.toString(period)); long start=System.currentTimeMillis(); - String request = - "GET "+uri+" HTTP/1.1\r\n"+ - "Host: localhost\r\n"+ - "start: "+start+"\r\n"+ - "result: "+__paths[p][1]+"\r\n"+ - ((l+1<loops)?"":"Connection: close\r\n")+ - "\r\n"; + String request = + "GET "+uri+" HTTP/1.1\r\n"+ + "Host: localhost\r\n"+ + "start: "+start+"\r\n"+ + "result: "+__paths[p][1]+"\r\n"+ + ((l+1<loops)?"":"Connection: close\r\n")+ + "\r\n"; socket[i].getOutputStream().write(request.getBytes("UTF-8")); socket[i].getOutputStream().flush(); } @@ -127,7 +142,7 @@ public class AsyncStressTest extends TestCase System.err.println(); Log.info("Sent "+(loops*__paths.length)+" requests"); - + String[] results=new String[connections]; for (int i=0;i<connections;i++) { @@ -141,14 +156,14 @@ public class AsyncStressTest extends TestCase Log.info("Read "+connections+" connections"); for (int i=0;i<connections;i++) - { + { int offset=0; String result=results[i]; for (int l=0;l<loops;l++) { String expect = __paths[path[i][l]][1]; expect=expect+" "+expect; - + offset=result.indexOf("200 OK",offset)+6; offset=result.indexOf("\r\n\r\n",offset)+4; int end=result.indexOf("\n",offset); @@ -159,28 +174,15 @@ public class AsyncStressTest extends TestCase } } - public void testAsync() throws Throwable - { - if (_stress) - { - System.err.println("STRESS!"); - doConnections(1600,240); - } - else - { - doConnections(80,80); - } - } - private static class SuspendHandler extends HandlerWrapper { private final Timer _timer; - - public SuspendHandler() + + private SuspendHandler() { _timer=new Timer(); } - + @Override public void handle(String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { @@ -189,9 +191,9 @@ public class AsyncStressTest extends TestCase long suspend_for=-1; long resume_after=-1; long complete_after=-1; - + final String uri=baseRequest.getUri().toString(); - + if (request.getParameter("read")!=null) read_before=Integer.parseInt(request.getParameter("read")); if (request.getParameter("sleep")!=null) @@ -202,7 +204,7 @@ public class AsyncStressTest extends TestCase resume_after=Integer.parseInt(request.getParameter("resume")); if (request.getParameter("complete")!=null) complete_after=Integer.parseInt(request.getParameter("complete")); - + if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) { if (read_before>0) @@ -224,7 +226,6 @@ public class AsyncStressTest extends TestCase asyncContext.addListener(__asyncListener); if (suspend_for>0) asyncContext.setTimeout(suspend_for); - if (complete_after>0) { TimerTask complete = new TimerTask() @@ -246,7 +247,7 @@ public class AsyncStressTest extends TestCase System.err.println(baseRequest+"=="+br); System.err.println(uri+"=="+br.getUri()); System.err.println(asyncContext+"=="+br.getAsyncContinuation()); - + Log.warn(e); System.exit(1); } @@ -283,7 +284,7 @@ public class AsyncStressTest extends TestCase { asyncContext.dispatch(); } - + } else if (sleep_for>=0) { @@ -298,14 +299,12 @@ public class AsyncStressTest extends TestCase response.setStatus(200); response.getOutputStream().println("SLEPT "+request.getHeader("result")); baseRequest.setHandled(true); - return; } else { response.setStatus(200); response.getOutputStream().println("NORMAL "+request.getHeader("result")); baseRequest.setHandled(true); - return; } } else if (request.getAttribute("TIMEOUT")!=null) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncUploadTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncUploadTest.java index 3ea0a80a31..92ef496db2 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncUploadTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncUploadTest.java @@ -20,89 +20,92 @@ import java.io.OutputStream; import java.net.Socket; import java.util.Arrays; import java.util.concurrent.TimeUnit; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSession; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationSupport; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.util.IO; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * @version $Revision: 889 $ $Date: 2009-09-14 14:52:16 +1000 (Mon, 14 Sep 2009) $ */ -public class AsyncUploadTest extends TestCase +public class AsyncUploadTest { - int _total; - - public void test() throws Exception + private static Server server; + private static Connector connector; + private static int total; + + @BeforeClass + public static void startServer() throws Exception { - Server server = new Server(); - SelectChannelConnector connector = new SelectChannelConnector(); + server = new Server(); + connector = new SelectChannelConnector(); server.addConnector(connector); - server.setHandler(new EmptyHandler()); - server.start(); - try - { - _total=0; - final Socket socket = new Socket("localhost",connector.getLocalPort()); - - byte[] content = new byte[16*4096]; - Arrays.fill(content, (byte)120); - - long start = System.nanoTime(); - OutputStream out = socket.getOutputStream(); - out.write("POST / HTTP/1.1\r\n".getBytes()); - out.write("Host: localhost\r\n".getBytes()); - out.write(("Content-Length: "+content.length+"\r\n").getBytes()); - out.write("Content-Type: bytes\r\n".getBytes()); - out.write("Connection: close\r\n".getBytes()); - out.write("\r\n".getBytes()); - out.flush(); - - out.write(content,0,4*4096); - Thread.sleep(100); - out.write(content,8192,4*4096); - Thread.sleep(100); - out.write(content,8*4096,content.length-8*4096); - - out.flush(); - - InputStream in = socket.getInputStream(); - String response = IO.toString(in); - // System.err.println(response); - assertTrue(response.indexOf("200 OK")>0); - - long end = System.nanoTime(); - System.err.println("upload time: " + TimeUnit.NANOSECONDS.toMillis(end - start)); - assertEquals(content.length,_total); - - } - finally - { - server.stop(); - } } - private class EmptyHandler extends AbstractHandler + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + server.join(); + } + + @Test + public void test() throws Exception + { + final Socket socket = new Socket("localhost",connector.getLocalPort()); + + byte[] content = new byte[16*4096]; + Arrays.fill(content, (byte)120); + + long start = System.nanoTime(); + OutputStream out = socket.getOutputStream(); + out.write("POST / HTTP/1.1\r\n".getBytes()); + out.write("Host: localhost\r\n".getBytes()); + out.write(("Content-Length: "+content.length+"\r\n").getBytes()); + out.write("Content-Type: bytes\r\n".getBytes()); + out.write("Connection: close\r\n".getBytes()); + out.write("\r\n".getBytes()); + out.flush(); + + out.write(content,0,4*4096); + Thread.sleep(100); + out.write(content,8192,4*4096); + Thread.sleep(100); + out.write(content,8*4096,content.length-8*4096); + + out.flush(); + + InputStream in = socket.getInputStream(); + String response = IO.toString(in); + // System.err.println(response); + assertTrue(response.indexOf("200 OK")>0); + + long end = System.nanoTime(); + System.err.println("upload time: " + TimeUnit.NANOSECONDS.toMillis(end - start)); + assertEquals(content.length, total); + } + + private static class EmptyHandler extends AbstractHandler { public void handle(String path, final Request request, HttpServletRequest httpRequest, final HttpServletResponse httpResponse) throws IOException, ServletException { - // System.out.println("path = " + path); - final Continuation continuation = ContinuationSupport.getContinuation(request); httpResponse.setStatus(500); request.setHandled(true); - + new Thread() { @Override @@ -113,20 +116,15 @@ public class AsyncUploadTest extends TestCase Thread.sleep(100); InputStream in = request.getInputStream(); byte[] b = new byte[4*4096]; - int l; - - while((l=in.read(b))>=0) - { - // System.err.println("read "+l); - _total+=l; - } - - System.err.println("Read "+_total); + int read; + while((read =in.read(b))>=0) + total += read; + System.err.println("Read "+ total); } catch(Exception e) { e.printStackTrace(); - _total=-1; + total =-1; } finally { @@ -135,16 +133,8 @@ public class AsyncUploadTest extends TestCase } } }.start(); - - continuation.suspend(); - } - } - private class EmptyHostnameVerifier implements HostnameVerifier - { - public boolean verify(String s, SSLSession sslSession) - { - return true; + continuation.suspend(); } } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingChannelServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingChannelServerTest.java index d05fdc0ffd..23c415d1ed 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingChannelServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingChannelServerTest.java @@ -4,23 +4,26 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; + import org.eclipse.jetty.server.nio.BlockingChannelConnector; +import org.junit.BeforeClass; /** * HttpServer Tester. */ public class BlockingChannelServerTest extends HttpServerTestBase { - public BlockingChannelServerTest() + @BeforeClass + public static void init() throws Exception { - super(new BlockingChannelConnector()); - } + startServer(new BlockingChannelConnector()); + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/BusySelectChannelServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/BusySelectChannelServerTest.java index 2948e325b8..a697bb2c63 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/BusySelectChannelServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/BusySelectChannelServerTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; @@ -23,22 +23,18 @@ import org.eclipse.jetty.io.nio.NIOBuffer; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; import org.eclipse.jetty.io.nio.SelectorManager.SelectSet; import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.BeforeClass; /** * HttpServer Tester. */ public class BusySelectChannelServerTest extends HttpServerTestBase { - - public BusySelectChannelServerTest() + @BeforeClass + public static void init() throws Exception { - super(new SelectChannelConnector() + startServer(new SelectChannelConnector() { - /* ------------------------------------------------------------ */ - /* (non-Javadoc) - * @see org.eclipse.jetty.server.server.nio.SelectChannelConnector#newEndPoint(java.nio.channels.SocketChannel, org.eclipse.io.nio.SelectorManager.SelectSet, java.nio.channels.SelectionKey) - */ @Override protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException { @@ -46,7 +42,7 @@ public class BusySelectChannelServerTest extends HttpServerTestBase { int write; int read; - + /* ------------------------------------------------------------ */ /* (non-Javadoc) * @see org.eclipse.io.nio.SelectChannelEndPoint#flush(org.eclipse.io.Buffer, org.eclipse.io.Buffer, org.eclipse.io.Buffer) @@ -103,7 +99,7 @@ public class BusySelectChannelServerTest extends HttpServerTestBase buffer.put(one.peek(0)); return l; } - + if (x<24 && buffer.space()>=2) { NIOBuffer two = new IndirectNIOBuffer(2); @@ -114,7 +110,7 @@ public class BusySelectChannelServerTest extends HttpServerTestBase buffer.put(two.peek(1)); return l; } - + if (x<64 && buffer.space()>=3) { NIOBuffer three = new IndirectNIOBuffer(3); @@ -127,18 +123,11 @@ public class BusySelectChannelServerTest extends HttpServerTestBase buffer.put(three.peek(2)); return l; } - + return super.fill(buffer); } }; - } - }); - } - - - @Override - protected void configServer(Server server) - { - server.setThreadPool(new QueuedThreadPool()); + } + }); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java index 2ab4d3c99b..286fdcd75b 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java @@ -4,42 +4,31 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; /** - * Test {@link AbstractConnector#checkForwardedHeaders(org.eclipse.io.EndPoint, Request)}. + * */ -public class CheckReverseProxyHeadersTest extends TestCase +public class CheckReverseProxyHeadersTest { - Server server=new Server(); - LocalConnector connector=new LocalConnector(); - - /** - * Constructor for CheckReverseProxyHeadersTest. - * @param name test case name. - */ - public CheckReverseProxyHeadersTest(String name) - { - super(name); - } - + @Test public void testCheckReverseProxyHeaders() throws Exception { // Classic ProxyPass from example.com:80 to localhost:8080 @@ -56,7 +45,7 @@ public class CheckReverseProxyHeadersTest extends TestCase assertEquals("example.com", request.getHeader("Host")); } }); - + // ProxyPass from example.com:81 to localhost:8080 testRequest("Host: localhost:8080\n" + "X-Forwarded-For: 10.20.30.40\n" + @@ -72,7 +61,7 @@ public class CheckReverseProxyHeadersTest extends TestCase assertEquals("example.com:81", request.getHeader("Host")); } }); - + // Multiple ProxyPass from example.com:80 to rp.example.com:82 to localhost:8080 testRequest("Host: localhost:8080\n" + "X-Forwarded-For: 10.20.30.40, 10.0.0.1\n" + @@ -94,21 +83,21 @@ public class CheckReverseProxyHeadersTest extends TestCase { Server server = new Server(); LocalConnector connector = new LocalConnector(); - + // Activate reverse proxy headers checking connector.setForwarded(true); - + server.setConnectors(new Connector[] {connector}); ValidationHandler validationHandler = new ValidationHandler(requestValidator); server.setHandler(validationHandler); - + try { server.start(); connector.getResponses("GET / HTTP/1.1\n" + headers + "\n\n"); - + Error error = validationHandler.getError(); - + if (error != null) { throw error; @@ -137,18 +126,14 @@ public class CheckReverseProxyHeadersTest extends TestCase */ private static class ValidationHandler extends AbstractHandler { - private RequestValidator _requestValidator; + private final RequestValidator _requestValidator; private Error _error; - - /** - * Create the validation handler with a request validator. - * @param requestValidator the request validator. - */ - public ValidationHandler(RequestValidator requestValidator) + + private ValidationHandler(RequestValidator requestValidator) { _requestValidator = requestValidator; } - + /** * Retrieve the validation error. * @return the validation error or <code>null</code> if there was no error. @@ -157,7 +142,7 @@ public class CheckReverseProxyHeadersTest extends TestCase { return _error; } - + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { try diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/EncodedHttpURITest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/EncodedHttpURITest.java index 0d75b485f6..4395e39422 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/EncodedHttpURITest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/EncodedHttpURITest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; @@ -16,28 +16,28 @@ package org.eclipse.jetty.server; import java.net.URLDecoder; import java.net.URLEncoder; -import junit.framework.TestCase; - import org.eclipse.jetty.http.EncodedHttpURI; +import org.junit.Test; -public class EncodedHttpURITest extends TestCase -{ +import static org.junit.Assert.assertEquals; - public void testNonURIAscii () - throws Exception +public class EncodedHttpURITest +{ + @Test + public void testNonURIAscii() throws Exception { String url = "http://www.foo.com/ma\u00F1ana"; byte[] asISO = url.getBytes("ISO-8859-1"); String str = new String(asISO, "ISO-8859-1"); - + //use a non UTF-8 charset as the encoding and url-escape as per //http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars - String s = URLEncoder.encode(url, "ISO-8859-1"); + String s = URLEncoder.encode(url, "ISO-8859-1"); EncodedHttpURI uri = new EncodedHttpURI("ISO-8859-1"); - + //parse it, using the same encoding uri.parse(s); - + //decode the url encoding String d = URLDecoder.decode(uri.getCompletePath(), "ISO-8859-1"); assertEquals(url, d); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index a779b79a33..4ea50b9c4c 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -21,60 +21,49 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.io.PrintWriter; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * - * */ -public class HttpConnectionTest extends TestCase +public class HttpConnectionTest { - Server server = new Server(); - LocalConnector connector = new LocalConnector(); - - /** - * Constructor - * @param arg0 - */ - public HttpConnectionTest(String arg0) - { - super(arg0); - server.setConnectors(new Connector[]{connector}); - server.setHandler(new DumpHandler()); - } + private Server server; + private LocalConnector connector; - /* - * @see TestCase#setUp() - */ - protected void setUp() throws Exception + @Before + public void init() throws Exception { - super.setUp(); - connector.setHeaderBufferSize(1024); + server = new Server(); + connector = new LocalConnector(); + server.addConnector(connector); + connector.setRequestHeaderSize(1024); + connector.setResponseHeaderSize(1024); + server.setHandler(new DumpHandler()); server.start(); } - /* - * @see TestCase#tearDown() - */ - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { - super.tearDown(); server.stop(); + server.join(); } - - - /* --------------------------------------------------------------- */ + @Test public void testFragmentedChunk() { String response=null; @@ -118,7 +107,7 @@ public class HttpConnectionTest extends TestCase } } - /* --------------------------------------------------------------- */ + @Test public void testEmpty() throws Exception { String response=connector.getResponses("GET /R1 HTTP/1.1\n"+ @@ -133,7 +122,7 @@ public class HttpConnectionTest extends TestCase offset = checkContains(response,offset,"/R1"); } - /* --------------------------------------------------------------- */ + @Test public void testBad() throws Exception { String response=connector.getResponses("GET & HTTP/1.1\n"+ @@ -163,7 +152,7 @@ public class HttpConnectionTest extends TestCase } - /* --------------------------------------------------------------- */ + @Test public void testAutoFlush() throws Exception { String response=null; @@ -184,7 +173,7 @@ public class HttpConnectionTest extends TestCase offset = checkContains(response,offset,"12345"); } - /* --------------------------------------------------------------- */ + @Test public void testCharset() { @@ -246,17 +235,15 @@ public class HttpConnectionTest extends TestCase } } - - - /* --------------------------------------------------------------- */ + @Test public void testUnconsumedError() throws Exception - { + { String response=null; String requests=null; int offset=0; - offset=0; + offset=0; requests="GET /R1?read=1&error=500 HTTP/1.1\n"+ "Host: localhost\n"+ "Transfer-Encoding: chunked\n"+ @@ -280,17 +267,17 @@ public class HttpConnectionTest extends TestCase offset = checkContains(response,offset,"/R2"); offset = checkContains(response,offset,"encoding=UTF-8"); offset = checkContains(response,offset,"abcdefghij"); - + } - - /* --------------------------------------------------------------- */ + + @Test public void testUnconsumedException() throws Exception - { + { String response=null; String requests=null; int offset=0; - offset=0; + offset=0; requests="GET /R1?read=1&ISE=true HTTP/1.1\n"+ "Host: localhost\n"+ "Transfer-Encoding: chunked\n"+ @@ -328,7 +315,8 @@ public class HttpConnectionTest extends TestCase } } - public void testConnection () + @Test + public void testConnection() { String response=null; try @@ -356,6 +344,7 @@ public class HttpConnectionTest extends TestCase } } + @Test public void testOversizedBuffer() { String response = null; @@ -381,11 +370,10 @@ public class HttpConnectionTest extends TestCase } } - - - public void testOversizedResponse () - throws Exception - { + + @Test + public void testOversizedResponse() throws Exception + { String str = "thisisastringthatshouldreachover1kbytes"; for (int i=0;i<400;i++) str+="xxxxxxxxxxxx"; @@ -393,7 +381,7 @@ public class HttpConnectionTest extends TestCase String response = null; server.stop(); server.setHandler(new DumpHandler() - { + { public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { try @@ -402,7 +390,7 @@ public class HttpConnectionTest extends TestCase response.setHeader(HttpHeaders.CONTENT_TYPE,MimeTypes.TEXT_HTML); response.setHeader("LongStr", longstr); PrintWriter writer = response.getWriter(); - writer.write("<html><h1>FOO</h1></html>"); + writer.write("<html><h1>FOO</h1></html>"); writer.flush(); writer.close(); throw new RuntimeException("SHOULD NOT GET HERE"); @@ -415,28 +403,28 @@ public class HttpConnectionTest extends TestCase } }); server.start(); - - try + + try { int offset = 0; - + response = connector.getResponses("GET / HTTP/1.1\n"+ "Host: localhost\n" + "\015\012" ); - + offset = checkContains(response, offset, "HTTP/1.1 500"); - } + } catch(Exception e) { e.printStackTrace(); if(response != null) System.err.println(response); - fail("Exception"); + fail("Exception"); } } - + @Test public void testAsterisk() { String response = null; @@ -492,6 +480,31 @@ public class HttpConnectionTest extends TestCase } + @Test + public void testCONNECT() + { + String response = null; + + try + { + int offset=0; + + response=connector.getResponses("CONNECT www.webtide.com:8080 HTTP/1.1\n"+ + "Host: myproxy:8888\015\012"+ + "\015\012"); + offset = checkContains(response,offset,"HTTP/1.1 200"); + + } + catch (Exception e) + { + e.printStackTrace(); + assertTrue(false); + if (response!=null) + System.err.println(response); + } + + } + private int checkContains(String s,int offset,String c) { int o=s.indexOf(c,offset); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java index c12d896bd8..2f163c6387 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; @@ -26,25 +26,26 @@ import java.net.Socket; import java.net.URL; import java.util.Arrays; import java.util.Random; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.AfterClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertTrue; + /** - * HttpServer Tester. + * */ -public class HttpServerTestBase extends TestCase +public abstract class HttpServerTestBase { - private static boolean stress=Boolean.getBoolean("STRESS"); - - // ~ Static fields/initializers - // --------------------------------------------- + private static final boolean stress = Boolean.getBoolean("STRESS"); /** The request. */ private static final String REQUEST1_HEADER="POST / HTTP/1.0\n"+"Host: localhost\n"+"Content-Type: text/xml; charset=utf-8\n"+"Connection: close\n"+"Content-Length: "; @@ -67,7 +68,6 @@ public class HttpServerTestBase extends TestCase "Host: localhost\n"+ "Content-Type: text/xml\n"+ "Content-Length: "; - private static final String REQUEST2_CONTENT= "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"+ "<nimbus xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"+ @@ -78,9 +78,9 @@ public class HttpServerTestBase extends TestCase " </getJobDetails>\n"+ " </request>\n"+ "</nimbus>"; - private static final String REQUEST2=REQUEST2_HEADER+REQUEST2_CONTENT.getBytes().length+"\n\n"+REQUEST2_CONTENT; + /** The second expected response. */ private static final String RESPONSE2_CONTENT= "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"+ "<nimbus xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"+ @@ -104,87 +104,102 @@ public class HttpServerTestBase extends TestCase private static final int LOOPS=stress?250:25; private static final String HOST="localhost"; - private Connector _connector; - private int port=0; + private static Server _server; + private static Connector _connector; - protected void tearDown() throws Exception + protected static void startServer(Connector connector) throws Exception { - super.tearDown(); - Thread.sleep(100); + _server = new Server(); + _connector = connector; + _server.addConnector(_connector); + _server.setHandler(new HandlerWrapper()); + _server.start(); } - // ~ Methods - // ---------------------------------------------------------------- + @AfterClass + public static void stopServer() throws Exception + { + _server.stop(); + _server.join(); + } - /** + protected void configureServer(Handler handler) throws Exception + { + HandlerWrapper current = (HandlerWrapper)_server.getHandler(); + current.stop(); + current.setHandler(handler); + current.start(); + } + + /* * Feed the server the entire request at once. - * - * @throws Exception - * @throws InterruptedException */ - public void testRequest1_jetty() throws Exception, InterruptedException + @Test + public void testRequest1_jetty() throws Exception { - Server server=startServer(new HelloWorldHandler()); - Socket client=new Socket(HOST,port); - OutputStream os=client.getOutputStream(); + configureServer(new HelloWorldHandler()); - os.write(REQUEST1.getBytes()); - os.flush(); + Socket client=new Socket(HOST,_connector.getLocalPort()); + try + { + OutputStream os=client.getOutputStream(); - // Read the response. - String response=readResponse(client); + os.write(REQUEST1.getBytes()); + os.flush(); - // Shut down - client.close(); - server.stop(); + // Read the response. + String response=readResponse(client); - // Check the response - assertEquals("response",RESPONSE1,response); + // Check the response + assertEquals("response",RESPONSE1,response); + } + finally + { + client.close(); + } } - /* --------------------------------------------------------------- */ + @Test public void testFragmentedChunk() throws Exception { + configureServer(new EchoHandler()); - Server server=startServer(new EchoHandler()); - Socket client=new Socket(HOST,port); - OutputStream os=client.getOutputStream(); - - os.write(("GET /R2 HTTP/1.1\015\012"+"Host: localhost\015\012"+"Transfer-Encoding: chunked\015\012"+"Content-Type: text/plain\015\012" - +"Connection: close\015\012"+"\015\012").getBytes()); - os.flush(); - Thread.sleep(PAUSE); - os.write(("5\015\012").getBytes()); - os.flush(); - Thread.sleep(PAUSE); - os.write(("ABCDE\015\012"+"0;\015\012\015\012").getBytes()); - os.flush(); - - // Read the response. - String response=readResponse(client); - - // Shut down - client.close(); - server.stop(); + Socket client=new Socket(HOST,_connector.getLocalPort()); + try + { + OutputStream os=client.getOutputStream(); - assertTrue(true); // nothing checked yet. + os.write(("GET /R2 HTTP/1.1\015\012"+"Host: localhost\015\012"+"Transfer-Encoding: chunked\015\012"+"Content-Type: text/plain\015\012" + +"Connection: close\015\012"+"\015\012").getBytes()); + os.flush(); + Thread.sleep(PAUSE); + os.write(("5\015\012").getBytes()); + os.flush(); + Thread.sleep(PAUSE); + os.write(("ABCDE\015\012"+"0;\015\012\015\012").getBytes()); + os.flush(); + // Read the response. + String response=readResponse(client); + assertTrue(true); // nothing checked yet. + } + finally + { + client.close(); + } } - /** + /* * Feed the server fragmentary headers and see how it copes with it. - * - * @throws Exception - * @throws InterruptedException */ + @Test public void testRequest1Fragments_jetty() throws Exception, InterruptedException { - Server server=startServer(new HelloWorldHandler()); - String response; + configureServer(new HelloWorldHandler()); + Socket client=new Socket(HOST,_connector.getLocalPort()); try { - Socket client=new Socket(HOST,port); OutputStream os=client.getOutputStream(); // Write a fragment, flush, sleep, write the next fragment, etc. @@ -198,30 +213,29 @@ public class HttpServerTestBase extends TestCase os.flush(); // Read the response - response=readResponse(client); + String response = readResponse(client); - // Shut down - client.close(); + // Check the response + assertEquals("response",RESPONSE1,response); } finally { - server.stop(); + client.close(); } - // Check the response - assertEquals("response",RESPONSE1,response); } + @Test public void testRequest2_jetty() throws Exception { - byte[] bytes=REQUEST2.getBytes(); - Server server=startServer(new EchoHandler()); + configureServer(new EchoHandler()); - try + byte[] bytes=REQUEST2.getBytes(); + for (int i=0; i<LOOPS; i++) { - for (int i=0; i<LOOPS; i++) + Socket client=new Socket(HOST,_connector.getLocalPort()); + try { - Socket client=new Socket(HOST,port); OutputStream os=client.getOutputStream(); os.write(bytes); @@ -229,50 +243,44 @@ public class HttpServerTestBase extends TestCase // Read the response String response=readResponse(client); - client.close(); // Check the response assertEquals("response "+i,RESPONSE2,response); } - } - finally - { - // Shut down - server.stop(); + finally + { + client.close(); + } } } - /** - * @throws Exception - */ + @Test public void testRequest2Fragments_jetty() throws Exception { - Random random=new Random(System.currentTimeMillis()); + configureServer(new EchoHandler()); + byte[] bytes=REQUEST2.getBytes(); final int pointCount=2; - Server server=startServer(new EchoHandler()); - - try + Random random=new Random(System.currentTimeMillis()); + for (int i=0; i<LOOPS; i++) { + int[] points=new int[pointCount]; + StringBuilder message=new StringBuilder(); - for (int i=0; i<LOOPS; i++) - { + message.append("iteration #").append(i + 1); - int[] points=new int[pointCount]; - StringBuilder message=new StringBuilder(); - - message.append("iteration #").append(i + 1); - - // Pick fragment points at random - for (int j=0; j<points.length; ++j) - { - points[j]=random.nextInt(bytes.length); - } + // Pick fragment points at random + for (int j=0; j<points.length; ++j) + { + points[j]=random.nextInt(bytes.length); + } - // Sort the list - Arrays.sort(points); + // Sort the list + Arrays.sort(points); - Socket client=new Socket(HOST,port); + Socket client=new Socket(HOST,_connector.getLocalPort()); + try + { OutputStream os=client.getOutputStream(); writeFragments(bytes,points,message,os); @@ -280,38 +288,35 @@ public class HttpServerTestBase extends TestCase // Read the response String response=readResponse(client); - // Close the client - client.close(); - // Check the response assertEquals("response for "+i+" "+message.toString(),RESPONSE2,response); } - } - finally - { - // Shut down - server.stop(); + finally + { + client.close(); + } } } + @Test public void testRequest2Iterate_jetty() throws Exception { - byte[] bytes=REQUEST2.getBytes(); - Server server=startServer(new EchoHandler()); + configureServer(new EchoHandler()); - try + byte[] bytes=REQUEST2.getBytes(); + for (int i=0; i<bytes.length; i+=3) { - for (int i=0; i<bytes.length; i+=3) - { - int[] points=new int[] { i }; - StringBuilder message=new StringBuilder(); + int[] points=new int[] { i }; + StringBuilder message=new StringBuilder(); - message.append("iteration #").append(i + 1); + message.append("iteration #").append(i + 1); - // Sort the list - Arrays.sort(points); + // Sort the list + Arrays.sort(points); - Socket client=new Socket(HOST,port); + Socket client=new Socket(HOST,_connector.getLocalPort()); + try + { OutputStream os=client.getOutputStream(); writeFragments(bytes,points,message,os); @@ -319,42 +324,37 @@ public class HttpServerTestBase extends TestCase // Read the response String response=readResponse(client); - // Close the client - client.close(); - // Check the response assertEquals("response for "+i+" "+message.toString(),RESPONSE2,response); } - } - finally - { - // Shut down - server.stop(); + finally + { + client.close(); + } } } - /** + /* * After several iterations, I generated some known bad fragment points. - * - * @throws Exception */ + @Test public void testRequest2KnownBad_jetty() throws Exception { + configureServer(new EchoHandler()); + byte[] bytes=REQUEST2.getBytes(); int[][] badPoints=new int[][] { - { 70 }, // beginning here, drops last line of request + { 70 }, // beginning here, drops last line of request { 71 }, // no response at all { 72 }, // again starts drops last line of request { 74 }, // again, no response at all }; - Server server=startServer(new EchoHandler()); - - try + for (int i=0; i<badPoints.length; ++i) { - for (int i=0; i<badPoints.length; ++i) + Socket client=new Socket(HOST,_connector.getLocalPort()); + try { - Socket client=new Socket(HOST,port); OutputStream os=client.getOutputStream(); StringBuilder message=new StringBuilder(); @@ -364,78 +364,66 @@ public class HttpServerTestBase extends TestCase // Read the response String response=readResponse(client); - // Close the client - client.close(); - // Check the response // TODO - change to equals when code gets fixed assertNotSame("response for "+message.toString(),RESPONSE2,response); } - } - finally - { - // Shut down - server.stop(); + finally + { + client.close(); + } } } - /** - * After several iterations, I generated some known bad fragment points. - * - * @throws Exception - */ + @Test public void testFlush() throws Exception { - Server server=startServer(new DataHandler()); - try - { - String[] encoding = {"NONE","UTF-8","ISO-8859-1","ISO-8859-2"}; + configureServer(new DataHandler()); - for (int e =0; e<encoding.length;e++) + String[] encoding = {"NONE","UTF-8","ISO-8859-1","ISO-8859-2"}; + for (int e =0; e<encoding.length;e++) + { + for (int b=1;b<=128;b=b==1?2:b==2?32:b==32?128:129) { - for (int b=1;b<=128;b=b==1?2:b==2?32:b==32?128:129) + for (int w=41;w<42;w+=4096) { - for (int w=41;w<42;w+=4096) + for (int c=0;c<1;c++) { - for (int c=0;c<1;c++) + String test=encoding[e]+"x"+b+"x"+w+"x"+c; + try { - String test=encoding[e]+"x"+b+"x"+w+"x"+c; - URL url=new URL("http://"+HOST+":"+port+"/?writes="+w+"&block="+b+ (e==0?"":("&encoding="+encoding[e]))+(c==0?"&chars=true":"")); + URL url=new URL("http://"+HOST+":"+_connector.getLocalPort()+"/?writes="+w+"&block="+b+ (e==0?"":("&encoding="+encoding[e]))+(c==0?"&chars=true":"")); InputStream in = (InputStream)url.getContent(); String response=IO.toString(in,e==0?null:encoding[e]); - + assertEquals(test,b*w,response.length()); } + catch(Exception x) + { + System.err.println(test); + throw x; + } } } } } - finally - { - // Shut down - server.stop(); - Thread.yield(); - } } - /** - * After several iterations, I generated some known bad fragment points. - * - * @throws Exception - */ + @Test public void testReadWriteBlocking() throws Exception { - Server server=startServer(new DataHandler()); + configureServer(new DataHandler()); + + long start=System.currentTimeMillis(); + Socket client=new Socket(HOST,_connector.getLocalPort()); try - { - long start=System.currentTimeMillis(); - Socket client=new Socket(HOST,port); + { OutputStream os=client.getOutputStream(); InputStream is=client.getInputStream(); os.write(( "GET /data?writes=1024&block=256 HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "connection: close\r\n"+ "content-type: unknown\r\n"+ "content-length: 30\r\n"+ @@ -457,11 +445,11 @@ public class HttpServerTestBase extends TestCase "0987654321\r\n" ).getBytes()); os.flush(); - + int total=0; int len=0; byte[] buf=new byte[1024*64]; - + while(len>=0) { Thread.sleep(500); @@ -475,29 +463,21 @@ public class HttpServerTestBase extends TestCase } finally { - // Shut down - server.stop(); - Thread.yield(); + client.close(); } - } - - /** - * After several iterations, I generated some known bad fragment points. - * - * @throws Exception - */ + @Test public void testPipeline() throws Exception { - Server server=startServer(new HelloWorldHandler()); + configureServer(new HelloWorldHandler()); - try - { - //for (int pipeline=1;pipeline<32;pipeline++) - for (int pipeline=1;pipeline<32;pipeline++) - { - Socket client=new Socket(HOST,port); + //for (int pipeline=1;pipeline<32;pipeline++) + for (int pipeline=1;pipeline<32;pipeline++) + { + Socket client=new Socket(HOST,_connector.getLocalPort()); + try + { client.setSoTimeout(5000); OutputStream os=client.getOutputStream(); @@ -506,15 +486,15 @@ public class HttpServerTestBase extends TestCase for (int i=1;i<pipeline;i++) request+= "GET /data?writes=1&block=16&id="+i+" HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "user-agent: testharness/1.0 (blah foo/bar)\r\n"+ "accept-encoding: nothing\r\n"+ "cookie: aaa=1234567890\r\n"+ "\r\n"; - + request+= "GET /data?writes=1&block=16 HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "user-agent: testharness/1.0 (blah foo/bar)\r\n"+ "accept-encoding: nothing\r\n"+ "cookie: aaa=bbbbbb\r\n"+ @@ -536,53 +516,38 @@ public class HttpServerTestBase extends TestCase } assertEquals(pipeline,count); } + finally + { + client.close(); + } } - finally - { - // Shut down - server.stop(); - Thread.yield(); - } - - } - - public void testStoppable() throws Exception - { - Server server=startServer(null); - server.setThreadPool(new QueuedThreadPool()); - server.start(); - Thread.sleep(1000); - server.stop(); } - - /** - */ + @Test public void testRecycledWriters() throws Exception { - Server server=startServer(new EchoHandler()); - + configureServer(new EchoHandler()); + + Socket client=new Socket(HOST,_connector.getLocalPort()); try - { - long start=System.currentTimeMillis(); - Socket client=new Socket(HOST,port); + { OutputStream os=client.getOutputStream(); InputStream is=client.getInputStream(); os.write(( "POST /echo?charset=utf-8 HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "content-type: text/plain; charset=utf-8\r\n"+ "content-length: 10\r\n"+ "\r\n").getBytes("iso-8859-1")); - + os.write(( "123456789\n" ).getBytes("utf-8")); os.write(( "POST /echo?charset=utf-8 HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "content-type: text/plain; charset=utf-8\r\n"+ "content-length: 10\r\n"+ "\r\n" @@ -596,7 +561,7 @@ public class HttpServerTestBase extends TestCase byte[] contentB=content.getBytes("utf-8"); os.write(( "POST /echo?charset=utf-16 HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "content-type: text/plain; charset=utf-8\r\n"+ "content-length: "+contentB.length+"\r\n"+ "connection: close\r\n"+ @@ -605,7 +570,7 @@ public class HttpServerTestBase extends TestCase os.write(contentB); os.flush(); - + ByteArrayOutputStream bout = new ByteArrayOutputStream(); IO.copy(is,bout); byte[] b=bout.toByteArray(); @@ -626,57 +591,51 @@ public class HttpServerTestBase extends TestCase if (state==1||state==3) state++; continue; - + default: state=0; } } - - + String in = new String(b,0,i,"utf-8"); assertTrue(in.indexOf("123456789")>=0); assertTrue(in.indexOf("abcdefghZ")>=0); assertTrue(in.indexOf("Wibble")<0); - + in = new String(b,i,b.length-i,"utf-16"); assertEquals("Wibble\n",in); - } finally { - // Shut down - server.stop(); - Thread.yield(); + client.close(); } } - /** - */ + @Test public void testRecycledReaders() throws Exception { - Server server=startServer(new EchoHandler()); - + configureServer(new EchoHandler()); + + Socket client=new Socket(HOST,_connector.getLocalPort()); try - { - long start=System.currentTimeMillis(); - Socket client=new Socket(HOST,port); + { OutputStream os=client.getOutputStream(); InputStream is=client.getInputStream(); os.write(( "POST /echo?charset=utf-8 HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "content-type: text/plain; charset=utf-8\r\n"+ "content-length: 10\r\n"+ "\r\n").getBytes("iso-8859-1")); - + os.write(( "123456789\n" ).getBytes("utf-8")); os.write(( "POST /echo?charset=utf-8 HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "content-type: text/plain; charset=utf-8\r\n"+ "content-length: 10\r\n"+ "\r\n" @@ -690,7 +649,7 @@ public class HttpServerTestBase extends TestCase byte[] contentB=content.getBytes("utf-16"); os.write(( "POST /echo?charset=utf-8 HTTP/1.1\r\n"+ - "host: "+HOST+":"+port+"\r\n"+ + "host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+ "content-type: text/plain; charset=utf-16\r\n"+ "content-length: "+contentB.length+"\r\n"+ "connection: close\r\n"+ @@ -699,30 +658,24 @@ public class HttpServerTestBase extends TestCase os.write(contentB); os.flush(); - + String in = IO.toString(is); assertTrue(in.indexOf("123456789")>=0); assertTrue(in.indexOf("abcdefghi")>=0); assertTrue(in.indexOf("Wibble")>=0); - } finally { - // Shut down - server.stop(); - Thread.yield(); + client.close(); } } - + /** * Read entire response from the client. Close the output. - * - * @param client - * Open client socket. - * + * + * @param client Open client socket. * @return The response string. - * - * @throws IOException + * @throws IOException in case of I/O problems */ private static String readResponse(Socket client) throws IOException { @@ -752,41 +705,6 @@ public class HttpServerTestBase extends TestCase } } - protected HttpServerTestBase(Connector connector) - { - _connector=connector; - } - - /** - * Create the server. - * - * @param handler - * - * @return Newly created server, ready to start. - * - * @throws Exception - */ - protected Server startServer(Handler handler) throws Exception - { - Server server=new Server(); - - _connector.setPort(0); - server.setConnectors(new Connector[] - { _connector }); - server.setHandler(handler); - - configServer(server); - - server.start(); - port=_connector.getLocalPort(); - return server; - } - - protected void configServer(Server server) - { - - } - private void writeFragments(byte[] bytes, int[] points, StringBuilder message, OutputStream os) throws IOException, InterruptedException { int last=0; @@ -811,12 +729,8 @@ public class HttpServerTestBase extends TestCase Thread.sleep(PAUSE); } - // ~ Inner Classes - // ---------------------------------------------------------- private static class EchoHandler extends AbstractHandler { - // ~ Methods - // ------------------------------------------------------------ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); @@ -827,12 +741,12 @@ public class HttpServerTestBase extends TestCase response.setCharacterEncoding(request.getParameter("charset")); else if (request.getCharacterEncoding()!=null) response.setCharacterEncoding(request.getCharacterEncoding()); - + PrintWriter writer=response.getWriter(); BufferedReader reader=request.getReader(); int count=0; String line; - + while ((line=reader.readLine())!=null) { writer.print(line); @@ -842,20 +756,18 @@ public class HttpServerTestBase extends TestCase if (count==0) throw new IllegalStateException("no input recieved"); - + // just to be difficult reader.close(); writer.close(); - + if (reader.read()>=0) throw new IllegalStateException("Not closed"); } } - // ---------------------------------------------------------- private static class HelloWorldHandler extends AbstractHandler { - // ------------------------------------------------------------ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); @@ -864,25 +776,23 @@ public class HttpServerTestBase extends TestCase } } - // ---------------------------------------------------------- private static class DataHandler extends AbstractHandler { - // ------------------------------------------------------------ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); response.setStatus(200); - + InputStream in = request.getInputStream(); String input=IO.toString(in); - + String tmp = request.getParameter("writes"); int writes=Integer.parseInt(tmp==null?"10":tmp); tmp = request.getParameter("block"); int block=Integer.parseInt(tmp==null?"10":tmp); String encoding=request.getParameter("encoding"); String chars=request.getParameter("chars"); - + String chunk = (input+"\u0a870123456789A\u0a87CDEFGHIJKLMNOPQRSTUVWXYZ\u0250bcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") .substring(0,block); response.setContentType("text/plain"); @@ -901,15 +811,14 @@ public class HttpServerTestBase extends TestCase for (int i=0;i<writes;i++) out.write(c); } - else + else { response.setCharacterEncoding(encoding); Writer out=response.getWriter(); for (int i=0;i<writes;i++) out.write(chunk); } - + } } - } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java index 88c8b5bfa0..2ea4cc5a9e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java @@ -4,62 +4,67 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; -import junit.framework.TestCase; - import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.io.ByteArrayBuffer; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -public class HttpURITest extends TestCase +public class HttpURITest { - String[][] partial_tests= - { - /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, - /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, - /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, - /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, - /* 4*/ {"/path/info;param",null,null,null,null,"/path/info","param",null,null}, - /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info","param",null,"fragment"}, - /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info","param","query",null}, - /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info","param","query","fragment"}, - /* 8*/ {"//host/path/info",null,"//host","host",null,"/path/info",null,null,null}, - /* 9*/ {"//user@host/path/info",null,"//user@host","host",null,"/path/info",null,null,null}, - /*10*/ {"//user@host:8080/path/info",null,"//user@host:8080","host","8080","/path/info",null,null,null}, - /*11*/ {"//host:8080/path/info",null,"//host:8080","host","8080","/path/info",null,null,null}, - /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, - /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, - /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, - /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, - /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info","param",null,null}, - /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info","param",null,"fragment"}, - /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info","param","query",null}, - /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info","param","query","fragment"}, - /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info","param","query","fragment"}, - /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info","param","query","fragment"}, - /*22*/ {"http:///;?#","http","//",null,null,"/","","",""}, - /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, - /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, - /*25*/ {"//host:8080//",null,"//host:8080","host","8080","//",null,null,null}, - /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, - /*27*/ {"//",null,"//",null,null,null,null,null,null}, + private final String[][] partial_tests= + { + /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, + /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, + /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, + /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, + /* 4*/ {"/path/info;param",null,null,null,null,"/path/info","param",null,null}, + /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info","param",null,"fragment"}, + /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info","param","query",null}, + /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info","param","query","fragment"}, + /* 8*/ {"//host/path/info",null,"//host","host",null,"/path/info",null,null,null}, + /* 9*/ {"//user@host/path/info",null,"//user@host","host",null,"/path/info",null,null,null}, + /*10*/ {"//user@host:8080/path/info",null,"//user@host:8080","host","8080","/path/info",null,null,null}, + /*11*/ {"//host:8080/path/info",null,"//host:8080","host","8080","/path/info",null,null,null}, + /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, + /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, + /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, + /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, + /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info","param",null,null}, + /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info","param",null,"fragment"}, + /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info","param","query",null}, + /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info","param","query","fragment"}, + /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info","param","query","fragment"}, + /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info","param","query","fragment"}, + /*22*/ {"http:///;?#","http","//",null,null,"/","","",""}, + /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, + /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, + /*25*/ {"//host:8080//",null,"//host:8080","host","8080","//",null,null,null}, + /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, + /*27*/ {"//",null,"//",null,null,null,null,null,null}, /*28*/ {"/;param",null, null, null,null,"/", "param",null,null}, /*29*/ {"/?x=y",null, null, null,null,"/", null,"x=y",null}, /*30*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null}, - /*31*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"}, + /*31*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"}, }; - public void testPartialURIs() - throws Exception + @Test + public void testPartialURIs() throws Exception { HttpURI uri = new HttpURI(true); - + for (int t=0;t<partial_tests.length;t++) { uri.parse(partial_tests[t][0].getBytes(),0,partial_tests[t][0].length()); @@ -73,39 +78,39 @@ public class HttpURITest extends TestCase assertEquals(t+" "+partial_tests[t][0],partial_tests[t][8],uri.getFragment()); assertEquals(partial_tests[t][0], uri.toString()); } - + } - String[][] path_tests= - { - /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, - /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, - /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, - /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, - /* 4*/ {"/path/info;param",null,null,null,null,"/path/info","param",null,null}, - /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info","param",null,"fragment"}, - /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info","param","query",null}, - /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info","param","query","fragment"}, - /* 8*/ {"//host/path/info",null,null,null,null,"//host/path/info",null,null,null}, - /* 9*/ {"//user@host/path/info",null,null,null,null,"//user@host/path/info",null,null,null}, - /*10*/ {"//user@host:8080/path/info",null,null,null,null,"//user@host:8080/path/info",null,null,null}, - /*11*/ {"//host:8080/path/info",null,null,null,null,"//host:8080/path/info",null,null,null}, - /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, - /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, - /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, - /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, - /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info","param",null,null}, - /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info","param",null,"fragment"}, - /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info","param","query",null}, - /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info","param","query","fragment"}, - /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info","param","query","fragment"}, - /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info","param","query","fragment"}, - /*22*/ {"http:///;?#","http","//",null,null,"/","","",""}, - /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, - /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, - /*25*/ {"//host:8080//",null,null,null,null,"//host:8080//",null,null,null}, - /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, - /*27*/ {"//",null,null,null,null,"//",null,null,null}, + private final String[][] path_tests= + { + /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null}, + /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"}, + /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null}, + /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"}, + /* 4*/ {"/path/info;param",null,null,null,null,"/path/info","param",null,null}, + /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info","param",null,"fragment"}, + /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info","param","query",null}, + /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info","param","query","fragment"}, + /* 8*/ {"//host/path/info",null,null,null,null,"//host/path/info",null,null,null}, + /* 9*/ {"//user@host/path/info",null,null,null,null,"//user@host/path/info",null,null,null}, + /*10*/ {"//user@host:8080/path/info",null,null,null,null,"//user@host:8080/path/info",null,null,null}, + /*11*/ {"//host:8080/path/info",null,null,null,null,"//host:8080/path/info",null,null,null}, + /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null}, + /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"}, + /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null}, + /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"}, + /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info","param",null,null}, + /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info","param",null,"fragment"}, + /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info","param","query",null}, + /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info","param","query","fragment"}, + /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info","param","query","fragment"}, + /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info","param","query","fragment"}, + /*22*/ {"http:///;?#","http","//",null,null,"/","","",""}, + /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null}, + /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null}, + /*25*/ {"//host:8080//",null,null,null,null,"//host:8080//",null,null,null}, + /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null}, + /*27*/ {"//",null,null,null,null,"//",null,null,null}, /*28*/ {"http://localhost/","http","//localhost","localhost",null,"/",null,null,null}, /*29*/ {"http://localhost:8080/", "http", "//localhost:8080", "localhost","8080","/", null, null,null}, /*30*/ {"http://localhost/?x=y", "http", "//localhost", "localhost",null,"/", null,"x=y",null}, @@ -121,13 +126,12 @@ public class HttpURITest extends TestCase /*40*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, /*41*/ {"*",null,null,null,null,"*",null, null,null} }; - - - public void testPathURIs() - throws Exception + + @Test + public void testPathURIs() throws Exception { HttpURI uri = new HttpURI(); - + for (int t=0;t<path_tests.length;t++) { uri.parse(path_tests[t][0].getBytes(),0,path_tests[t][0].length()); @@ -141,17 +145,18 @@ public class HttpURITest extends TestCase assertEquals(t+" "+path_tests[t][0],path_tests[t][8],uri.getFragment()); assertEquals(path_tests[t][0], uri.toString()); } - + } - + + @Test public void testInvalidAddress() throws Exception { assertInvalidURI("http://[ffff::1:8080/", "Invalid URL; no closing ']' -- should throw exception"); assertInvalidURI("**", "only '*', not '**'"); assertInvalidURI("*/", "only '*', not '*/'"); } - - public void assertInvalidURI(String invalidURI, String message) + + private void assertInvalidURI(String invalidURI, String message) { HttpURI uri = new HttpURI(); try @@ -165,24 +170,54 @@ public class HttpURITest extends TestCase } } - String[][] encoding_tests= - { - /* 0*/ {"/path/info","/path/info"}, - /* 1*/ {"/path/%69nfo","/path/info"}, - /* 2*/ {"http://host/path/%69nfo","/path/info"}, - /* 3*/ {"http://host/path/%69nf%c2%a4","/path/inf\u00a4"}, + private final String[][] encoding_tests= + { + /* 0*/ {"/path/info","/path/info"}, + /* 1*/ {"/path/%69nfo","/path/info"}, + /* 2*/ {"http://host/path/%69nfo","/path/info"}, + /* 3*/ {"http://host/path/%69nf%c2%a4","/path/inf\u00a4"}, }; - + + @Test public void testEncoded() { - HttpURI uri = new HttpURI(); - + for (int t=0;t<encoding_tests.length;t++) { uri.parse(encoding_tests[t][0]); assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath()); - + + } + } + + private final String[][] connect_tests= + { + /* 0*/ {" localhost:8080 ","localhost","8080"}, + /* 1*/ {" 127.0.0.1:8080 ","127.0.0.1","8080"}, + /* 2*/ {" [127::0::0::1]:8080 ","[127::0::0::1]","8080"}, + /* 3*/ {" error ",null,null}, + /* 4*/ {" http://localhost:8080/ ",null,null}, + }; + + @Test + public void testCONNECT() throws Exception + { + HttpURI uri = new HttpURI(); + for (int i=0;i<connect_tests.length;i++) + { + try + { + ByteArrayBuffer buf = new ByteArrayBuffer(connect_tests[i][0]); + uri.parseConnect(buf.array(),2,buf.length()-4); + assertEquals("path"+i,connect_tests[i][1]+":"+connect_tests[i][2],uri.getPath()); + assertEquals("host"+i,connect_tests[i][1],uri.getHost()); + assertEquals("port"+i,Integer.parseInt(connect_tests[i][2]),uri.getPort()); + } + catch(Exception e) + { + assertNull("error"+i,connect_tests[i][1]); + } } } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java index ac9bea7728..73bc4ba9de 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java @@ -2,8 +2,6 @@ package org.eclipse.jetty.server; import java.io.IOException; -import junit.framework.TestCase; - import org.eclipse.jetty.http.AbstractGenerator; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; @@ -13,23 +11,39 @@ import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.util.StringUtil; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -public class HttpWriterTest extends TestCase +public class HttpWriterTest { - HttpWriter _writer; - ByteArrayBuffer _bytes; - - /* ------------------------------------------------------------ */ - @Override - protected void setUp() throws Exception + private HttpWriter _writer; + private ByteArrayBuffer _bytes; + + @Before + public void init() throws Exception { _bytes = new ByteArrayBuffer(2048); - + Buffers buffers = new SimpleBuffers(new ByteArrayBuffer(1024),new ByteArrayBuffer(1024)); ByteArrayEndPoint endp = new ByteArrayEndPoint(); AbstractGenerator generator = new AbstractGenerator(buffers,endp) { @Override + public boolean isRequest() + { + return false; + } + + @Override + public boolean isResponse() + { + return true; + } + + @Override public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException { } @@ -56,37 +70,33 @@ public class HttpWriterTest extends TestCase { return false; } - + }; - + HttpOutput httpOut = new HttpOutput(generator,60000); _writer = new HttpWriter(httpOut); } - - private void assertArrayEquals(byte[] b1, byte[] b2) - { - assertEquals(b1.length,b2.length); - for (int i=0;i<b1.length;i++) - assertEquals(""+i,b1[i],b2[i]); - } - + + @Test public void testSimpleUTF8() throws Exception { _writer.setCharacterEncoding(StringUtil.__UTF8); - _writer.write("Now is the time"); + _writer.write("Now is the time"); assertArrayEquals("Now is the time".getBytes(StringUtil.__UTF8),_bytes.asArray()); } - + + @Test public void testUTF8() throws Exception { _writer.setCharacterEncoding(StringUtil.__UTF8); - _writer.write("How now \uFF22rown cow"); + _writer.write("How now \uFF22rown cow"); assertArrayEquals("How now \uFF22rown cow".getBytes(StringUtil.__UTF8),_bytes.asArray()); } - + + @Test public void testMultiByteOverflowUTF8() throws Exception { - _writer.setCharacterEncoding(StringUtil.__UTF8); + _writer.setCharacterEncoding(StringUtil.__UTF8); final String singleByteStr = "a"; final String multiByteDuplicateStr = "\uFF22"; int remainSize = 1; @@ -109,41 +119,47 @@ public class HttpWriterTest extends TestCase assertEquals(sb.toString(),new String(_bytes.asArray(),StringUtil.__UTF8)); } - + + @Test public void testISO8859() throws Exception { _writer.setCharacterEncoding(StringUtil.__ISO_8859_1); - _writer.write("How now \uFF22rown cow"); + _writer.write("How now \uFF22rown cow"); assertEquals("How now ?rown cow",new String(_bytes.asArray(),StringUtil.__ISO_8859_1)); } - public void testOutput() - throws Exception + @Test + public void testOutput() throws Exception { Buffer sb=new ByteArrayBuffer(1500); Buffer bb=new ByteArrayBuffer(8096); HttpFields fields = new HttpFields(); ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[0],4096); - + HttpGenerator hb = new HttpGenerator(new SimpleBuffers(sb,bb),endp); hb.setResponse(200,"OK"); - + HttpOutput output = new HttpOutput(hb,10000); HttpWriter writer = new HttpWriter(output); writer.setCharacterEncoding(StringUtil.__UTF8); - + char[] chars = new char[1024]; for (int i=0;i<chars.length;i++) chars[i]=(char)('0'+(i%10)); chars[0]='\u0553'; writer.write(chars); - + hb.completeHeader(fields,true); hb.flush(10000); String response = new String(endp.getOut().asArray(),StringUtil.__UTF8); assertTrue(response.startsWith("HTTP/1.1 200 OK\r\nContent-Length: 1025\r\n\r\n\u05531234567890")); - - - } + } + + private void assertArrayEquals(byte[] b1, byte[] b2) + { + assertEquals(b1.length,b2.length); + for (int i=0;i<b1.length;i++) + assertEquals(""+i,b1[i],b2[i]); + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/InclusiveByteRangeTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/InclusiveByteRangeTest.java index ad33210b35..c80daf1a15 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/InclusiveByteRangeTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/InclusiveByteRangeTest.java @@ -5,13 +5,13 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; @@ -19,9 +19,13 @@ package org.eclipse.jetty.server; import java.util.List; import java.util.Vector; -import junit.framework.TestCase; +import org.junit.Test; -public class InclusiveByteRangeTest extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class InclusiveByteRangeTest { @SuppressWarnings("unchecked") private void assertInvalidRange(String rangeString) @@ -32,7 +36,7 @@ public class InclusiveByteRangeTest extends TestCase List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),200); assertNull("Invalid Range [" + rangeString + "] should result in no satisfiable ranges",ranges); } - + private void assertRange(String msg, int expectedFirst, int expectedLast, int size, InclusiveByteRange actualRange) { assertEquals(msg + " - first",expectedFirst,actualRange.getFirst(size)); @@ -74,25 +78,28 @@ public class InclusiveByteRangeTest extends TestCase assertNotNull("Satisfiable Ranges should not be null",ranges); return ranges; } - + + @Test public void testHeader416RangeString() { assertEquals("416 Header on size 100","bytes */100",InclusiveByteRange.to416HeaderRangeString(100)); assertEquals("416 Header on size 123456789","bytes */123456789",InclusiveByteRange.to416HeaderRangeString(123456789)); } - + + @Test public void testInvalidRanges() { // Invalid if parsing "Range" header assertInvalidRange("bytes=a-b"); // letters invalid assertInvalidRange("byte=10-3"); // key is bad assertInvalidRange("onceuponatime=5-10"); // key is bad - assertInvalidRange("bytes=300-310"); // outside of size (200) + assertInvalidRange("bytes=300-310"); // outside of size (200) } /** * Ranges have a multiple ranges, all absolutely defined. */ + @Test public void testMultipleAbsoluteRanges() { int size = 50; @@ -109,6 +116,7 @@ public class InclusiveByteRangeTest extends TestCase /** * Range definition has a range that is clipped due to the size. */ + @Test public void testMultipleRangesClipped() { String rangeString; @@ -122,6 +130,7 @@ public class InclusiveByteRangeTest extends TestCase assertRange("Range [" + rangeString + "]",45,49,50,ranges.get(2)); } + @Test public void testMultipleRangesOverlapping() { String rangeString; @@ -134,6 +143,7 @@ public class InclusiveByteRangeTest extends TestCase assertRange("Range [" + rangeString + "]",15,25,200,ranges.get(1)); } + @Test public void testMultipleRangesSplit() { String rangeString; @@ -145,6 +155,7 @@ public class InclusiveByteRangeTest extends TestCase assertRange("Range [" + rangeString + "]",15,20,200,ranges.get(1)); } + @Test public void testSimpleRange() { assertSimpleRange(5,10,"bytes=5-10",200); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RFC2616Test.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RFC2616Test.java index 10cda0874f..b937a23e5e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RFC2616Test.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RFC2616Test.java @@ -23,33 +23,32 @@ import java.util.Date; import java.util.Enumeration; import java.util.List; -import junit.framework.TestCase; - import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.StdErrLog; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * - * */ -public class RFC2616Test extends TestCase +public class RFC2616Test { - Server server=new Server(); - LocalConnector connector=new LocalConnector(); - - /** - * Constructor for RFC2616Test. - * - * @param arg0 - */ - public RFC2616Test(String arg0) + private Server server; + private LocalConnector connector; + + @Before + public void init() throws Exception { - super(arg0); - server.setConnectors(new Connector[] - { connector }); + server = new Server(); + connector = new LocalConnector(); + server.addConnector(connector); ContextHandler vcontext=new ContextHandler(); vcontext.setContextPath("/"); @@ -66,28 +65,18 @@ public class RFC2616Test extends TestCase { vcontext, context }); server.setHandler(collection); - } - - /* - * @see TestCase#setUp() - */ - protected void setUp() throws Exception - { - super.setUp(); server.start(); } - /* - * @see TestCase#tearDown() - */ - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { - super.tearDown(); server.stop(); + server.join(); } - /* --------------------------------------------------------------- */ + @Test public void test3_3() { try @@ -114,10 +103,9 @@ public class RFC2616Test extends TestCase } } - /* --------------------------------------------------------------- */ + @Test public void test3_6() { - String response=null; try { @@ -178,7 +166,7 @@ public class RFC2616Test extends TestCase } } - /* --------------------------------------------------------------- */ + @Test public void test3_9() { try @@ -202,12 +190,11 @@ public class RFC2616Test extends TestCase } } - /* --------------------------------------------------------------- */ + @Test public void test4_4() { try { - String response; int offset=0; @@ -265,7 +252,7 @@ public class RFC2616Test extends TestCase } } - /* --------------------------------------------------------------- */ + @Test public void test5_2() throws Exception { String response; @@ -297,10 +284,9 @@ public class RFC2616Test extends TestCase offset=0; response=connector.getResponses("GET /path/R1 HTTP/1.1\n"+"\n"); offset=checkContains(response,offset,"HTTP/1.1 400","3. no host")+1; - } - /* --------------------------------------------------------------- */ + @Test public void test8_1() { try @@ -335,7 +321,7 @@ public class RFC2616Test extends TestCase } } - /* --------------------------------------------------------------- */ + @Test public void test8_2() { try @@ -391,6 +377,20 @@ public class RFC2616Test extends TestCase offset=checkContains(response,offset,"654321","8.2.3 expect 100")+1; */ + // Expect 100 not sent + ((StdErrLog)Log.getLog()).setHideStacks(true); + offset=0; + + response=connector.getResponses("GET /R1?error=401 HTTP/1.1\n"+ + "Host: localhost\n"+ + "Expect: 100-continue\n"+ + "Content-Type: text/plain\n"+ + "Content-Length: 8\n"+ + "\n",true); + checkNotContained(response,offset,"HTTP/1.1 100","8.2.3 expect 100"); + offset=checkContains(response,offset,"HTTP/1.1 401 ","8.2.3 expect 100")+1; + offset=checkContains(response,offset,"Connection: close","8.2.3 expect 100")+1; + ((StdErrLog)Log.getLog()).setHideStacks(false); } catch (Exception e) @@ -398,12 +398,9 @@ public class RFC2616Test extends TestCase e.printStackTrace(); assertTrue(false); } - finally - { - } } - /* --------------------------------------------------------------- */ + @Test public void test9_2() { // TODO @@ -420,7 +417,7 @@ public class RFC2616Test extends TestCase */ } - /* --------------------------------------------------------------- */ + @Test public void test9_4() { try @@ -443,7 +440,7 @@ public class RFC2616Test extends TestCase } } - /* --------------------------------------------------------------- */ + @Test public void test9_8() { // TODO @@ -461,7 +458,7 @@ public class RFC2616Test extends TestCase */ } - /* --------------------------------------------------------------- */ + @Test public void test10_2_7() { // TODO @@ -514,7 +511,7 @@ public class RFC2616Test extends TestCase */ } - /* --------------------------------------------------------------- */ + @Test public void test10_3() { // TODO @@ -564,61 +561,7 @@ public class RFC2616Test extends TestCase */ } - /* --------------------------------------------------------------- */ - public void checkContentRange(LocalConnector listener, String tname, String path, String reqRanges, int expectedStatus, String expectedRange, - String expectedData) - { - try - { - String response; - int offset=0; - - String byteRangeHeader=""; - if (reqRanges!=null) - { - byteRangeHeader="Range: "+reqRanges+"\n"; - } - - response=connector.getResponses("GET /"+path+" HTTP/1.1\n"+"Host: localhost\n"+byteRangeHeader+"Connection: close\n"+"\n"); - - switch (expectedStatus) - { - case 200: - { - offset=checkContains(response,offset,"HTTP/1.1 200 OK\r\n",tname+".1. proper 200 OK status code"); - break; - } - case 206: - { - offset=checkContains(response,offset,"HTTP/1.1 206 Partial Content\r\n",tname+".1. proper 206 Partial Content status code"); - break; - } - case 416: - { - offset=checkContains(response,offset,"HTTP/1.1 416 Requested Range Not Satisfiable\r\n",tname - +".1. proper 416 Requested Range not Satisfiable status code"); - break; - } - } - - if (expectedRange!=null) - { - String expectedContentRange="Content-Range: bytes "+expectedRange+"\r\n"; - offset=checkContains(response,offset,expectedContentRange,tname+".2. _content range "+expectedRange); - } - - if (expectedStatus==200||expectedStatus==206) - { - offset=checkContains(response,offset,expectedData,tname+".3. subrange data: \""+expectedData+"\""); - } - } - catch (Exception e) - { - e.printStackTrace(); - assertTrue(false); - } - } - + @Test public void test14_16() { // TODO @@ -671,12 +614,11 @@ public class RFC2616Test extends TestCase */ } - /* --------------------------------------------------------------- */ + @Test public void test14_23() { try { - String response; int offset=0; @@ -705,7 +647,7 @@ public class RFC2616Test extends TestCase } } - /* --------------------------------------------------------------- */ + @Test public void test14_35() { // TODO @@ -742,7 +684,7 @@ public class RFC2616Test extends TestCase * catch(Exception e) { e.printStackTrace(); assertTrue(false); } */} - /* --------------------------------------------------------------- */ + @Test public void test14_39() { // TODO @@ -764,12 +706,11 @@ public class RFC2616Test extends TestCase */ } - /* --------------------------------------------------------------- */ + @Test public void test19_6() { try { - String response; int offset=0; @@ -821,7 +762,59 @@ public class RFC2616Test extends TestCase offset=checkContains(response,offset,"/R2","19.6.2 Keep-alive close")+3; assertEquals("19.6.2 closed",-1,response.indexOf("/R3")); + } + catch (Exception e) + { + e.printStackTrace(); + assertTrue(false); + } + } + + private void checkContentRange(LocalConnector listener, String tname, String path, String reqRanges, int expectedStatus, String expectedRange, String expectedData) + { + try + { + String response; + int offset=0; + + String byteRangeHeader=""; + if (reqRanges!=null) + { + byteRangeHeader="Range: "+reqRanges+"\n"; + } + response=connector.getResponses("GET /"+path+" HTTP/1.1\n"+"Host: localhost\n"+byteRangeHeader+"Connection: close\n"+"\n"); + + switch (expectedStatus) + { + case 200: + { + offset=checkContains(response,offset,"HTTP/1.1 200 OK\r\n",tname+".1. proper 200 OK status code"); + break; + } + case 206: + { + offset=checkContains(response,offset,"HTTP/1.1 206 Partial Content\r\n",tname+".1. proper 206 Partial Content status code"); + break; + } + case 416: + { + offset=checkContains(response,offset,"HTTP/1.1 416 Requested Range Not Satisfiable\r\n",tname + +".1. proper 416 Requested Range not Satisfiable status code"); + break; + } + } + + if (expectedRange!=null) + { + String expectedContentRange="Content-Range: bytes "+expectedRange+"\r\n"; + offset=checkContains(response,offset,expectedContentRange,tname+".2. _content range "+expectedRange); + } + + if (expectedStatus==200||expectedStatus==206) + { + offset=checkContains(response,offset,expectedData,tname+".3. subrange data: \""+expectedData+"\""); + } } catch (Exception e) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index d8b62a085c..d6a4e73fc9 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -18,73 +18,58 @@ import java.io.InputStream; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; - import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.StringUtil; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; /** * - * - * To change the template for this generated type comment go to - * Window - Preferences - Java - Code Generation - Code and Comments */ -public class RequestTest extends TestCase +public class RequestTest { - Server _server = new Server(); - LocalConnector _connector = new LocalConnector(); - RequestHandler _handler = new RequestHandler(); + private Server _server; + private LocalConnector _connector; + private RequestHandler _handler; + @Before + public void init() throws Exception { + _server = new Server(); + _connector = new LocalConnector(); _connector.setHeaderBufferSize(512); _connector.setRequestBufferSize(1024); _connector.setResponseBufferSize(2048); - } - - public RequestTest(String arg0) - { - super(arg0); - _server.setConnectors(new Connector[]{_connector}); - - } - - public static void main(String[] args) - { - junit.textui.TestRunner.run(RequestTest.class); - } - - /* - * @see TestCase#setUp() - */ - protected void setUp() throws Exception - { - super.setUp(); - + _server.addConnector(_connector); + _handler = new RequestHandler(); _server.setHandler(_handler); _server.start(); } - /* - * @see TestCase#tearDown() - */ - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { - super.tearDown(); _server.stop(); + _server.join(); } - - public void testContentTypeEncoding() - throws Exception + @Test + public void testContentTypeEncoding() throws Exception { - final ArrayList results = new ArrayList(); + final ArrayList<String> results = new ArrayList<String>(); _handler._checker = new RequestTester() { public boolean check(HttpServletRequest request,HttpServletResponse response) @@ -127,18 +112,13 @@ public class RequestTest extends TestCase assertEquals("text/html; charset=\"utf8\"",results.get(i++)); assertEquals("utf8",results.get(i++)); - assertTrue(((String)results.get(i++)).startsWith("text/html")); + assertTrue(results.get(i++).startsWith("text/html")); assertEquals(" x=z; ",results.get(i++)); - - } - - - public void testContent() - throws Exception + @Test + public void testContent() throws Exception { - final int[] length=new int[1]; _handler._checker = new RequestTester() @@ -170,8 +150,8 @@ public class RequestTest extends TestCase } } - public void testPartialRead() - throws Exception + @Test + public void testPartialRead() throws Exception { Handler handler = new AbstractHandler() { @@ -185,7 +165,7 @@ public class RequestTest extends TestCase response.getOutputStream().write(b); response.flushBuffer(); } - + }; _server.stop(); _server.setHandler(handler); @@ -207,17 +187,16 @@ public class RequestTest extends TestCase String responses = _connector.getResponses(request); System.err.println("response="+responses); - + int index=responses.indexOf("read="+(int)'0'); assertTrue(index>0); - + index=responses.indexOf("read="+(int)'A',index+7); assertTrue(index>0); - } - public void testPartialInput() - throws Exception + @Test + public void testPartialInput() throws Exception { Handler handler = new AbstractHandler() { @@ -259,11 +238,10 @@ public class RequestTest extends TestCase index=responses.indexOf("read="+(int)'A',index+7); assertTrue(index>0); - } - public void testConnectionClose() - throws Exception + @Test + public void testConnectionClose() throws Exception { String response; @@ -306,8 +284,6 @@ public class RequestTest extends TestCase assertTrue(response.indexOf("Connection: close")>0); assertTrue(response.indexOf("Hello World")>0); - - response=_connector.getResponses( "GET / HTTP/1.0\n"+ "Host: whatever\n"+ @@ -337,9 +313,6 @@ public class RequestTest extends TestCase assertTrue(response.indexOf("Connection: keep-alive")>0); assertTrue(response.indexOf("Hello World")>0); - - - _handler._checker = new RequestTester() { public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException @@ -371,10 +344,10 @@ public class RequestTest extends TestCase assertTrue(response.indexOf("Hello World")>0); } - + @Test public void testCookies() throws Exception { - final ArrayList cookies = new ArrayList(); + final ArrayList<Cookie> cookies = new ArrayList<Cookie>(); _handler._checker = new RequestTester() { @@ -409,8 +382,8 @@ public class RequestTest extends TestCase ); assertTrue(response.startsWith("HTTP/1.1 200 OK")); assertEquals(1,cookies.size()); - assertEquals("name",((Cookie)cookies.get(0)).getName()); - assertEquals("quoted=\\\"value\\\"",((Cookie)cookies.get(0)).getValue()); + assertEquals("name", cookies.get(0).getName()); + assertEquals("quoted=\\\"value\\\"", cookies.get(0).getValue()); cookies.clear(); response=_connector.getResponses( @@ -421,10 +394,10 @@ public class RequestTest extends TestCase ); assertTrue(response.startsWith("HTTP/1.1 200 OK")); assertEquals(2,cookies.size()); - assertEquals("name",((Cookie)cookies.get(0)).getName()); - assertEquals("value",((Cookie)cookies.get(0)).getValue()); - assertEquals("other",((Cookie)cookies.get(1)).getName()); - assertEquals("quoted=;value",((Cookie)cookies.get(1)).getValue()); + assertEquals("name", cookies.get(0).getName()); + assertEquals("value", cookies.get(0).getValue()); + assertEquals("other", cookies.get(1).getName()); + assertEquals("quoted=;value", cookies.get(1).getValue()); cookies.clear(); @@ -442,14 +415,13 @@ public class RequestTest extends TestCase ); assertTrue(response.startsWith("HTTP/1.1 200 OK")); assertEquals(4,cookies.size()); - assertEquals("name",((Cookie)cookies.get(0)).getName()); - assertEquals("value",((Cookie)cookies.get(0)).getValue()); - assertEquals("other",((Cookie)cookies.get(1)).getName()); - assertEquals("quoted=;value",((Cookie)cookies.get(1)).getValue()); - - assertTrue((Cookie)cookies.get(0)==(Cookie)cookies.get(2)); - assertTrue((Cookie)cookies.get(1)==(Cookie)cookies.get(3)); + assertEquals("name", cookies.get(0).getName()); + assertEquals("value", cookies.get(0).getValue()); + assertEquals("other", cookies.get(1).getName()); + assertEquals("quoted=;value", cookies.get(1).getValue()); + assertSame(cookies.get(0), cookies.get(2)); + assertSame(cookies.get(1), cookies.get(3)); cookies.clear(); response=_connector.getResponses( @@ -466,15 +438,17 @@ public class RequestTest extends TestCase ); assertTrue(response.startsWith("HTTP/1.1 200 OK")); assertEquals(4,cookies.size()); - assertEquals("name",((Cookie)cookies.get(0)).getName()); - assertEquals("value",((Cookie)cookies.get(0)).getValue()); - assertEquals("other",((Cookie)cookies.get(1)).getName()); - assertEquals("quoted=;value",((Cookie)cookies.get(1)).getValue()); + assertEquals("name", cookies.get(0).getName()); + assertEquals("value", cookies.get(0).getValue()); + assertEquals("other", cookies.get(1).getName()); + assertEquals("quoted=;value", cookies.get(1).getValue()); - assertTrue((Cookie)cookies.get(0)!=(Cookie)cookies.get(2)); - assertTrue((Cookie)cookies.get(1)!=(Cookie)cookies.get(3)); + assertNotSame(cookies.get(0), cookies.get(2)); + assertNotSame(cookies.get(1), cookies.get(3)); cookies.clear(); +//NOTE: the javax.servlet.http.Cookie class sets the system property org.glassfish.web.rfc2109_cookie_names_enforced +//to TRUE by default, and rejects all cookie names containing punctuation.Therefore this test cannot use "name2". response=_connector.getResponses( "POST / HTTP/1.1\r\n"+ "Host: whatever\r\n"+ @@ -484,33 +458,31 @@ public class RequestTest extends TestCase "Connection: close\r\n"+ "\r\n"); - assertEquals("name0",((Cookie)cookies.get(0)).getName()); - assertEquals("value0",((Cookie)cookies.get(0)).getValue()); - assertEquals("name1",((Cookie)cookies.get(1)).getName()); - assertEquals("value1",((Cookie)cookies.get(1)).getValue()); - assertEquals("name2",((Cookie)cookies.get(2)).getName()); - assertEquals("\"value2\"",((Cookie)cookies.get(2)).getValue()); - assertEquals("name3",((Cookie)cookies.get(3)).getName()); - assertEquals("value3=value3",((Cookie)cookies.get(3)).getValue()); - assertEquals(2,((Cookie)cookies.get(3)).getVersion()); - assertEquals("/path",((Cookie)cookies.get(3)).getPath()); - assertEquals("acme.com",((Cookie)cookies.get(3)).getDomain()); - assertEquals("$port=8080",((Cookie)cookies.get(3)).getComment()); - assertEquals("name4",((Cookie)cookies.get(4)).getName()); - assertEquals("",((Cookie)cookies.get(4)).getValue()); - assertEquals("name5",((Cookie)cookies.get(5)).getName()); - assertEquals("",((Cookie)cookies.get(5)).getValue()); - assertEquals("name6",((Cookie)cookies.get(6)).getName()); - assertEquals("",((Cookie)cookies.get(6)).getValue()); - assertEquals("name7",((Cookie)cookies.get(7)).getName()); - assertEquals("value7",((Cookie)cookies.get(7)).getValue()); - + assertEquals("name0", cookies.get(0).getName()); + assertEquals("value0", cookies.get(0).getValue()); + assertEquals("name1", cookies.get(1).getName()); + assertEquals("value1", cookies.get(1).getValue()); + assertEquals("name2", cookies.get(2).getName()); + assertEquals("\"value2\"", cookies.get(2).getValue()); + assertEquals("name3", cookies.get(3).getName()); + assertEquals("value3=value3", cookies.get(3).getValue()); + assertEquals(2, cookies.get(3).getVersion()); + assertEquals("/path", cookies.get(3).getPath()); + assertEquals("acme.com", cookies.get(3).getDomain()); + assertEquals("$port=8080", cookies.get(3).getComment()); + assertEquals("name4", cookies.get(4).getName()); + assertEquals("", cookies.get(4).getValue()); + assertEquals("name5", cookies.get(5).getName()); + assertEquals("", cookies.get(5).getValue()); + assertEquals("name6", cookies.get(6).getName()); + assertEquals("", cookies.get(6).getValue()); + assertEquals("name7", cookies.get(7).getName()); + assertEquals("value7", cookies.get(7).getValue()); } - public void testCookieLeak() - throws Exception + @Test + public void testCookieLeak() throws Exception { - final String[] cookie=new String[10]; _handler._checker = new RequestTester() @@ -529,7 +501,6 @@ public class RequestTest extends TestCase } }; - String request="POST / HTTP/1.1\r\n"+ "Host: whatever\r\n"+ "Cookie: other=cookie\r\n"+ @@ -561,7 +532,6 @@ public class RequestTest extends TestCase assertEquals(null,cookie[0]); assertEquals(null,cookie[1]); - request="POST / HTTP/1.1\r\n"+ "Host: whatever\r\n"+ "Cookie: name=value\r\n"+ @@ -579,22 +549,17 @@ public class RequestTest extends TestCase assertEquals("value",cookie[0]); assertEquals(null,cookie[1]); - - } - - - interface RequestTester { boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException; } - class RequestHandler extends AbstractHandler + private class RequestHandler extends AbstractHandler { - RequestTester _checker; - String _content; + private RequestTester _checker; + private String _content; public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { @@ -607,9 +572,6 @@ public class RequestTest extends TestCase response.setStatus(200); else response.sendError(500); - - } } - } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java index c8d16f44c2..f90e1220ca 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; @@ -16,27 +16,27 @@ package org.eclipse.jetty.server; import java.io.File; import java.io.FileOutputStream; -import junit.framework.TestCase; - import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.server.ResourceCache.Content; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -public class ResourceCacheTest extends TestCase +public class ResourceCacheTest { - Resource directory; - File[] files=new File[10]; - String[] names=new String[files.length]; - ResourceCache cache = new ResourceCache(new MimeTypes()); - ResourceFactory factory; - - /* ------------------------------------------------------------ */ - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - @Override - protected void setUp() throws Exception + private Resource directory; + private File[] files=new File[10]; + private String[] names=new String[files.length]; + private ResourceCache cache = new ResourceCache(new MimeTypes()); + private ResourceFactory factory; + + @Before + public void init() throws Exception { for (int i=0;i<files.length;i++) { @@ -49,9 +49,9 @@ public class ResourceCacheTest extends TestCase out.write('\n'); out.close(); } - + directory=Resource.newResource(files[0].getParentFile().getAbsolutePath()); - + factory = new ResourceFactory() { public Resource getResource(String path) @@ -65,7 +65,7 @@ public class ResourceCacheTest extends TestCase return null; } } - + }; cache.setMaxCacheSize(95); cache.setMaxCachedFileSize(85); @@ -73,54 +73,50 @@ public class ResourceCacheTest extends TestCase cache.start(); } - /* ------------------------------------------------------------ */ - /* (non-Javadoc) - * @see junit.framework.TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { cache.stop(); } - /* ------------------------------------------------------------ */ + @Test public void testResourceCache() throws Exception { assertTrue(cache.lookup("does not exist",factory)==null); assertTrue(cache.lookup(names[9],factory)==null); - + Content content; content=cache.lookup(names[8],factory); assertTrue(content!=null); assertEquals(80,content.getContentLength()); - + assertEquals(80,cache.getCachedSize()); assertEquals(1,cache.getCachedFiles()); content=cache.lookup(names[1],factory); assertEquals(90,cache.getCachedSize()); assertEquals(2,cache.getCachedFiles()); - + content=cache.lookup(names[2],factory); assertEquals(30,cache.getCachedSize()); assertEquals(2,cache.getCachedFiles()); - + content=cache.lookup(names[3],factory); assertEquals(60,cache.getCachedSize()); assertEquals(3,cache.getCachedFiles()); - + content=cache.lookup(names[4],factory); assertEquals(90,cache.getCachedSize()); assertEquals(3,cache.getCachedFiles()); - + content=cache.lookup(names[5],factory); assertEquals(90,cache.getCachedSize()); assertEquals(2,cache.getCachedFiles()); - + content=cache.lookup(names[6],factory); assertEquals(60,cache.getCachedSize()); assertEquals(1,cache.getCachedFiles()); - + FileOutputStream out = new FileOutputStream(files[6]); out.write(' '); out.close(); @@ -131,27 +127,25 @@ public class ResourceCacheTest extends TestCase content=cache.lookup(names[6],factory); assertEquals(71,cache.getCachedSize()); assertEquals(2,cache.getCachedFiles()); - + content=cache.lookup(names[0],factory); assertEquals(72,cache.getCachedSize()); assertEquals(3,cache.getCachedFiles()); - + content=cache.lookup(names[1],factory); assertEquals(82,cache.getCachedSize()); assertEquals(4,cache.getCachedFiles()); - + content=cache.lookup(names[2],factory); assertEquals(32,cache.getCachedSize()); assertEquals(4,cache.getCachedFiles()); - + content=cache.lookup(names[3],factory); assertEquals(61,cache.getCachedSize()); assertEquals(4,cache.getCachedFiles()); - + cache.flushCache(); assertEquals(0,cache.getCachedSize()); assertEquals(0,cache.getCachedFiles()); - - } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 63e736061e..c6f9842abc 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -22,15 +22,12 @@ import java.util.Enumeration; import java.util.Iterator; import java.util.Locale; import java.util.Map; - import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSessionContext; -import junit.framework.TestCase; - import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; @@ -40,54 +37,43 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.session.AbstractSessionManager; import org.eclipse.jetty.server.session.HashSessionIdManager; import org.eclipse.jetty.server.session.HashSessionManager; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * - * - * To change the template for this generated type comment go to - * Window - Preferences - Java - Code Generation - Code and Comments */ -public class ResponseTest extends TestCase +public class ResponseTest { - Server server = new Server(); - LocalConnector connector = new LocalConnector(); + private Server server; + private LocalConnector connector; - public ResponseTest(String arg0) + @Before + public void init() throws Exception { - super(arg0); - server.setConnectors(new Connector[]{connector}); + server = new Server(); + connector = new LocalConnector(); + server.addConnector(connector); server.setHandler(new DumpHandler()); - } - - public static void main(String[] args) - { - junit.textui.TestRunner.run(ResponseTest.class); - } - - /* - * @see TestCase#setUp() - */ - protected void setUp() throws Exception - { - super.setUp(); - server.start(); } - /* - * @see TestCase#tearDown() - */ - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { - super.tearDown(); server.stop(); + server.join(); } - - public void testContentType() - throws Exception + @Test + public void testContentType() throws Exception { - HttpConnection connection = new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()); Response response = connection.getResponse(); @@ -122,9 +108,8 @@ public class ResponseTest extends TestCase response.recycle(); } - - public void testLocale() - throws Exception + @Test + public void testLocale() throws Exception { HttpConnection connection = new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()); @@ -148,8 +133,8 @@ public class ResponseTest extends TestCase assertTrue(response.toString().indexOf("charset=UTF-8")>0); } - public void testContentTypeCharacterEncoding() - throws Exception + @Test + public void testContentTypeCharacterEncoding() throws Exception { HttpConnection connection = new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()); @@ -181,8 +166,8 @@ public class ResponseTest extends TestCase } - public void testCharacterEncodingContentType() - throws Exception + @Test + public void testCharacterEncodingContentType() throws Exception { Response response = new Response(new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer())); @@ -210,8 +195,8 @@ public class ResponseTest extends TestCase } - public void testContentTypeWithCharacterEncoding() - throws Exception + @Test + public void testContentTypeWithCharacterEncoding() throws Exception { Response response = new Response(new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer())); @@ -239,8 +224,8 @@ public class ResponseTest extends TestCase } - public void testContentTypeWithOther() - throws Exception + @Test + public void testContentTypeWithOther() throws Exception { Response response = new Response(new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer())); @@ -262,9 +247,8 @@ public class ResponseTest extends TestCase assertEquals("text/xml;charset=UTF-8",response.getContentType()); } - - public void testContentTypeWithCharacterEncodingAndOther() - throws Exception + @Test + public void testContentTypeWithCharacterEncodingAndOther() throws Exception { Response response = new Response(new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer())); @@ -292,6 +276,7 @@ public class ResponseTest extends TestCase } + @Test public void testStatusCodes() throws Exception { Response response=newResponse(); @@ -321,14 +306,18 @@ public class ResponseTest extends TestCase assertEquals("must-revalidate,no-cache,no-store", response.getHeader(HttpHeaders.CACHE_CONTROL)); } + @Test public void testEncodeRedirect() throws Exception { HttpConnection connection=new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()); Response response = new Response(connection); Request request = connection.getRequest(); + request.setServerName("myhost"); + request.setServerPort(8888); + request.setContextPath("/path"); - assertEquals("http://host:port/path/info;param?query=0&more=1#target",response.encodeRedirectUrl("http://host:port/path/info;param?query=0&more=1#target")); + assertEquals("http://myhost:8888/path/info;param?query=0&more=1#target",response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target")); request.setRequestedSessionId("12345"); request.setRequestedSessionIdFromCookie(false); @@ -337,12 +326,22 @@ public class ResponseTest extends TestCase request.setSessionManager(manager); request.setSession(new TestSession(manager,"12345")); - assertEquals("http://host:port/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeRedirectUrl("http://host:port/path/info;param?query=0&more=1#target")); + manager.setCheckingRemoteSessionIdEncoding(false); + + assertEquals("http://myhost:8888/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target")); + assertEquals("http://other:8888/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://other:8888/path/info;param?query=0&more=1#target")); + assertEquals("http://myhost/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost/path/info;param?query=0&more=1#target")); + assertEquals("http://myhost:8888/other/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost:8888/other/info;param?query=0&more=1#target")); + manager.setCheckingRemoteSessionIdEncoding(true); + assertEquals("http://myhost:8888/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target")); + assertEquals("http://other:8888/path/info;param?query=0&more=1#target",response.encodeURL("http://other:8888/path/info;param?query=0&more=1#target")); + assertEquals("http://myhost/path/info;param?query=0&more=1#target",response.encodeURL("http://myhost/path/info;param?query=0&more=1#target")); + assertEquals("http://myhost:8888/other/info;param?query=0&more=1#target",response.encodeURL("http://myhost:8888/other/info;param?query=0&more=1#target")); } - public void testSetBufferSize () - throws Exception + @Test + public void testSetBufferSize () throws Exception { Response response = new Response(new HttpConnection(connector,new ByteArrayEndPoint(), connector.getServer())); response.setBufferSize(20*1024); @@ -358,6 +357,7 @@ public class ResponseTest extends TestCase } } + @Test public void testHead() throws Exception { Server server = new Server(); @@ -417,7 +417,7 @@ public class ResponseTest extends TestCase return response; } - class TestSession extends AbstractSessionManager.Session + private class TestSession extends AbstractSessionManager.Session { public TestSession(AbstractSessionManager abstractSessionManager, String id) { @@ -507,7 +507,6 @@ public class ResponseTest extends TestCase protected Map newAttributeMap() { - // TODO Auto-generated method stub return null; } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelServerTest.java index b7dadeda08..76f24ff9fe 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelServerTest.java @@ -4,23 +4,25 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.junit.BeforeClass; /** * HttpServer Tester. */ public class SelectChannelServerTest extends HttpServerTestBase { - public SelectChannelServerTest() + @BeforeClass + public static void init() throws Exception { - super(new SelectChannelConnector()); - } + startServer(new SelectChannelConnector()); + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java index ee71c54c53..497535d752 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java @@ -4,30 +4,33 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; import java.util.Random; -import junit.framework.TestCase; - import org.eclipse.jetty.server.handler.DefaultHandler; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; /** * @version $Revision$ */ -public class ServerTest extends TestCase +public class ServerTest { /** * JETTY-87, adding a handler to a server without any handlers should not * throw an exception */ + @Test public void testAddHandlerToEmptyServer() { Server server=new Server(); @@ -42,6 +45,7 @@ public class ServerTest extends TestCase } } + @Test public void testServerWithPort() { int port=new Random().nextInt(20000)+10000; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/SocketServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/SocketServerTest.java index d644616c00..918ea9f7e3 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/SocketServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/SocketServerTest.java @@ -4,23 +4,25 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; import org.eclipse.jetty.server.bio.SocketConnector; +import org.junit.BeforeClass; /** * HttpServer Tester. */ public class SocketServerTest extends HttpServerTestBase { - public SocketServerTest() + @BeforeClass + public static void init() throws Exception { - super(new SocketConnector()); - } + startServer(new SocketConnector()); + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/StressTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/StressTest.java index eecf2d80e5..7f05ba9f02 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/StressTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/StressTest.java @@ -4,51 +4,47 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetAddress; import java.net.Socket; import java.util.Queue; import java.util.Random; -import java.util.Timer; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; -public class StressTest extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class StressTest { - protected Server _server = new Server(); - protected TestHandler _handler = new TestHandler(); - protected Connector _connector; - protected InetAddress _addr; - protected int _port; - protected volatile AtomicInteger[] _loops; - protected QueuedThreadPool _threads=new QueuedThreadPool(new BlockingArrayQueue<Runnable>(4,4)); - // protected ExecutorThreadPool _threads=new ExecutorThreadPool(100,500,10000,TimeUnit.MILLISECONDS); - protected boolean _stress; - private AtomicInteger _handled=new AtomicInteger(0); - private ConcurrentLinkedQueue[] _latencies= { + private static boolean _stress; + private static QueuedThreadPool _threads; + private static Server _server; + private static SelectChannelConnector _connector; + private static final AtomicInteger _handled=new AtomicInteger(0); + private static final ConcurrentLinkedQueue[] _latencies= { new ConcurrentLinkedQueue<Long>(), new ConcurrentLinkedQueue<Long>(), new ConcurrentLinkedQueue<Long>(), @@ -56,44 +52,10 @@ public class StressTest extends TestCase new ConcurrentLinkedQueue<Long>(), new ConcurrentLinkedQueue<Long>() }; - private Random _random=new Random(); - - @Override - protected void setUp() throws Exception - { - _stress= Boolean.getBoolean("STRESS"); - - _threads.setMaxThreads(500); - _server.setThreadPool(_threads); - SelectChannelConnector c_connector=new SelectChannelConnector(); - c_connector.setAcceptors(1); - c_connector.setAcceptQueueSize(1000); - - // c_connector.setPort(8080); - - _connector=c_connector; - _connector.setMaxIdleTime(30000); - - _server.setConnectors(new Connector[]{ _connector }); - _server.setHandler(_handler); - _server.start(); - _port=_connector.getLocalPort(); - _addr=InetAddress.getLocalHost(); - // _addr=Inet4Address.getByName("10.10.1.16"); - // System.err.println("ADDR "+_addr+":"+_port); - - for (Queue q:_latencies) - q.clear(); - _handled.set(0); - } - @Override - protected void tearDown() throws Exception - { - _server.stop(); - } - - final static String[] __tests = + private volatile AtomicInteger[] _loops; + private final Random _random=new Random(); + private static final String[] __tests = { "/path/0", "/path/1", @@ -112,166 +74,103 @@ public class StressTest extends TestCase "/path/e", "/path/f", }; - - - public void doPaths(int thread,String name,boolean persistent) throws Exception - { - if (persistent) - { - long start=System.currentTimeMillis(); - Socket socket= new Socket(_addr,_port); - socket.setSoTimeout(30000); - socket.setSoLinger(false,0); - - long connected=System.currentTimeMillis(); - - for (int i=0;i<__tests.length;i++) - { - String uri=__tests[i]+"/"+name+"/"+i; - - String close=((i+1)<__tests.length)?"":"Connection: close\r\n"; - String request = - "GET "+uri+" HTTP/1.1\r\n"+ - "Host: localhost\r\n"+ - "start: "+start+"\r\n"+ - close+"\r\n"; - socket.getOutputStream().write(request.getBytes()); - socket.getOutputStream().flush(); - Thread.yield(); - } - - long written=System.currentTimeMillis(); - - String response = IO.toString(socket.getInputStream()); - socket.close(); - - long end=System.currentTimeMillis(); - - int bodies = count(response,"HTTP/1.1 200 OK"); - if (__tests.length!=bodies) - System.err.println("responses=\n"+response+"\n---"); - assertEquals(name,__tests.length,bodies);bodies = count(response,"HTTP/1.1 200 OK"); - - long bind=connected-start; - long flush=(written-connected)/__tests.length; - long read=(end-written)/__tests.length; - - int offset=0; - for (int i=0;i<__tests.length;i++) - { - offset=response.indexOf("DATA "+__tests[i],offset); - assertTrue(offset>=0); - offset+=__tests[i].length()+5; - - if (bind<0 || flush<0 || read <0) - { - System.err.println(bind+","+flush+","+read); - } - - _latencies[0].add((i==0)?new Long(bind):0); - _latencies[1].add((i==0)?new Long(bind+flush):flush); - _latencies[5].add((i==0)?new Long(bind+flush+read):(flush+read)); - } - } - else - { - for (int i=0;i<__tests.length;i++) - { - String uri=__tests[i]+"/"+name+"/"+i; - - long start=System.currentTimeMillis(); - String close="Connection: close\r\n"; - String request = - "GET "+uri+" HTTP/1.1\r\n"+ - "Host: localhost\r\n"+ - "start: "+start+"\r\n"+ - close+"\r\n"; - - Socket socket = new Socket(_addr,_port); - socket.setSoTimeout(10000); - socket.setSoLinger(false,0); - - _latencies[0].add(new Long(System.currentTimeMillis()-start)); + @BeforeClass + public static void init() throws Exception + { + _stress= Boolean.getBoolean("STRESS"); - socket.getOutputStream().write(request.getBytes()); - socket.getOutputStream().flush(); + _threads = new QueuedThreadPool(new BlockingArrayQueue<Runnable>(4,4)); + _threads.setMaxThreads(500); + _server = new Server(); + _server.setThreadPool(_threads); - _latencies[1].add(new Long(System.currentTimeMillis()-start)); + _connector = new SelectChannelConnector(); + _connector.setAcceptors(1); + _connector.setAcceptQueueSize(1000); + _connector.setMaxIdleTime(30000); + _server.addConnector(_connector); - String response = IO.toString(socket.getInputStream()); - socket.close(); - long end=System.currentTimeMillis(); + TestHandler _handler = new TestHandler(); + _server.setHandler(_handler); - response=response.substring(response.indexOf("\r\n\r\n")+4); + _server.start(); + } - assertTrue(uri,response.startsWith("DATA "+__tests[i])); - long latency=end-start; + @AfterClass + public static void destroy() throws Exception + { + _server.stop(); + _server.join(); + } - _latencies[5].add(new Long(latency)); - } - } + @Before + public void reset() + { + _handled.set(0); + for (Queue q : _latencies) + q.clear(); } - - public void doLoops(int thread, String name, int loops,boolean persistent) throws Exception + + @Test + public void testNonPersistent() throws Throwable { - try + if (_stress) { - for (int i=0;i<loops;i++) - { - _loops[thread].set(i); - doPaths(thread,name+"-"+i,persistent); - Thread.sleep(1+_random.nextInt(10)*_random.nextInt(10)); - Thread.sleep(10); - } - _loops[thread].set(loops); + System.err.println("STRESS!"); + doThreads(200,100,false); } - catch(Exception e) + else + doThreads(10,20,false); + } + + @Test + public void testPersistent() throws Throwable + { + if (_stress) { - System.err.println(e); - _loops[thread].set(-_loops[thread].get()); - throw e; + System.err.println("STRESS!"); + doThreads(200,100,true); } + else + doThreads(20,40,true); } - public void doThreads(int threads,final int loops,final boolean persistent) throws Throwable + private void doThreads(int threadCount, final int loops, final boolean persistent) throws Throwable { - final Throwable[] throwable=new Throwable[threads]; - final Thread[] thread=new Thread[threads]; + final Throwable[] throwables = new Throwable[threadCount]; + final Thread[] threads = new Thread[threadCount]; try { - for (int i=0;i<threads;i++) + for (int i=0;i< threadCount;i++) { final int id=i; final String name = "T"+i; - thread[i]=new Thread() + threads[i]=new Thread() { @Override - public void run() - { + public void run() + { try { - doLoops(id,name,loops,persistent); + doLoops(id,name,loops,persistent); } catch(Throwable th) { th.printStackTrace(); - throwable[id]=th; - } - finally - { + throwables[id]=th; } } }; } - _loops=new AtomicInteger[threads]; - for (int i=0;i<threads;i++) + _loops=new AtomicInteger[threadCount]; + for (int i=0;i< threadCount;i++) { _loops[i]=new AtomicInteger(0); - thread[i].start(); + threads[i].start(); } String last=null; @@ -285,7 +184,7 @@ public class StressTest extends TestCase int min=loops; int max=0; int total=0; - for (int i=0;i<threads;i++) + for (int i=0;i< threadCount;i++) { int l=_loops[i].get(); if (l<0) @@ -301,10 +200,10 @@ public class StressTest extends TestCase max=l; total+=l; if (l==loops) - finished++; - } + finished++; + } } - String status = "min/ave/max/target="+min+"/"+(total/threads)+"/"+max+"/"+loops+" errors/finished/loops="+errors+"/"+finished+"/"+threads+" idle/threads="+(_threads.getIdleThreads())+"/"+_threads.getThreads(); + String status = "min/ave/max/target="+min+"/"+(total/ threadCount)+"/"+max+"/"+loops+" errors/finished/loops="+errors+"/"+finished+"/"+ threadCount +" idle/threads="+(_threads.getIdleThreads())+"/"+_threads.getThreads(); if (status.equals(last)) { if (same++>5) @@ -320,19 +219,19 @@ public class StressTest extends TestCase same=0; last=status; Log.info(_server.getThreadPool().toString()+" "+status); - if ((finished+errors)==threads) + if ((finished+errors)== threadCount) break; } - for (int i=0;i<threads;i++) - thread[i].join(); + for (Thread thread : threads) + thread.join(); - for (int i=0;i<threads;i++) - if (throwable[i]!=null) - throw throwable[i]; - - for (int i=0;i<_latencies.length;i++) - assertEquals(_handled.get(),_latencies[i].size()); + for (Throwable throwable : throwables) + if (throwable!=null) + throw throwable; + + for (ConcurrentLinkedQueue _latency : _latencies) + assertEquals(_handled.get(), _latency.size()); } finally { @@ -348,18 +247,18 @@ public class StressTest extends TestCase length[i] = latencies.size(); loop: - for (long latency:(Queue<Long>)(_latencies[i])) + for (long latency : latencies) + { + for (int q=0;q<quantums;q++) { - for (int q=0;q<quantums;q++) + if (latency>=(q*100) && latency<((q+1)*100)) { - if (latency>=(q*100) && latency<((q+1)*100)) - { - count[i][q]++; - continue loop; - } + count[i][q]++; + continue loop; } - other[i]++; } + other[i]++; + } } System.out.println(" stage:\tbind\twrite\trecv\tdispatch\twrote\ttotal"); @@ -387,76 +286,164 @@ public class StressTest extends TestCase } } - public void testNonPersistent() throws Throwable + private void doLoops(int thread, String name, int loops,boolean persistent) throws Exception { - if (_stress) + try { - System.err.println("STRESS!"); - doThreads(200,100,false); + for (int i=0;i<loops;i++) + { + _loops[thread].set(i); + doPaths(thread,name+"-"+i,persistent); + Thread.sleep(1+_random.nextInt(10)*_random.nextInt(10)); + Thread.sleep(10); + } + _loops[thread].set(loops); + } + catch(Exception e) + { + System.err.println(e); + _loops[thread].set(-_loops[thread].get()); + throw e; } - else - doThreads(10,20,false); } - public void testPersistent() throws Throwable + private void doPaths(int thread,String name,boolean persistent) throws Exception { - if (_stress) + if (persistent) { - System.err.println("STRESS!"); - doThreads(200,400,true); + long start=System.currentTimeMillis(); + Socket socket= new Socket("localhost", _connector.getLocalPort()); + socket.setSoTimeout(30000); + socket.setSoLinger(false,0); + + long connected=System.currentTimeMillis(); + + for (int i=0;i<__tests.length;i++) + { + String uri=__tests[i]+"/"+name+"/"+i; + + String close=((i+1)<__tests.length)?"":"Connection: close\r\n"; + String request = + "GET "+uri+" HTTP/1.1\r\n"+ + "Host: localhost\r\n"+ + "start: "+start+"\r\n"+ + close+"\r\n"; + + socket.getOutputStream().write(request.getBytes()); + socket.getOutputStream().flush(); + Thread.yield(); + } + + long written=System.currentTimeMillis(); + + String response = IO.toString(socket.getInputStream()); + socket.close(); + + long end=System.currentTimeMillis(); + + int bodies = count(response,"HTTP/1.1 200 OK"); + if (__tests.length!=bodies) + System.err.println("responses=\n"+response+"\n---"); + assertEquals(name,__tests.length,bodies); + bodies = count(response,"HTTP/1.1 200 OK"); + + long bind=connected-start; + long flush=(written-connected)/__tests.length; + long read=(end-written)/__tests.length; + + int offset=0; + for (int i=0;i<__tests.length;i++) + { + offset=response.indexOf("DATA "+__tests[i],offset); + assertTrue(offset>=0); + offset+=__tests[i].length()+5; + + if (bind<0 || flush<0 || read <0) + { + System.err.println(bind+","+flush+","+read); + } + + _latencies[0].add((i==0)?new Long(bind):0); + _latencies[1].add((i==0)?new Long(bind+flush):flush); + _latencies[5].add((i==0)?new Long(bind+flush+read):(flush+read)); + } } else - doThreads(20,40,true); + { + for (int i=0;i<__tests.length;i++) + { + String uri=__tests[i]+"/"+name+"/"+i; + + long start=System.currentTimeMillis(); + String close="Connection: close\r\n"; + String request = + "GET "+uri+" HTTP/1.1\r\n"+ + "Host: localhost\r\n"+ + "start: "+start+"\r\n"+ + close+"\r\n"; + + Socket socket = new Socket("localhost", _connector.getLocalPort()); + socket.setSoTimeout(10000); + socket.setSoLinger(false,0); + + _latencies[0].add(new Long(System.currentTimeMillis()-start)); + + socket.getOutputStream().write(request.getBytes()); + socket.getOutputStream().flush(); + + _latencies[1].add(new Long(System.currentTimeMillis()-start)); + + String response = IO.toString(socket.getInputStream()); + socket.close(); + long end=System.currentTimeMillis(); + + response=response.substring(response.indexOf("\r\n\r\n")+4); + + assertTrue(uri,response.startsWith("DATA "+__tests[i])); + long latency=end-start; + + _latencies[5].add(new Long(latency)); + } + } } - - private int count(String s,String sub) { int count=0; int index=s.indexOf(sub); - + while(index>=0) { count++; index=s.indexOf(sub,index+sub.length()); - } + } return count; } - - private class TestHandler extends HandlerWrapper + + private static class TestHandler extends HandlerWrapper { - private Timer _timer; - - public TestHandler() - { - _timer=new Timer(); - } - @Override public void handle(String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { long now=System.currentTimeMillis(); long start=Long.parseLong(baseRequest.getHeader("start")); long received=baseRequest.getTimeStamp(); - + _handled.incrementAndGet(); long delay=received-start; if (delay<0) delay=0; _latencies[2].add(new Long(delay)); _latencies[3].add(new Long(now-start)); - + response.setStatus(200); response.getOutputStream().print("DATA "+request.getPathInfo()+"\n\n"); baseRequest.setHandled(true); long end=System.currentTimeMillis(); - + _latencies[4].add(new Long(System.currentTimeMillis()-start)); - + return; } } - - } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/UnreadInputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/UnreadInputTest.java index 148dbe9c6e..a71510f82e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/UnreadInputTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/UnreadInputTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server; @@ -17,17 +17,17 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.bio.SocketConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class UnreadInputTest extends TestCase +public class UnreadInputTest { public static final String __OK_RESPONSE = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nServer: Jetty(7.0.x)\r\n\r\n"; protected Server _server = new Server(); @@ -36,23 +36,9 @@ public class UnreadInputTest extends TestCase protected Socket _socket; protected OutputStream _outputStream; protected InputStream _inputStream; - - public class NoopHandler extends AbstractHandler - { - public void handle(String target, Request baseRequest, - HttpServletRequest request, HttpServletResponse response) throws IOException, - ServletException - { - //don't read the input, just send something back - ((Request)request).setHandled(true); - response.setStatus(200); - } - } - - - - @Override - protected void setUp() throws Exception + + @Before + public void init() throws Exception { //server side _connector = new SocketConnector(); @@ -60,23 +46,24 @@ public class UnreadInputTest extends TestCase _server.setHandler(new NoopHandler()); _server.start(); _port = _connector.getLocalPort(); - + //client side _socket = new Socket((String)null, _port); _outputStream = _socket.getOutputStream(); _inputStream = _socket.getInputStream(); } - @Override - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { + _socket.close(); + _server.stop(); + _server.join(); } - - - public void testUnreadInput () - throws Exception + @Test + public void testUnreadInput () throws Exception { for (int i=0; i<2; i++) { @@ -107,18 +94,24 @@ public class UnreadInputTest extends TestCase Thread.sleep(1000L); //write the rest - _outputStream.write(bytes, bytes.length/2, (bytes.length - bytes.length/2)); + _outputStream.write(bytes, bytes.length/2, (bytes.length - bytes.length/2)); } - + byte[] inbuf = new byte[__OK_RESPONSE.getBytes().length*2]; int x = _inputStream.read(inbuf); System.err.println(new String(inbuf, 0, x)); - - _inputStream.close(); - _outputStream.close(); - _socket.close(); } - - + + public class NoopHandler extends AbstractHandler + { + public void handle(String target, Request baseRequest, + HttpServletRequest request, HttpServletResponse response) throws IOException, + ServletException + { + //don't read the input, just send something back + ((Request)request).setHandled(true); + response.setStatus(200); + } + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AbstractProxyHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AbstractProxyHandlerTest.java new file mode 100644 index 0000000000..3f9635a319 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AbstractProxyHandlerTest.java @@ -0,0 +1,173 @@ +package org.eclipse.jetty.server.handler; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.net.Socket; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.junit.AfterClass; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @version $Revision$ $Date$ + */ +public abstract class AbstractProxyHandlerTest +{ + protected static Server server; + protected static Connector serverConnector; + protected static Server proxy; + protected static Connector proxyConnector; + + protected static void startServer(Connector connector, Handler handler) throws Exception + { + server = new Server(); + serverConnector = connector; + server.addConnector(serverConnector); + server.setHandler(handler); + server.start(); + } + + protected static void startProxy() throws Exception + { + proxy = new Server(); + proxyConnector = new SelectChannelConnector(); + proxy.addConnector(proxyConnector); + proxy.setHandler(new ProxyHandler()); + proxy.start(); + } + + @AfterClass + public static void stop() throws Exception + { + stopProxy(); + stopServer(); + } + + protected static void stopServer() throws Exception + { + server.stop(); + server.join(); + } + + protected static void stopProxy() throws Exception + { + proxy.stop(); + proxy.join(); + } + + protected Response readResponse(BufferedReader reader) throws IOException + { + // Simplified parser for HTTP responses + String line = reader.readLine(); + if (line == null) + throw new EOFException(); + Matcher responseLine = Pattern.compile("HTTP/1\\.1\\s+(\\d+)").matcher(line); + assertTrue(responseLine.lookingAt()); + String code = responseLine.group(1); + + Map<String, String> headers = new LinkedHashMap<String, String>(); + while ((line = reader.readLine()) != null) + { + if (line.trim().length() == 0) + break; + + Matcher header = Pattern.compile("([^:]+):\\s*(.*)").matcher(line); + assertTrue(header.lookingAt()); + String headerName = header.group(1); + String headerValue = header.group(2); + headers.put(headerName.toLowerCase(), headerValue.toLowerCase()); + } + + StringBuilder body = new StringBuilder(); + if (headers.containsKey("content-length")) + { + int length = Integer.parseInt(headers.get("content-length")); + for (int i = 0; i < length; ++i) + { + char c = (char)reader.read(); + body.append(c); + } + } + else if ("chunked".equals(headers.get("transfer-encoding"))) + { + while ((line = reader.readLine()) != null) + { + if ("0".equals(line)) + { + line = reader.readLine(); + assertEquals("", line); + break; + } + + int length = Integer.parseInt(line, 16); + for (int i = 0; i < length; ++i) + { + char c = (char)reader.read(); + body.append(c); + } + line = reader.readLine(); + assertEquals("", line); + } + } + + return new Response(code, headers, body.toString().trim()); + } + + protected Socket newSocket() throws IOException + { + Socket socket = new Socket("localhost", proxyConnector.getLocalPort()); + socket.setSoTimeout(5000); + return socket; + } + + protected class Response + { + private final String code; + private final Map<String, String> headers; + private final String body; + + private Response(String code, Map<String, String> headers, String body) + { + this.code = code; + this.headers = headers; + this.body = body; + } + + public String getCode() + { + return code; + } + + public Map<String, String> getHeaders() + { + return headers; + } + + public String getBody() + { + return body; + } + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + builder.append(code).append("\r\n"); + for (Map.Entry<String, String> entry : headers.entrySet()) + builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n"); + builder.append("\r\n"); + builder.append(body); + return builder.toString(); + } + } +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java index 6099320cf1..fa8022e1c2 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java @@ -4,30 +4,32 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server.handler; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; +import org.junit.Test; -public class ContextHandlerCollectionTest extends TestCase +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ContextHandlerCollectionTest { + @Test public void testVirtualHostNormalization() throws Exception { Server server = new Server(); @@ -83,23 +85,23 @@ public class ContextHandlerCollectionTest extends TestCase { server.stop(); } - } - + + @Test public void testVirtualHostWildcard() throws Exception { Server server = new Server(); LocalConnector connector = new LocalConnector(); server.setConnectors(new Connector[] { connector }); - + ContextHandler context = new ContextHandler("/"); - + IsHandledHandler handler = new IsHandledHandler(); context.setHandler(handler); ContextHandlerCollection c = new ContextHandlerCollection(); c.addHandler(context); - + server.setHandler(c); try @@ -107,19 +109,19 @@ public class ContextHandlerCollectionTest extends TestCase server.start(); checkWildcardHost(true,server,null,new String[] {"example.com", ".example.com", "vhost.example.com"}); checkWildcardHost(false,server,new String[] {null},new String[] {"example.com", ".example.com", "vhost.example.com"}); - + checkWildcardHost(true,server,new String[] {"example.com", "*.example.com"}, new String[] {"example.com", ".example.com", "vhost.example.com"}); checkWildcardHost(false,server,new String[] {"example.com", "*.example.com"}, new String[] {"badexample.com", ".badexample.com", "vhost.badexample.com"}); - + checkWildcardHost(false,server,new String[] {"*."}, new String[] {"anything.anything"}); - + checkWildcardHost(true,server,new String[] {"*.example.com"}, new String[] {"vhost.example.com", ".example.com"}); checkWildcardHost(false,server,new String[] {"*.example.com"}, new String[] {"vhost.www.example.com", "example.com", "www.vhost.example.com"}); checkWildcardHost(true,server,new String[] {"*.sub.example.com"}, new String[] {"vhost.sub.example.com", ".sub.example.com"}); checkWildcardHost(false,server,new String[] {"*.sub.example.com"}, new String[] {".example.com", "sub.example.com", "vhost.example.com"}); - - checkWildcardHost(false,server,new String[] {"example.*.com","example.com.*"}, new String[] {"example.vhost.com", "example.com.vhost", "example.com"}); + + checkWildcardHost(false,server,new String[] {"example.*.com","example.com.*"}, new String[] {"example.vhost.com", "example.com.vhost", "example.com"}); } finally { @@ -137,11 +139,11 @@ public class ContextHandlerCollectionTest extends TestCase context.setVirtualHosts(contextHosts); // trigger this manually; it's supposed to be called when adding the handler handlerCollection.mapContexts(); - + for(String host : requestHosts) { connector.getResponses("GET / HTTP/1.1\n" + "Host: "+host+"\n\n"); - if(succeed) + if(succeed) assertTrue("'"+host+"' should have been handled.",handler.isHandled()); else assertFalse("'"+host + "' should not have been handled.", handler.isHandled()); @@ -149,8 +151,8 @@ public class ContextHandlerCollectionTest extends TestCase } } - - public static final class IsHandledHandler extends AbstractHandler + + private static final class IsHandledHandler extends AbstractHandler { private boolean handled; @@ -170,5 +172,4 @@ public class ContextHandlerCollectionTest extends TestCase handled = false; } } - } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java index 180b7fe280..8e141d64b2 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java @@ -5,86 +5,56 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.server.handler; import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; +import junit.framework.Assert; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.resource.Resource; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** * @version $Revision$ */ -public class ContextHandlerTest extends TestCase +public class ContextHandlerTest { + @Test public void testGetResourcePathsWhenSuppliedPathEndsInSlash() throws Exception { checkResourcePathsForExampleWebApp("/WEB-INF/"); } + @Test public void testGetResourcePathsWhenSuppliedPathDoesNotEndInSlash() throws Exception { checkResourcePathsForExampleWebApp("/WEB-INF"); } - private void checkResourcePathsForExampleWebApp(String root) throws IOException, MalformedURLException - { - File testDirectory = setupTestDirectory(); - - ContextHandler handler = new ContextHandler(); - - assertTrue("Not a directory " + testDirectory,testDirectory.isDirectory()); - handler.setBaseResource(Resource.newResource(testDirectory.toURL())); - - List paths = new ArrayList(handler.getResourcePaths(root)); - assertEquals(2,paths.size()); - - Collections.sort(paths); - assertEquals("/WEB-INF/jsp/",paths.get(0)); - assertEquals("/WEB-INF/web.xml",paths.get(1)); - } - - private File setupTestDirectory() throws IOException - { - File tmpDir = new File( System.getProperty( "basedir" ) + "/target/tmp/ContextHandlerTest" ); - tmpDir.mkdirs(); - File tmp = File.createTempFile("cht",null, tmpDir ); - tmp.delete(); - tmp.mkdir(); - tmp.deleteOnExit(); - File root = new File(tmp,getClass().getName()); - root.mkdir(); - - File webInf = new File(root,"WEB-INF"); - webInf.mkdir(); - - new File(webInf,"jsp").mkdir(); - new File(webInf,"web.xml").createNewFile(); - - return root; - } - + @Test public void testVirtualHostNormalization() throws Exception { Server server = new Server(); @@ -142,7 +112,8 @@ public class ContextHandlerTest extends TestCase } } - + + @Test public void testVirtualHostWildcard() throws Exception { Server server = new Server(); @@ -150,7 +121,7 @@ public class ContextHandlerTest extends TestCase server.setConnectors(new Connector[] { connector }); ContextHandler context = new ContextHandler("/"); - + IsHandledHandler handler = new IsHandledHandler(); context.setHandler(handler); @@ -161,19 +132,118 @@ public class ContextHandlerTest extends TestCase server.start(); checkWildcardHost(true,server,null,new String[] {"example.com", ".example.com", "vhost.example.com"}); checkWildcardHost(false,server,new String[] {null},new String[] {"example.com", ".example.com", "vhost.example.com"}); - + checkWildcardHost(true,server,new String[] {"example.com", "*.example.com"}, new String[] {"example.com", ".example.com", "vhost.example.com"}); checkWildcardHost(false,server,new String[] {"example.com", "*.example.com"}, new String[] {"badexample.com", ".badexample.com", "vhost.badexample.com"}); - + checkWildcardHost(false,server,new String[] {"*."}, new String[] {"anything.anything"}); - + checkWildcardHost(true,server,new String[] {"*.example.com"}, new String[] {"vhost.example.com", ".example.com"}); checkWildcardHost(false,server,new String[] {"*.example.com"}, new String[] {"vhost.www.example.com", "example.com", "www.vhost.example.com"}); checkWildcardHost(true,server,new String[] {"*.sub.example.com"}, new String[] {"vhost.sub.example.com", ".sub.example.com"}); checkWildcardHost(false,server,new String[] {"*.sub.example.com"}, new String[] {".example.com", "sub.example.com", "vhost.example.com"}); + + checkWildcardHost(false,server,new String[] {"example.*.com","example.com.*"}, new String[] {"example.vhost.com", "example.com.vhost", "example.com"}); + } + finally + { + server.stop(); + } + } + + @Test + public void testAttributes() throws Exception + { + ContextHandler handler = new ContextHandler(); + handler.setAttribute("aaa","111"); + handler.getServletContext().setAttribute("bbb","222"); + assertEquals("111",handler.getServletContext().getAttribute("aaa")); + assertEquals(null,handler.getAttribute("bbb")); + + handler.start(); + + handler.getServletContext().setAttribute("aaa","000"); + handler.setAttribute("ccc","333"); + handler.getServletContext().setAttribute("ddd","444"); + assertEquals("111",handler.getServletContext().getAttribute("aaa")); + assertEquals(null,handler.getServletContext().getAttribute("bbb")); + handler.getServletContext().setAttribute("bbb","222"); + assertEquals("333",handler.getServletContext().getAttribute("ccc")); + assertEquals("444",handler.getServletContext().getAttribute("ddd")); + + assertEquals("111",handler.getAttribute("aaa")); + assertEquals(null,handler.getAttribute("bbb")); + assertEquals("333",handler.getAttribute("ccc")); + assertEquals(null,handler.getAttribute("ddd")); + + handler.stop(); + + assertEquals("111",handler.getServletContext().getAttribute("aaa")); + assertEquals(null,handler.getServletContext().getAttribute("bbb")); + assertEquals("333",handler.getServletContext().getAttribute("ccc")); + assertEquals(null,handler.getServletContext().getAttribute("ddd")); + } + + private void checkResourcePathsForExampleWebApp(String root) throws IOException + { + File testDirectory = setupTestDirectory(); + + ContextHandler handler = new ContextHandler(); + + assertTrue("Not a directory " + testDirectory,testDirectory.isDirectory()); + handler.setBaseResource(Resource.newResource(testDirectory.toURI().toURL())); + + List<String> paths = new ArrayList<String>(handler.getResourcePaths(root)); + assertEquals(2,paths.size()); + + Collections.sort(paths); + assertEquals("/WEB-INF/jsp/",paths.get(0)); + assertEquals("/WEB-INF/web.xml",paths.get(1)); + } + + private File setupTestDirectory() throws IOException + { + File tmpDir = new File( System.getProperty( "basedir" ) + "/target/tmp/ContextHandlerTest" ); + if (!tmpDir.exists()) + assertTrue(tmpDir.mkdirs()); + File tmp = File.createTempFile("cht",null, tmpDir ); + assertTrue(tmp.delete()); + assertTrue(tmp.mkdir()); + tmp.deleteOnExit(); + File root = new File(tmp,getClass().getName()); + assertTrue(root.mkdir()); + + File webInf = new File(root,"WEB-INF"); + assertTrue(webInf.mkdir()); + + assertTrue(new File(webInf,"jsp").mkdir()); + assertTrue(new File(webInf,"web.xml").createNewFile()); + + return root; + } + + @Test + public void testUncheckedPrintWriter() throws Exception + { + Server server = new Server(); + LocalConnector connector = new LocalConnector(); + server.setConnectors(new Connector[] { connector }); + ContextHandler context = new ContextHandler("/"); + WriterHandler handler = new WriterHandler(); + context.setHandler(handler); + server.setHandler(context); + + try + { + server.start(); - checkWildcardHost(false,server,new String[] {"example.*.com","example.com.*"}, new String[] {"example.vhost.com", "example.com.vhost", "example.com"}); + String response = connector.getResponses("GET / HTTP/1.1\n" + "Host: www.example.com.\n\n"); + + Assert.assertTrue(response.indexOf("Goodbye")>0); + Assert.assertTrue(response.indexOf("dead")<0); + Assert.assertTrue(handler.error); + Assert.assertTrue(handler.throwable!=null); } finally { @@ -186,12 +256,12 @@ public class ContextHandlerTest extends TestCase LocalConnector connector = (LocalConnector)server.getConnectors()[0]; ContextHandler context = (ContextHandler)server.getHandler(); context.setVirtualHosts(contextHosts); - + IsHandledHandler handler = (IsHandledHandler)context.getHandler(); for(String host : requestHosts) { connector.getResponses("GET / HTTP/1.1\n" + "Host: "+host+"\n\n"); - if(succeed) + if(succeed) assertTrue("'"+host+"' should have been handled.",handler.isHandled()); else assertFalse("'"+host + "' should not have been handled.", handler.isHandled()); @@ -199,8 +269,8 @@ public class ContextHandlerTest extends TestCase } } - - public static final class IsHandledHandler extends AbstractHandler + + private static final class IsHandledHandler extends AbstractHandler { private boolean handled; @@ -220,38 +290,35 @@ public class ContextHandlerTest extends TestCase handled = false; } } - - public void testAttributes() throws Exception + + private static final class WriterHandler extends AbstractHandler { - ContextHandler handler = new ContextHandler(); - handler.setAttribute("aaa","111"); - handler.getServletContext().setAttribute("bbb","222"); - assertEquals("111",handler.getServletContext().getAttribute("aaa")); - assertEquals("222",handler.getAttribute("bbb")); - - handler.start(); + boolean error; + Throwable throwable; - handler.getServletContext().setAttribute("aaa","000"); - handler.setAttribute("ccc","333"); - handler.getServletContext().setAttribute("ddd","444"); - assertEquals("111",handler.getServletContext().getAttribute("aaa")); - assertEquals("222",handler.getServletContext().getAttribute("bbb")); - assertEquals("333",handler.getServletContext().getAttribute("ccc")); - assertEquals("444",handler.getServletContext().getAttribute("ddd")); - - assertEquals("111",handler.getAttribute("aaa")); - assertEquals("222",handler.getAttribute("bbb")); - assertEquals("333",handler.getAttribute("ccc")); - assertEquals(null,handler.getAttribute("ddd")); - - - handler.stop(); - - assertEquals("111",handler.getServletContext().getAttribute("aaa")); - assertEquals("222",handler.getServletContext().getAttribute("bbb")); - assertEquals("333",handler.getServletContext().getAttribute("ccc")); - assertEquals(null,handler.getServletContext().getAttribute("ddd")); - + public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + error = false; + throwable=null; + + response.setStatus(200); + response.setContentType("text/plain; charset=utf-8"); + response.setHeader("Connection","close"); + PrintWriter writer = response.getWriter(); + try + { + writer.write("Goodbye cruel world\n"); + writer.close(); + response.flushBuffer(); + writer.write("speaking from the dead"); + } + catch(Throwable th) + { + throwable=th; + } + error=writer.checkError(); + } } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java new file mode 100644 index 0000000000..6ac5e7969f --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java @@ -0,0 +1,395 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.server.handler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.bio.SocketConnector; +import org.eclipse.jetty.util.log.Log; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class IPAccessHandlerTest +{ + private static Server _server; + private static Connector _connector; + private static IPAccessHandler _handler; + + private String _white; + private String _black; + private String _host; + private String _uri; + private String _code; + + @BeforeClass + public static void setUp() + throws Exception + { + _server = new Server(); + _connector = new SocketConnector(); + _server.setConnectors(new Connector[] { _connector }); + + _handler = new IPAccessHandler(); + _handler.setHandler(new AbstractHandler() + { + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + response.setStatus(HttpStatus.OK_200); + } + }); + _server.setHandler(_handler); + _server.start(); + } + + /* ------------------------------------------------------------ */ + @AfterClass + public static void tearDown() + throws Exception + { + _server.stop(); + } + + /* ------------------------------------------------------------ */ + public IPAccessHandlerTest(String white, String black, String host, String uri, String code) + { + _white = white; + _black = black; + _host = host; + _uri = uri; + _code = code; + } + + /* ------------------------------------------------------------ */ + @Test + public void testHandler() + throws Exception + { + _handler.setWhite(_white.split(";",-1)); + _handler.setBlack(_black.split(";",-1)); + + String request = "GET " + _uri + " HTTP/1.1\n" + "Host: "+ _host + "\n\n"; + Socket socket = new Socket("localhost", _connector.getLocalPort()); + socket.setSoTimeout(5000); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + Response response = readResponse(input); + assertEquals(_code, response.getCode()); + } + finally + { + socket.close(); + } + } + + /* ------------------------------------------------------------ */ + protected Response readResponse(BufferedReader reader) + throws IOException + { + // Simplified parser for HTTP responses + String line = reader.readLine(); + if (line == null) + throw new EOFException(); + Matcher responseLine = Pattern.compile("HTTP/1\\.1\\s+(\\d+)").matcher(line); + assertTrue(responseLine.lookingAt()); + String code = responseLine.group(1); + + Map<String, String> headers = new LinkedHashMap<String, String>(); + while ((line = reader.readLine()) != null) + { + if (line.trim().length() == 0) + break; + + Matcher header = Pattern.compile("([^:]+):\\s*(.*)").matcher(line); + assertTrue(header.lookingAt()); + String headerName = header.group(1); + String headerValue = header.group(2); + headers.put(headerName.toLowerCase(), headerValue.toLowerCase()); + } + + StringBuilder body = new StringBuilder(); + if (headers.containsKey("content-length")) + { + int length = Integer.parseInt(headers.get("content-length")); + for (int i = 0; i < length; ++i) + { + char c = (char)reader.read(); + body.append(c); + } + } + else if ("chunked".equals(headers.get("transfer-encoding"))) + { + while ((line = reader.readLine()) != null) + { + if ("0".equals(line)) + { + line = reader.readLine(); + assertEquals("", line); + break; + } + + int length = Integer.parseInt(line, 16); + for (int i = 0; i < length; ++i) + { + char c = (char)reader.read(); + body.append(c); + } + line = reader.readLine(); + assertEquals("", line); + } + } + + return new Response(code, headers, body.toString().trim()); + } + + /* ------------------------------------------------------------ */ + protected class Response + { + private final String code; + private final Map<String, String> headers; + private final String body; + + /* ------------------------------------------------------------ */ + private Response(String code, Map<String, String> headers, String body) + { + this.code = code; + this.headers = headers; + this.body = body; + } + + /* ------------------------------------------------------------ */ + public String getCode() + { + return code; + } + + /* ------------------------------------------------------------ */ + public Map<String, String> getHeaders() + { + return headers; + } + + /* ------------------------------------------------------------ */ + public String getBody() + { + return body; + } + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + builder.append(code).append("\r\n"); + for (Map.Entry<String, String> entry : headers.entrySet()) + builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n"); + builder.append("\r\n"); + builder.append(body); + return builder.toString(); + } + } + + /* ------------------------------------------------------------ */ + @Parameters + public static Collection<Object[]> data() { + Object[][] data = new Object[][] { + // Empty lists + {"", "", "127.0.0.1", "/", "200"}, + {"", "", "127.0.0.1", "/dump/info", "200"}, + + // White list + {"127.0.0.1", "", "127.0.0.1", "/", "200"}, + {"127.0.0.1", "", "127.0.0.1", "/dispatch", "200"}, + {"127.0.0.1", "", "127.0.0.1", "/dump/info", "200"}, + + {"127.0.0.1|/", "", "127.0.0.1", "/", "200"}, + {"127.0.0.1|/", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/", "", "127.0.0.1", "/dump/info", "403"}, + + {"127.0.0.1|/*", "", "127.0.0.1", "/", "200"}, + {"127.0.0.1|/*", "", "127.0.0.1", "/dispatch", "200"}, + {"127.0.0.1|/*", "", "127.0.0.1", "/dump/info", "200"}, + + {"127.0.0.1|/dump/*", "", "127.0.0.1", "/", "403"}, + {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dump/test", "200"}, + + {"127.0.0.1|/dump/info", "", "127.0.0.1", "/", "403"}, + {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dump/test", "403"}, + + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/", "403"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/test", "200"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.0-2|", "", "127.0.0.1", "/", "200"}, + {"127.0.0.0-2|", "", "127.0.0.1", "/dump/info", "200"}, + + {"127.0.0.0-2|/", "", "127.0.0.1", "/", "200"}, + {"127.0.0.0-2|/", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.0-2|/", "", "127.0.0.1", "/dump/info", "403"}, + + {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/", "403"}, + {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/dump/info", "200"}, + + {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/", "403"}, + {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dump/test", "403"}, + + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/", "403"}, + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/test", "200"}, + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/fail", "403"}, + + // Black list + {"", "127.0.0.1", "127.0.0.1", "/", "403"}, + {"", "127.0.0.1", "127.0.0.1", "/dispatch", "403"}, + {"", "127.0.0.1", "127.0.0.1", "/dump/info", "403"}, + + {"", "127.0.0.1|/", "127.0.0.1", "/", "403"}, + {"", "127.0.0.1|/", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.1|/", "127.0.0.1", "/dump/info", "200"}, + + {"", "127.0.0.1|/*", "127.0.0.1", "/", "403"}, + {"", "127.0.0.1|/*", "127.0.0.1", "/dispatch", "403"}, + {"", "127.0.0.1|/*", "127.0.0.1", "/dump/info", "403"}, + + {"", "127.0.0.1|/dump/*", "127.0.0.1", "/", "200"}, + {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dump/test", "403"}, + + {"", "127.0.0.1|/dump/info", "127.0.0.1", "/", "200"}, + {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dump/test", "200"}, + + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/", "200"}, + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/test", "403"}, + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/fail", "200"}, + + {"", "127.0.0.0-2|", "127.0.0.1", "/", "403"}, + {"", "127.0.0.0-2|", "127.0.0.1", "/dump/info", "403"}, + + {"", "127.0.0.0-2|/", "127.0.0.1", "/", "403"}, + {"", "127.0.0.0-2|/", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.0-2|/", "127.0.0.1", "/dump/info", "200"}, + + {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/", "200"}, + {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/dump/info", "403"}, + + {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/", "200"}, + {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dump/test", "200"}, + + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/", "200"}, + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/test", "403"}, + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/fail", "200"}, + + // Both lists + {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"}, + {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "403"}, + {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/test", "403"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump", "403"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/test", "403"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.1|/;127.0.0.0-2|/dump/*", "127.0.0.0,1|/dump/fail", "127.0.0.1", "/", "200"}, + {"127.0.0.1|/;127.0.0.0-2|/dump/*", "127.0.0.0,1|/dump/fail", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/;127.0.0.0-2|/dump/*", "127.0.0.0,1|/dump/fail", "127.0.0.1", "/dump/fail", "403"}, + + // Different address + {"127.0.0.2", "", "127.0.0.1", "/", "403"}, + {"127.0.0.2", "", "127.0.0.1", "/dump/info", "403"}, + + {"127.0.0.2|/dump/*", "", "127.0.0.1", "/", "403"}, + {"127.0.0.2|/dump/*", "", "127.0.0.1", "/dump/info", "403"}, + + {"127.0.0.2|/dump/info", "", "127.0.0.1", "/", "403"}, + {"127.0.0.2|/dump/info", "", "127.0.0.1", "/dump/info", "403"}, + {"127.0.0.2|/dump/info", "", "127.0.0.1", "/dump/test", "403"}, + + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/", "403"}, + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/test", "403"}, + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/fail", "403"}, + + {"172.0.0.0-255", "", "127.0.0.1", "/", "403"}, + {"172.0.0.0-255", "", "127.0.0.1", "/dump/info", "403"}, + + {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/", "403"}, + {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/dispatch", "403"}, + {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/dump/info", "200"}, + }; + return Arrays.asList(data); + }; +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ProxyHandlerConnectSSLTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ProxyHandlerConnectSSLTest.java new file mode 100644 index 0000000000..433ef64244 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ProxyHandlerConnectSSLTest.java @@ -0,0 +1,221 @@ +package org.eclipse.jetty.server.handler; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +/** + * @version $Revision$ $Date$ + */ +public class ProxyHandlerConnectSSLTest extends AbstractProxyHandlerTest +{ + @BeforeClass + public static void init() throws Exception + { + SslSelectChannelConnector connector = new SslSelectChannelConnector(); + + String keyStorePath = System.getProperty("basedir"); + keyStorePath += File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator + "keystore"; + connector.setKeystore(keyStorePath); + connector.setPassword("storepwd"); + connector.setKeyPassword("keypwd"); + + startServer(connector, new ServerHandler()); + startProxy(); + } + + @Test + public void testGETRequest() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + // Be sure the buffered input does not have anything buffered + assertFalse(input.ready()); + + // Upgrade the socket to SSL + SSLSocket sslSocket = wrapSocket(socket); + try + { + output = sslSocket.getOutputStream(); + input = new BufferedReader(new InputStreamReader(sslSocket.getInputStream())); + + request = "" + + "GET /echo HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("GET /echo", response.getBody()); + } + finally + { + sslSocket.close(); + } + } + finally + { + socket.close(); + } + } + + @Test + public void testPOSTRequests() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + // Be sure the buffered input does not have anything buffered + assertFalse(input.ready()); + + // Upgrade the socket to SSL + SSLSocket sslSocket = wrapSocket(socket); + try + { + output = sslSocket.getOutputStream(); + input = new BufferedReader(new InputStreamReader(sslSocket.getInputStream())); + + for (int i = 0; i < 10; ++i) + { + request = "" + + "POST /echo?param=" + i + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "HELLO"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("POST /echo?param=" + i + "\r\nHELLO", response.getBody()); + } + } + finally + { + sslSocket.close(); + } + } + finally + { + socket.close(); + } + } + + private SSLSocket wrapSocket(Socket socket) throws Exception + { + SSLContext sslContext = SSLContext.getInstance("SSLv3"); + sslContext.init(null, new TrustManager[]{new AlwaysTrustManager()}, new SecureRandom()); + SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket sslSocket = (SSLSocket)socketFactory.createSocket(socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true); + sslSocket.setUseClientMode(true); + sslSocket.startHandshake(); + return sslSocket; + } + + private class AlwaysTrustManager implements X509TrustManager + { + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException + { + } + + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException + { + } + + public X509Certificate[] getAcceptedIssuers() + { + return null; + } + } + + private static class ServerHandler extends AbstractHandler + { + public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException + { + request.setHandled(true); + + String uri = httpRequest.getRequestURI(); + if ("/echo".equals(uri)) + { + StringBuilder builder = new StringBuilder(); + builder.append(httpRequest.getMethod()).append(" ").append(uri); + if (httpRequest.getQueryString() != null) + builder.append("?").append(httpRequest.getQueryString()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream input = httpRequest.getInputStream(); + int read = -1; + while ((read = input.read()) >= 0) + baos.write(read); + baos.close(); + + ServletOutputStream output = httpResponse.getOutputStream(); + output.println(builder.toString()); + output.write(baos.toByteArray()); + } + else + { + throw new ServletException(); + } + } + } +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ProxyHandlerConnectTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ProxyHandlerConnectTest.java new file mode 100644 index 0000000000..9bc2fa21ac --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ProxyHandlerConnectTest.java @@ -0,0 +1,517 @@ +package org.eclipse.jetty.server.handler; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.nio.channels.SocketChannel; +import java.util.concurrent.ConcurrentMap; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @version $Revision$ $Date$ + */ +public class ProxyHandlerConnectTest extends AbstractProxyHandlerTest +{ + @BeforeClass + public static void init() throws Exception + { + startServer(new SelectChannelConnector(), new ServerHandler()); + startProxy(); + } + + @Test + public void testCONNECT() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + } + finally + { + socket.close(); + } + } + + @Test + public void testCONNECTAndGET() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + request = "" + + "GET /echo" + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("GET /echo", response.getBody()); + } + finally + { + socket.close(); + } + } + + @Test + public void testCONNECT10AndGET() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.0\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + request = "" + + "GET /echo" + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("GET /echo", response.getBody()); + } + finally + { + socket.close(); + } + } + + @Test + public void testCONNECTAndGETPipelined() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n" + + "GET /echo" + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + // The pipelined request must have gone up to the server as is + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("GET /echo", response.getBody()); + } + finally + { + socket.close(); + } + } + + @Test + public void testCONNECTAndMultipleGETs() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + for (int i = 0; i < 10; ++i) + { + request = "" + + "GET /echo" + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("GET /echo", response.getBody()); + } + } + finally + { + socket.close(); + } + } + + @Test + public void testCONNECTAndGETServerStop() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + request = "" + + "GET /echo HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("GET /echo", response.getBody()); + + // Idle server is shut down + stopServer(); + + int read = input.read(); + assertEquals(-1, read); + } + finally + { + socket.close(); + // Restart the server for the next test + server.start(); + } + } + + @Test + public void testCONNECTAndGETAndServerSideClose() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + request = "" + + "GET /close HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + int read = input.read(); + assertEquals(-1, read); + } + finally + { + socket.close(); + } + } + + @Test + public void testCONNECTAndPOSTAndGET() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + request = "" + + "POST /echo HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "Content-Length: 5\r\n" + + "\r\n" + + "HELLO"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("POST /echo\r\nHELLO", response.getBody()); + + request = "" + + "GET /echo" + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("GET /echo", response.getBody()); + } + finally + { + socket.close(); + } + } + + @Test + public void testCONNECTAndPOSTWithBigBody() throws Exception + { + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + StringBuilder body = new StringBuilder(); + String chunk = "0123456789ABCDEF"; + for (int i = 0; i < 1024; ++i) + body.append(chunk); + + request = "" + + "POST /echo HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "Content-Length: " + body.length() + "\r\n" + + "\r\n" + + body; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("POST /echo\r\n" + body, response.getBody()); + } + finally + { + socket.close(); + } + } + + @Test + public void testCONNECTAndPOSTWithContext() throws Exception + { + final String contextKey = "contextKey"; + final String contextValue = "contextValue"; + + // Replace the default ProxyHandler with a subclass to test context information passing + stopProxy(); + proxy.setHandler(new ProxyHandler() + { + @Override + protected boolean handleAuthentication(HttpServletRequest request, HttpServletResponse response, String address) throws ServletException, IOException + { + request.setAttribute(contextKey, contextValue); + return super.handleAuthentication(request, response, address); + } + + @Override + protected SocketChannel connect(HttpServletRequest request, String host, int port) throws IOException + { + assertEquals(contextValue, request.getAttribute(contextKey)); + return super.connect(request, host, port); + } + + @Override + protected void prepareContext(HttpServletRequest request, ConcurrentMap<String, Object> context) + { + // Transfer data from the HTTP request to the connection context + assertEquals(contextValue, request.getAttribute(contextKey)); + context.put(contextKey, request.getAttribute(contextKey)); + } + + @Override + protected int read(EndPoint endPoint, Buffer buffer, ConcurrentMap<String, Object> context) throws IOException + { + assertEquals(contextValue, context.get(contextKey)); + return super.read(endPoint, buffer, context); + } + + @Override + protected int write(EndPoint endPoint, Buffer buffer, ConcurrentMap<String, Object> context) throws IOException + { + assertEquals(contextValue, context.get(contextKey)); + return super.write(endPoint, buffer, context); + } + }); + proxy.start(); + + String hostPort = "localhost:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + Socket socket = newSocket(); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + // Expect 200 OK from the CONNECT request + Response response = readResponse(input); + assertEquals("200", response.getCode()); + + String body = "0123456789ABCDEF"; + request = "" + + "POST /echo HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "Content-Length: " + body.length() + "\r\n" + + "\r\n" + + body; + output.write(request.getBytes("UTF-8")); + output.flush(); + + response = readResponse(input); + assertEquals("200", response.getCode()); + assertEquals("POST /echo\r\n" + body, response.getBody()); + } + finally + { + socket.close(); + } + } + + private static class ServerHandler extends AbstractHandler + { + public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException + { + request.setHandled(true); + + String uri = httpRequest.getRequestURI(); + if ("/echo".equals(uri)) + { + StringBuilder builder = new StringBuilder(); + builder.append(httpRequest.getMethod()).append(" ").append(uri); + if (httpRequest.getQueryString() != null) + builder.append("?").append(httpRequest.getQueryString()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream input = httpRequest.getInputStream(); + int read = -1; + while ((read = input.read()) >= 0) + baos.write(read); + baos.close(); + + ServletOutputStream output = httpResponse.getOutputStream(); + output.println(builder.toString()); + output.write(baos.toByteArray()); + } + else if ("/close".equals(uri)) + { + request.getConnection().getEndPoint().close(); + } + else + { + throw new ServletException(); + } + } + } +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ScopedHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ScopedHandlerTest.java index 13312809f4..5956b54b48 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ScopedHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ScopedHandlerTest.java @@ -1,23 +1,29 @@ package org.eclipse.jetty.server.handler; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.Request; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; -public class ScopedHandlerTest extends TestCase +public class ScopedHandlerTest { - StringBuilder _history=new StringBuilder(); + private StringBuilder _history=new StringBuilder(); - public void testSingle() - throws Exception + @Before + public void resetHistory() { _history.setLength(0); + } + + @Test + public void testSingle() throws Exception + { TestHandler handler0 = new TestHandler("0"); handler0.start(); handler0.handle("target",null,null,null); @@ -27,10 +33,9 @@ public class ScopedHandlerTest extends TestCase assertEquals(">S0>W0<W0<S0",history); } - public void testSimpleDouble() - throws Exception + @Test + public void testSimpleDouble() throws Exception { - _history.setLength(0); TestHandler handler0 = new TestHandler("0"); TestHandler handler1 = new TestHandler("1"); handler0.setHandler(handler1); @@ -42,10 +47,9 @@ public class ScopedHandlerTest extends TestCase assertEquals(">S0>S1>W0>W1<W1<W0<S1<S0",history); } - public void testSimpleTriple() - throws Exception + @Test + public void testSimpleTriple() throws Exception { - _history.setLength(0); TestHandler handler0 = new TestHandler("0"); TestHandler handler1 = new TestHandler("1"); TestHandler handler2 = new TestHandler("2"); @@ -59,10 +63,9 @@ public class ScopedHandlerTest extends TestCase assertEquals(">S0>S1>S2>W0>W1>W2<W2<W1<W0<S2<S1<S0",history); } - public void testDouble() - throws Exception + @Test + public void testDouble() throws Exception { - _history.setLength(0); TestHandler handler0 = new TestHandler("0"); OtherHandler handlerA = new OtherHandler("A"); TestHandler handler1 = new TestHandler("1"); @@ -78,10 +81,9 @@ public class ScopedHandlerTest extends TestCase assertEquals(">S0>S1>W0>HA>W1>HB<HB<W1<HA<W0<S1<S0",history); } - public void testTriple() - throws Exception + @Test + public void testTriple() throws Exception { - _history.setLength(0); TestHandler handler0 = new TestHandler("0"); OtherHandler handlerA = new OtherHandler("A"); TestHandler handler1 = new TestHandler("1"); @@ -100,15 +102,16 @@ public class ScopedHandlerTest extends TestCase System.err.println(history); assertEquals(">S0>S1>S2>W0>HA>W1>HB>W2>HC<HC<W2<HB<W1<HA<W0<S2<S1<S0",history); } - + private class TestHandler extends ScopedHandler { - String _name; - TestHandler(String name) + private final String _name; + + private TestHandler(String name) { _name=name; } - + @Override public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { @@ -122,7 +125,7 @@ public class ScopedHandlerTest extends TestCase _history.append("<S").append(_name); } } - + @Override public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { @@ -138,16 +141,16 @@ public class ScopedHandlerTest extends TestCase } } - + private class OtherHandler extends HandlerWrapper { - String _name; - - OtherHandler(String name) + private final String _name; + + private OtherHandler(String name) { _name=name; } - + @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java index bf29e8657d..b4877e071e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java @@ -18,29 +18,34 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationSupport; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -public class StatisticsHandlerTest extends TestCase +public class StatisticsHandlerTest { private Server _server; private LocalConnector _connector; private LatchHandler _latchHandler; private StatisticsHandler _statsHandler; - @Override - protected void setUp() throws Exception + @Before + public void init() throws Exception { _server = new Server(); @@ -55,17 +60,18 @@ public class StatisticsHandlerTest extends TestCase _latchHandler.setHandler(_statsHandler); } - @Override - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { _server.stop(); _server.join(); } + @Test public void testRequest() throws Exception { final CyclicBarrier barrier[] = { new CyclicBarrier(2), new CyclicBarrier(2)}; - + _statsHandler.setHandler(new AbstractHandler() { public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException @@ -75,7 +81,7 @@ public class StatisticsHandlerTest extends TestCase { barrier[0].await(); barrier[1].await(); - + } catch (Exception x) { @@ -94,11 +100,11 @@ public class StatisticsHandlerTest extends TestCase barrier[0].await(); assertEquals(1, _connector.getConnectionsOpen()); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getRequestsActiveMax()); - + assertEquals(1, _statsHandler.getDispatched()); assertEquals(1, _statsHandler.getDispatchedActive()); assertEquals(1, _statsHandler.getDispatchedActiveMax()); @@ -107,11 +113,11 @@ public class StatisticsHandlerTest extends TestCase barrier[1].await(); boolean passed = _latchHandler.await(1000); assertTrue(passed); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(0, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getRequestsActiveMax()); - + assertEquals(1, _statsHandler.getDispatched()); assertEquals(0, _statsHandler.getDispatchedActive()); assertEquals(1, _statsHandler.getDispatchedActiveMax()); @@ -120,21 +126,21 @@ public class StatisticsHandlerTest extends TestCase assertEquals(0, _statsHandler.getResumes()); assertEquals(0, _statsHandler.getExpires()); assertEquals(1, _statsHandler.getResponses2xx()); - + _latchHandler.reset(); barrier[0].reset(); barrier[1].reset(); - + _connector.executeRequest(request); barrier[0].await(); - + assertEquals(2, _connector.getConnectionsOpen()); - + assertEquals(2, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getRequestsActiveMax()); - + assertEquals(2, _statsHandler.getDispatched()); assertEquals(1, _statsHandler.getDispatchedActive()); assertEquals(1, _statsHandler.getDispatchedActiveMax()); @@ -143,11 +149,11 @@ public class StatisticsHandlerTest extends TestCase barrier[1].await(); passed = _latchHandler.await(1000); assertTrue(passed); - + assertEquals(2, _statsHandler.getRequests()); assertEquals(0, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getRequestsActiveMax()); - + assertEquals(2, _statsHandler.getDispatched()); assertEquals(0, _statsHandler.getDispatchedActive()); assertEquals(1, _statsHandler.getDispatchedActiveMax()); @@ -160,18 +166,18 @@ public class StatisticsHandlerTest extends TestCase _latchHandler.reset(2); barrier[0]=new CyclicBarrier(3); barrier[1]=new CyclicBarrier(3); - + _connector.executeRequest(request); _connector.executeRequest(request); barrier[0].await(); - + assertEquals(4, _connector.getConnectionsOpen()); - + assertEquals(4, _statsHandler.getRequests()); assertEquals(2, _statsHandler.getRequestsActive()); assertEquals(2, _statsHandler.getRequestsActiveMax()); - + assertEquals(4, _statsHandler.getDispatched()); assertEquals(2, _statsHandler.getDispatchedActive()); assertEquals(2, _statsHandler.getDispatchedActiveMax()); @@ -180,11 +186,11 @@ public class StatisticsHandlerTest extends TestCase barrier[1].await(); passed = _latchHandler.await(1000); assertTrue(passed); - + assertEquals(4, _statsHandler.getRequests()); assertEquals(0, _statsHandler.getRequestsActive()); assertEquals(2, _statsHandler.getRequestsActiveMax()); - + assertEquals(4, _statsHandler.getDispatched()); assertEquals(0, _statsHandler.getDispatchedActive()); assertEquals(2, _statsHandler.getDispatchedActiveMax()); @@ -193,10 +199,11 @@ public class StatisticsHandlerTest extends TestCase assertEquals(0, _statsHandler.getResumes()); assertEquals(0, _statsHandler.getExpires()); assertEquals(4, _statsHandler.getResponses2xx()); - - + + } + @Test public void testSuspendResume() throws Exception { final AtomicReference<Continuation> continuationHandle = new AtomicReference<Continuation>(); @@ -217,7 +224,7 @@ public class StatisticsHandlerTest extends TestCase continuation.suspend(); continuationHandle.set(continuation); } - + } catch (Exception x) { @@ -232,8 +239,9 @@ public class StatisticsHandlerTest extends TestCase } catch (Exception x) { + x.printStackTrace(); Thread.currentThread().interrupt(); - throw (IOException)new IOException().initCause(x); + fail(); } } @@ -245,12 +253,12 @@ public class StatisticsHandlerTest extends TestCase "Host: localhost\r\n" + "\r\n"; _connector.executeRequest(request); - + barrier[0].await(); - + assertEquals(1, _connector.getConnectionsOpen()); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); @@ -260,7 +268,7 @@ public class StatisticsHandlerTest extends TestCase assertTrue(_latchHandler.await(1000)); assertNotNull(continuationHandle.get()); assertTrue(continuationHandle.get().isSuspended()); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); @@ -270,24 +278,24 @@ public class StatisticsHandlerTest extends TestCase _latchHandler.reset(); barrier[0].reset(); barrier[1].reset(); - + continuationHandle.get().addContinuationListener(new ContinuationListener() { public void onTimeout(Continuation continuation) { } - + public void onComplete(Continuation continuation) { try { barrier[2].await(); } catch(Exception e) {} } }); - + continuationHandle.get().resume(); - + barrier[0].await(); - + assertEquals(1, _connector.getConnectionsOpen()); assertEquals(1, _statsHandler.getRequests()); @@ -298,29 +306,30 @@ public class StatisticsHandlerTest extends TestCase barrier[1].await(); assertTrue(_latchHandler.await(1000)); barrier[2].await(); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(0, _statsHandler.getRequestsActive()); assertEquals(2, _statsHandler.getDispatched()); assertEquals(0, _statsHandler.getDispatchedActive()); - - + + assertEquals(1, _statsHandler.getSuspends()); assertEquals(1, _statsHandler.getResumes()); assertEquals(0, _statsHandler.getExpires()); assertEquals(1, _statsHandler.getResponses2xx()); - - + + assertTrue(_statsHandler.getRequestTimeTotal()>=30); assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax()); - assertEquals(_statsHandler.getRequestTimeTotal()*1.0,_statsHandler.getRequestTimeMean()); - + assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01); + assertTrue(_statsHandler.getDispatchedTimeTotal()>=20); assertTrue(_statsHandler.getDispatchedTimeMean()+10<=_statsHandler.getDispatchedTimeTotal()); assertTrue(_statsHandler.getDispatchedTimeMax()+10<=_statsHandler.getDispatchedTimeTotal()); - + } + @Test public void testSuspendExpire() throws Exception { final AtomicReference<Continuation> continuationHandle = new AtomicReference<Continuation>(); @@ -342,7 +351,7 @@ public class StatisticsHandlerTest extends TestCase continuation.suspend(); continuationHandle.set(continuation); } - + } catch (Exception x) { @@ -357,8 +366,9 @@ public class StatisticsHandlerTest extends TestCase } catch (Exception x) { + x.printStackTrace(); Thread.currentThread().interrupt(); - throw (IOException)new IOException().initCause(x); + fail(); } } @@ -370,10 +380,10 @@ public class StatisticsHandlerTest extends TestCase "Host: localhost\r\n" + "\r\n"; _connector.executeRequest(request); - + barrier[0].await(); - + assertEquals(1, _connector.getConnectionsOpen()); assertEquals(1, _statsHandler.getRequests()); @@ -385,19 +395,19 @@ public class StatisticsHandlerTest extends TestCase assertTrue(_latchHandler.await(1000)); assertNotNull(continuationHandle.get()); assertTrue(continuationHandle.get().isSuspended()); - + continuationHandle.get().addContinuationListener(new ContinuationListener() { public void onTimeout(Continuation continuation) { } - + public void onComplete(Continuation continuation) { try { barrier[2].await(); } catch(Exception e) {} } }); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); @@ -408,7 +418,7 @@ public class StatisticsHandlerTest extends TestCase barrier[1].reset(); barrier[0].await(); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(2, _statsHandler.getDispatched()); @@ -417,28 +427,29 @@ public class StatisticsHandlerTest extends TestCase barrier[1].await(); assertTrue(_latchHandler.await(1000)); barrier[2].await(); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(0, _statsHandler.getRequestsActive()); assertEquals(2, _statsHandler.getDispatched()); assertEquals(0, _statsHandler.getDispatchedActive()); - + assertEquals(1, _statsHandler.getSuspends()); assertEquals(1, _statsHandler.getResumes()); assertEquals(1, _statsHandler.getExpires()); assertEquals(1, _statsHandler.getResponses2xx()); - - + + assertTrue(_statsHandler.getRequestTimeTotal()>=30); assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax()); - assertEquals(_statsHandler.getRequestTimeTotal()*1.0,_statsHandler.getRequestTimeMean()); - + assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01); + assertTrue(_statsHandler.getDispatchedTimeTotal()>=20); assertTrue(_statsHandler.getDispatchedTimeMean()+10<=_statsHandler.getDispatchedTimeTotal()); assertTrue(_statsHandler.getDispatchedTimeMax()+10<=_statsHandler.getDispatchedTimeTotal()); - + } + @Test public void testSuspendComplete() throws Exception { final AtomicReference<Continuation> continuationHandle = new AtomicReference<Continuation>(); @@ -460,7 +471,7 @@ public class StatisticsHandlerTest extends TestCase continuation.suspend(); continuationHandle.set(continuation); } - + } catch (Exception x) { @@ -475,8 +486,9 @@ public class StatisticsHandlerTest extends TestCase } catch (Exception x) { + x.printStackTrace(); Thread.currentThread().interrupt(); - throw (IOException)new IOException().initCause(x); + fail(); } } @@ -488,18 +500,18 @@ public class StatisticsHandlerTest extends TestCase "Host: localhost\r\n" + "\r\n"; _connector.executeRequest(request); - + barrier[0].await(); - + assertEquals(1, _connector.getConnectionsOpen()); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); assertEquals(1, _statsHandler.getDispatchedActive()); - + barrier[1].await(); assertTrue(_latchHandler.await(1000)); assertNotNull(continuationHandle.get()); @@ -509,13 +521,13 @@ public class StatisticsHandlerTest extends TestCase public void onTimeout(Continuation continuation) { } - + public void onComplete(Continuation continuation) { try { barrier[2].await(); } catch(Exception e) {} } }); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); @@ -524,27 +536,27 @@ public class StatisticsHandlerTest extends TestCase Thread.sleep(10); continuationHandle.get().complete(); barrier[2].await(); - + assertEquals(1, _statsHandler.getRequests()); assertEquals(0, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); assertEquals(0, _statsHandler.getDispatchedActive()); - + assertEquals(1, _statsHandler.getSuspends()); assertEquals(0, _statsHandler.getResumes()); assertEquals(0, _statsHandler.getExpires()); assertEquals(1, _statsHandler.getResponses2xx()); - + assertTrue(_statsHandler.getRequestTimeTotal()>=20); assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax()); - assertEquals(_statsHandler.getRequestTimeTotal()*1.0,_statsHandler.getRequestTimeMean()); - + assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01); + assertTrue(_statsHandler.getDispatchedTimeTotal()>=10); assertTrue(_statsHandler.getDispatchedTimeTotal()<_statsHandler.getRequestTimeTotal()); assertEquals(_statsHandler.getDispatchedTimeTotal(),_statsHandler.getDispatchedTimeMax()); - assertEquals(_statsHandler.getDispatchedTimeTotal()*1.0,_statsHandler.getDispatchedTimeMean()); + assertEquals(_statsHandler.getDispatchedTimeTotal(),_statsHandler.getDispatchedTimeMean(), 0.01); } - + /** * This handler is external to the statistics handler and it is used to ensure that statistics handler's @@ -573,12 +585,12 @@ public class StatisticsHandlerTest extends TestCase { _latch=new CountDownLatch(1); } - + private void reset(int count) { _latch=new CountDownLatch(count); } - + private boolean await(long ms) throws InterruptedException { return _latch.await(ms, TimeUnit.MILLISECONDS); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java index a449286267..f79a018b52 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java @@ -10,7 +10,6 @@ import java.util.EventListener; import java.util.Locale; import java.util.Map; import java.util.Set; - import javax.servlet.AsyncContext; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; @@ -27,20 +26,21 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.Part; import javax.servlet.DispatcherType; -import junit.framework.Assert; -import junit.framework.TestCase; - import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.server.SessionManager; +import org.junit.Test; -public class SessionHandlerTest extends TestCase -{ +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +public class SessionHandlerTest +{ + @Test public void testRequestedIdFromCookies() { - final String cookieName = "SessionId"; final String sessionId = "1234.host"; HttpServletRequest httpRequest = new MockHttpServletRequest() @@ -54,7 +54,7 @@ public class SessionHandlerTest extends TestCase Request baseRequest = new Request(); baseRequest.setDispatcherType(DispatcherType.REQUEST); - Assert.assertEquals(DispatcherType.REQUEST,baseRequest.getDispatcherType()); + assertEquals(DispatcherType.REQUEST,baseRequest.getDispatcherType()); SessionHandler sessionHandler = new SessionHandler(); sessionHandler.setSessionManager(new MockSessionManager() @@ -163,14 +163,13 @@ public class SessionHandlerTest extends TestCase }); sessionHandler.setRequestedId(baseRequest,httpRequest); - Assert.assertEquals(sessionId,baseRequest.getRequestedSessionId()); - Assert.assertTrue(baseRequest.isRequestedSessionIdFromCookie()); - + assertEquals(sessionId,baseRequest.getRequestedSessionId()); + assertTrue(baseRequest.isRequestedSessionIdFromCookie()); } + @Test public void testRequestedIdFromURI() { - final String parameterName = "sessionid"; final String sessionId = "1234.host"; HttpServletRequest httpRequest = new MockHttpServletRequest() @@ -184,7 +183,7 @@ public class SessionHandlerTest extends TestCase Request baseRequest = new Request(); baseRequest.setDispatcherType(DispatcherType.REQUEST); - Assert.assertEquals(DispatcherType.REQUEST,baseRequest.getDispatcherType()); + assertEquals(DispatcherType.REQUEST,baseRequest.getDispatcherType()); SessionHandler sessionHandler = new SessionHandler(); sessionHandler.setSessionManager(new MockSessionManager() @@ -205,17 +204,16 @@ public class SessionHandlerTest extends TestCase sessionHandler.setRequestedId(baseRequest,httpRequest); - Assert.assertEquals(sessionId,baseRequest.getRequestedSessionId()); - Assert.assertFalse(baseRequest.isRequestedSessionIdFromCookie()); + assertEquals(sessionId,baseRequest.getRequestedSessionId()); + assertFalse(baseRequest.isRequestedSessionIdFromCookie()); } /** * Mock class for HttpServletRequest interface. */ @SuppressWarnings("unchecked") - class MockHttpServletRequest implements HttpServletRequest + private class MockHttpServletRequest implements HttpServletRequest { - public String getRequestURI() { return null; @@ -595,7 +593,7 @@ public class SessionHandlerTest extends TestCase /** * Mock class for SessionManager interface. */ - class MockSessionManager implements SessionManager + private class MockSessionManager implements SessionManager { public HttpCookie access(HttpSession session, boolean secure) { @@ -830,6 +828,16 @@ public class SessionHandlerTest extends TestCase } - } + private boolean _checkRemote=false; + + public boolean isCheckingRemoteSessionIdEncoding() + { + return _checkRemote; + } + public void setCheckingRemoteSessionIdEncoding(boolean remote) + { + _checkRemote=remote; + } + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java index f8b3f730f1..269c02ac0c 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== // JettyTest.java -- @@ -29,7 +29,6 @@ import java.net.HttpURLConnection; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.URL; - import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; @@ -41,22 +40,24 @@ import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.IO; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** - * HttpServer Tester. + * */ -public class SSLEngineTest extends TestCase +public class SSLEngineTest { - // ~ Static fields/initializers - // --------------------------------------------- - // Useful constants private static final String HELLO_WORLD="Hello world. The quick brown fox jumped over the lazy dog. How now brown cow. The rain in spain falls mainly on the plain.\n"; private static final String JETTY_VERSION=Server.getVersion(); @@ -68,7 +69,7 @@ public class SSLEngineTest extends TestCase private static final String REQUEST_CONTENT="<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" +"<requests xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"+" xsi:noNamespaceSchemaLocation=\"commander.xsd\" version=\"" +PROTOCOL_VERSION+"\">\n"+"</requests>"; - + private static final String REQUEST0=REQUEST0_HEADER+REQUEST_CONTENT.getBytes().length+"\n\n"+REQUEST_CONTENT; private static final String REQUEST1=REQUEST1_HEADER+REQUEST_CONTENT.getBytes().length+"\n\n"+REQUEST_CONTENT; @@ -76,8 +77,10 @@ public class SSLEngineTest extends TestCase private static final String RESPONSE0="HTTP/1.1 200 OK\n"+"Content-Length: "+HELLO_WORLD.length()+"\n"+"Server: Jetty("+JETTY_VERSION+")\n"+'\n'+HELLO_WORLD; private static final String RESPONSE1="HTTP/1.1 200 OK\n"+"Connection: close\n"+"Server: Jetty("+JETTY_VERSION+")\n"+'\n'+HELLO_WORLD; + private static final int BODY_SIZE=300; + private static final TrustManager[] s_dummyTrustManagers=new TrustManager[] - { + { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() @@ -86,33 +89,29 @@ public class SSLEngineTest extends TestCase } public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) - { } public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) - { } } }; - Server server; - SslSelectChannelConnector connector; - - // ~ Methods - // ---------------------------------------------------------------- + private static Server server; + private static SslSelectChannelConnector connector; - @Override - public void setUp() throws Exception + @BeforeClass + public static void startServer() throws Exception { - super.setUp(); - server=new Server(); connector=new SslSelectChannelConnector(); + String keystore = System.getProperty("user.dir") + File.separator + + "src" + File.separator + + "test" + File.separator + + "resources" + File.separator + + "keystore"; - String keystore = System.getProperty("user.dir")+File.separator+"src"+File.separator+"test"+File.separator+"resources"+File.separator+"keystore"; - connector.setPort(0); connector.setKeystore(keystore); connector.setPassword("storepwd"); @@ -120,32 +119,19 @@ public class SSLEngineTest extends TestCase connector.setRequestBufferSize(512); connector.setRequestHeaderSize(512); - server.setConnectors(new Connector[] - { connector }); + server.setConnectors(new Connector[]{connector }); server.setHandler(new HelloWorldHandler()); server.start(); - Thread.sleep(100); } - - - @Override - public void tearDown() throws Exception + + @AfterClass + public static void stopServer() throws Exception { - Thread.sleep(2000); server.stop(); - super.tearDown(); - } - - public void testNothing() throws Exception - { - + server.join(); } - /** - * Feed the server the entire request at once. - * - * @throws Exception - */ + @Test public void testBigResponse() throws Exception { SSLContext ctx=SSLContext.getInstance("SSLv3"); @@ -156,25 +142,21 @@ public class SSLEngineTest extends TestCase Socket client=ctx.getSocketFactory().createSocket("localhost",port); OutputStream os=client.getOutputStream(); - String request = + String request = "GET /?dump=102400 HTTP/1.1\r\n"+ "Host: localhost:8080\r\n"+ "Connection: close\r\n"+ "\r\n"; - + os.write(request.getBytes()); os.flush(); - + String response = IO.toString(client.getInputStream()); - + assertTrue(response.length()>102400); } - - /** - * Feed the server the entire request at once. - * - * @throws Exception - */ + + @Test public void testRequestJettyHttps() throws Exception { final int loops=10; @@ -231,8 +213,6 @@ public class SSLEngineTest extends TestCase client[i].close(); } } - - } } } @@ -241,22 +221,74 @@ public class SSLEngineTest extends TestCase System.err.println(); } } - + + @Test + public void testServletPost() throws Exception + { + stopServer(); + + StreamHandler handler = new StreamHandler(); + server.setHandler(handler); + server.start(); + + SSLContext context = SSLContext.getInstance("SSL"); + context.init(null,s_dummyTrustManagers,new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); + + URL url = new URL("https://localhost:"+connector.getLocalPort()+"/test"); + + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + if (conn instanceof HttpsURLConnection) + { + ((HttpsURLConnection)conn).setHostnameVerifier(new HostnameVerifier() + { + public boolean verify(String urlHostName, SSLSession session) + { + return true; + } + }); + } + + conn.setConnectTimeout(10000); + conn.setReadTimeout(100000); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type","text/plain"); + conn.setChunkedStreamingMode(128); + conn.connect(); + byte[] b = new byte[BODY_SIZE]; + for (int i = 0; i < BODY_SIZE; i++) + { + b[i] = 'x'; + } + OutputStream os = conn.getOutputStream(); + os.write(b); + os.flush(); + + int len = 0; + InputStream is = conn.getInputStream(); + int bytes=0; + while ((len = is.read(b)) > -1) + bytes+=len; + is.close(); + + assertEquals(BODY_SIZE,handler.bytes); + assertEquals(BODY_SIZE,bytes); + } + /** - * Read entire response from the client. Close the output. - * - * @param client - * Open client socket. - * + * Reads entire response from the client. Close the output. + * + * @param client Open client socket. * @return The response string. - * - * @throws IOException + * @throws IOException in case of I/O errors */ private static String readResponse(Socket client) throws IOException { BufferedReader br=null; StringBuilder sb=new StringBuilder(1000); - + try { client.setSoTimeout(5000); @@ -287,9 +319,6 @@ public class SSLEngineTest extends TestCase private static class HelloWorldHandler extends AbstractHandler { - // ~ Methods - // ------------------------------------------------------------ - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // System.err.println("HANDLE "+request.getRequestURI()); @@ -304,7 +333,7 @@ public class SSLEngineTest extends TestCase buf[i]=(byte)('0'+(i%10)); out.write(buf); out.close(); - } + } else { PrintWriter out=response.getWriter(); @@ -313,92 +342,11 @@ public class SSLEngineTest extends TestCase } } } - - - public final static int BODY_SIZE=300; - - public void testServletPost() throws Exception - { - Server server=new Server(); - SslSelectChannelConnector connector=new SslSelectChannelConnector(); - - String keystore = System.getProperty("user.dir")+File.separator+"src"+File.separator+"test"+File.separator+"resources"+File.separator+"keystore"; - - connector.setPort(0); - connector.setKeystore(keystore); - connector.setPassword("storepwd"); - connector.setKeyPassword("keypwd"); - connector.setTruststore(keystore); - connector.setTrustPassword("storepwd"); - - server.setConnectors(new Connector[] - { connector }); - StreamHandler handler = new StreamHandler(); - server.setHandler(handler); - - try - { - SSLContext context = SSLContext.getInstance("SSL"); - context.init(null,s_dummyTrustManagers,new java.security.SecureRandom()); - HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); - - server.start(); - - URL url = new URL("https://localhost:"+connector.getLocalPort()+"/test"); - - HttpURLConnection conn = (HttpURLConnection)url.openConnection(); - if (conn instanceof HttpsURLConnection) - { - ((HttpsURLConnection)conn).setHostnameVerifier(new HostnameVerifier() - { - public boolean verify(String urlHostName, SSLSession session) - { - return true; - } - }); - } - - conn.setConnectTimeout(10000); - conn.setReadTimeout(100000); - conn.setDoInput(true); - conn.setDoOutput(true); - conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-Type","text/plain"); //$NON-NLS-1$ - conn.setChunkedStreamingMode(128); - conn.connect(); - byte[] b = new byte[BODY_SIZE]; - for (int i = 0; i < BODY_SIZE; i++) - { - b[i] = 'x'; - } - OutputStream os = conn.getOutputStream(); - os.write(b); - os.flush(); - int rc = conn.getResponseCode(); - - int len = 0; - InputStream is = conn.getInputStream(); - int bytes=0; - while ((len = is.read(b)) > -1) - bytes+=len; - is.close(); - - assertEquals(BODY_SIZE,handler.bytes); - assertEquals(BODY_SIZE,bytes); - - } - finally - { - server.stop(); - } - } - - - public static class StreamHandler extends AbstractHandler + private static class StreamHandler extends AbstractHandler { - public int bytes=0; - + private int bytes=0; + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/plain"); @@ -406,7 +354,6 @@ public class SSLEngineTest extends TestCase byte[] b = new byte[BODY_SIZE]; int len = 0; InputStream is = request.getInputStream(); - while ((len = is.read(b)) > -1) { bytes+=len; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslRenegotiateTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslRenegotiateTest.java index bbc43e0856..1be64430f0 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslRenegotiateTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslRenegotiateTest.java @@ -6,16 +6,14 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; - -import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLProtocolException; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -27,14 +25,14 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; +import org.junit.Test; -import junit.framework.TestCase; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; - -public class SslRenegotiateTest extends TestCase +public class SslRenegotiateTest { - - static TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() + private static final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { @@ -50,47 +48,41 @@ public class SslRenegotiateTest extends TestCase } } }; - static HostnameVerifier hostnameVerifier = new HostnameVerifier() - { - public boolean verify( String urlHostName, SSLSession session ) - { - Log.warn( "Warning: URL Host: " + urlHostName + " vs." + session.getPeerHost() ); - return true; - } - }; - - ByteBuffer _outAppB; - ByteBuffer _outPacketB; - ByteBuffer _inAppB; - ByteBuffer _inPacketB; - SocketChannel _socket; - SSLEngine _engine; - + private ByteBuffer _outAppB; + private ByteBuffer _outPacketB; + private ByteBuffer _inAppB; + private ByteBuffer _inPacketB; + private SocketChannel _socket; + private SSLEngine _engine; + @Test public void testRenegNIO() throws Exception { - doRequests(new SslSelectChannelConnector(),true); + // TODO This test breaks on JVMs with the fix +// doRequests(new SslSelectChannelConnector(),true); } - + + @Test public void testNoRenegNIO() throws Exception { doRequests(new SslSelectChannelConnector(),false); } + + @Test public void testRenegBIO() throws Exception { - /** TODO - this test is too non deterministic due to call back timing - doRequests(new SslSocketConnector(),true); - */ + // TODO - this test is too non deterministic due to call back timing +// doRequests(new SslSocketConnector(),true); } - + + @Test public void testNoRenegBIO() throws Exception { - /** TODO - this test is too non deterministic due to call back timing - doRequests(new SslSocketConnector(),false); - */ + // TODO - this test is too non deterministic due to call back timing +// doRequests(new SslSocketConnector(),false); } - public void doRequests(SslConnector connector,boolean reneg) throws Exception + private void doRequests(SslConnector connector, boolean reneg) throws Exception { Server server=new Server(); try @@ -106,29 +98,29 @@ public class SslRenegotiateTest extends TestCase server.setHandler(new HelloWorldHandler()); server.start(); - + SocketAddress addr = new InetSocketAddress("localhost",connector.getLocalPort()); _socket = SocketChannel.open(addr); _socket.configureBlocking(true); - + SSLContext context=SSLContext.getInstance("SSL"); context.init( null, trustAllCerts, new java.security.SecureRandom() ); _engine = context.createSSLEngine(); _engine.setUseClientMode(true); SSLSession session=_engine.getSession(); - + _outAppB = ByteBuffer.allocate(session.getApplicationBufferSize()); _outPacketB = ByteBuffer.allocate(session.getPacketBufferSize()); _inAppB = ByteBuffer.allocate(session.getApplicationBufferSize()); _inPacketB = ByteBuffer.allocate(session.getPacketBufferSize()); - - + + _outAppB.put("GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n".getBytes(StringUtil.__ISO_8859_1)); _outAppB.flip(); - + _engine.beginHandshake(); - + runHandshake(); doWrap(); @@ -137,7 +129,7 @@ public class SslRenegotiateTest extends TestCase String response=new IndirectNIOBuffer(_inAppB,true).toString(); // System.err.println(response); assertTrue(response.startsWith("HTTP/1.1 200 OK")); - + if (response.indexOf("HELLO WORLD")<0) { _inAppB.clear(); @@ -145,9 +137,9 @@ public class SslRenegotiateTest extends TestCase _inAppB.flip(); response=new IndirectNIOBuffer(_inAppB,true).toString(); } - + assertTrue(response.indexOf("HELLO WORLD")>=0); - + _inAppB.clear(); _outAppB.clear(); _outAppB.put("GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n".getBytes(StringUtil.__ISO_8859_1)); @@ -158,7 +150,7 @@ public class SslRenegotiateTest extends TestCase session.invalidate(); _engine.beginHandshake(); runHandshake(); - + doWrap(); doUnwrap(); _inAppB.flip(); @@ -176,25 +168,19 @@ public class SslRenegotiateTest extends TestCase Log.warn(e); assertFalse(reneg); } - return; } - } finally { server.stop(); + server.join(); } } - + void runHandshake() throws Exception { - SSLEngineResult result; - while (true) { - //System.err.println(); - //System.err.println(_engine.getHandshakeStatus()); - switch(_engine.getHandshakeStatus()) { case NEED_TASK: @@ -203,25 +189,25 @@ public class SslRenegotiateTest extends TestCase _engine.getDelegatedTask().run(); break; } - + case NEED_WRAP: { doWrap(); break; } - + case NEED_UNWRAP: { doUnwrap(); break; } - + default: return; } } } - + private void doWrap() throws Exception { SSLEngineResult result =_engine.wrap(_outAppB,_outPacketB); @@ -235,7 +221,7 @@ public class SslRenegotiateTest extends TestCase } _outPacketB.clear(); } - + private void doUnwrap() throws Exception { _inPacketB.clear(); @@ -243,7 +229,7 @@ public class SslRenegotiateTest extends TestCase // System.err.println("read "+l); if (l<0) throw new IOException("EOF"); - + _inPacketB.flip(); SSLEngineResult result; @@ -251,17 +237,15 @@ public class SslRenegotiateTest extends TestCase { result =_engine.unwrap(_inPacketB,_inAppB); // System.err.println("unwrapped "+result.bytesConsumed()+" to "+result.bytesProduced()+" "+_engine.getHandshakeStatus()); - + } while(result.bytesConsumed()>0 && - _inPacketB.remaining()>0 && + _inPacketB.remaining()>0 && (_engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP || _engine.getHandshakeStatus()==HandshakeStatus.NOT_HANDSHAKING)); - } private static class HelloWorldHandler extends AbstractHandler { - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslUploadTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslUploadTest.java index 8cb045bf58..e44c5d946e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslUploadTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslUploadTest.java @@ -21,34 +21,37 @@ import java.io.OutputStream; import java.security.KeyStore; import java.util.Arrays; import java.util.concurrent.TimeUnit; - -import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManagerFactory; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.IO; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; /** * @version $Revision$ $Date$ */ -public class SslUploadTest extends TestCase +public class SslUploadTest { - int _total; - - public void test() throws Exception + private static Server server; + private static SslSelectChannelConnector connector; + private static int total; + + @BeforeClass + public static void startServer() throws Exception { - Server server = new Server(); - SslConnector connector = new SslSelectChannelConnector(); + server = new Server(); + connector = new SslSelectChannelConnector(); server.addConnector(connector); String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore"; @@ -61,100 +64,86 @@ public class SslUploadTest extends TestCase server.setHandler(new EmptyHandler()); server.start(); - try + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + server.join(); + } + + @Test + public void test() throws Exception + { + KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); + keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray()); + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keystore); + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustManagerFactory.getTrustManagers(), null); + + final SSLSocket socket = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost",connector.getLocalPort()); + + // Simulate async close + /* + new Thread() { - KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); - keystore.load(new FileInputStream(keystorePath), "storepwd".toCharArray()); - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(keystore); - SSLContext sslContext = SSLContext.getInstance("SSL"); - sslContext.init(null, trustManagerFactory.getTrustManagers(), null); - - _total=0; - final SSLSocket socket = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost",connector.getLocalPort()); - - // Simulate async close - /* - new Thread() + @Override + public void run() { - @Override - public void run() + try { - try - { - sleep(100); - socket.close(); - } - catch (IOException x) - { - x.printStackTrace(); - } - catch (InterruptedException x) - { - Thread.currentThread().interrupt(); - } + sleep(100); + socket.close(); } - }.start(); - */ - - - - long start = System.nanoTime(); - OutputStream out = socket.getOutputStream(); - out.write("POST / HTTP/1.1\r\n".getBytes()); - out.write("Host: localhost\r\n".getBytes()); - out.write("Content-Length: 16777216\r\n".getBytes()); - out.write("Content-Type: bytes\r\n".getBytes()); - out.write("Connection: close\r\n".getBytes()); - out.write("\r\n".getBytes()); - out.flush(); - - byte[] requestContent = new byte[16777216]; - Arrays.fill(requestContent, (byte)120); - out.write(requestContent); - out.flush(); - - InputStream in = socket.getInputStream(); - String response = IO.toString(in); - // System.err.println(response); - - long end = System.nanoTime(); - System.out.println("upload time: " + TimeUnit.NANOSECONDS.toMillis(end - start)); - assertEquals(requestContent.length,_total); - - } - finally - { - server.stop(); - } + catch (IOException x) + { + x.printStackTrace(); + } + catch (InterruptedException x) + { + Thread.currentThread().interrupt(); + } + } + }.start(); + */ + + long start = System.nanoTime(); + OutputStream out = socket.getOutputStream(); + out.write("POST / HTTP/1.1\r\n".getBytes()); + out.write("Host: localhost\r\n".getBytes()); + out.write("Content-Length: 16777216\r\n".getBytes()); + out.write("Content-Type: bytes\r\n".getBytes()); + out.write("Connection: close\r\n".getBytes()); + out.write("\r\n".getBytes()); + out.flush(); + + byte[] requestContent = new byte[16777216]; + Arrays.fill(requestContent, (byte)120); + out.write(requestContent); + out.flush(); + + InputStream in = socket.getInputStream(); + String response = IO.toString(in); + // System.err.println(response); + + long end = System.nanoTime(); + System.out.println("upload time: " + TimeUnit.NANOSECONDS.toMillis(end - start)); + assertEquals(requestContent.length, total); } - private class EmptyHandler extends AbstractHandler + private static class EmptyHandler extends AbstractHandler { public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { - // System.out.println("path = " + path); request.setHandled(true); - InputStream in = request.getInputStream(); byte[] b = new byte[4096*4]; - int l; - - while((l=in.read(b))>=0) - { - // System.out.println("Read "+l); - _total+=l; - } - System.err.println("Read "+_total); - - } - } - - private class EmptyHostnameVerifier implements HostnameVerifier - { - public boolean verify(String s, SSLSession sslSession) - { - return true; + int read; + while((read = in.read(b))>=0) + total += read; + System.err.println("Read "+ total); } } } diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index 4a2779f1e9..48557e1c6b 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -47,11 +47,12 @@ </execution> </executions> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.servlet.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> @@ -59,6 +60,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java index c2d32241ea..d27681f02b 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlet; @@ -16,12 +16,12 @@ package org.eclipse.jetty.servlet; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.util.Enumeration; import java.util.List; import java.util.Map; - import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -47,9 +47,9 @@ import org.eclipse.jetty.server.ResourceCache; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.nio.NIOConnector; +import org.eclipse.jetty.server.ssl.SslConnector; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.MultiPartOutputStream; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.FileResource; @@ -60,85 +60,85 @@ import org.eclipse.jetty.util.resource.ResourceFactory; /* ------------------------------------------------------------ */ -/** The default servlet. - * This servlet, normally mapped to /, provides the handling for static - * content, OPTION and TRACE methods for the context. +/** The default servlet. + * This servlet, normally mapped to /, provides the handling for static + * content, OPTION and TRACE methods for the context. * The following initParameters are supported, these can be set either * on the servlet itself or as ServletContext initParameters with a prefix - * of org.eclipse.jetty.servlet.Default. : - * <PRE> - * acceptRanges If true, range requests and responses are - * supported - * - * dirAllowed If true, directory listings are returned if no - * welcome file is found. Else 403 Forbidden. + * of org.eclipse.jetty.servlet.Default. : + * <PRE> + * acceptRanges If true, range requests and responses are + * supported + * + * dirAllowed If true, directory listings are returned if no + * welcome file is found. Else 403 Forbidden. * * welcomeServlets If true, attempt to dispatch to welcome files * that are servlets, but only after no matching static - * resources could be found. If false, then a welcome - * file must exist on disk. If "exact", then exact + * resources could be found. If false, then a welcome + * file must exist on disk. If "exact", then exact * servlet matches are supported without an existing file. * Default is true. - * + * * This must be false if you want directory listings, * but have index.jsp in your welcome file list. * * redirectWelcome If true, welcome files are redirected rather than * forwarded to. * - * gzip If set to true, then static content will be served as - * gzip content encoded if a matching resource is + * gzip If set to true, then static content will be served as + * gzip content encoded if a matching resource is * found ending with ".gz" * * resourceBase Set to replace the context resource base * - * relativeResourceBase + * relativeResourceBase * Set with a pathname relative to the base of the * servlet context root. Useful for only serving static content out * of only specific subdirectories. - * + * * aliases If True, aliases of resources are allowed (eg. symbolic * links and caps variations). May bypass security constraints. - * + * * maxCacheSize The maximum total size of the cache or 0 for no cache. * maxCachedFileSize The maximum size of a file to cache * maxCachedFiles The maximum number of files to cache - * cacheType Set to "bio", "nio" or "both" to determine the type resource cache. + * cacheType Set to "bio", "nio" or "both" to determine the type resource cache. * A bio cached buffer may be used by nio but is not as efficient as an - * nio buffer. An nio cached buffer may not be used by bio. - * - * useFileMappedBuffer + * nio buffer. An nio cached buffer may not be used by bio. + * + * useFileMappedBuffer * If set to true, it will use mapped file buffer to serve static content * when using NIO connector. Setting this value to false means that - * a direct buffer will be used instead of a mapped file buffer. + * a direct buffer will be used instead of a mapped file buffer. * By default, this is set to true. - * + * * cacheControl If set, all static content will have this value set as the cache-control * header. - * - * + * + * * </PRE> - * * - * - * + * + * + * */ public class DefaultServlet extends HttpServlet implements ResourceFactory -{ +{ private ServletContext _servletContext; private ContextHandler _contextHandler; - + private boolean _acceptRanges=true; private boolean _dirAllowed=true; private boolean _welcomeServlets=true; private boolean _welcomeExactServlets=false; private boolean _redirectWelcome=false; private boolean _gzip=true; - + private Resource _resourceBase; private NIOResourceCache _nioCache; private ResourceCache _bioCache; - + private MimeTypes _mimeTypes; private String[] _welcomes; private boolean _useFileMappedBuffer=false; @@ -146,8 +146,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory private String _relativeResourceBase; private ServletHandler _servletHandler; private ServletHolder _defaultHolder; - - + + /* ------------------------------------------------------------ */ @Override public void init() @@ -159,18 +159,18 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory _contextHandler=((ContextHandler.Context)_servletContext).getContextHandler(); else _contextHandler = ContextHandler.getCurrentContext().getContextHandler(); - + _mimeTypes = _contextHandler.getMimeTypes(); - + _welcomes = _contextHandler.getWelcomeFiles(); if (_welcomes==null) _welcomes=new String[] {"index.html","index.jsp"}; - + _acceptRanges=getInitBoolean("acceptRanges",_acceptRanges); _dirAllowed=getInitBoolean("dirAllowed",_dirAllowed); _redirectWelcome=getInitBoolean("redirectWelcome",_redirectWelcome); _gzip=getInitBoolean("gzip",_gzip); - + if ("exact".equals(getInitParameter("welcomeServlets"))) { _welcomeExactServlets=true; @@ -178,37 +178,37 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } else _welcomeServlets=getInitBoolean("welcomeServlets", _welcomeServlets); - + if (getInitParameter("aliases")!=null) _contextHandler.setAliases(getInitBoolean("aliases",false)); - + boolean aliases=_contextHandler.isAliases(); if (!aliases && !FileResource.getCheckAliases()) throw new IllegalStateException("Alias checking disabled"); if (aliases) _servletContext.log("Aliases are enabled"); - + _useFileMappedBuffer=getInitBoolean("useFileMappedBuffer",_useFileMappedBuffer); - + _relativeResourceBase = getInitParameter("relativeResourceBase"); - + String rb=getInitParameter("resourceBase"); if (rb!=null) { if (_relativeResourceBase!=null) - throw new UnavailableException("resourceBase & relativeResourceBase"); + throw new UnavailableException("resourceBase & relativeResourceBase"); try{_resourceBase=_contextHandler.newResource(rb);} - catch (Exception e) + catch (Exception e) { Log.warn(Log.EXCEPTION,e); - throw new UnavailableException(e.toString()); + throw new UnavailableException(e.toString()); } } - + String t=getInitParameter("cacheControl"); if (t!=null) _cacheControl=new ByteArrayBuffer(t); - + try { String cache_type =getInitParameter("cacheType"); @@ -223,9 +223,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory _nioCache=new NIOResourceCache(_mimeTypes); _nioCache.setUseFileMappedBuffer(_useFileMappedBuffer); if (max_cache_size>0) - _nioCache.setMaxCacheSize(max_cache_size); + _nioCache.setMaxCacheSize(max_cache_size); if (max_cached_file_size>=-1) - _nioCache.setMaxCachedFileSize(max_cached_file_size); + _nioCache.setMaxCachedFileSize(max_cached_file_size); if (max_cached_files>=-1) _nioCache.setMaxCachedFiles(max_cached_files); _nioCache.start(); @@ -237,9 +237,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory { _bioCache=new ResourceCache(_mimeTypes); if (max_cache_size>0) - _bioCache.setMaxCacheSize(max_cache_size); + _bioCache.setMaxCacheSize(max_cache_size); if (max_cached_file_size>=-1) - _bioCache.setMaxCachedFileSize(max_cached_file_size); + _bioCache.setMaxCachedFileSize(max_cached_file_size); if (max_cached_files>=-1) _bioCache.setMaxCachedFiles(max_cached_files); _bioCache.start(); @@ -247,19 +247,19 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } if (_nioCache==null) _bioCache=null; - + } - catch (Exception e) + catch (Exception e) { Log.warn(Log.EXCEPTION,e); - throw new UnavailableException(e.toString()); + throw new UnavailableException(e.toString()); } _servletHandler= (ServletHandler) _contextHandler.getChildHandlerByClass(ServletHandler.class); for (ServletHolder h :_servletHandler.getServlets()) if (h.getServletInstance()==this) _defaultHolder=h; - + if (Log.isDebugEnabled()) Log.debug("resource base = "+_resourceBase); } @@ -272,7 +272,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory value=super.getInitParameter(name); return value; } - + /* ------------------------------------------------------------ */ private boolean getInitBoolean(String name, boolean dft) { @@ -285,7 +285,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory value.startsWith("Y")|| value.startsWith("1")); } - + /* ------------------------------------------------------------ */ private int getInitInt(String name, int dft) { @@ -296,7 +296,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory return Integer.parseInt(value); return dft; } - + /* ------------------------------------------------------------ */ /** get Resource to serve. * Map a path to a resource. The default implementation calls @@ -310,7 +310,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory Resource r=null; if (_relativeResourceBase!=null) pathInContext=URIUtil.addPaths(_relativeResourceBase,pathInContext); - + try { if (_resourceBase!=null) @@ -320,8 +320,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory URL u = _servletContext.getResource(pathInContext); r = _contextHandler.newResource(u); } - - if (Log.isDebugEnabled()) + + if (Log.isDebugEnabled()) Log.debug("RESOURCE "+pathInContext+"="+r); } catch (IOException e) @@ -330,7 +330,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } return r; } - + /* ------------------------------------------------------------ */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) @@ -361,10 +361,10 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory if (!hasDefinedRange(reqRanges)) reqRanges = null; } - + String pathInContext=URIUtil.addPaths(servletPath,pathInfo); boolean endsWithSlash=pathInContext.endsWith(URIUtil.SLASH); - + // Can we gzip this request? String pathInContextGz=null; boolean gzip=false; @@ -374,19 +374,19 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory if (accept!=null && accept.indexOf("gzip")>=0) gzip=true; } - + // Find the resource and content Resource resource=null; HttpContent content=null; - + Connector connector = HttpConnection.getCurrentConnection().getConnector(); - ResourceCache cache=(connector instanceof NIOConnector) ?_nioCache:_bioCache; + ResourceCache cache=(connector instanceof NIOConnector && !(connector instanceof SslConnector)) ?_nioCache:_bioCache; try - { + { // Try gzipped content first if (gzip) { - pathInContextGz=pathInContext+".gz"; + pathInContextGz=pathInContext+".gz"; if (cache==null) { @@ -414,7 +414,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory pathInContextGz=null; } } - + // find resource if (!gzip) { @@ -430,15 +430,15 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory resource=getResource(pathInContext); } } - + if (Log.isDebugEnabled()) Log.debug("resource="+resource+(content!=null?" content":"")); - + // Handle resource if (resource==null || !resource.exists()) response.sendError(HttpServletResponse.SC_NOT_FOUND); else if (!resource.isDirectory()) - { + { if (endsWithSlash && _contextHandler.isAliases() && pathInContext.length()>1) { String q=request.getQueryString(); @@ -452,8 +452,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory // ensure we have content if (content==null) content=new UnCachedContent(resource); - - if (included.booleanValue() || passConditionalHeaders(request,response, resource,content)) + + if (included.booleanValue() || passConditionalHeaders(request,response, resource,content)) { if (gzip) { @@ -462,14 +462,14 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory if (mt!=null) response.setContentType(mt); } - sendData(request,response,included.booleanValue(),resource,content,reqRanges); + sendData(request,response,included.booleanValue(),resource,content,reqRanges); } } } else { String welcome=null; - + if (!endsWithSlash || (pathInContext.length()==1 && request.getAttribute("org.eclipse.jetty.server.nullPathInfo")!=null)) { StringBuffer buf=request.getRequestURL(); @@ -519,7 +519,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } } } - else + else { content=new UnCachedContent(resource); if (included.booleanValue() || passConditionalHeaders(request,response, resource,content)) @@ -540,9 +540,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory else if (resource!=null) resource.release(); } - + } - + /* ------------------------------------------------------------ */ private boolean hasDefinedRange(Enumeration reqRanges) { @@ -556,7 +556,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory { doGet(request,response); } - + /* ------------------------------------------------------------ */ /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doTrace(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) @@ -568,8 +568,16 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } /* ------------------------------------------------------------ */ + @Override + protected void doOptions(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + resp.setHeader("Allow", "GET,HEAD,POST,OPTIONS"); + } + + /* ------------------------------------------------------------ */ /** - * Finds a matching welcome file for the supplied {@link Resource}. This will be the first entry in the list of + * Finds a matching welcome file for the supplied {@link Resource}. This will be the first entry in the list of * configured {@link #_welcomes welcome files} that existing within the directory referenced by the <code>Resource</code>. * If the resource is not a directory, or no matching file is found, then it may look for a valid servlet mapping. * If there is none, then <code>null</code> is returned. @@ -584,7 +592,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory { if (_welcomes==null) return null; - + String welcome_servlet=null; for (int i=0;i<_welcomes.length;i++) { @@ -599,7 +607,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory if (entry!=null && entry.getValue()!=_defaultHolder && (_welcomeServlets || (_welcomeExactServlets && entry.getKey().equals(welcome_in_context)))) welcome_servlet=welcome_in_context; - + } } return welcome_servlet; @@ -632,7 +640,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } } } - + long ifmsl=request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE); if (ifmsl!=-1) { @@ -648,7 +656,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory // Parse the if[un]modified dates and compare to resource long date=request.getDateHeader(HttpHeaders.IF_UNMODIFIED_SINCE); - + if (date!=-1) { if (resource.lastModified()/1000 > date/1000) @@ -657,7 +665,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory return false; } } - + } } catch(IllegalArgumentException iae) @@ -668,8 +676,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } return true; } - - + + /* ------------------------------------------------------------------- */ protected void sendDirectory(HttpServletRequest request, HttpServletResponse response, @@ -682,16 +690,16 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory response.sendError(HttpServletResponse.SC_FORBIDDEN); return; } - + byte[] data=null; String base = URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH); - + // handle ResourceCollection if (_resourceBase instanceof ResourceCollection) resource=_resourceBase.addPath(pathInContext); else if (_contextHandler.getBaseResource() instanceof ResourceCollection) resource=_contextHandler.getBaseResource().addPath(pathInContext); - + String dir = resource.getListHTML(base,pathInContext.length()>1); if (dir==null) { @@ -699,13 +707,13 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory "No directory"); return; } - + data=dir.getBytes("UTF-8"); response.setContentType("text/html; charset=UTF-8"); response.setContentLength(data.length); response.getOutputStream().write(data); } - + /* ------------------------------------------------------------ */ protected void sendData(HttpServletRequest request, HttpServletResponse response, @@ -716,12 +724,12 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory throws IOException { long content_length=content==null?resource.length():content.getContentLength(); - + // Get the output stream (or writer) OutputStream out =null; try{out = response.getOutputStream();} catch(IllegalStateException e) {out = new WriterOutputStream(response.getWriter());} - + if ( reqRanges == null || !reqRanges.hasMoreElements() || content_length<0) { // if there were no ranges, send entire entity @@ -762,19 +770,19 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory { // Parse the satisfiable ranges List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,content_length); - + // if there are no satisfiable ranges, send 416 response if (ranges==null || ranges.size()==0) { writeHeaders(response, content, content_length); response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); - response.setHeader(HttpHeaders.CONTENT_RANGE, + response.setHeader(HttpHeaders.CONTENT_RANGE, InclusiveByteRange.to416HeaderRangeString(content_length)); resource.writeTo(out,0,content_length); return; } - - // if there is only a single valid range (must be satisfiable + + // if there is only a single valid range (must be satisfiable // since were here now), send that range with a 216 response if ( ranges.size()== 1) { @@ -783,21 +791,21 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory long singleLength = singleSatisfiableRange.getSize(content_length); writeHeaders(response,content,singleLength ); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); - response.setHeader(HttpHeaders.CONTENT_RANGE, + response.setHeader(HttpHeaders.CONTENT_RANGE, singleSatisfiableRange.toHeaderRangeString(content_length)); resource.writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength); return; } - + // multiple non-overlapping valid ranges cause a multipart - // 216 response which does not require an overall + // 216 response which does not require an overall // content-length header // writeHeaders(response,content,-1); String mimetype=content.getContentType().toString(); MultiPartOutputStream multi = new MultiPartOutputStream(out); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); - + // If the request has a "Request-Range" header then we need to // send an old style multipart/x-byteranges Content-Type. This // keeps Netscape and acrobat happy. This is what Apache does. @@ -807,10 +815,10 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory else ctp = "multipart/byteranges; boundary="; response.setContentType(ctp+multi.getBoundary()); - + InputStream in=resource.getInputStream(); long pos=0; - + // calculate the content-length int length=0; String[] header = new String[ranges.size()]; @@ -820,20 +828,20 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory header[i]=ibr.toHeaderRangeString(content_length); length+= ((i>0)?2:0)+ - 2+multi.getBoundary().length()+2+ - HttpHeaders.CONTENT_TYPE.length()+2+mimetype.length()+2+ - HttpHeaders.CONTENT_RANGE.length()+2+header[i].length()+2+ + 2+multi.getBoundary().length()+2+ + HttpHeaders.CONTENT_TYPE.length()+2+mimetype.length()+2+ + HttpHeaders.CONTENT_RANGE.length()+2+header[i].length()+2+ 2+ (ibr.getLast(content_length)-ibr.getFirst(content_length))+1; } length+=2+2+multi.getBoundary().length()+2+2; response.setContentLength(length); - + for (int i=0;i<ranges.size();i++) { InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i); multi.startPart(mimetype,new String[]{HttpHeaders.CONTENT_RANGE+": "+header[i]}); - + long start=ibr.getFirst(content_length); long size=ibr.getSize(content_length); if (in!=null) @@ -856,7 +864,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory else // Handle cached resource (resource).writeTo(multi,start,size); - + } if (in!=null) in.close(); @@ -864,20 +872,20 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } return; } - + /* ------------------------------------------------------------ */ protected void writeHeaders(HttpServletResponse response,HttpContent content,long count) throws IOException - { + { if (content.getContentType()!=null && response.getContentType()==null) response.setContentType(content.getContentType().toString()); - + if (response instanceof Response) { Response r=(Response)response; HttpFields fields = r.getHttpFields(); - if (content.getLastModified()!=null) + if (content.getLastModified()!=null) fields.put(HttpHeaders.LAST_MODIFIED_BUFFER,content.getLastModified(),content.getResource().lastModified()); else if (content.getResource()!=null) { @@ -885,7 +893,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory if (lml!=-1) fields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER,lml); } - + if (count != -1) r.setLongContentLength(count); @@ -901,27 +909,27 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory { if (count<Integer.MAX_VALUE) response.setContentLength((int)count); - else - response.setHeader(HttpHeaders.CONTENT_LENGTH,TypeUtil.toString(count)); + else + response.setHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(count)); } - + writeOptionHeaders(response); } } /* ------------------------------------------------------------ */ protected void writeOptionHeaders(HttpFields fields) throws IOException - { + { if (_acceptRanges) fields.put(HttpHeaders.ACCEPT_RANGES_BUFFER,HttpHeaderValues.BYTES_BUFFER); if (_cacheControl!=null) fields.put(HttpHeaders.CACHE_CONTROL_BUFFER,_cacheControl); } - + /* ------------------------------------------------------------ */ protected void writeOptionHeaders(HttpServletResponse response) throws IOException - { + { if (_acceptRanges) response.setHeader(HttpHeaders.ACCEPT_RANGES,"bytes"); @@ -930,7 +938,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.Servlet#destroy() */ @Override @@ -940,8 +948,6 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory { if (_nioCache!=null) _nioCache.stop(); - if (_bioCache!=null) - _bioCache.stop(); } catch(Exception e) { @@ -949,7 +955,19 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory } finally { - super.destroy(); + try + { + if (_bioCache!=null) + _bioCache.stop(); + } + catch(Exception e) + { + Log.warn(Log.EXCEPTION,e); + } + finally + { + super.destroy(); + } } } @@ -959,12 +977,12 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory private class UnCachedContent implements HttpContent { Resource _resource; - + UnCachedContent(Resource resource) { _resource=resource; } - + /* ------------------------------------------------------------ */ public Buffer getContentType() { @@ -1007,6 +1025,6 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory _resource.release(); _resource=null; } - + } } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java index 989b8b01b0..94d0515e8f 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlet; @@ -18,7 +18,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -30,34 +29,30 @@ import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ErrorHandler; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; /** Error Page Error Handler - * + * * An ErrorHandler that maps exceptions and status codes to URIs for dispatch using * the internal ERROR style of dispatch. - * + * * */ public class ErrorPageErrorHandler extends ErrorHandler { public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page"; - + protected ServletContext _servletContext; protected Map _errorPages; // code or exception to URL - protected List _errorPageList; // list of ErrorCode by range + protected List _errorPageList; // list of ErrorCode by range /* ------------------------------------------------------------ */ - /** - * @param context - */ public ErrorPageErrorHandler() {} /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.handler.ErrorHandler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int) + /** + * @see org.eclipse.jetty.server.handler.ErrorHandler#handle(String, Request, HttpServletRequest, HttpServletResponse) */ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { @@ -71,7 +66,7 @@ public class ErrorPageErrorHandler extends ErrorHandler { String error_page= null; Class exClass= (Class)request.getAttribute(Dispatcher.ERROR_EXCEPTION_TYPE); - + if (ServletException.class.equals(exClass)) { error_page= (String)_errorPages.get(exClass.getName()); @@ -84,20 +79,20 @@ public class ErrorPageErrorHandler extends ErrorHandler exClass= th.getClass(); } } - + while (error_page == null && exClass != null ) { error_page= (String)_errorPages.get(exClass.getName()); exClass= exClass.getSuperclass(); } - + if (error_page == null) { // look for an exact code match Integer code=(Integer)request.getAttribute(Dispatcher.ERROR_STATUS_CODE); if (code!=null) { - error_page= (String)_errorPages.get(TypeUtil.toString(code.intValue())); + error_page= (String)_errorPages.get(Integer.toString(code)); // if still not found if ((error_page == null) && (_errorPageList != null)) @@ -106,7 +101,7 @@ public class ErrorPageErrorHandler extends ErrorHandler for (int i = 0; i < _errorPageList.size(); i++) { ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i); - if (errCode.isInRange(code.intValue())) + if (errCode.isInRange(code)) { error_page = errCode.getUri(); break; @@ -115,19 +110,19 @@ public class ErrorPageErrorHandler extends ErrorHandler } } } - + if (error_page!=null) { String old_error_page=(String)request.getAttribute(ERROR_PAGE); if (old_error_page==null || !old_error_page.equals(error_page)) { request.setAttribute(ERROR_PAGE, error_page); - + Dispatcher dispatcher = (Dispatcher) _servletContext.getRequestDispatcher(error_page); try { if(dispatcher!=null) - { + { dispatcher.error(request, response); return; } @@ -144,7 +139,7 @@ public class ErrorPageErrorHandler extends ErrorHandler } } } - + super.handle(target, baseRequest, request, response); } @@ -156,7 +151,7 @@ public class ErrorPageErrorHandler extends ErrorHandler { return _errorPages; } - + /* ------------------------------------------------------------ */ /** * @param errorPages The errorPages to set. A map of Exception class name or error code as a string to URI string @@ -170,7 +165,7 @@ public class ErrorPageErrorHandler extends ErrorHandler /** Add Error Page mapping for an exception class * This method is called as a result of an exception-type element in a web.xml file * or may be called directly - * @param code The class (or superclass) of the matching exceptions + * @param exception The exception * @param uri The URI of the error page. */ public void addErrorPage(Class exception,String uri) @@ -179,7 +174,7 @@ public class ErrorPageErrorHandler extends ErrorHandler _errorPages=new HashMap(); _errorPages.put(exception.getName(),uri); } - + /* ------------------------------------------------------------ */ /** Add Error Page mapping for a status code. * This method is called as a result of an error-code element in a web.xml file @@ -191,9 +186,9 @@ public class ErrorPageErrorHandler extends ErrorHandler { if (_errorPages==null) _errorPages=new HashMap(); - _errorPages.put(TypeUtil.toString(code),uri); + _errorPages.put(Integer.toString(code),uri); } - + /* ------------------------------------------------------------ */ /** Add Error Page mapping for a status code range. * This method is not available from web.xml and must be called @@ -232,36 +227,36 @@ public class ErrorPageErrorHandler extends ErrorHandler private int _from; private int _to; private String _uri; - + ErrorCodeRange(int from, int to, String uri) throws IllegalArgumentException { if (from > to) throw new IllegalArgumentException("from>to"); - + _from = from; _to = to; _uri = uri; } - + boolean isInRange(int value) { if ((value >= _from) && (value <= _to)) { return true; } - + return false; } - + String getUri() { return _uri; } - + public String toString() { return "from: " + _from + ",to: " + _to + ",uri: " + _uri; } - } + } } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java index 079c63787c..3ade48fb43 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java @@ -124,7 +124,7 @@ public class FilterHolder extends Holder<Filter> Log.warn(e); } } - if (!_instance) + if (!_extInstance) _filter=null; _config=null; @@ -147,7 +147,7 @@ public class FilterHolder extends Holder<Filter> public synchronized void setFilter(Filter filter) { _filter=filter; - _instance=true; + _extInstance=true; setHeldClass(filter.getClass()); if (getName()==null) setName(filter.getClass().getName()); @@ -160,6 +160,7 @@ public class FilterHolder extends Holder<Filter> } /* ------------------------------------------------------------ */ + @Override public String toString() { return getName(); @@ -245,8 +246,3 @@ public class FilterHolder extends Holder<Filter> } } } - - - - - diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java index be57231330..a13ebfeafd 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java @@ -167,6 +167,20 @@ public class FilterMapping /* ------------------------------------------------------------ */ /** + * @param dispatches The dispatches to set. + * @see #DEFAULT + * @see #REQUEST + * @see #ERROR + * @see #FORWARD + * @see #INCLUDE + */ + public void setDispatches(int dispatches) + { + _dispatches = dispatches; + } + + /* ------------------------------------------------------------ */ + /** * @param filterName The filterName to set. */ public void setFilterName(String filterName) diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java index bfa1b59e23..d1817bb793 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java @@ -37,20 +37,19 @@ import org.eclipse.jetty.util.log.Log; public class Holder<T> extends AbstractLifeCycle { public enum Source { EMBEDDED, JAVAX_API, DESCRIPTOR, ANNOTATION }; - final private Source _source; - protected transient Class<? extends T> _class; + protected final Map<String,String> _initParams=new HashMap<String,String>(3); protected String _className; protected String _displayName; - protected Map<String,String> _initParams; - protected boolean _instance; - protected boolean _asyncSupported; + protected boolean _extInstance; + protected boolean _asyncSupported=true; /* ---------------------------------------------------------------- */ protected String _name; protected ServletHandler _servletHandler; + /* ---------------------------------------------------------------- */ protected Holder(Source source) { _source=source; @@ -67,7 +66,7 @@ public class Holder<T> extends AbstractLifeCycle */ public boolean isInstance() { - return _instance; + return _extInstance; } /* ------------------------------------------------------------ */ @@ -99,7 +98,7 @@ public class Holder<T> extends AbstractLifeCycle public void doStop() throws Exception { - if (!_instance) + if (!_extInstance) _class=null; } @@ -176,7 +175,7 @@ public class Holder<T> extends AbstractLifeCycle /* ------------------------------------------------------------ */ /** - * @param className The className to set. + * @param held The class to hold */ public void setHeldClass(Class<? extends T> held) { @@ -198,15 +197,14 @@ public class Holder<T> extends AbstractLifeCycle /* ------------------------------------------------------------ */ public void setInitParameter(String param,String value) { - if (_initParams==null) - _initParams=new HashMap(3); _initParams.put(param,value); } /* ---------------------------------------------------------------- */ - public void setInitParameters(Map map) + public void setInitParameters(Map<String,String> map) { - _initParams=map; + _initParams.clear(); + _initParams.putAll(map); } /* ------------------------------------------------------------ */ diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index 588d298f8d..f739b1dc3d 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -49,6 +49,7 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerWrapper; +import org.eclipse.jetty.server.handler.ScopedHandler; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.Loader; @@ -141,7 +142,6 @@ public class ServletContextHandler extends ContextHandler else if (parent instanceof HandlerCollection) ((HandlerCollection)parent).addHandler(this); } - /* ------------------------------------------------------------ */ @@ -248,7 +248,18 @@ public class ServletContextHandler extends ContextHandler handler=_sessionHandler; } - setHandler(handler); + // skip any wrapped handlers + HandlerWrapper wrapper=this; + while (wrapper!=handler && wrapper.getHandler() instanceof HandlerWrapper) + wrapper=(HandlerWrapper)wrapper.getHandler(); + + // if we are not already linked + if (wrapper!=handler) + { + if (wrapper.getHandler()!=null ) + throw new IllegalStateException("!ScopedHandler"); + wrapper.setHandler(handler); + } super.startContext(); @@ -398,7 +409,7 @@ public class ServletContextHandler extends ContextHandler /* ------------------------------------------------------------ */ /** - * @param securityHandler The {@link org.eclipse.jetty.server.handler.SecurityHandler} to set on this context. + * @param securityHandler The {@link SecurityHandler} to set on this context. */ public void setSecurityHandler(SecurityHandler securityHandler) { diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 40c71bd05c..9c56b23b8c 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -68,9 +68,6 @@ import org.eclipse.jetty.util.log.Log; * * Unless run as part of a {@link ServletContextHandler} or derivative, the {@link #initialize()} * method must be called manually after start(). - * - * @see org.eclipse.jetty.webapp.WebAppContext - * */ public class ServletHandler extends ScopedHandler { @@ -383,7 +380,7 @@ public class ServletHandler extends ScopedHandler baseRequest.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, ((ServletHolder.Registration)servlet_holder.getRegistration()).getMultipartConfig()); // start manual inline of nextScope(target,baseRequest,request,response); - if (false) + if (never()) nextScope(target,baseRequest,request,response); else if (_nextScope!=null) _nextScope.doScope(target,baseRequest,request, response); @@ -813,8 +810,8 @@ public class ServletHandler extends ScopedHandler /** Convenience method to add a servlet with a servlet mapping. * @param className * @param pathSpec - * @return - * @deprecated + * @return the ServletHolder + * @deprecated use {@link #addServletWithMapping(Class, String)} instead */ public ServletHolder addServlet (String className, String pathSpec) { @@ -842,7 +839,7 @@ public class ServletHandler extends ScopedHandler /* ------------------------------------------------------------ */ /** - * @see {@link #newFilterHolder(Class)} + * @see #newFilterHolder(Class) */ public FilterHolder newFilterHolder(Holder.Source source) { @@ -857,7 +854,7 @@ public class ServletHandler extends ScopedHandler /* ------------------------------------------------------------ */ - /** conveniance method to add a filter. + /** Convenience method to add a filter. * @param filter class of filter to create * @param pathSpec filter mappings for filter * @param dispatches see {@link FilterMapping#setDispatches(int)} @@ -873,7 +870,7 @@ public class ServletHandler extends ScopedHandler } /* ------------------------------------------------------------ */ - /** convenience method to add a filter. + /** Convenience method to add a filter. * @param className of filter * @param pathSpec filter mappings for filter * @param dispatches see {@link FilterMapping#setDispatches(int)} @@ -890,7 +887,7 @@ public class ServletHandler extends ScopedHandler } /* ------------------------------------------------------------ */ - /** conveniance method to add a filter. + /** Convenience method to add a filter. * @param holder filter holder to add * @param pathSpec filter mappings for filter * @param dispatches see {@link FilterMapping#setDispatches(int)} @@ -929,7 +926,8 @@ public class ServletHandler extends ScopedHandler * @param className * @param pathSpec * @param dispatches - * @return + * @return the filter holder created + * @deprecated use {@link #addFilterWithMapping(Class, String, int)} instead */ public FilterHolder addFilter (String className,String pathSpec,EnumSet<DispatcherType> dispatches) { @@ -1371,6 +1369,7 @@ public class ServletHandler extends ScopedHandler b.append(indent); b.append(" +-"); b.append(f); + b.append(f.getFilterHolder().getInitParameters()); b.append('\n'); } } @@ -1383,6 +1382,9 @@ public class ServletHandler extends ScopedHandler b.append(indent); b.append(" +-"); b.append(m); + ServletHolder h = getServlet(m.getServletName()); + if (h!=null) + b.append(h.getInitParameters()); b.append('\n'); } } @@ -1396,6 +1398,7 @@ public class ServletHandler extends ScopedHandler b.append(indent); b.append(" +-[]==>"); b.append(h.getName()); + b.append(h.getInitParameters()); b.append('\n'); } } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java index fc6a496a90..ec1f9cd940 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java @@ -120,7 +120,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope if (servlet==null || servlet instanceof SingleThreadModel) throw new IllegalArgumentException(); - _instance=true; + _extInstance=true; _servlet=servlet; setHeldClass(servlet.getClass()); if (getName()==null) @@ -263,7 +263,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class)) _servlet = new SingleThreadedWrapper(); - if (_instance || _initOnStartup) + if (_extInstance || _initOnStartup) { try { @@ -304,7 +304,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope } } - if (!_instance) + if (!_extInstance) _servlet=null; _config=null; diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java index 80e8d802c1..b0c908e737 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java @@ -28,7 +28,7 @@ public class ServletMapping /* ------------------------------------------------------------ */ /** - * @return Returns the pathSpec. + * @return Returns the pathSpecs. */ public String[] getPathSpecs() { @@ -46,7 +46,7 @@ public class ServletMapping /* ------------------------------------------------------------ */ /** - * @param pathSpec The pathSpec to set. + * @param pathSpecs The pathSpecs to set. */ public void setPathSpecs(String[] pathSpecs) { diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java index 2906a2635c..ce2f6f924a 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java @@ -5,26 +5,28 @@ import java.io.FileOutputStream; import java.io.IOException; import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.StringUtil; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; -public class DefaultServletTest extends TestCase +public class DefaultServletTest { private boolean _runningOnWindows; private Server server; private LocalConnector connector; private ServletContextHandler context; - protected void setUp() throws Exception + @Before + public void init() throws Exception { _runningOnWindows = System.getProperty( "os.name" ).startsWith( "Windows" ); - super.setUp(); - server = new Server(); server.setSendServerVersion(false); @@ -32,7 +34,7 @@ public class DefaultServletTest extends TestCase context = new ServletContextHandler(); context.setContextPath("/context"); - context.setWelcomeFiles(new String[] {"index.html","index.jsp","index.htm"}); + context.setWelcomeFiles(new String[] {"index.html","index.jsp","index.htm"}); server.setHandler(context); server.addConnector(connector); @@ -40,16 +42,14 @@ public class DefaultServletTest extends TestCase server.start(); } - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { - super.tearDown(); - - if (server != null) - { - server.stop(); - } + server.stop(); + server.join(); } + @Test public void testListingWithSession() throws Exception { ServletHolder defholder = context.addServlet(DefaultServlet.class,"/*"); @@ -57,15 +57,15 @@ public class DefaultServletTest extends TestCase defholder.setInitParameter("redirectWelcome","false"); defholder.setInitParameter("gzip","false"); - File testDir = new File("target/tests/" + getName()); + File testDir = new File("target/tests/" + DefaultServletTest.class.getSimpleName()); prepareEmptyTestDir(testDir); /* create some content in the docroot */ File resBase = new File(testDir, "docroot"); - resBase.mkdirs(); - new File(resBase, "one").mkdir(); - new File(resBase, "two").mkdir(); - new File(resBase, "three").mkdir(); + assertTrue(resBase.mkdirs()); + assertTrue(new File(resBase, "one").mkdir()); + assertTrue(new File(resBase, "two").mkdir()); + assertTrue(new File(resBase, "three").mkdir()); String resBasePath = resBase.getAbsolutePath(); defholder.setInitParameter("resourceBase",resBasePath); @@ -84,6 +84,7 @@ public class DefaultServletTest extends TestCase assertResponseNotContains("<script>",response); } + @Test public void testListingXSS() throws Exception { ServletHolder defholder = context.addServlet(DefaultServlet.class,"/*"); @@ -91,15 +92,15 @@ public class DefaultServletTest extends TestCase defholder.setInitParameter("redirectWelcome","false"); defholder.setInitParameter("gzip","false"); - File testDir = new File("target/tests/" + getName()); + File testDir = new File("target/tests/" + DefaultServletTest.class.getSimpleName()); prepareEmptyTestDir(testDir); /* create some content in the docroot */ File resBase = new File(testDir, "docroot"); - resBase.mkdirs(); - new File(resBase, "one").mkdir(); - new File(resBase, "two").mkdir(); - new File(resBase, "three").mkdir(); + assertTrue(resBase.mkdirs()); + assertTrue(new File(resBase, "one").mkdir()); + assertTrue(new File(resBase, "two").mkdir()); + assertTrue(new File(resBase, "three").mkdir()); if ( !_runningOnWindows ) assertTrue("Creating dir 'f??r' (Might not work in Windows)", new File(resBase, "f??r").mkdir()); @@ -126,6 +127,7 @@ public class DefaultServletTest extends TestCase assertResponseNotContains( "<script>", response ); } + @Test public void testListingProperUrlEncoding() throws Exception { ServletHolder defholder = context.addServlet(DefaultServlet.class,"/*"); @@ -133,18 +135,18 @@ public class DefaultServletTest extends TestCase defholder.setInitParameter("redirectWelcome","false"); defholder.setInitParameter("gzip","false"); - File testDir = new File("target/tests/" + getName()); + File testDir = new File("target/tests/" + DefaultServletTest.class.getSimpleName()); prepareEmptyTestDir(testDir); /* create some content in the docroot */ File resBase = new File(testDir, "docroot"); - resBase.mkdirs(); + assertTrue(resBase.mkdirs()); File wackyDir = new File(resBase, "dir;"); // this should not be double-encoded. assertTrue(wackyDir.mkdirs()); - new File(wackyDir, "four").mkdir(); - new File(wackyDir, "five").mkdir(); - new File(wackyDir, "six").mkdir(); + assertTrue(new File(wackyDir, "four").mkdir()); + assertTrue(new File(wackyDir, "five").mkdir()); + assertTrue(new File(wackyDir, "six").mkdir()); /* At this point we have the following * testListingProperUrlEncoding/ @@ -163,7 +165,6 @@ public class DefaultServletTest extends TestCase assertResponseContains("HTTP/1.1 404 Not Found", response); - // Now send request in proper, encoded format. response = connector.getResponses("GET /context/dir%3B/ HTTP/1.0\r\n\r\n"); @@ -178,6 +179,7 @@ public class DefaultServletTest extends TestCase assertResponseContains("/dir%3B/six/",response); } + @Test public void testListingContextBreakout() throws Exception { ServletHolder defholder = context.addServlet(DefaultServlet.class,"/"); @@ -186,12 +188,12 @@ public class DefaultServletTest extends TestCase defholder.setInitParameter("gzip","false"); defholder.setInitParameter("aliases","true"); - File testDir = new File("target/tests/" + getName()); + File testDir = new File("target/tests/" + DefaultServletTest.class.getSimpleName()); prepareEmptyTestDir(testDir); /* create some content in the docroot */ File resBase = new File(testDir, "docroot"); - resBase.mkdirs(); + assertTrue(resBase.mkdirs()); File index = new File(resBase, "index.html"); createFile(index, "<h1>Hello Index</h1>"); @@ -207,7 +209,7 @@ public class DefaultServletTest extends TestCase /* create some content outside of the docroot */ File sekret = new File(testDir, "sekret"); - sekret.mkdirs(); + assertTrue(sekret.mkdirs()); File pass = new File(sekret, "pass"); createFile(pass, "Sssh, you shouldn't be seeing this"); @@ -286,17 +288,15 @@ public class DefaultServletTest extends TestCase assertResponseNotContains("Sssh",response); } - - + @Test public void testWelcome() throws Exception { - File testDir = new File("target/tests/" + getName()); + File testDir = new File("target/tests/" + DefaultServletTest.class.getSimpleName()); prepareEmptyTestDir(testDir); File resBase = new File(testDir, "docroot"); - resBase.mkdirs(); + assertTrue(resBase.mkdirs()); File inde = new File(resBase, "index.htm"); File index = new File(resBase, "index.html"); - String resBasePath = resBase.getAbsolutePath(); @@ -306,41 +306,39 @@ public class DefaultServletTest extends TestCase defholder.setInitParameter("welcomeServlets","false"); defholder.setInitParameter("gzip","false"); defholder.setInitParameter("resourceBase",resBasePath); - - ServletHolder jspholder = context.addServlet(NoJspServlet.class,"*.jsp"); - String response; + ServletHolder jspholder = context.addServlet(NoJspServlet.class,"*.jsp"); - response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); + String response = connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("403",response); createFile(index, "<h1>Hello Index</h1>"); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Index</h1>",response); - + createFile(inde, "<h1>Hello Inde</h1>"); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Index</h1>",response); - index.delete(); + assertTrue(index.delete()); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Inde</h1>",response); - - inde.delete(); + + assertTrue(inde.delete()); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("403",response); - } + @Test public void testWelcomeServlet() throws Exception { - File testDir = new File("target/tests/" + getName()); + File testDir = new File("target/tests/" + DefaultServletTest.class.getSimpleName()); prepareEmptyTestDir(testDir); File resBase = new File(testDir, "docroot"); - resBase.mkdirs(); + assertTrue(resBase.mkdirs()); File inde = new File(resBase, "index.htm"); File index = new File(resBase, "index.html"); - + String resBasePath = resBase.getAbsolutePath(); @@ -350,7 +348,7 @@ public class DefaultServletTest extends TestCase defholder.setInitParameter("welcomeServlets","true"); defholder.setInitParameter("gzip","false"); defholder.setInitParameter("resourceBase",resBasePath); - + ServletHolder jspholder = context.addServlet(NoJspServlet.class,"*.jsp"); String response; @@ -361,30 +359,29 @@ public class DefaultServletTest extends TestCase createFile(index, "<h1>Hello Index</h1>"); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Index</h1>",response); - + createFile(inde, "<h1>Hello Inde</h1>"); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Index</h1>",response); - index.delete(); + assertTrue(index.delete()); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Inde</h1>",response); - - inde.delete(); + + assertTrue(inde.delete()); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("JSP support not configured",response); - } + @Test public void testWelcomeExactServlet() throws Exception { - File testDir = new File("target/tests/" + getName()); + File testDir = new File("target/tests/" + DefaultServletTest.class.getSimpleName()); prepareEmptyTestDir(testDir); File resBase = new File(testDir, "docroot"); - resBase.mkdirs(); + assertTrue(resBase.mkdirs()); File inde = new File(resBase, "index.htm"); File index = new File(resBase, "index.html"); - String resBasePath = resBase.getAbsolutePath(); @@ -394,7 +391,7 @@ public class DefaultServletTest extends TestCase defholder.setInitParameter("welcomeServlets","exact"); defholder.setInitParameter("gzip","false"); defholder.setInitParameter("resourceBase",resBasePath); - + ServletHolder jspholder = context.addServlet(NoJspServlet.class,"*.jsp"); context.addServlet(jspholder,"/index.jsp"); @@ -406,46 +403,42 @@ public class DefaultServletTest extends TestCase createFile(index, "<h1>Hello Index</h1>"); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Index</h1>",response); - + createFile(inde, "<h1>Hello Inde</h1>"); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Index</h1>",response); - index.delete(); + assertTrue(index.delete()); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("<h1>Hello Inde</h1>",response); - - inde.delete(); + + assertTrue(inde.delete()); response= connector.getResponses("GET /context/ HTTP/1.0\r\n\r\n"); assertResponseContains("JSP support not configured",response); - } + @Test public void testRangeRequests() throws Exception { - File testDir = new File("target/tests/" + getName()); + File testDir = new File("target/tests/" + DefaultServletTest.class.getSimpleName()); prepareEmptyTestDir(testDir); File resBase = new File(testDir, "docroot"); - resBase.mkdirs(); + assertTrue(resBase.mkdirs()); File data = new File(resBase, "data.txt"); createFile(data,"01234567890123456789012345678901234567890123456789012345678901234567890123456789"); String resBasePath = resBase.getAbsolutePath(); - - ServletHolder defholder = context.addServlet(DefaultServlet.class,"/"); defholder.setInitParameter("acceptRanges","true"); defholder.setInitParameter("resourceBase",resBasePath); - - String response; - response= connector.getResponses( - "GET /context/data.txt HTTP/1.1\r\n"+ - "Host: localhost\r\n"+ - "\r\n"); + String response = connector.getResponses( + "GET /context/data.txt HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"); assertResponseContains("200 OK",response); assertResponseContains("Accept-Ranges: bytes",response); - + response= connector.getResponses( "GET /context/data.txt HTTP/1.1\r\n"+ "Host: localhost\r\n"+ @@ -486,7 +479,7 @@ public class DefaultServletTest extends TestCase assertResponseContains("Content-Range: bytes 70-79/80",response); assertResponseContains("Content-Length: "+body.length(),response); assertTrue(body.endsWith(boundary+"--\r\n")); - + response= connector.getResponses( "GET /context/data.txt HTTP/1.1\r\n"+ "Host: localhost\r\n"+ @@ -503,10 +496,8 @@ public class DefaultServletTest extends TestCase assertResponseContains("Content-Range: bytes 70-79/80",response); assertResponseContains("Content-Length: "+body.length(),response); assertTrue(body.endsWith(boundary+"--\r\n")); - } - private void createFile(File file, String str) throws IOException { FileOutputStream out = null; @@ -527,7 +518,7 @@ public class DefaultServletTest extends TestCase } else { - testdir.mkdirs(); + assertTrue(testdir.mkdirs()); } assertTrue("test dir should exists",testdir.exists()); @@ -538,9 +529,7 @@ public class DefaultServletTest extends TestCase private boolean isEmpty(File dir) { if (!dir.isDirectory()) - { return true; - } return dir.list().length == 0; } @@ -548,10 +537,8 @@ public class DefaultServletTest extends TestCase private void emptyDir(File dir) { File entries[] = dir.listFiles(); - for (int i = 0; i < entries.length; i++) - { - deletePath(entries[i]); - } + for (File entry : entries) + deletePath(entry); } private void deletePath(File path) @@ -559,10 +546,8 @@ public class DefaultServletTest extends TestCase if (path.isDirectory()) { File entries[] = path.listFiles(); - for (int i = 0; i < entries.length; i++) - { - deletePath(entries[i]); - } + for (File entry : entries) + deletePath(entry); } assertTrue("Deleting: " + path.getAbsolutePath(),path.delete()); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java index 7c041fa71d..78a84a61ac 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java @@ -4,21 +4,19 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlet; - import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.List; - import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletException; @@ -26,19 +24,24 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.Dispatcher; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class DispatcherTest extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class DispatcherTest { - private Server _server = new Server(); + private Server _server; private LocalConnector _connector; private ServletContextHandler _context; - protected void setUp() throws Exception + @Before + public void init() throws Exception { _server = new Server(); _server.setSendServerVersion(false); @@ -51,6 +54,14 @@ public class DispatcherTest extends TestCase _server.start(); } + @After + public void destroy() throws Exception + { + _server.stop(); + _server.join(); + } + + @Test public void testForward() throws Exception { _context.addServlet(ForwardServlet.class, "/ForwardServlet/*"); @@ -63,10 +74,11 @@ public class DispatcherTest extends TestCase "\r\n"; String responses = _connector.getResponses("GET /context/ForwardServlet?do=assertforward&do=more&test=1 HTTP/1.1\n" + "Host: localhost\n\n"); - - assertEquals(expected, responses); + + assertEquals(expected, responses); } - + + @Test public void testInclude() throws Exception { _context.addServlet(IncludeServlet.class, "/IncludeServlet/*"); @@ -78,10 +90,11 @@ public class DispatcherTest extends TestCase "\r\n"; String responses = _connector.getResponses("GET /context/IncludeServlet?do=assertinclude&do=more&test=1 HTTP/1.1\n" + "Host: localhost\n\n"); - - assertEquals(expected, responses); + + assertEquals(expected, responses); } - + + @Test public void testForwardThenInclude() throws Exception { _context.addServlet(ForwardServlet.class, "/ForwardServlet/*"); @@ -94,16 +107,17 @@ public class DispatcherTest extends TestCase "\r\n"; String responses = _connector.getResponses("GET /context/ForwardServlet/forwardpath?do=include HTTP/1.1\n" + "Host: localhost\n\n"); - + assertEquals(expected, responses); } - + + @Test public void testIncludeThenForward() throws Exception { _context.addServlet(IncludeServlet.class, "/IncludeServlet/*"); _context.addServlet(ForwardServlet.class, "/ForwardServlet/*"); _context.addServlet(AssertIncludeForwardServlet.class, "/AssertIncludeForwardServlet/*"); - + String expected= "HTTP/1.1 200 OK\r\n"+ @@ -113,16 +127,16 @@ public class DispatcherTest extends TestCase "\r\n"; String responses = _connector.getResponses("GET /context/IncludeServlet/includepath?do=forward HTTP/1.1\n" + "Host: localhost\n\n"); - + assertEquals(expected, responses); } - - public static class ForwardServlet extends HttpServlet implements Servlet + + public static class ForwardServlet extends HttpServlet implements Servlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestDispatcher dispatcher = null; - + if(request.getParameter("do").equals("include")) dispatcher = getServletContext().getRequestDispatcher("/IncludeServlet/includepath?do=assertforwardinclude"); else if(request.getParameter("do").equals("assertincludeforward")) @@ -130,15 +144,15 @@ public class DispatcherTest extends TestCase else if(request.getParameter("do").equals("assertforward")) dispatcher = getServletContext().getRequestDispatcher("/AssertForwardServlet?do=end&do=the"); dispatcher.forward(request, response); - } + } } - - public static class IncludeServlet extends HttpServlet implements Servlet + + public static class IncludeServlet extends HttpServlet implements Servlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestDispatcher dispatcher = null; - + if(request.getParameter("do").equals("forward")) dispatcher = getServletContext().getRequestDispatcher("/ForwardServlet/forwardpath?do=assertincludeforward"); else if(request.getParameter("do").equals("assertforwardinclude")) @@ -146,7 +160,7 @@ public class DispatcherTest extends TestCase else if(request.getParameter("do").equals("assertinclude")) dispatcher = getServletContext().getRequestDispatcher("/AssertIncludeServlet?do=end&do=the"); dispatcher.include(request, response); - } + } } public static class AssertForwardServlet extends HttpServlet implements Servlet @@ -159,29 +173,24 @@ public class DispatcherTest extends TestCase assertEquals( null, request.getAttribute(Dispatcher.FORWARD_PATH_INFO)); assertEquals( "do=assertforward&do=more&test=1", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING) ); - - List expectedAttributeNames = Arrays.asList(new String[] { - Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH, - Dispatcher.FORWARD_SERVLET_PATH, Dispatcher.FORWARD_QUERY_STRING - }); + List expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH, + Dispatcher.FORWARD_SERVLET_PATH, Dispatcher.FORWARD_QUERY_STRING); List requestAttributeNames = Collections.list(request.getAttributeNames()); assertTrue(requestAttributeNames.containsAll(expectedAttributeNames)); - - + assertEquals(null, request.getPathInfo()); assertEquals(null, request.getPathTranslated()); assertEquals("do=end&do=the&test=1", request.getQueryString()); assertEquals("/context/AssertForwardServlet", request.getRequestURI()); assertEquals("/context", request.getContextPath()); assertEquals("/AssertForwardServlet", request.getServletPath()); - + response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); - } } - public static class AssertIncludeServlet extends HttpServlet implements Servlet + public static class AssertIncludeServlet extends HttpServlet implements Servlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -189,34 +198,28 @@ public class DispatcherTest extends TestCase assertEquals( "/context", request.getAttribute(Dispatcher.INCLUDE_CONTEXT_PATH) ); assertEquals( "/AssertIncludeServlet", request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH)); assertEquals( null, request.getAttribute(Dispatcher.INCLUDE_PATH_INFO)); - assertEquals( "do=end&do=the", request.getAttribute(Dispatcher.INCLUDE_QUERY_STRING)); - - List expectedAttributeNames = Arrays.asList(new String[] { - Dispatcher.INCLUDE_REQUEST_URI, Dispatcher.INCLUDE_CONTEXT_PATH, - Dispatcher.INCLUDE_SERVLET_PATH, Dispatcher.INCLUDE_QUERY_STRING - }); + assertEquals( "do=end&do=the", request.getAttribute(Dispatcher.INCLUDE_QUERY_STRING)); + + List expectedAttributeNames = Arrays.asList(Dispatcher.INCLUDE_REQUEST_URI, Dispatcher.INCLUDE_CONTEXT_PATH, + Dispatcher.INCLUDE_SERVLET_PATH, Dispatcher.INCLUDE_QUERY_STRING); List requestAttributeNames = Collections.list(request.getAttributeNames()); assertTrue(requestAttributeNames.containsAll(expectedAttributeNames)); - - assertEquals(null, request.getPathInfo()); assertEquals(null, request.getPathTranslated()); assertEquals("do=assertinclude&do=more&test=1", request.getQueryString()); assertEquals("/context/IncludeServlet", request.getRequestURI()); assertEquals("/context", request.getContextPath()); assertEquals("/IncludeServlet", request.getServletPath()); - + response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); - } } - - - public static class AssertForwardIncludeServlet extends HttpServlet implements Servlet + + public static class AssertForwardIncludeServlet extends HttpServlet implements Servlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // include doesn't hide forward assertEquals( "/context/ForwardServlet/forwardpath", request.getAttribute(Dispatcher.FORWARD_REQUEST_URI)); @@ -224,64 +227,56 @@ public class DispatcherTest extends TestCase assertEquals( "/ForwardServlet", request.getAttribute(Dispatcher.FORWARD_SERVLET_PATH)); assertEquals( "/forwardpath", request.getAttribute(Dispatcher.FORWARD_PATH_INFO)); assertEquals( "do=include", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING) ); - + assertEquals( "/context/AssertForwardIncludeServlet/assertpath", request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI)); assertEquals( "/context", request.getAttribute(Dispatcher.INCLUDE_CONTEXT_PATH) ); assertEquals( "/AssertForwardIncludeServlet", request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH)); assertEquals( "/assertpath", request.getAttribute(Dispatcher.INCLUDE_PATH_INFO)); - assertEquals( "do=end", request.getAttribute(Dispatcher.INCLUDE_QUERY_STRING)); - - - List expectedAttributeNames = Arrays.asList(new String[] { - Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH, Dispatcher.FORWARD_SERVLET_PATH, - Dispatcher.FORWARD_PATH_INFO, Dispatcher.FORWARD_QUERY_STRING, - Dispatcher.INCLUDE_REQUEST_URI, Dispatcher.INCLUDE_CONTEXT_PATH, Dispatcher.INCLUDE_SERVLET_PATH, - Dispatcher.INCLUDE_PATH_INFO, Dispatcher.INCLUDE_QUERY_STRING - }); + assertEquals( "do=end", request.getAttribute(Dispatcher.INCLUDE_QUERY_STRING)); + + List expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH, Dispatcher.FORWARD_SERVLET_PATH, + Dispatcher.FORWARD_PATH_INFO, Dispatcher.FORWARD_QUERY_STRING, + Dispatcher.INCLUDE_REQUEST_URI, Dispatcher.INCLUDE_CONTEXT_PATH, Dispatcher.INCLUDE_SERVLET_PATH, + Dispatcher.INCLUDE_PATH_INFO, Dispatcher.INCLUDE_QUERY_STRING); List requestAttributeNames = Collections.list(request.getAttributeNames()); - assertTrue(requestAttributeNames.containsAll(expectedAttributeNames)); - - + assertTrue(requestAttributeNames.containsAll(expectedAttributeNames)); + assertEquals("/includepath", request.getPathInfo()); assertEquals(null, request.getPathTranslated()); assertEquals("do=assertforwardinclude", request.getQueryString()); assertEquals("/context/IncludeServlet/includepath", request.getRequestURI()); assertEquals("/context", request.getContextPath()); assertEquals("/IncludeServlet", request.getServletPath()); - + response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); - } + } } - + public static class AssertIncludeForwardServlet extends HttpServlet implements Servlet { - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // forward hides include assertEquals( null, request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI)); assertEquals( null, request.getAttribute(Dispatcher.INCLUDE_CONTEXT_PATH) ); assertEquals( null, request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH)); assertEquals( null, request.getAttribute(Dispatcher.INCLUDE_PATH_INFO)); - assertEquals( null, request.getAttribute(Dispatcher.INCLUDE_QUERY_STRING)); + assertEquals( null, request.getAttribute(Dispatcher.INCLUDE_QUERY_STRING)); assertEquals( "/context/IncludeServlet/includepath", request.getAttribute(Dispatcher.FORWARD_REQUEST_URI)); assertEquals( "/context", request.getAttribute(Dispatcher.FORWARD_CONTEXT_PATH) ); assertEquals( "/IncludeServlet", request.getAttribute(Dispatcher.FORWARD_SERVLET_PATH)); assertEquals( "/includepath", request.getAttribute(Dispatcher.FORWARD_PATH_INFO)); assertEquals( "do=forward", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING) ); - - - List expectedAttributeNames = Arrays.asList(new String[] { - Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH, Dispatcher.FORWARD_SERVLET_PATH, - Dispatcher.FORWARD_PATH_INFO, Dispatcher.FORWARD_QUERY_STRING, - }); + + List expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH, Dispatcher.FORWARD_SERVLET_PATH, + Dispatcher.FORWARD_PATH_INFO, Dispatcher.FORWARD_QUERY_STRING); List requestAttributeNames = Collections.list(request.getAttributeNames()); assertTrue(requestAttributeNames.containsAll(expectedAttributeNames)); - - + assertEquals("/assertpath", request.getPathInfo()); - assertEquals(null, request.getPathTranslated()); + assertEquals(null, request.getPathTranslated()); assertEquals("do=end", request.getQueryString()); assertEquals("/context/AssertIncludeForwardServlet/assertpath", request.getRequestURI()); assertEquals("/context", request.getContextPath()); @@ -289,7 +284,6 @@ public class DispatcherTest extends TestCase response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); - } + } } - } diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/InvokerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/InvokerTest.java index e08626e684..1456e80cb5 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/InvokerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/InvokerTest.java @@ -14,46 +14,54 @@ package org.eclipse.jetty.servlet; import java.io.IOException; - import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; /** * - * */ -public class InvokerTest extends TestCase +public class InvokerTest { - Server _server; - LocalConnector _connector; - ServletContextHandler _context; + private Server _server; + private LocalConnector _connector; - protected void setUp() throws Exception + @Before + public void init() throws Exception { - super.setUp(); _server = new Server(); _connector = new LocalConnector(); - _context = new ServletContextHandler(ServletContextHandler.SESSIONS); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); _server.setSendServerVersion(false); _server.addConnector(_connector); - _server.setHandler(_context); + _server.setHandler(context); - _context.setContextPath("/"); + context.setContextPath("/"); - ServletHolder holder = _context.addServlet(Invoker.class, "/servlet/*"); + ServletHolder holder = context.addServlet(Invoker.class, "/servlet/*"); holder.setInitParameter("nonContextServlets","true"); _server.start(); } + @After + public void destroy() throws Exception + { + _server.stop(); + _server.join(); + } + + @Test public void testInvoker() throws Exception { String requestPath = "/servlet/"+TestServlet.class.getName(); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/StatisticsServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/StatisticsServletTest.java index 12b55e7a51..7154d32aca 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/StatisticsServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/StatisticsServletTest.java @@ -4,31 +4,31 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlet; import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.StatisticsHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class StatisticsServletTest extends TestCase +public class StatisticsServletTest { - Server server; - LocalConnector connector; - ServletContextHandler context; - - protected void setUp() throws Exception - { - super.setUp(); + private Server server; + private LocalConnector connector; + private ServletContextHandler context; + @Before + public void init() throws Exception + { server = new Server(); server.setSendServerVersion(false); context = new ServletContextHandler(); @@ -37,25 +37,22 @@ public class StatisticsServletTest extends TestCase holder.setServlet(new org.eclipse.jetty.servlet.StatisticsServlet()); holder.setInitParameter("restrictToLocalhost", "false"); context.addServlet(holder, "/stats"); - + server.setHandler(context); connector = new LocalConnector(); server.addConnector(connector); } - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { - super.tearDown(); - - if (server != null) - { - server.stop(); - } + server.stop(); + server.join(); } - - + + @Test public void testNoHandler () throws Exception - { + { server.start(); StringBuffer req1 = new StringBuffer(); @@ -64,25 +61,25 @@ public class StatisticsServletTest extends TestCase req1.append("\n"); String response = connector.getResponses(req1.toString()); - assertResponseContains("503", response); + assertResponseContains("503", response); } - + + @Test public void testWithHandler () throws Exception { StatisticsHandler statsHandler = new StatisticsHandler(); statsHandler.setHandler(context); server.setHandler(statsHandler); server.start(); - + StringBuffer req1 = new StringBuffer(); req1.append("GET /stats HTTP/1.1\n"); req1.append("Host: localhost\n"); req1.append("\n"); - + String response = connector.getResponses(req1.toString()); - assertResponseContains("Statistics gathering started ", response); + assertResponseContains("Statistics gathering started ", response); } - private void assertResponseContains(String expected, String response) { diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index 32332a0831..ace6f655b8 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -39,11 +39,12 @@ </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.servlets.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> @@ -51,6 +52,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java index 7cf2859f75..694267d847 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java @@ -162,7 +162,7 @@ public class CrossOriginFilter implements Filter { String origin = request.getHeader(ORIGIN_HEADER); // Is it a cross origin request ? - if (origin != null) + if (origin != null && isEnabled(request)) { if (originMatches(origin)) { @@ -186,6 +186,18 @@ public class CrossOriginFilter implements Filter chain.doFilter(request, response); } + protected boolean isEnabled(HttpServletRequest request) + { + // WebSocket clients such as Chrome 5 implement a version of the WebSocket + // protocol that does not accept extra response headers on the upgrade response + if ("Upgrade".equalsIgnoreCase(request.getHeader("Connection")) && + "WebSocket".equalsIgnoreCase(request.getHeader("Upgrade"))) + { + return false; + } + return true; + } + private boolean originMatches(String origin) { if (anyOriginAllowed) return true; diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java index 5043905a51..a678441988 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlets; @@ -21,7 +21,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; - import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -38,12 +37,13 @@ import javax.servlet.http.HttpSessionBindingListener; import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationSupport; +import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.Timeout; /** * Denial of Service filter - * + * * <p> * This filter is based on the {@link QoSFilter}. it is useful for limiting * exposure to abuse from request flooding, whether malicious, or as a result of @@ -61,35 +61,53 @@ import org.eclipse.jetty.util.thread.Timeout; * The {@link #extractUserId(ServletRequest request)} function should be * implemented, in order to uniquely identify authenticated users. * <p> - * The following init parameters control the behavior of the filter: - * - * maxRequestsPerSec the maximum number of requests from a connection per - * second. Requests in excess of this are first delayed, - * then throttled. - * - * delayMs is the delay given to all requests over the rate limit, - * before they are considered at all. -1 means just reject request, - * 0 means no delay, otherwise it is the delay. - * - * maxWaitMs how long to blocking wait for the throttle semaphore. - * - * throttledRequests is the number of requests over the rate limit able to be - * considered at once. - * - * throttleMs how long to async wait for semaphore. + * The following init parameters control the behavior of the filter:<dl> + * + * <dt>maxRequestsPerSec</dt> + * <dd>the maximum number of requests from a connection per + * second. Requests in excess of this are first delayed, + * then throttled.</dd> + * + * <dt>delayMs</dt> + * <dd>is the delay given to all requests over the rate limit, + * before they are considered at all. -1 means just reject request, + * 0 means no delay, otherwise it is the delay.</dd> + * + * <dt>maxWaitMs</dt> + * <dd>how long to blocking wait for the throttle semaphore.</dd> + * + * <dt>throttledRequests</dt> + * <dd>is the number of requests over the rate limit able to be + * considered at once.</dd> + * + * <dt>throttleMs</dt> + * <dd>how long to async wait for semaphore.</dd> + * + * <dt>maxRequestMs</dt> + * <dd>how long to allow this request to run.</dd> + * + * <dt>maxIdleTrackerMs</dt> + * <dd>how long to keep track of request rates for a connection, + * before deciding that the user has gone away, and discarding it</dd> + * + * <dt>insertHeaders</dt> + * <dd>if true , insert the DoSFilter headers into the response. Defaults to true.</dd> + * + * <dt>trackSessions</dt> + * <dd>if true, usage rate is tracked by session if a session exists. Defaults to true.</dd> + * + * <dt>remotePort</dt> + * <dd>if true and session tracking is not used, then rate is tracked by IP+port (effectively connection). Defaults to false.</dd> + * + * <dt>ipWhitelist</dt> + * <dd>a comma-separated list of IP addresses that will not be rate limited</dd> * - * maxRequestMs how long to allow this request to run. - * - * maxIdleTrackerMs how long to keep track of request rates for a connection, - * before deciding that the user has gone away, and discarding it - * - * insertHeaders if true , insert the DoSFilter headers into the response. Defaults to true. - * - * trackSessions if true, usage rate is tracked by session if a session exists. Defaults to true. - * - * remotePort if true and session tracking is not used, then rate is tracked by IP+port (effectively connection). Defaults to false. - * - * ipWhitelist a comma-separated list of IP addresses that will not be rate limited + * <dt>managedAttr</dt> + * <dd>if set to true, then this servlet is set as a {@link ServletContext} attribute with the + * filter name as the attribute name. This allows context external mechanism (eg JMX via {@link ContextHandler#MANAGED_ATTRIBUTES}) to + * manage the configuration of the filter.</dd> + * </dl> + * </p> */ public class DoSFilter implements Filter @@ -105,6 +123,7 @@ public class DoSFilter implements Filter final static long __DEFAULT_MAX_REQUEST_MS_INIT_PARAM=30000L; final static long __DEFAULT_MAX_IDLE_TRACKER_MS_INIT_PARAM=30000L; + final static String MANAGED_ATTR_INIT_PARAM="managedAttr"; final static String MAX_REQUESTS_PER_S_INIT_PARAM = "maxRequestsPerSec"; final static String DELAY_MS_INIT_PARAM = "delayMs"; final static String THROTTLED_REQUESTS_INIT_PARAM = "throttledRequests"; @@ -124,22 +143,25 @@ public class DoSFilter implements Filter ServletContext _context; + protected String _name; protected long _delayMs; protected long _throttleMs; - protected long _waitMs; + protected long _maxWaitMs; protected long _maxRequestMs; protected long _maxIdleTrackerMs; protected boolean _insertHeaders; protected boolean _trackSessions; protected boolean _remotePort; + protected int _throttledRequests; protected Semaphore _passes; protected Queue<Continuation>[] _queue; protected ContinuationListener[] _listener; protected int _maxRequestsPerSec; protected final ConcurrentHashMap<String, RateTracker> _rateTrackers=new ConcurrentHashMap<String, RateTracker>(); - private HashSet<String> _whitelist; - + protected String _whitelistStr; + private final HashSet<String> _whitelist = new HashSet<String>(); + private final Timeout _requestTimeoutQ = new Timeout(); private final Timeout _trackerTimeoutQ = new Timeout(); @@ -155,12 +177,13 @@ public class DoSFilter implements Filter for (int p = 0; p < _queue.length; p++) { _queue[p] = new ConcurrentLinkedQueue<Continuation>(); - + final int priority=p; _listener[p] = new ContinuationListener() { public void onComplete(Continuation continuation) - {} + { + } public void onTimeout(Continuation continuation) { @@ -169,6 +192,8 @@ public class DoSFilter implements Filter }; } + _rateTrackers.clear(); + int baseRateLimit = __DEFAULT_MAX_REQUESTS_PER_SEC; if (filterConfig.getInitParameter(MAX_REQUESTS_PER_S_INIT_PARAM) != null) baseRateLimit = Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_PER_S_INIT_PARAM)); @@ -179,15 +204,16 @@ public class DoSFilter implements Filter delay = Integer.parseInt(filterConfig.getInitParameter(DELAY_MS_INIT_PARAM)); _delayMs = delay; - int passes = __DEFAULT_THROTTLE; + int throttledRequests = __DEFAULT_THROTTLE; if (filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM) != null) - passes = Integer.parseInt(filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM)); - _passes = new Semaphore(passes,true); + throttledRequests = Integer.parseInt(filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM)); + _passes = new Semaphore(throttledRequests,true); + _throttledRequests = throttledRequests; long wait = __DEFAULT_WAIT_MS; if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM) != null) wait = Integer.parseInt(filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM)); - _waitMs = wait; + _maxWaitMs = wait; long suspend = __DEFAULT_THROTTLE_MS; if (filterConfig.getInitParameter(THROTTLE_MS_INIT_PARAM) != null) @@ -203,39 +229,27 @@ public class DoSFilter implements Filter if (filterConfig.getInitParameter(MAX_IDLE_TRACKER_MS_INIT_PARAM) != null ) maxIdleTrackerMs = Long.parseLong(filterConfig.getInitParameter(MAX_IDLE_TRACKER_MS_INIT_PARAM)); _maxIdleTrackerMs = maxIdleTrackerMs; - - String whitelistString = ""; + + _whitelistStr = ""; if (filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM) !=null ) - whitelistString = filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM); - - // empty - if (whitelistString.length() == 0 ) - _whitelist = new HashSet<String>(); - else - { - StringTokenizer tokenizer = new StringTokenizer(whitelistString, ","); - _whitelist = new HashSet<String>(tokenizer.countTokens()); - while (tokenizer.hasMoreTokens()) - _whitelist.add(tokenizer.nextToken().trim()); - - Log.info("Whitelisted IP addresses: {}", _whitelist.toString()); - } + _whitelistStr = filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM); + initWhitelist(); String tmp = filterConfig.getInitParameter(INSERT_HEADERS_INIT_PARAM); - _insertHeaders = tmp==null || Boolean.parseBoolean(tmp); - + _insertHeaders = tmp==null || Boolean.parseBoolean(tmp); + tmp = filterConfig.getInitParameter(TRACK_SESSIONS_INIT_PARAM); _trackSessions = tmp==null || Boolean.parseBoolean(tmp); - + tmp = filterConfig.getInitParameter(REMOTE_PORT_INIT_PARAM); _remotePort = tmp!=null&& Boolean.parseBoolean(tmp); _requestTimeoutQ.setNow(); _requestTimeoutQ.setDuration(_maxRequestMs); - + _trackerTimeoutQ.setNow(); _trackerTimeoutQ.setDuration(_maxIdleTrackerMs); - + _running=true; _timerThread = (new Thread() { @@ -245,12 +259,15 @@ public class DoSFilter implements Filter { while (_running) { + long now; synchronized (_requestTimeoutQ) { - _requestTimeoutQ.setNow(); + now = _requestTimeoutQ.setNow(); _requestTimeoutQ.tick(); - - _trackerTimeoutQ.setNow(_requestTimeoutQ.getNow()); + } + synchronized (_trackerTimeoutQ) + { + _trackerTimeoutQ.setNow(now); _trackerTimeoutQ.tick(); } try @@ -270,26 +287,29 @@ public class DoSFilter implements Filter } }); _timerThread.start(); + + if (_context!=null && Boolean.parseBoolean(filterConfig.getInitParameter(MANAGED_ATTR_INIT_PARAM))) + _context.setAttribute(filterConfig.getFilterName(),this); } - + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain) throws IOException, ServletException { final HttpServletRequest srequest = (HttpServletRequest)request; final HttpServletResponse sresponse = (HttpServletResponse)response; - + final long now=_requestTimeoutQ.getNow(); - + // Look for the rate tracker for this request RateTracker tracker = (RateTracker)request.getAttribute(__TRACKER); if (tracker==null) { // This is the first time we have seen this request. - + // get a rate tracker associated with this request, and record one hit tracker = getRateTracker(request); - + // Calculate the rate and check it is over the allowed limit final boolean overRateLimit = tracker.isRateExceeded(now); @@ -298,55 +318,66 @@ public class DoSFilter implements Filter { doFilterChain(filterchain,srequest,sresponse); return; - } - + } + // We are over the limit. Log.warn("DOS ALERT: ip="+srequest.getRemoteAddr()+",session="+srequest.getRequestedSessionId()+",user="+srequest.getUserPrincipal()); - + // So either reject it, delay it or throttle it switch((int)_delayMs) { - case -1: + case -1: { // Reject this request if (_insertHeaders) ((HttpServletResponse)response).addHeader("DoSFilter","unavailable"); + ((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } case 0: { - // fall through to throttle code + // fall through to throttle code request.setAttribute(__TRACKER,tracker); break; } default: - { + { // insert a delay before throttling the request if (_insertHeaders) ((HttpServletResponse)response).addHeader("DoSFilter","delayed"); Continuation continuation = ContinuationSupport.getContinuation(request); request.setAttribute(__TRACKER,tracker); - continuation.setTimeout(_delayMs); + if (_delayMs > 0) + continuation.setTimeout(_delayMs); + continuation.addContinuationListener(new ContinuationListener() + { + public void onComplete(Continuation continuation) + { + } + + public void onTimeout(Continuation continuation) + { + } + }); continuation.suspend(); return; } } } - // Throttle the request boolean accepted = false; try { // check if we can afford to accept another request at this time - accepted = _passes.tryAcquire(_waitMs,TimeUnit.MILLISECONDS); + accepted = _passes.tryAcquire(_maxWaitMs,TimeUnit.MILLISECONDS); if (!accepted) { // we were not accepted, so either we suspend to wait,or if we were woken up we insist or we fail final Continuation continuation = ContinuationSupport.getContinuation(request); - + Boolean throttled = (Boolean)request.getAttribute(__THROTTLED); if (throttled!=Boolean.TRUE && _throttleMs>0) { @@ -370,12 +401,12 @@ public class DoSFilter implements Filter accepted = true; } } - + // if we were accepted (either immediately or after throttle) - if (accepted) + if (accepted) // call the chain doFilterChain(filterchain,srequest,sresponse); - else + else { // fail the request if (_insertHeaders) @@ -388,6 +419,10 @@ public class DoSFilter implements Filter _context.log("DoS",e); ((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); } + catch (Exception e) + { + e.printStackTrace(); + } finally { if (accepted) @@ -414,11 +449,11 @@ public class DoSFilter implements Filter * @throws IOException * @throws ServletException */ - protected void doFilterChain(FilterChain chain, final HttpServletRequest request, final HttpServletResponse response) + protected void doFilterChain(FilterChain chain, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { final Thread thread=Thread.currentThread(); - + final Timeout.Task requestTimeout = new Timeout.Task() { public void expired() @@ -458,7 +493,7 @@ public class DoSFilter implements Filter { response.setHeader("Connection", "close"); } - try + try { try { @@ -473,14 +508,14 @@ public class DoSFilter implements Filter { Log.warn(e); } - + // interrupt the handling thread thread.interrupt(); } - + /** * Get priority for this request, based on user type - * + * * @param request * @param tracker * @return priority @@ -507,39 +542,44 @@ public class DoSFilter implements Filter * track of this connection's request rate. If this is not the first request * from this connection, return the existing object with the stored stats. * If it is the first request, then create a new request tracker. - * + * * Assumes that each connection has an identifying characteristic, and goes * through them in order, taking the first that matches: user id (logged * in), session id, client IP address. Unidentifiable connections are lumped * into one. - * + * * When a session expires, its rate tracker is automatically deleted. - * + * * @param request * @return the request rate tracker for the current connection */ public RateTracker getRateTracker(ServletRequest request) { HttpServletRequest srequest = (HttpServletRequest)request; + HttpSession session=srequest.getSession(false); - String loadId; + String loadId = extractUserId(request); final int type; - - loadId = extractUserId(request); - HttpSession session=srequest.getSession(false); - if (_trackSessions && session!=null && !session.isNew()) + if (loadId != null) { - loadId=session.getId(); - type = USER_SESSION; + type = USER_AUTH; } else { - loadId = _remotePort?(request.getRemoteAddr()+request.getRemotePort()):request.getRemoteAddr(); - type = USER_IP; + if (_trackSessions && session!=null && !session.isNew()) + { + loadId=session.getId(); + type = USER_SESSION; + } + else + { + loadId = _remotePort?(request.getRemoteAddr()+request.getRemotePort()):request.getRemoteAddr(); + type = USER_IP; + } } RateTracker tracker=_rateTrackers.get(loadId); - + if (tracker==null) { RateTracker t; @@ -551,11 +591,11 @@ public class DoSFilter implements Filter { t = new RateTracker(loadId,type,_maxRequestsPerSec); } - + tracker=_rateTrackers.putIfAbsent(loadId,t); if (tracker==null) tracker=t; - + if (type == USER_IP) { // USER_IP expiration from _rateTrackers is handled by the _trackerTimeoutQ @@ -579,14 +619,19 @@ public class DoSFilter implements Filter synchronized (_requestTimeoutQ) { _requestTimeoutQ.cancelAll(); + } + synchronized (_trackerTimeoutQ) + { _trackerTimeoutQ.cancelAll(); } + _rateTrackers.clear(); + _whitelist.clear(); } /** * Returns the user id, used to track this connection. * This SHOULD be overridden by subclasses. - * + * * @param request * @return a unique user id, if logged in; otherwise null. */ @@ -595,6 +640,281 @@ public class DoSFilter implements Filter return null; } + /* ------------------------------------------------------------ */ + /** + * Initialize the IP address whitelist + */ + protected void initWhitelist() + { + _whitelist.clear(); + StringTokenizer tokenizer = new StringTokenizer(_whitelistStr, ","); + while (tokenizer.hasMoreTokens()) + _whitelist.add(tokenizer.nextToken().trim()); + + Log.info("Whitelisted IP addresses: {}", _whitelist.toString()); + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum number of requests from a connection per + * second. Requests in excess of this are first delayed, + * then throttled. + * + * @return maximum number of requests + */ + public int getMaxRequestsPerSec() + { + return _maxRequestsPerSec; + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum number of requests from a connection per + * second. Requests in excess of this are first delayed, + * then throttled. + * + * @param value maximum number of requests + */ + public void setMaxRequestsPerSec(int value) + { + _maxRequestsPerSec = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get delay (in milliseconds) that is applied to all requests + * over the rate limit, before they are considered at all. + */ + public long getDelayMs() + { + return _delayMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set delay (in milliseconds) that is applied to all requests + * over the rate limit, before they are considered at all. + * + * @param value delay (in milliseconds), 0 - no delay, -1 - reject request + */ + public void setDelayMs(long value) + { + _delayMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum amount of time (in milliseconds) the filter will + * blocking wait for the throttle semaphore. + * + * @return maximum wait time + */ + public long getMaxWaitMs() + { + return _maxWaitMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set maximum amount of time (in milliseconds) the filter will + * blocking wait for the throttle semaphore. + * + * @param value maximum wait time + */ + public void setMaxWaitMs(long value) + { + _maxWaitMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get number of requests over the rate limit able to be + * considered at once. + * + * @return number of requests + */ + public long getThrottledRequests() + { + return _throttledRequests; + } + + /* ------------------------------------------------------------ */ + /** + * Set number of requests over the rate limit able to be + * considered at once. + * + * @param value number of requests + */ + public void setThrottledRequests(int value) + { + _passes = new Semaphore((value-_throttledRequests+_passes.availablePermits()), true); + _throttledRequests = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get amount of time (in milliseconds) to async wait for semaphore. + * + * @return wait time + */ + public long getThrottleMs() + { + return _throttleMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set amount of time (in milliseconds) to async wait for semaphore. + * + * @param value wait time + */ + public void setThrottleMs(long value) + { + _throttleMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum amount of time (in milliseconds) to allow + * the request to process. + * + * @return maximum processing time + */ + public long getMaxRequestMs() + { + return _maxRequestMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set maximum amount of time (in milliseconds) to allow + * the request to process. + * + * @param value maximum processing time + */ + public void setMaxRequestMs(long value) + { + _maxRequestMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum amount of time (in milliseconds) to keep track + * of request rates for a connection, before deciding that + * the user has gone away, and discarding it. + * + * @return maximum tracking time + */ + public long getMaxIdleTrackerMs() + { + return _maxIdleTrackerMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set maximum amount of time (in milliseconds) to keep track + * of request rates for a connection, before deciding that + * the user has gone away, and discarding it. + * + * @param value maximum tracking time + */ + public void setMaxIdleTrackerMs(long value) + { + _maxIdleTrackerMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Check flag to insert the DoSFilter headers into the response. + * + * @return value of the flag + */ + public boolean isInsertHeaders() + { + return _insertHeaders; + } + + /* ------------------------------------------------------------ */ + /** + * Set flag to insert the DoSFilter headers into the response. + * + * @param value value of the flag + */ + public void setInsertHeaders(boolean value) + { + _insertHeaders = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get flag to have usage rate tracked by session if a session exists. + * + * @return value of the flag + */ + public boolean isTrackSessions() + { + return _trackSessions; + } + + /* ------------------------------------------------------------ */ + /** + * Set flag to have usage rate tracked by session if a session exists. + * @param value value of the flag + */ + public void setTrackSessions(boolean value) + { + _trackSessions = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get flag to have usage rate tracked by IP+port (effectively connection) + * if session tracking is not used. + * + * @return value of the flag + */ + public boolean isRemotePort() + { + return _remotePort; + } + + + /* ------------------------------------------------------------ */ + /** + * Set flag to have usage rate tracked by IP+port (effectively connection) + * if session tracking is not used. + * + * @param value value of the flag + */ + public void setRemotePort(boolean value) + { + _remotePort = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get a list of IP addresses that will not be rate limited. + * + * @return comma-separated whitelist + */ + public String getWhitelist() + { + return _whitelistStr; + } + + + /* ------------------------------------------------------------ */ + /** + * Set a list of IP addresses that will not be rate limited. + * + * @param value comma-separated whitelist + */ + public void setWhitelist(String value) + { + _whitelistStr = value; + initWhitelist(); + } + /** * A RateTracker is associated with a connection, and stores request rate * data. @@ -605,7 +925,7 @@ public class DoSFilter implements Filter protected final int _type; protected final long[] _timestamps; protected int _next; - + public RateTracker(String id, int type,int maxRequestsPerSecond) { _id = id; @@ -642,7 +962,7 @@ public class DoSFilter implements Filter return _type; } - + public void valueBound(HttpSessionBindingEvent event) { } @@ -651,14 +971,14 @@ public class DoSFilter implements Filter { _rateTrackers.remove(_id); } - + public void expired() { long now = _trackerTimeoutQ.getNow(); - int latestIndex = _next == 0 ? 3 : (_next - 1 ) % _timestamps.length; + int latestIndex = _next == 0 ? 3 : (_next - 1 ) % _timestamps.length; long last=_timestamps[latestIndex]; boolean hasRecentRequest = last != 0 && (now-last)<1000L; - + if (hasRecentRequest) reschedule(); else @@ -671,7 +991,7 @@ public class DoSFilter implements Filter return "RateTracker/"+_id+"/"+_type; } } - + class FixedRateTracker extends RateTracker { public FixedRateTracker(String id, int type, int numRecentRequestsTracked) @@ -693,11 +1013,11 @@ public class DoSFilter implements Filter return false; } - + @Override public String toString() { return "Fixed"+super.toString(); } } -}
\ No newline at end of file +} diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java index 6193d79d57..1c98cf46ee 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlets; @@ -22,8 +22,12 @@ import java.net.MalformedURLException; import java.net.Socket; import java.net.URI; import java.net.URISyntaxException; +import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; import javax.servlet.Servlet; import javax.servlet.ServletConfig; @@ -43,10 +47,11 @@ import org.eclipse.jetty.http.HttpHeaderValues; import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.util.HostMap; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.QueuedThreadPool; @@ -54,7 +59,7 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; /** * Asynchronous Proxy Servlet. - * + * * Forward requests to another server either as a standard web proxy (as defined by * RFC2616) or as a transparent proxy. * <p> @@ -62,22 +67,22 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; * the web application. * <p> * To facilitate JMX monitoring, the "HttpClient", it's "ThreadPool" and the "Logger" - * are set as context attributes prefixed with "org.eclipse.jetty.servlets."+name - * (unless otherwise set with attrPrefix). This attribute prefix is also used for the - * logger name. + * are set as context attributes prefixed with the servlet name. * <p> * The following init parameters may be used to configure the servlet: <ul> * <li>name - Name of Proxy servlet (default: "ProxyServlet" * <li>maxThreads - maximum threads * <li>maxConnections - maximum connections per destination * <li>HostHeader - Force the host header to a particular value - * </ul> + * <li>whiteList - comma-separated list of allowed proxy destinations + * <li>blackList - comma-separated list of forbidden proxy destinations + * </ul> */ public class ProxyServlet implements Servlet { - protected Logger _log; - HttpClient _client; - String _hostHeader; + protected Logger _log; + protected HttpClient _client; + protected String _hostHeader; protected HashSet<String> _DontProxyHeaders = new HashSet<String>(); { @@ -94,7 +99,8 @@ public class ProxyServlet implements Servlet protected ServletConfig _config; protected ServletContext _context; - protected String _name="ProxyServlet"; + protected HostMap<PathMap> _white = new HostMap<PathMap>(); + protected HostMap<PathMap> _black = new HostMap<PathMap>(); /* ------------------------------------------------------------ */ /* (non-Javadoc) @@ -107,35 +113,43 @@ public class ProxyServlet implements Servlet _client=new HttpClient(); _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - + _hostHeader=config.getInitParameter("HostHeader"); - - + + try { - String t = config.getInitParameter("attrPrefix"); - if (t!=null) - _name=t; - _log= Log.getLogger("org.eclipse.jetty.servlets."+_name); + _log= Log.getLogger("org.eclipse.jetty.servlets."+config.getServletName()); - t = config.getInitParameter("maxThreads"); + String t = config.getInitParameter("maxThreads"); if (t!=null) _client.setThreadPool(new QueuedThreadPool(Integer.parseInt(t))); else _client.setThreadPool(new QueuedThreadPool()); - ((QueuedThreadPool)_client.getThreadPool()).setName(_name.substring(_name.lastIndexOf('.')+1)); - + ((QueuedThreadPool)_client.getThreadPool()).setName(config.getServletName()); + t = config.getInitParameter("maxConnections"); if (t!=null) _client.setMaxConnectionsPerAddress(Integer.parseInt(t)); - + _client.start(); - + if (_context!=null) { - _context.setAttribute("org.eclipse.jetty.servlets."+_name+".Logger",_log); - _context.setAttribute("org.eclipse.jetty.servlets."+_name+".ThreadPool",_client.getThreadPool()); - _context.setAttribute("org.eclipse.jetty.servlets."+_name+".HttpClient",_client); + _context.setAttribute(config.getServletName()+".Logger",_log); + _context.setAttribute(config.getServletName()+".ThreadPool",_client.getThreadPool()); + _context.setAttribute(config.getServletName()+".HttpClient",_client); + } + + String white = config.getInitParameter("whiteList"); + if (white != null) + { + parseList(white, _white); + } + String black = config.getInitParameter("blackList"); + if (black != null) + { + parseList(black, _black); } } catch (Exception e) @@ -145,6 +159,95 @@ public class ProxyServlet implements Servlet } /* ------------------------------------------------------------ */ + /** + * Helper function to process a parameter value containing a list + * of new entries and initialize the specified host map. + * + * @param list comma-separated list of new entries + * @param hostMap target host map + */ + private void parseList(String list, HostMap<PathMap> hostMap) + { + if (list != null && list.length() > 0) + { + int idx; + String entry; + + StringTokenizer entries = new StringTokenizer(list, ","); + while(entries.hasMoreTokens()) + { + entry = entries.nextToken(); + idx = entry.indexOf('/'); + + String host = idx > 0 ? entry.substring(0,idx) : entry; + String path = idx > 0 ? entry.substring(idx) : "/*"; + + host = host.trim(); + PathMap pathMap = hostMap.get(host); + if (pathMap == null) + { + pathMap = new PathMap(true); + hostMap.put(host,pathMap); + } + if (path != null) + { + pathMap.put(path,path); + } + } + } + } + + /* ------------------------------------------------------------ */ + /** + * Check the request hostname and path against white- and blacklist. + * + * @param host hostname to check + * @param path path to check + * @return true if request is allowed to be proxied + */ + public boolean validateDestination(String host, String path) + { + if (_white.size()>0) + { + boolean match = false; + + Object whiteObj = _white.getLazyMatches(host); + if (whiteObj != null) + { + List whiteList = (whiteObj instanceof List) ? (List)whiteObj : Collections.singletonList(whiteObj); + + for (Object entry: whiteList) + { + PathMap pathMap = ((Map.Entry<String, PathMap>)entry).getValue(); + if (match = (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null))) + break; + } + } + + if (!match) + return false; + } + + if (_black.size() > 0) + { + Object blackObj = _black.getLazyMatches(host); + if (blackObj != null) + { + List blackList = (blackObj instanceof List) ? (List)blackObj : Collections.singletonList(blackObj); + + for (Object entry: blackList) + { + PathMap pathMap = ((Map.Entry<String, PathMap>)entry).getValue(); + if (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null)) + return false; + } + } + } + + return true; + } + + /* ------------------------------------------------------------ */ /* (non-Javadoc) * @see javax.servlet.Servlet#getServletConfig() */ @@ -153,7 +256,7 @@ public class ProxyServlet implements Servlet return _config; } - + /* ------------------------------------------------------------ */ /** Get the hostHeader. * @return the hostHeader @@ -180,7 +283,7 @@ public class ProxyServlet implements Servlet IOException { final int debug=_log.isDebugEnabled()?req.hashCode():0; - + final HttpServletRequest request = (HttpServletRequest)req; final HttpServletResponse response = (HttpServletResponse)res; if ("CONNECT".equalsIgnoreCase(request.getMethod())) @@ -193,7 +296,7 @@ public class ProxyServlet implements Servlet final OutputStream out=response.getOutputStream(); final Continuation continuation = ContinuationSupport.getContinuation(request); - + if (!continuation.isInitial()) response.sendError(HttpServletResponse.SC_GATEWAY_TIMEOUT); // Need better test that isInitial else @@ -206,10 +309,10 @@ public class ProxyServlet implements Servlet request.getServerName(), request.getServerPort(), uri); - + if (debug!=0) _log.debug(debug+" proxy "+uri+"-->"+url); - + if (url==null) { response.sendError(HttpServletResponse.SC_FORBIDDEN); @@ -248,7 +351,7 @@ public class ProxyServlet implements Servlet { if (debug!=0) _log.debug(debug+" "+version+" "+status+" "+reason); - + if (reason!=null && reason.length()>0) response.setStatus(status,reason.toString()); else @@ -264,7 +367,7 @@ public class ProxyServlet implements Servlet { if (debug!=0) _log.debug(debug+" "+name+": "+value); - + response.addHeader(name.toString(),value.toString()); } else if (debug!=0) @@ -303,7 +406,7 @@ public class ProxyServlet implements Servlet exchange.setMethod(request.getMethod()); exchange.setURL(url.toString()); exchange.setVersion(request.getProtocol()); - + if (debug!=0) _log.debug(debug+" "+request.getMethod()+" "+url+" "+request.getProtocol()); @@ -320,7 +423,7 @@ public class ProxyServlet implements Servlet // force host if (_hostHeader!=null) exchange.setRequestHeader("Host",_hostHeader); - + // copy headers boolean xForwardedFor=false; boolean hasContent=false; @@ -344,7 +447,7 @@ public class ProxyServlet implements Servlet else if ("content-length".equals(lhdr)) { contentLength=request.getContentLength(); - exchange.setRequestHeader(HttpHeaders.CONTENT_LENGTH,TypeUtil.toString(contentLength)); + exchange.setRequestHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(contentLength)); if (contentLength>0) hasContent=true; } @@ -373,8 +476,8 @@ public class ProxyServlet implements Servlet if (hasContent) exchange.setRequestContentSource(in); - - continuation.suspend(response); + + continuation.suspend(response); _client.send(exchange); } @@ -431,6 +534,9 @@ public class ProxyServlet implements Servlet protected HttpURI proxyHttpURI(String scheme, String serverName, int serverPort, String uri) throws MalformedURLException { + if (!validateDestination(serverName, uri)) + return null; + return new HttpURI(scheme+"://"+serverName+":"+serverPort+uri); } @@ -450,17 +556,17 @@ public class ProxyServlet implements Servlet { } - + /** * Transparent Proxy. - * - * This convenience extension to ProxyServlet configures the servlet as a transparent proxy. + * + * This convenience extension to ProxyServlet configures the servlet as a transparent proxy. * The servlet is configured with init parameters: * <ul> * <li>ProxyTo - a URI like http://host:80/context to which the request is proxied. * <li>Prefix - a URI prefix that is striped from the start of the forwarded URI. * </ul> - * For example, if a request was received at /foo/bar and the ProxyTo was http://host:80/context + * For example, if a request was received at /foo/bar and the ProxyTo was http://host:80/context * and the Prefix was /foo, then the request would be proxied to http://host:80/context/bar * */ @@ -515,7 +621,7 @@ public class ProxyServlet implements Servlet if (!_prefix.startsWith("/")) throw new UnavailableException("Prefix parameter must start with a '/'."); - _log.info(_name + " @ " + _prefix + " to " + _proxyTo); + _log.info(config.getServletName()+" @ " + _prefix + " to " + _proxyTo); } @Override @@ -525,8 +631,13 @@ public class ProxyServlet implements Servlet { if (!uri.startsWith(_prefix)) return null; + + URI dstUri = new URI(_proxyTo + uri.substring(_prefix.length())).normalize(); + + if (!validateDestination(dstUri.getHost(),dstUri.getPath())) + return null; - return new HttpURI(new URI(_proxyTo + uri.substring(_prefix.length())).normalize().toString()); + return new HttpURI(dstUri.toString()); } catch (URISyntaxException ex) { diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PutFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PutFilter.java index ecaac08ede..858428a9fc 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PutFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PutFilter.java @@ -60,6 +60,7 @@ public class PutFilter implements Filter Set<String> _operations = new HashSet<String>(); protected ConcurrentMap<String,String> _hidden = new ConcurrentHashMap<String, String>(); + protected String _options; protected ServletContext _context; protected String _baseURI; @@ -87,10 +88,12 @@ public class PutFilter implements Filter _operations.add(__OPTIONS); _operations.add(__PUT); + _options="GET,HEAD,POST,OPTIONS,PUT"; if (_delAllowed) { _operations.add(__DELETE); _operations.add(__MOVE); + _options+=",DELETE"; } } @@ -284,15 +287,13 @@ public class PutFilter implements Filter response.setStatus(HttpServletResponse.SC_NO_CONTENT); response.flushBuffer(); - - } /* ------------------------------------------------------------ */ public void handleOptions(HttpServletRequest request, HttpServletResponse response) throws IOException { - // TODO implement - throw new UnsupportedOperationException("Not Implemented"); + // TODO filter real options and add PUT & DELETE + response.setHeader("Allow", _options); } /* ------------------------------------------------------------ */ diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java index a726412b30..cf3a97dea5 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java @@ -33,21 +33,23 @@ import javax.servlet.http.HttpSession; import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationSupport; +import org.eclipse.jetty.server.handler.ContextHandler; /** * Quality of Service Filter. + * * This filter limits the number of active requests to the number set by the "maxRequests" init parameter (default 10). * If more requests are received, they are suspended and placed on priority queues. Priorities are determined by * the {@link #getPriority(ServletRequest)} method and are a value between 0 and the value given by the "maxPriority" * init parameter (default 10), with higher values having higher priority. - * <p> + * </p><p> * This filter is ideal to prevent wasting threads waiting for slow/limited * resources such as a JDBC connection pool. It avoids the situation where all of a * containers thread pool may be consumed blocking on such a slow resource. * By limiting the number of active threads, a smaller thread pool may be used as * the threads are not wasted waiting. Thus more memory may be available for use by * the active threads. - * <p> + * </p><p> * Furthermore, this filter uses a priority when resuming waiting requests. So that if * a container is under load, and there are many requests waiting for resources, * the {@link #getPriority(ServletRequest)} method is used, so that more important @@ -55,12 +57,16 @@ import org.eclipse.jetty.continuation.ContinuationSupport; * maxRequest limit slightly smaller than the containers thread pool and a high priority * allocated to admin users. Thus regardless of load, admin users would always be * able to access the web application. - * <p> + * </p><p> * The maxRequest limit is policed by a {@link Semaphore} and the filter will wait a short while attempting to acquire * the semaphore. This wait is controlled by the "waitMs" init parameter and allows the expense of a suspend to be * avoided if the semaphore is shortly available. If the semaphore cannot be obtained, the request will be suspended * for the default suspend period of the container or the valued set as the "suspendMs" init parameter. - * + * </p><p> + * If the "managedAttr" init parameter is set to true, then this servlet is set as a {@link ServletContext} attribute with the + * filter name as the attribute name. This allows context external mechanism (eg JMX via {@link ContextHandler#MANAGED_ATTRIBUTES}) to + * manage the configuration of the filter. + * </p> * * */ @@ -71,23 +77,31 @@ public class QoSFilter implements Filter final static int __DEFAULT_WAIT_MS=50; final static long __DEFAULT_TIMEOUT_MS = -1; + final static String MANAGED_ATTR_INIT_PARAM="managedAttr"; final static String MAX_REQUESTS_INIT_PARAM="maxRequests"; final static String MAX_PRIORITY_INIT_PARAM="maxPriority"; final static String MAX_WAIT_INIT_PARAM="waitMs"; final static String SUSPEND_INIT_PARAM="suspendMs"; ServletContext _context; - long _waitMs; - long _suspendMs; - Semaphore _passes; - Queue<Continuation>[] _queue; - ContinuationListener[] _listener; - String _suspended="QoSFilter@"+this.hashCode(); + + protected long _waitMs; + protected long _suspendMs; + protected int _maxRequests; + private Semaphore _passes; + private Queue<Continuation>[] _queue; + private ContinuationListener[] _listener; + private String _suspended="QoSFilter@"+this.hashCode(); + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) + */ public void init(FilterConfig filterConfig) { _context=filterConfig.getServletContext(); - + int max_priority=__DEFAULT_MAX_PRIORITY; if (filterConfig.getInitParameter(MAX_PRIORITY_INIT_PARAM)!=null) max_priority=Integer.parseInt(filterConfig.getInitParameter(MAX_PRIORITY_INIT_PARAM)); @@ -110,10 +124,11 @@ public class QoSFilter implements Filter }; } - int passes=__DEFAULT_PASSES; + int maxRequests=__DEFAULT_PASSES; if (filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM)!=null) - passes=Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM)); - _passes=new Semaphore(passes,true); + maxRequests=Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM)); + _passes=new Semaphore(maxRequests,true); + _maxRequests = maxRequests; long wait = __DEFAULT_WAIT_MS; if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM)!=null) @@ -124,8 +139,15 @@ public class QoSFilter implements Filter if (filterConfig.getInitParameter(SUSPEND_INIT_PARAM)!=null) suspend=Integer.parseInt(filterConfig.getInitParameter(SUSPEND_INIT_PARAM)); _suspendMs=suspend; + + if (_context!=null && Boolean.parseBoolean(filterConfig.getInitParameter(MANAGED_ATTR_INIT_PARAM))) + _context.setAttribute(filterConfig.getFilterName(),this); } + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) + */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @@ -220,7 +242,7 @@ public class QoSFilter implements Filter * This method may be specialised to provide application specific priorities. * * @param request - * @return + * @return the request priority */ protected int getPriority(ServletRequest request) { @@ -238,6 +260,83 @@ public class QoSFilter implements Filter } + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#destroy() + */ public void destroy(){} + /* ------------------------------------------------------------ */ + /** + * Get the (short) amount of time (in milliseconds) that the filter would wait + * for the semaphore to become available before suspending a request. + * + * @return wait time (in milliseconds) + */ + public long getWaitMs() + { + return _waitMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set the (short) amount of time (in milliseconds) that the filter would wait + * for the semaphore to become available before suspending a request. + * + * @param value wait time (in milliseconds) + */ + public void setWaitMs(long value) + { + _waitMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get the amount of time (in milliseconds) that the filter would suspend + * a request for while waiting for the semaphore to become available. + * + * @return suspend time (in milliseconds) + */ + public long getSuspendMs() + { + return _suspendMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set the amount of time (in milliseconds) that the filter would suspend + * a request for while waiting for the semaphore to become available. + * + * @param value suspend time (in milliseconds) + */ + public void setSuspendMs(long value) + { + _suspendMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get the maximum number of requests allowed to be processed + * at the same time. + * + * @return maximum number of requests + */ + public int getMaxRequests() + { + return _maxRequests; + } + + /* ------------------------------------------------------------ */ + /** + * Set the maximum number of requests allowed to be processed + * at the same time. + * + * @param passes the _passes to set + */ + public void setMaxRequests(int value) + { + _passes = new Semaphore((value-_maxRequests+_passes.availablePermits()), true); + _maxRequests = value; + } + } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java new file mode 100644 index 0000000000..34651edb09 --- /dev/null +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java @@ -0,0 +1,344 @@ +package org.eclipse.jetty.servlets; + +import java.io.IOException; +import java.net.Socket; +import java.util.EnumSet; + +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.testing.ServletTester; +import org.eclipse.jetty.util.IO; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @version $Revision$ $Date$ + */ +public abstract class AbstractDoSFilterTest +{ + private static ServletTester _tester; + private static String _host; + private static int _port; + private static long _requestMaxTime = 200; + private static FilterHolder _dosFilter; + private static FilterHolder _timeoutFilter; + + public static void startServer(Class<? extends Filter> filter) throws Exception + { + _tester = new ServletTester(); + HttpURI uri = new HttpURI(_tester.createChannelConnector(true)); + _host = uri.getHost(); + _port = uri.getPort(); + + _tester.setContextPath("/ctx"); + _tester.addServlet(TestServlet.class, "/*"); + + _dosFilter = _tester.addFilter(filter, "/dos/*", EnumSet.allOf(DispatcherType.class)); + _dosFilter.setInitParameter("maxRequestsPerSec", "4"); + _dosFilter.setInitParameter("delayMs", "200"); + _dosFilter.setInitParameter("throttledRequests", "1"); + _dosFilter.setInitParameter("waitMs", "10"); + _dosFilter.setInitParameter("throttleMs", "4000"); + _dosFilter.setInitParameter("remotePort", "false"); + _dosFilter.setInitParameter("insertHeaders", "true"); + + _timeoutFilter = _tester.addFilter(filter, "/timeout/*", EnumSet.allOf(DispatcherType.class)); + _timeoutFilter.setInitParameter("maxRequestsPerSec", "4"); + _timeoutFilter.setInitParameter("delayMs", "200"); + _timeoutFilter.setInitParameter("throttledRequests", "1"); + _timeoutFilter.setInitParameter("waitMs", "10"); + _timeoutFilter.setInitParameter("throttleMs", "4000"); + _timeoutFilter.setInitParameter("remotePort", "false"); + _timeoutFilter.setInitParameter("insertHeaders", "true"); + _timeoutFilter.setInitParameter("maxRequestMs", _requestMaxTime + ""); + + _tester.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + _tester.stop(); + } + + @Before + public void startFilters() throws Exception + { + _dosFilter.start(); + _timeoutFilter.start(); + } + + @After + public void stopFilters() throws Exception + { + _timeoutFilter.stop(); + _dosFilter.stop(); + } + + private String doRequests(String requests, int loops, long pause0, long pause1, String request) throws Exception + { + Socket socket = new Socket(_host, _port); + socket.setSoTimeout(30000); + + for (int i=loops;i-->0;) + { + socket.getOutputStream().write(requests.getBytes("UTF-8")); + socket.getOutputStream().flush(); + if (i>0 && pause0>0) + Thread.sleep(pause0); + } + if (pause1>0) + Thread.sleep(pause1); + socket.getOutputStream().write(request.getBytes("UTF-8")); + socket.getOutputStream().flush(); + + + String response; + if (requests.contains("/unresponsive")) + { + // don't read in anything, forcing the request to time out + Thread.sleep(_requestMaxTime * 2); + response = IO.toString(socket.getInputStream(),"UTF-8"); + } + else + { + response = IO.toString(socket.getInputStream(),"UTF-8"); + } + socket.close(); + return response; + } + + private int count(String responses,String substring) + { + int count=0; + int i=responses.indexOf(substring); + while (i>=0) + { + count++; + i=responses.indexOf(substring,i+substring.length()); + } + + return count; + } + + @Test + public void testEvenLowRateIP() throws Exception + { + String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; + String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String responses = doRequests(request,11,300,300,last); + assertEquals(12,count(responses,"HTTP/1.1 200 OK")); + assertEquals(0,count(responses,"DoSFilter:")); + } + + @Test + public void testBurstLowRateIP() throws Exception + { + String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; + String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String responses = doRequests(request+request+request+request,2,1100,1100,last); + + assertEquals(9,count(responses,"HTTP/1.1 200 OK")); + assertEquals(0,count(responses,"DoSFilter:")); + } + + @Test + public void testDelayedIP() throws Exception + { + String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; + String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String responses = doRequests(request+request+request+request+request,2,1100,1100,last); + + assertEquals(11,count(responses,"HTTP/1.1 200 OK")); + assertEquals(2,count(responses,"DoSFilter: delayed")); + } + + @Test + public void testThrottledIP() throws Exception + { + Thread other = new Thread() + { + public void run() + { + try + { + // Cause a delay, then sleep while holding pass + String request="GET /ctx/dos/sleeper HTTP/1.1\r\nHost: localhost\r\n\r\n"; + String last="GET /ctx/dos/sleeper?sleep=3000 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String responses = doRequests(request+request+request+request,1,0,0,last); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }; + other.start(); + Thread.sleep(1500); + + String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; + String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String responses = doRequests(request+request+request+request,1,0,0,last); + //System.out.println("responses are " + responses); + assertEquals("200 OK responses", 5,count(responses,"HTTP/1.1 200 OK")); + assertEquals("delayed responses", 1,count(responses,"DoSFilter: delayed")); + assertEquals("throttled responses", 1,count(responses,"DoSFilter: throttled")); + assertEquals("unavailable responses", 0,count(responses,"DoSFilter: unavailable")); + + other.join(); + } + + @Test + public void testUnavailableIP() throws Exception + { + Thread other = new Thread() + { + public void run() + { + try + { + // Cause a delay, then sleep while holding pass + String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; + String last="GET /ctx/dos/test?sleep=5000 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String responses = doRequests(request+request+request+request,1,0,0,last); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }; + other.start(); + Thread.sleep(500); + + String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; + String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String responses = doRequests(request+request+request+request,1,0,0,last); + + assertEquals(4,count(responses,"HTTP/1.1 200 OK")); + assertEquals(1,count(responses,"HTTP/1.1 503")); + assertEquals(1,count(responses,"DoSFilter: delayed")); + assertEquals(1,count(responses,"DoSFilter: throttled")); + assertEquals(1,count(responses,"DoSFilter: unavailable")); + + other.join(); + } + + @Test + public void testSessionTracking() throws Exception + { + // get a session, first + String requestSession="GET /ctx/dos/test?session=true HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String response=doRequests("",1,0,0,requestSession); + String sessionId=response.substring(response.indexOf("Set-Cookie: ")+12, response.indexOf(";")); + + // all other requests use this session + String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nCookie: " + sessionId + "\r\n\r\n"; + String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\nCookie: " + sessionId + "\r\n\r\n"; + String responses = doRequests(request+request+request+request+request,2,1100,1100,last); + + assertEquals(11,count(responses,"HTTP/1.1 200 OK")); + assertEquals(2,count(responses,"DoSFilter: delayed")); + } + + @Test + public void testMultipleSessionTracking() throws Exception + { + // get some session ids, first + String requestSession="GET /ctx/dos/test?session=true HTTP/1.1\r\nHost: localhost\r\n\r\n"; + String closeRequest="GET /ctx/dos/test?session=true HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String response=doRequests(requestSession+requestSession,1,0,0,closeRequest); + + String[] sessions = response.split("\r\n\r\n"); + + String sessionId1=sessions[0].substring(sessions[0].indexOf("Set-Cookie: ")+12, sessions[0].indexOf(";")); + String sessionId2=sessions[1].substring(sessions[1].indexOf("Set-Cookie: ")+12, sessions[1].indexOf(";")); + + // alternate between sessions + String request1="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nCookie: " + sessionId1 + "\r\n\r\n"; + String request2="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nCookie: " + sessionId2 + "\r\n\r\n"; + String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\nCookie: " + sessionId2 + "\r\n\r\n"; + + // ensure the sessions are new + String responses = doRequests(request1+request2,1,1100,1100,last); + Thread.sleep(1000); + + responses = doRequests(request1+request2+request1+request2+request1,2,1100,1100,last); + + assertEquals(11,count(responses,"HTTP/1.1 200 OK")); + assertEquals(0,count(responses,"DoSFilter: delayed")); + + // alternate between sessions + responses = doRequests(request1+request2+request1+request2+request1,2,550,550,last); + + assertEquals(11,count(responses,"HTTP/1.1 200 OK")); + int delayedRequests = count(responses,"DoSFilter: delayed"); + assertTrue(delayedRequests >= 2 && delayedRequests <= 3); + } + + @Test + public void testUnresponsiveClient() throws Exception + { + int numRequests = 1000; + + String last="GET /ctx/timeout/unresponsive?lines="+numRequests+" HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; + String responses = doRequests("",0,0,0,last); + // was expired, and stopped before reaching the end of the requests + int responseLines = count(responses, "Line:"); + assertTrue(responses.contains("DoSFilter: timeout")); + assertTrue(responseLines > 0 && responseLines < numRequests); + } + + public static class TestServlet extends HttpServlet implements Servlet + { + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + if (request.getParameter("session")!=null) + request.getSession(true); + if (request.getParameter("sleep")!=null) + { + try + { + Thread.sleep(Long.parseLong(request.getParameter("sleep"))); + } + catch(InterruptedException e) + { + } + } + + if (request.getParameter("lines")!=null) + { + int count = Integer.parseInt(request.getParameter("lines")); + for(int i = 0; i < count; ++i) + { + response.getWriter().append("Line: " + i+"\n"); + response.flushBuffer(); + + try + { + Thread.sleep(10); + } + catch(InterruptedException e) + { + } + + } + } + + response.setContentType("text/plain"); + } + } +} diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java index 0768969fd0..95defdd12a 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java @@ -4,75 +4,44 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlets; -import java.util.EnumSet; -import javax.servlet.DispatcherType; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.testing.ServletTester; import org.eclipse.jetty.util.log.Log; +import org.junit.BeforeClass; -public class CloseableDoSFilterTest extends DoSFilterTest +public class CloseableDoSFilterTest extends AbstractDoSFilterTest { - protected void setUp() throws Exception + @BeforeClass + public static void setUp() throws Exception { - _tester = new ServletTester(); - HttpURI uri=new HttpURI(_tester.createSocketConnector(true)); - _host=uri.getHost(); - _port=uri.getPort(); - - _tester.setContextPath("/ctx"); - _tester.addServlet(TestServlet.class, "/*"); - - FilterHolder dos=_tester.addFilter(CloseableDoSFilter2.class,"/dos/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC)); - dos.setInitParameter("maxRequestsPerSec","4"); - dos.setInitParameter("delayMs","200"); - dos.setInitParameter("throttledRequests","1"); - dos.setInitParameter("waitMs","10"); - dos.setInitParameter("throttleMs","4000"); - dos.setInitParameter("remotePort", "false"); - dos.setInitParameter("insertHeaders", "true"); - - FilterHolder quickTimeout = _tester.addFilter(CloseableDoSFilter2.class,"/timeout/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC)); - quickTimeout.setInitParameter("maxRequestsPerSec","4"); - quickTimeout.setInitParameter("delayMs","200"); - quickTimeout.setInitParameter("throttledRequests","1"); - quickTimeout.setInitParameter("waitMs","10"); - quickTimeout.setInitParameter("throttleMs","4000"); - quickTimeout.setInitParameter("remotePort", "false"); - quickTimeout.setInitParameter("insertHeaders", "true"); - quickTimeout.setInitParameter("maxRequestMs", _maxRequestMs + ""); - - _tester.start(); - + startServer(CloseableDoSFilter2.class); } - + public static class CloseableDoSFilter2 extends CloseableDoSFilter - { + { public void closeConnection(HttpServletRequest request, HttpServletResponse response, Thread thread) { - try - { - response.getWriter().append("DoSFilter: timeout"); - response.flushBuffer(); - super.closeConnection(request,response,thread); - } - catch (Exception e) - { - Log.warn(e); - } - } + try + { + response.getWriter().append("DoSFilter: timeout"); + response.flushBuffer(); + super.closeConnection(request, response, thread); + } + catch (Exception e) + { + Log.warn(e); + } } + } } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java index 1cfb0bee32..d7a2b31bd0 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java @@ -3,7 +3,7 @@ // ------------------------------------------------------------------------ // Licensed 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 +// 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, @@ -14,340 +14,26 @@ package org.eclipse.jetty.servlets; -import java.io.IOException; -import java.net.Socket; -import java.util.EnumSet; - -import javax.servlet.DispatcherType; -import javax.servlet.FilterChain; -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.server.AsyncContinuation; -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.testing.ServletTester; -import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; +import org.junit.BeforeClass; -public class DoSFilterTest extends TestCase +public class DoSFilterTest extends AbstractDoSFilterTest { - protected ServletTester _tester; - protected String _host; - protected int _port; - - protected int _maxRequestMs = 200; - protected void setUp() throws Exception - { - _tester = new ServletTester(); - HttpURI uri=new HttpURI(_tester.createChannelConnector(true)); - _host=uri.getHost(); - _port=uri.getPort(); - - _tester.setContextPath("/ctx"); - _tester.addServlet(TestServlet.class, "/*"); - - FilterHolder dos=_tester.addFilter(DoSFilter2.class,"/dos/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC)); - dos.setInitParameter("maxRequestsPerSec","4"); - dos.setInitParameter("delayMs","200"); - dos.setInitParameter("throttledRequests","1"); - dos.setInitParameter("waitMs","10"); - dos.setInitParameter("throttleMs","4000"); - dos.setInitParameter("remotePort", "false"); - dos.setInitParameter("insertHeaders", "true"); - dos.setAsyncSupported(true); - - FilterHolder quickTimeout = _tester.addFilter(DoSFilter2.class,"/timeout/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC)); - quickTimeout.setInitParameter("maxRequestsPerSec","4"); - quickTimeout.setInitParameter("delayMs","200"); - quickTimeout.setInitParameter("throttledRequests","1"); - quickTimeout.setInitParameter("waitMs","10"); - quickTimeout.setInitParameter("throttleMs","4000"); - quickTimeout.setInitParameter("remotePort", "false"); - quickTimeout.setInitParameter("insertHeaders", "true"); - quickTimeout.setInitParameter("maxRequestMs", _maxRequestMs + ""); - quickTimeout.setAsyncSupported(true); - - _tester.start(); - - } - - protected void tearDown() throws Exception + @BeforeClass + public static void setUp() throws Exception { - _tester.stop(); + startServer(DoSFilter2.class); } - - private String doRequests(String requests, int loops, long pause0,long pause1,String request) - throws Exception - { - Socket socket = new Socket(_host,_port); - socket.setSoTimeout(300000); - - for (int i=loops;i-->0;) - { - socket.getOutputStream().write(requests.getBytes("UTF-8")); - socket.getOutputStream().flush(); - if (i>0 && pause0>0) - Thread.sleep(pause0); - } - if (pause1>0) - Thread.sleep(pause1); - socket.getOutputStream().write(request.getBytes("UTF-8")); - socket.getOutputStream().flush(); - - - String response = ""; - if (requests.contains("/unresponsive")) - { - // don't read in anything, forcing the request to time out - Thread.sleep(_maxRequestMs * 2); - response = IO.toString(socket.getInputStream(),"UTF-8"); - } - else - { - response = IO.toString(socket.getInputStream(),"UTF-8"); - } - socket.close(); - return response; - } - - private int count(String responses,String substring) - { - int count=0; - int i=responses.indexOf(substring); - while (i>=0) - { - count++; - i=responses.indexOf(substring,i+substring.length()); - } - - return count; - } - - public void testEvenLowRateIP() - throws Exception - { - String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; - String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String responses = doRequests(request,11,300,300,last); - assertEquals(12,count(responses,"HTTP/1.1 200 OK")); - assertEquals(0,count(responses,"DoSFilter:")); - } - - public void testBurstLowRateIP() - throws Exception - { - String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; - String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String responses = doRequests(request+request+request+request,2,1100,1100,last); - - assertEquals(9,count(responses,"HTTP/1.1 200 OK")); - assertEquals(0,count(responses,"DoSFilter:")); - } - - public void testDelayedIP() - throws Exception - { - String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; - String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - - String responses = doRequests(request+request+request+request+request,2,1100,1100,last); - - assertEquals(11,count(responses,"HTTP/1.1 200 OK")); - assertEquals(2,count(responses,"DoSFilter: delayed")); - } - - public void testThrottledIP() - throws Exception - { - Thread other = new Thread() - { - public void run() - { - try - { - // Cause a delay, then sleep while holding pass - String request="GET /ctx/dos/sleeper HTTP/1.1\r\nHost: localhost\r\n\r\n"; - String last="GET /ctx/dos/sleeper?sleep=3000 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String responses = doRequests(request+request+request+request,1,0,0,last); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - }; - other.start(); - Thread.sleep(1500); - - String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; - String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String responses = doRequests(request+request+request+request,1,0,0,last); - assertEquals(5,count(responses,"HTTP/1.1 200 OK")); - assertEquals(1,count(responses,"DoSFilter: delayed")); - assertEquals(1,count(responses,"DoSFilter: throttled")); - assertEquals(0,count(responses,"DoSFilter: unavailable")); - - other.join(); - } - - public void testUnavailableIP() - throws Exception - { - Thread other = new Thread() - { - public void run() - { - try - { - // Cause a delay, then sleep while holding pass - String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; - String last="GET /ctx/dos/test?sleep=5000 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String responses = doRequests(request+request+request+request,1,0,0,last); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - }; - other.start(); - Thread.sleep(500); - - String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; - String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String responses = doRequests(request+request+request+request,1,0,0,last); - - assertEquals(4,count(responses,"HTTP/1.1 200 OK")); - assertEquals(1,count(responses,"HTTP/1.1 503")); - assertEquals(1,count(responses,"DoSFilter: delayed")); - assertEquals(1,count(responses,"DoSFilter: throttled")); - assertEquals(1,count(responses,"DoSFilter: unavailable")); - - other.join(); - } - - public void testSessionTracking() - throws Exception - { - // get a session, first - String requestSession="GET /ctx/dos/test?session=true HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String response=doRequests("",1,0,0,requestSession); - String sessionId=response.substring(response.indexOf("Set-Cookie: ")+12, response.indexOf(";")); - - // all other requests use this session - String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nCookie: " + sessionId + "\r\n\r\n"; - String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\nCookie: " + sessionId + "\r\n\r\n"; - String responses = doRequests(request+request+request+request+request,2,1100,1100,last); - - assertEquals(11,count(responses,"HTTP/1.1 200 OK")); - assertEquals(2,count(responses,"DoSFilter: delayed")); - } - - public void testMultipleSessionTracking() - throws Exception - { - // get some session ids, first - String requestSession="GET /ctx/dos/test?session=true HTTP/1.1\r\nHost: localhost\r\n\r\n"; - String closeRequest="GET /ctx/dos/test?session=true HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String response=doRequests(requestSession+requestSession,1,0,0,closeRequest); - - String[] sessions = response.split("\r\n\r\n"); - - String sessionId1=sessions[0].substring(sessions[0].indexOf("Set-Cookie: ")+12, sessions[0].indexOf(";")); - String sessionId2=sessions[1].substring(sessions[1].indexOf("Set-Cookie: ")+12, sessions[1].indexOf(";")); - - // alternate between sessions - String request1="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nCookie: " + sessionId1 + "\r\n\r\n"; - String request2="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nCookie: " + sessionId2 + "\r\n\r\n"; - String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\nCookie: " + sessionId2 + "\r\n\r\n"; - - // ensure the sessions are new - String responses = doRequests(request1+request2,1,1100,1100,last); - Thread.sleep(1000); - - responses = doRequests(request1+request2+request1+request2+request1,2,1100,1100,last); - - assertEquals(11,count(responses,"HTTP/1.1 200 OK")); - assertEquals(0,count(responses,"DoSFilter: delayed")); - - // alternate between sessions - responses = doRequests(request1+request2+request1+request2+request1,2,550,550,last); - - assertEquals(11,count(responses,"HTTP/1.1 200 OK")); - int delayedRequests = count(responses,"DoSFilter: delayed"); - assertTrue(delayedRequests >= 2 && delayedRequests <= 3); - } - - public void testUnresponsiveClient() - throws Exception - { - int numRequests = 1000; - - String last="GET /ctx/timeout/unresponsive?lines="+numRequests+" HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; - String responses = doRequests("",0,0,0,last); - // was expired, and stopped before reaching the end of the requests - int responseLines = count(responses, "Line:"); - assertTrue(responses.contains("DoSFilter: timeout")); - assertTrue(responseLines > 0 && responseLines < numRequests); - } - - public static class TestServlet extends HttpServlet implements Servlet - { - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - if (request.getParameter("session")!=null) - request.getSession(true); - if (request.getParameter("sleep")!=null) - { - try - { - long sleep=Long.parseLong(request.getParameter("sleep")); - Thread.sleep(sleep); - } - catch(InterruptedException e) - { - e.printStackTrace(); - } - } - - if (request.getParameter("lines")!=null) - { - int count = Integer.parseInt(request.getParameter("lines")); - for(int i = 0; i < count; ++i) - { - response.getWriter().append("Line: " + i+"\n"); - response.flushBuffer(); - - try - { - Thread.sleep(10); - } - catch(InterruptedException e) - { - } - - } - } - - response.setContentType("text/plain"); - - } - } - public static class DoSFilter2 extends DoSFilter { public void closeConnection(HttpServletRequest request, HttpServletResponse response, Thread thread) { - try { + try + { response.getWriter().append("DoSFilter: timeout"); super.closeConnection(request,response,thread); } @@ -356,5 +42,5 @@ public class DoSFilterTest extends TestCase Log.warn(e); } } - } + } } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java index b1f815b0cc..a0469f4854 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlets; @@ -19,31 +19,34 @@ import java.io.OutputStream; import java.net.Socket; import java.net.URL; import java.util.EnumSet; - import javax.servlet.DispatcherType; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.testing.HttpTester; import org.eclipse.jetty.testing.ServletTester; import org.eclipse.jetty.util.IO; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; -public class PutFilterTest extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class PutFilterTest { - File _dir; - ServletTester tester; - - protected void setUp() throws Exception + private File _dir; + private ServletTester tester; + + @Before + public void setUp() throws Exception { _dir = File.createTempFile("testPutFilter",null); - _dir.delete(); - _dir.mkdir(); + assertTrue(_dir.delete()); + assertTrue(_dir.mkdir()); _dir.deleteOnExit(); assertTrue(_dir.isDirectory()); - - super.setUp(); + tester=new ServletTester(); tester.setContextPath("/context"); tester.setResourceBase(_dir.getCanonicalPath()); @@ -51,21 +54,21 @@ public class PutFilterTest extends TestCase FilterHolder holder = tester.addFilter(PutFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); holder.setInitParameter("delAllowed","true"); tester.start(); - - } - protected void tearDown() throws Exception + @After + public void tearDown() throws Exception { - super.tearDown(); + tester.stop(); } + @Test public void testHandlePut() throws Exception { // generated and parsed test HttpTester request = new HttpTester(); HttpTester response = new HttpTester(); - + // test GET request.setMethod("GET"); request.setVersion("HTTP/1.0"); @@ -84,7 +87,7 @@ public class PutFilterTest extends TestCase response.parse(tester.getResponses(request.generate())); assertTrue(response.getMethod()==null); assertEquals(HttpServletResponse.SC_CREATED,response.getStatus()); - + File file=new File(_dir,"file.txt"); assertTrue(file.exists()); assertEquals(data0,IO.toString(new FileInputStream(file))); @@ -108,12 +111,10 @@ public class PutFilterTest extends TestCase response.parse(tester.getResponses(request.generate())); assertTrue(response.getMethod()==null); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - + file=new File(_dir,"file.txt"); assertTrue(file.exists()); assertEquals(data1,IO.toString(new FileInputStream(file))); - - // test PUT2 request.setMethod("PUT"); @@ -144,7 +145,7 @@ public class PutFilterTest extends TestCase out.write(to_send.substring(l-5).getBytes()); out.flush(); String in=IO.toString(socket.getInputStream()); - + request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); @@ -153,10 +154,9 @@ public class PutFilterTest extends TestCase assertTrue(response.getMethod()==null); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); assertEquals(data2,response.getContent()); - - } + @Test public void testHandleDelete() throws Exception { // generated and parsed test @@ -174,20 +174,18 @@ public class PutFilterTest extends TestCase response.parse(tester.getResponses(request.generate())); assertTrue(response.getMethod()==null); assertEquals(HttpServletResponse.SC_CREATED,response.getStatus()); - + File file=new File(_dir,"file.txt"); assertTrue(file.exists()); FileInputStream fis = new FileInputStream(file); assertEquals(data1,IO.toString(fis)); fis.close(); - request.setMethod("DELETE"); request.setURI("/context/file.txt"); response.parse(tester.getResponses(request.generate())); assertTrue(response.getMethod()==null); assertEquals(HttpServletResponse.SC_NO_CONTENT,response.getStatus()); - assertTrue(!file.exists()); @@ -196,10 +194,9 @@ public class PutFilterTest extends TestCase response.parse(tester.getResponses(request.generate())); assertTrue(response.getMethod()==null); assertEquals(HttpServletResponse.SC_FORBIDDEN,response.getStatus()); - - } + @Test public void testHandleMove() throws Exception { // generated and parsed test @@ -217,13 +214,12 @@ public class PutFilterTest extends TestCase response.parse(tester.getResponses(request.generate())); assertTrue(response.getMethod()==null); assertEquals(HttpServletResponse.SC_CREATED,response.getStatus()); - + File file=new File(_dir,"file.txt"); assertTrue(file.exists()); FileInputStream fis = new FileInputStream(file); assertEquals(data1,IO.toString(fis)); fis.close(); - request.setMethod("MOVE"); request.setURI("/context/file.txt"); @@ -231,22 +227,22 @@ public class PutFilterTest extends TestCase response.parse(tester.getResponses(request.generate())); assertTrue(response.getMethod()==null); assertEquals(HttpServletResponse.SC_NO_CONTENT,response.getStatus()); - + assertTrue(!file.exists()); File n_file=new File(_dir,"blah.txt"); assertTrue(n_file.exists()); - } + @Test public void testHandleOptions() { // TODO implement } + @Test public void testPassConditionalHeaders() { // TODO implement } - } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java index 391c76e63a..acf14cfb58 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java @@ -4,21 +4,19 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.servlets; import java.io.IOException; -import java.io.InputStream; import java.net.URL; import java.util.EnumSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.DispatcherType; import javax.servlet.Servlet; import javax.servlet.ServletException; @@ -27,16 +25,20 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.testing.HttpTester; import org.eclipse.jetty.testing.ServletTester; import org.eclipse.jetty.util.log.Log; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -public class QoSFilterTest extends TestCase +public class QoSFilterTest { private ServletTester _tester; private LocalConnector[] _connectors; @@ -44,42 +46,46 @@ public class QoSFilterTest extends TestCase private final int NUM_CONNECTIONS = 8; private final int NUM_LOOPS = 6; private final int MAX_QOS = 4; - - protected void setUp() throws Exception + + @Before + public void setUp() throws Exception { _tester = new ServletTester(); _tester.setContextPath("/context"); _tester.addServlet(TestServlet.class, "/test"); TestServlet.__maxSleepers=0; TestServlet.__sleepers=0; - + _connectors = new LocalConnector[NUM_CONNECTIONS]; for(int i = 0; i < _connectors.length; ++i) _connectors[i] = _tester.createLocalConnector(); - + _doneRequests = new CountDownLatch(NUM_CONNECTIONS*NUM_LOOPS); - + _tester.start(); } - - protected void tearDown() throws Exception + + @After + public void tearDown() throws Exception { _tester.stop(); } + @Test public void testNoFilter() throws Exception - { + { for(int i = 0; i < NUM_CONNECTIONS; ++i ) { new Thread(new Worker(i)).start(); } - + _doneRequests.await(10,TimeUnit.SECONDS); - + assertFalse("TEST WAS NOT PARALLEL ENOUGH!",TestServlet.__maxSleepers<=MAX_QOS); assertTrue(TestServlet.__maxSleepers<=NUM_CONNECTIONS); } + @Test public void testBlockingQosFilter() throws Exception { FilterHolder holder = new FilterHolder(QoSFilter2.class); @@ -97,23 +103,23 @@ public class QoSFilterTest extends TestCase assertTrue(TestServlet.__maxSleepers==MAX_QOS); } + @Test public void testQosFilter() throws Exception - { + { FilterHolder holder = new FilterHolder(QoSFilter2.class); holder.setAsyncSupported(true); holder.setInitParameter(QoSFilter.MAX_REQUESTS_INIT_PARAM, ""+MAX_QOS); _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC)); - for(int i = 0; i < NUM_CONNECTIONS; ++i ) { new Thread(new Worker2(i)).start(); } - + _doneRequests.await(20,TimeUnit.SECONDS); assertFalse("TEST WAS NOT PARALLEL ENOUGH!",TestServlet.__maxSleepers<MAX_QOS); assertTrue(TestServlet.__maxSleepers<=MAX_QOS); } - + class Worker implements Runnable { private int _num; public Worker(int num) @@ -126,7 +132,6 @@ public class QoSFilterTest extends TestCase for (int i=0;i<NUM_LOOPS;i++) { HttpTester request = new HttpTester(); - HttpTester response = new HttpTester(); request.setMethod("GET"); request.setHeader("host", "tester"); @@ -135,22 +140,14 @@ public class QoSFilterTest extends TestCase try { String responseString = _tester.getResponses(request.generate(), _connectors[_num]); - int index=-1; - if((index = responseString.indexOf("HTTP", index+1))!=-1) + if(responseString.indexOf("HTTP")!=-1) { - responseString = response.parse(responseString); _doneRequests.countDown(); } } - catch (IOException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - catch (Exception e) + catch (Exception x) { - // TODO Auto-generated catch block - e.printStackTrace(); + assertTrue(false); } } } @@ -173,25 +170,24 @@ public class QoSFilterTest extends TestCase { url=new URL(addr+"/context/test?priority="+(_num%QoSFilter.__DEFAULT_MAX_PRIORITY)+"&n="+_num+"&l="+i); // System.err.println(_num+"-"+i+" Try "+url); - InputStream in = (InputStream)url.getContent(); + url.getContent(); _doneRequests.countDown(); // System.err.println(_num+"-"+i+" Got "+IO.toString(in)+" "+_doneRequests.getCount()); } } catch(Exception e) { - Log.warn(url.toString()); + Log.warn(String.valueOf(url)); Log.debug(e); } } } - + public static class TestServlet extends HttpServlet implements Servlet { - private int _count; private static int __sleepers; private static int __maxSleepers; - + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try @@ -214,25 +210,24 @@ public class QoSFilterTest extends TestCase } response.setContentType("text/plain"); - response.getWriter().println("DONE!"); + response.getWriter().println("DONE!"); } catch (InterruptedException e) { e.printStackTrace(); response.sendError(500); - } + } } } - + public static class QoSFilter2 extends QoSFilter { public int getPriority(ServletRequest request) { - String p = ((HttpServletRequest)request).getParameter("priority"); + String p = request.getParameter("priority"); if (p!=null) return Integer.parseInt(p); return 0; } } - } diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 7db1492776..9979d03167 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -20,6 +20,13 @@ </archive> </configuration> </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.start.*</onlyAnalyze> + </configuration> + </plugin> </plugins> </build> <properties> @@ -29,6 +36,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Config.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Config.java index 61a369bb90..3fb06a8561 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Config.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Config.java @@ -422,7 +422,7 @@ public class Config * Get the classpath for the named section * * @param sectionId - * @return + * @return the classpath for the specified section id */ public Classpath getSectionClasspath(String sectionId) { @@ -432,7 +432,7 @@ public class Config /** * Get the list of section Ids. * - * @return + * @return the set of unique section ids */ public Set<String> getSectionIds() { @@ -517,7 +517,7 @@ public class Config /** * Parse the configuration * - * @param buf + * @param stream the stream to read from * @throws IOException */ public void parse(InputStream stream) throws IOException diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java index 435b008417..a067dd5e44 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java @@ -13,17 +13,18 @@ package org.eclipse.jetty.start; import java.io.BufferedReader; +import java.io.Closeable; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; -import java.io.Reader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.ConnectException; @@ -33,12 +34,11 @@ import java.security.Policy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.TimeZone; -import org.eclipse.jetty.start.log.RedirectedStreamLogger; /*-------------------------------------------*/ /** @@ -49,21 +49,28 @@ import org.eclipse.jetty.start.log.RedirectedStreamLogger; * * <p> * The behaviour of Main is controlled by the parsing of the {@link Config} "org/eclipse/start/start.config" file - * obtained as a resource or file. This can be overridden with the START system property. + * obtained as a resource or file. * </p> */ public class Main { + private static final int EXIT_USAGE = 1; + private static final int ERR_LOGGING = -1; + private static final int ERR_INVOKE_MAIN = -2; + private static final int ERR_SECURITY = -3; + private static final int ERR_NOT_STOPPED = -4; + private static final int ERR_UNKNOWN = -5; private boolean _showUsage = false; private boolean _dumpVersions = false; + private boolean _listConfig = false; private boolean _listOptions = false; private boolean _dryRun = false; private boolean _exec = false; private boolean _secure = false; - private boolean _fromDaemon = false; private final Config _config = new Config(); private Set<String> _sysProps = new HashSet<String>(); - private List<String> _xArgs = new ArrayList<String>(); + private List<String> _jvmArgs = new ArrayList<String>(); + private String _startConfig = null; private String _jettyHome; @@ -77,6 +84,7 @@ public class Main catch (Throwable t) { t.printStackTrace(System.err); + System.exit(ERR_UNKNOWN); } } @@ -86,16 +94,43 @@ public class Main { List<String> arguments = new ArrayList<String>(); - arguments.addAll(loadStartIni()); // Add Arguments from start.ini (if it exists) - if (args.length>0) - arguments.addAll(Arrays.asList(args)); // Add Arguments on Command Line + // add the command line args and look for start.ini args + boolean ini=false; + for (String arg : args) + { + if (arg.startsWith("--ini=")||arg.equals("--ini")) + { + ini=true; + if (arg.length()>6) + { + arguments.addAll(loadStartIni(arg.substring(6))); + continue; + } + } + else if (arg.startsWith("--config=")) + { + _startConfig=arg.substring(9); + } + else + { + arguments.add(arg); + } + } + + // if no non-option inis, add the start.ini + if (!ini) + { + arguments.addAll(0,loadStartIni(null)); + } // The XML Configuration Files to initialize with List<String> xmls = new ArrayList<String>(); + // Process the arguments + int startup=0; for (String arg : arguments) { - if ("--help".equals(arg)) + if ("--help".equals(arg) || "-?".equals(arg)) { _showUsage = true; continue; @@ -103,8 +138,8 @@ public class Main if ("--stop".equals(arg)) { - int port = Integer.parseInt(_config.getProperty("STOP.KEY",System.getProperty("STOP.PORT","-1"))); - String key = _config.getProperty("STOP.KETY",System.getProperty("STOP.KEY",null)); + int port = Integer.parseInt(_config.getProperty("STOP.PORT",System.getProperty("STOP.PORT","-1"))); + String key = _config.getProperty("STOP.KEY",System.getProperty("STOP.KEY",null)); stop(port,key); return; } @@ -121,6 +156,12 @@ public class Main continue; } + if ("--list-config".equals(arg)) + { + _listConfig=true; + continue; + } + if ("--exec-print".equals(arg)||"--dry-run".equals(arg)) { _dryRun = true; @@ -134,12 +175,31 @@ public class Main } // Special internal indicator that jetty was started by the jetty.sh Daemon - if ("--fromDaemon".equals(arg)) + if ("--daemon".equals(arg)) { - _fromDaemon = true; - PrintStream logger = new PrintStream(new RedirectedStreamLogger("daemon_yyyy_mm_dd.log",false,90,TimeZone.getTimeZone("GMT"))); + File startDir = new File(System.getProperty("jetty.logs","logs")); + if (!startDir.exists() || !startDir.canWrite() ) + startDir = new File("."); + File startLog = new File(startDir,"start.log"); + if (!startLog.exists() && !startLog.createNewFile()) + { + // Output about error is lost in majority of cases. + System.err.println("Unable to create: " + startLog.getAbsolutePath()); + // Toss a unique exit code indicating this failure. + System.exit(ERR_LOGGING); + } + + if (!startLog.canWrite()) + { + // Output about error is lost in majority of cases. + System.err.println("Unable to write to: " + startLog.getAbsolutePath()); + // Toss a unique exit code indicating this failure. + System.exit(ERR_LOGGING); + } + PrintStream logger = new PrintStream(new FileOutputStream(startLog,false)); System.setOut(logger); System.setErr(logger); + System.out.println("Establishing start.log on " + new Date()); continue; } @@ -149,9 +209,9 @@ public class Main continue; } - if (arg.startsWith("-X")) + if (arg.startsWith("--pre=")) { - _xArgs.add(arg); + xmls.add(startup++,arg.substring(6)); continue; } @@ -173,15 +233,30 @@ public class Main continue; } + if (arg.startsWith("-")) + { + _jvmArgs.add(arg); + continue; + } + // Is this a Property? - else if (arg.indexOf('=') >= 0) + if (arg.indexOf('=') >= 0) { String[] assign = arg.split("=",2); switch(assign.length) { case 2: - this._config.setProperty(assign[0],assign[1]); + if ("OPTIONS".equals(assign[0])) + { + String opts[] = assign[1].split(","); + for (String opt : opts) + _config.addActiveOption(opt); + } + else + { + this._config.setProperty(assign[0],assign[1]); + } break; case 1: this._config.setProperty(assign[0],null); @@ -189,21 +264,13 @@ public class Main default: break; } + continue; } - + // Anything else is considered an XML file. xmls.add(arg); } - - // Special case for OPTIONS property - String options = _config.getProperty("OPTIONS"); - if (options!=null) - { - String ids[] = options.split(","); - for (String id : ids) - _config.addActiveOption(id); - } start(xmls); } @@ -211,18 +278,23 @@ public class Main { t.printStackTrace(System.err); System.out.println("Use java -jar start.jar --help for usage information."); + System.exit(ERR_UNKNOWN); } } /** * If a start.ini is present in the CWD, then load it into the argument list. */ - private List<String> loadStartIni() + private List<String> loadStartIni(String ini) { String jettyHome=System.getProperty("jetty.home"); - File startIniFile = (jettyHome!=null)? new File(jettyHome,"start.ini"):new File("start.ini"); + File startIniFile = ini==null?((jettyHome!=null)? new File(jettyHome,"start.ini"):new File("start.ini")):new File(ini); if (!startIniFile.exists() || !startIniFile.canRead()) { + if (ini != null) + { + System.err.println("Warning - can't find ini file: " + ini); + } // No start.ini found, skip load. return Collections.emptyList(); } @@ -239,15 +311,18 @@ public class Main String arg; while ((arg = buf.readLine()) != null) { - arg=arg.trim(); - if (arg.length()==0 || arg.startsWith("#")) + arg = arg.trim(); + if (arg.length() == 0 || arg.startsWith("#")) + { continue; + } args.add(arg); } } catch (IOException e) { - e.printStackTrace(); + e.printStackTrace(System.err); + System.exit(ERR_UNKNOWN); } finally { @@ -267,7 +342,7 @@ public class Main { System.err.println("Usage: java -jar start.jar [options] [properties] [configs]"); System.err.println("ERROR: detailed usage resource unavailable"); - System.exit(1); + System.exit(EXIT_USAGE); } BufferedReader buf = null; @@ -278,61 +353,81 @@ public class Main while ((line = buf.readLine()) != null) { - if (line.startsWith("@OPTIONS@")) + if (line.endsWith("@") && line.indexOf('@')!=line.lastIndexOf('@')) { - List<String> sortedOptions = new ArrayList<String>(); - sortedOptions.addAll(_config.getSectionIds()); - Collections.sort(sortedOptions); - - System.err.println(" Available OPTIONS: "); + String indent=line.substring(0,line.indexOf("@")); + String info=line.substring(line.indexOf('@'),line.lastIndexOf('@')); - for (String option : sortedOptions) - { - System.err.println(" [" + option + "]"); - } - } - else if (line.startsWith("@CONFIGS@")) - { - System.err.println(" Configurations Available in ${jetty.home}/etc/: "); - File etc = new File(System.getProperty("jetty.home","."),"etc"); - if (!etc.exists()) + if (info.equals("@OPTIONS")) { - System.err.println(" Unable to find " + etc); - continue; - } + List<String> sortedOptions = new ArrayList<String>(); + sortedOptions.addAll(_config.getSectionIds()); + Collections.sort(sortedOptions); - if (!etc.isDirectory()) - { - System.err.println(" Unable list dir " + etc); - continue; + for (String option : sortedOptions) + { + if ("*".equals(option) || option.trim().length()==0) + continue; + System.out.print(indent); + System.out.println(option); + } } - - File configs[] = etc.listFiles(new FileFilter() + else if (info.equals("@CONFIGS")) { - public boolean accept(File path) + File etc = new File(System.getProperty("jetty.home","."),"etc"); + if (!etc.exists() || !etc.isDirectory()) + { + System.out.print(indent); + System.out.println("Unable to find/list " + etc); + continue; + } + + File configs[] = etc.listFiles(new FileFilter() { - if (!path.isFile()) + public boolean accept(File path) { - return false; - } + if (!path.isFile()) + { + return false; + } - String name = path.getName().toLowerCase(); - return (name.startsWith("jetty") && name.endsWith(".xml")); - } - }); + String name = path.getName().toLowerCase(); + return (name.startsWith("jetty") && name.endsWith(".xml")); + } + }); - List<File> configFiles = new ArrayList<File>(); - configFiles.addAll(Arrays.asList(configs)); - Collections.sort(configFiles); + List<File> configFiles = new ArrayList<File>(); + configFiles.addAll(Arrays.asList(configs)); + Collections.sort(configFiles); - for (File configFile : configFiles) + for (File configFile : configFiles) + { + System.out.print(indent); + System.out.print("etc/"); + System.out.println(configFile.getName()); + } + } + else if (info.equals("@STARTINI")) { - System.err.println(" etc/" + configFile.getName()); + List<String> ini = loadStartIni(null); + if (ini!=null && ini.size()>0) + { + for (String a : ini) + { + System.out.print(indent); + System.out.println(a); + } + } + else + { + System.out.print(indent); + System.out.println("none"); + } } } else { - System.err.println(line); + System.out.println(line); } } } @@ -342,19 +437,9 @@ public class Main } finally { - if (buf != null) - { - try - { - buf.close(); - } - catch (IOException ignore) - { - /* ignore */ - } - } + close(buf); } - System.exit(1); + System.exit(EXIT_USAGE); } public void invokeMain(ClassLoader classloader, String classname, List<String> args) throws IllegalAccessException, InvocationTargetException, @@ -374,13 +459,19 @@ public class Main if (Config.isDebug() || invoked_class == null) { if (invoked_class == null) + { System.err.println("ClassNotFound: " + classname); + } else + { System.err.println(classname + " " + invoked_class.getPackage().getImplementationVersion()); + } if (invoked_class == null) { - usage(); + System.err.println("Usage: java -jar start.jar [options] [properties] [configs]"); + System.err.println(" java -jar start.jar --help # for more information"); + System.exit(ERR_INVOKE_MAIN); return; } } @@ -395,36 +486,19 @@ public class Main } /* ------------------------------------------------------------ */ - public static void close(Reader reader) + public static void close(Closeable c) { - if (reader == null) + if (c == null) { return; } try { - reader.close(); + c.close(); } catch (IOException e) { - e.printStackTrace(); - } - } - - /* ------------------------------------------------------------ */ - public static void close(InputStream stream) - { - if (stream == null) - { - return; - } - try - { - stream.close(); - } - catch (IOException e) - { - e.printStackTrace(); + e.printStackTrace(System.err); } } @@ -443,12 +517,6 @@ public class Main throw new FileNotFoundException("No XML configuration files specified in start.config or command line."); } - // Add required logging if executed via the daemon. - if (_fromDaemon) - { - configuredXmls.add("etc/jetty-logging.xml"); - } - // Add mandatory options for secure mode if (_secure) { @@ -496,6 +564,12 @@ public class Main showAllOptionsWithVersions(classpath); return; } + + if (_listConfig) + { + listConfig(); + return; + } // Show Command Line to execute Jetty if (_dryRun) @@ -516,8 +590,10 @@ public class Main return; } - if (_xArgs.size()>0 || _sysProps.size()>0) + if (_jvmArgs.size() > 0 || _sysProps.size() > 0) + { System.err.println("WARNING: System properties and/or JVM args set. Consider using --dry-run or --exec"); + } // Set current context class loader to what is selected. Thread.currentThread().setContextClassLoader(cl); @@ -534,12 +610,16 @@ public class Main // Check for override of start class (via "jetty.server" property) String mainClass = System.getProperty("jetty.server"); if (mainClass != null) + { classname = mainClass; + } // Check for override of start class (via "main.class" property) mainClass = System.getProperty("main.class"); if (mainClass != null) + { classname = mainClass; + } Config.debug("main.class=" + classname); @@ -547,7 +627,8 @@ public class Main } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(System.err); + System.exit(ERR_INVOKE_MAIN); } } @@ -609,18 +690,18 @@ public class Main { StringBuilder cmd = new StringBuilder(); cmd.append(findJavaBin()); - for (String x:_xArgs) + for (String x:_jvmArgs) cmd.append(' ').append(x); cmd.append(" -Djetty.home=").append(_jettyHome); for (String p:_sysProps) { - cmd.append(" -D").append(p); + cmd.append(" -D").append(p); String v=System.getProperty(p); - if (v!=null) + if (v!=null && v.length()>0) cmd.append('=').append(v); } - cmd.append(" -cp ").append(classpath.toString()); - cmd.append(' ').append(_config.getMainClassname()); + cmd.append(" -cp ").append(classpath.toString()); + cmd.append(" ").append(_config.getMainClassname()); for (String xml : xmls) { cmd.append(' ').append(xml); @@ -785,28 +866,23 @@ public class Main } catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } catch (NoSuchMethodException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } catch (InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } } } @@ -861,12 +937,15 @@ public class Main { Policy policy = Policy.getPolicy(); if (policy != null) + { policy.refresh(); + } } } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(System.err); + System.exit(ERR_SECURITY); } } @@ -881,6 +960,34 @@ public class Main return ret; } + private void listConfig() + { + InputStream cfgstream = null; + try + { + cfgstream=getConfigStream(); + byte[] buf=new byte[4096]; + + int len=0; + + while (len>=0) + { + len=cfgstream.read(buf); + if (len>0) + System.out.write(buf,0,len); + } + } + catch (Exception e) + { + e.printStackTrace(System.err); + System.exit(ERR_UNKNOWN); + } + finally + { + close(cfgstream); + } + } + /** * Load Configuration. * @@ -898,18 +1005,9 @@ public class Main { // Pass in xmls.size into Config so that conditions based on "nargs" work. _config.setArgCount(xmls.size()); - - // What start.config should we use? - String cfgName = System.getProperty("START","org/eclipse/jetty/start/start.config"); - Config.debug("config=" + cfgName); - - // Look up config as resource first. - cfgstream = getClass().getClassLoader().getResourceAsStream(cfgName); - - // resource not found, try filesystem next - if (cfgstream == null) - cfgstream = new FileInputStream(cfgName); - + + cfgstream=getConfigStream(); + // parse the config _config.parse(cfgstream); @@ -937,8 +1035,8 @@ public class Main catch (Exception e) { e.printStackTrace(); - System.exit(1); - return null; // never executed (just to satisfy javac compiler) + System.exit(ERR_UNKNOWN); + return null; // never executed (just here to satisfy javac compiler) } finally { @@ -946,10 +1044,32 @@ public class Main } } + private InputStream getConfigStream() throws FileNotFoundException + { + String config=_startConfig; + if (config == null || config.length() == 0) + { + config = System.getProperty("START","org/eclipse/jetty/start/start.config"); + } + + Config.debug("config=" + config); + + // Look up config as resource first. + InputStream cfgstream = getClass().getClassLoader().getResourceAsStream(config); + + // resource not found, try filesystem next + if (cfgstream == null) + { + cfgstream = new FileInputStream(config); + } + + return cfgstream; + } + private void startMonitor() { - int port = Integer.parseInt(System.getProperty("STOP.PORT","-1")); - String key = System.getProperty("STOP.KEY",null); + int port = Integer.parseInt(_config.getProperty("STOP.PORT",System.getProperty("STOP.PORT","-1"))); + String key = _config.getProperty("STOP.KEY",System.getProperty("STOP.KEY",null)); Monitor.monitor(port,key); } @@ -965,7 +1085,9 @@ public class Main try { if (_port <= 0) + { System.err.println("STOP.PORT system property must be specified"); + } if (_key == null) { _key = ""; @@ -974,18 +1096,26 @@ public class Main } Socket s = new Socket(InetAddress.getByName("127.0.0.1"),_port); - OutputStream out = s.getOutputStream(); - out.write((_key + "\r\nstop\r\n").getBytes()); - out.flush(); - s.close(); + try + { + OutputStream out = s.getOutputStream(); + out.write((_key + "\r\nstop\r\n").getBytes()); + out.flush(); + } + finally + { + s.close(); + } } catch (ConnectException e) { System.err.println("ERROR: Not running!"); + System.exit(ERR_NOT_STOPPED); } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(System.err); + System.exit(ERR_UNKNOWN); } } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/log/RedirectedStreamLogger.java b/jetty-start/src/main/java/org/eclipse/jetty/start/log/RedirectedStreamLogger.java deleted file mode 100644 index 65ba90f2b1..0000000000 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/log/RedirectedStreamLogger.java +++ /dev/null @@ -1,299 +0,0 @@ -package org.eclipse.jetty.start.log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.TimeZone; -import java.util.Timer; -import java.util.TimerTask; - -public class RedirectedStreamLogger extends FilterOutputStream -{ - private static Timer __rollover; - - final static String YYYY_MM_DD = "yyyy_mm_dd"; - final static String ROLLOVER_FILE_DATE_FORMAT = "yyyy_MM_dd"; - final static String ROLLOVER_FILE_BACKUP_FORMAT = "HHmmssSSS"; - final static int ROLLOVER_FILE_RETAIN_DAYS = 31; - - private RollTask _rollTask; - private SimpleDateFormat _fileBackupFormat; - private SimpleDateFormat _fileDateFormat; - - private String _filename; - private File _file; - private boolean _append; - private int _retainDays; - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @throws IOException - */ - public RedirectedStreamLogger(String filename) throws IOException - { - this(filename,true,ROLLOVER_FILE_RETAIN_DAYS); - } - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @param append - * If true, existing files will be appended to. - * @throws IOException - */ - public RedirectedStreamLogger(String filename, boolean append) throws IOException - { - this(filename,append,ROLLOVER_FILE_RETAIN_DAYS); - } - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @param append - * If true, existing files will be appended to. - * @param retainDays - * The number of days to retain files before deleting them. 0 to retain forever. - * @throws IOException - */ - public RedirectedStreamLogger(String filename, boolean append, int retainDays) throws IOException - { - this(filename,append,retainDays,TimeZone.getDefault()); - } - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @param append - * If true, existing files will be appended to. - * @param retainDays - * The number of days to retain files before deleting them. 0 to retain forever. - * @throws IOException - */ - public RedirectedStreamLogger(String filename, boolean append, int retainDays, TimeZone zone) throws IOException - { - this(filename,append,retainDays,zone,null,null); - } - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @param append - * If true, existing files will be appended to. - * @param retainDays - * The number of days to retain files before deleting them. 0 to retain forever. - * @param dateFormat - * The format for the date file substitution. The default is "yyyy_MM_dd". - * @param backupFormat - * The format for the file extension of backup files. The default is "HHmmssSSS". - * @throws IOException - */ - public RedirectedStreamLogger(String filename, boolean append, int retainDays, TimeZone zone, String dateFormat, String backupFormat) throws IOException - { - super(null); - - if (dateFormat == null) - dateFormat = ROLLOVER_FILE_DATE_FORMAT; - _fileDateFormat = new SimpleDateFormat(dateFormat); - - if (backupFormat == null) - backupFormat = ROLLOVER_FILE_BACKUP_FORMAT; - _fileBackupFormat = new SimpleDateFormat(backupFormat); - - _fileBackupFormat.setTimeZone(zone); - _fileDateFormat.setTimeZone(zone); - - if (filename != null) - { - filename = filename.trim(); - if (filename.length() == 0) - filename = null; - } - if (filename == null) - throw new IllegalArgumentException("Invalid filename"); - - _filename = filename; - _append = append; - _retainDays = retainDays; - setFile(); - - synchronized (RedirectedStreamLogger.class) - { - if (__rollover == null) - __rollover = new Timer(RedirectedStreamLogger.class.getName(),true); - - _rollTask = new RollTask(); - - Calendar now = Calendar.getInstance(); - now.setTimeZone(zone); - - GregorianCalendar midnight = new GregorianCalendar(now.get(Calendar.YEAR),now.get(Calendar.MONTH),now.get(Calendar.DAY_OF_MONTH),23,0); - midnight.setTimeZone(zone); - midnight.add(Calendar.HOUR,1); - __rollover.scheduleAtFixedRate(_rollTask,midnight.getTime(),1000L * 60 * 60 * 24); - } - } - - /* ------------------------------------------------------------ */ - public String getFilename() - { - return _filename; - } - - /* ------------------------------------------------------------ */ - public String getDatedFilename() - { - if (_file == null) - return null; - return _file.toString(); - } - - /* ------------------------------------------------------------ */ - public int getRetainDays() - { - return _retainDays; - } - - /* ------------------------------------------------------------ */ - private synchronized void setFile() throws IOException - { - // Check directory - File file = new File(_filename); - _filename = file.getCanonicalPath(); - file = new File(_filename); - File dir = new File(file.getParent()); - if (!dir.isDirectory() || !dir.canWrite()) - throw new IOException("Cannot write log directory " + dir); - - Date now = new Date(); - - // Is this a rollover file? - String filename = file.getName(); - int i = filename.toLowerCase().indexOf(YYYY_MM_DD); - if (i >= 0) - { - file = new File(dir,filename.substring(0,i) + _fileDateFormat.format(now) + filename.substring(i + YYYY_MM_DD.length())); - } - - if (file.exists() && !file.canWrite()) - throw new IOException("Cannot write log file " + file); - - // Do we need to change the output stream? - if (out == null || !file.equals(_file)) - { - // Yep - _file = file; - if (!_append && file.exists()) - file.renameTo(new File(file.toString() + "." + _fileBackupFormat.format(now))); - OutputStream oldOut = out; - out = new FileOutputStream(file.toString(),_append); - if (oldOut != null) - oldOut.close(); - //if(log.isDebugEnabled())log.debug("Opened "+_file); - } - } - - /* ------------------------------------------------------------ */ - private void removeOldFiles() - { - if (_retainDays > 0) - { - long now = System.currentTimeMillis(); - - File file = new File(_filename); - File dir = new File(file.getParent()); - String fn = file.getName(); - int s = fn.toLowerCase().indexOf(YYYY_MM_DD); - if (s < 0) - return; - String prefix = fn.substring(0,s); - String suffix = fn.substring(s + YYYY_MM_DD.length()); - - String[] logList = dir.list(); - for (int i = 0; i < logList.length; i++) - { - fn = logList[i]; - if (fn.startsWith(prefix) && fn.indexOf(suffix,prefix.length()) >= 0) - { - File f = new File(dir,fn); - long date = f.lastModified(); - if (((now - date) / (1000 * 60 * 60 * 24)) > _retainDays) - f.delete(); - } - } - } - } - - /* ------------------------------------------------------------ */ - @Override - public void write(byte[] buf) throws IOException - { - out.write(buf); - } - - /* ------------------------------------------------------------ */ - @Override - public void write(byte[] buf, int off, int len) throws IOException - { - out.write(buf,off,len); - } - - /* ------------------------------------------------------------ */ - /** - */ - @Override - public void close() throws IOException - { - synchronized (RedirectedStreamLogger.class) - { - try - { - super.close(); - } - finally - { - out = null; - _file = null; - } - - _rollTask.cancel(); - } - } - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - private class RollTask extends TimerTask - { - @Override - public void run() - { - try - { - RedirectedStreamLogger.this.setFile(); - RedirectedStreamLogger.this.removeOldFiles(); - - } - catch (IOException e) - { - e.printStackTrace(); - } - } - } -} diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config b/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config index 38b51c91dc..94d2609611 100644 --- a/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config +++ b/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config @@ -139,16 +139,20 @@ $(jetty.home)/lib/setuid/** $(jetty.home)/lib/jetty-policy-$(version).jar ! available org.eclipse.jetty.policy.JettyPolicy $(jetty.home)/lib/policy/jetty.policy -[All,client] +[All,Client,client] $(jetty.home)/lib/jetty-http-$(version).jar ! available org.eclipse.jetty.http.HttpParser $(jetty.home)/lib/jetty-client-$(version).jar ! available org.eclipse.jetty.client.HttpClient [All,websocket] $(jetty.home)/lib/jetty-websocket-$(version).jar ! available org.eclipse.jetty.websocket.WebSocket +[Client] +$(jetty.home)/lib/jetty-http-$(version).jar ! available org.eclipse.jetty.http.HttpParser + [All,websocket] $(jetty.home)/lib/jetty-websocket-$(version).jar ! available org.eclipse.jetty.websocket.WebSocket - + + # Add ext if it exists [Server,All,default,ext] $(jetty.home)/lib/ext/** diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt index 18a0e3b495..7371be3f99 100644 --- a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt +++ b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt @@ -1,58 +1,75 @@ -Usage: java -jar start.jar [options] [properties] [configs] +Usage: java -jar start.jar [options...] [properties...] [configs...] The start.jar builds a classpath and executes a main java class with a classloader built from that classpath. By default the start.jar mechanism is configured to start the jetty server, but it can be configured to start any java main class. -Common Options: +Command Line Options: --help This help / usage information. - --version Print the version information for Jetty, then exit. - --stop Stop the running Jetty instance. - -Advanced Options: - - --list-options List available options, then exit. - (see OPTION property in section below) + + --version Print the version information for Jetty and + dependent jars, then exit. + --list-options List the details of each classpath OPTION + + --list-config List the start.config file. + --dry-run Print the command line that the start.jar generates, then exit. This may be used to generate command lines when the start.ini includes -X or -D arguments. - On unix, the resulting command line can be run with - eval $(java -jar start.jar --dry-run) - This is more efficient than the --exec option, which - creates a second JVM instance --exec Run the generated command line (see --dry-run) in a sub processes. This can be used when start.ini contains -X or -D arguments, but creates an extra JVM instance. + + --stop Stop the running Jetty instance. + + --daemon Start in daemon mode with stderr and stdout + redirected to ${jetty.log}/start.log + + --config=<file> Specify an alternate start.config file. + The default is the start.config file inside + the start.jar. The default can also be specified + with the START system property. + + --ini=<file> Load command line arguments from a file. If + no --ini options are specified, then the + start.ini file will be read if it exists. + A --ini option with no file indicates that + start.ini should not be read. - --secure Enable Security: - * JVM Security Manager - * Security Policies - * Secure Logging - * Audit Logging - - If the file start.ini exists in the working directory, then it's each line - of it's contents is prepended to the as an argument to the command line. + --pre=<file> Specify a configuration file that is to be processed + before any configuration files listed in start.ini System Properties: These are set with a command line like "java -Dname=value ..." and are accessible via the java.lang.System#getProperty(String) API. Some key system properties are: + org.eclipse.jetty.util.log.class=[class] A Low Level Jetty Logger Implementation to use (default: org.eclipse.jetty.util.log.Slf4jLog) + org.eclipse.jetty.util.log.DEBUG=[boolean] Debug logging for the stderr and javautil Loggers. Slf4j and other loggers must be separately configured for debug. (default: false) + org.eclipse.jetty.util.log.IGNORED=[boolean] Ignored exceptions are logged, independent of DEBUG settings (default: false) -Start Properties: + org.eclipse.jetty.util.log.SOURCE=[boolean] + The source location of logs is logged in the stderr Logger. + (default: false) + + com.sun.management.jmxremote + Enable remote JMX management in Sun JVMS. + + +Properties: These are set with a command line like "java -jar start.jar name=value" and only affect the start mechanism. Some of these are defined in the default start.config and will not be available if another configuration @@ -61,29 +78,46 @@ Start Properties: path=[directory] An additional class path element to add to the started class path. Typically this is used to add directories of classes and/or resources + lib=[directory] An additional library directory to add to the started class path. This must be a (deep) directory of jars + STOP.PORT=[number] The port to use to stop the running Jetty server. Required along with STOP.KEY if you want to use the --stop option above. + STOP.KEY=[alphanumeric] The passphrase defined to stop the server. Requried along with STOP.PORT if you want to use the --stop option above. + DEBUG=true Enable debug on the start mechanism and sets the org.eclipse.jetty.util.log.stderr.DEBUG system property to true. (default: false) - OPTIONS=[option,option,...] - Classpath Options to use. By convention, option names starting with capitals - will include associated options (eg Server includes jetty-server, jetty-webapp, - jetty-deploy, etc). An option starting with a lowercase letter includes - just the direct dependencies of the option (eg jsp includes just jetty-jsp - module and it's dependencies). - (default: "default,*") -@OPTIONS@ + OPTIONS=[option,option,...] + Enable classpath OPTIONS. Each options represents one or more jars + to be added to the classpath. The options are defined in + the start.config file and can be listed with --help or --list-options. + By convention, options starting with a capital letter (eg Server) + are aggregations of other available options. Available OPTIONS: + + @OPTIONS@ + + +Available Configurations: + By convention, configuration files are kept in $JETTY_HOME/etc. + The known configuration files are: + + @CONFIGS@ + + +Defaults: + A start.ini file may be used to specify default arguments to start.jar, + which are used if no command line arguments are provided and override + the defaults in the start.config file. If --ini options are provided on + the command line, then start.ini will no be read. The current start.ini + arguments are: -Configs: - XML Configurations to use. -@CONFIGS@ + @STARTINI@ diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigTest.java index d3d3557b6f..fcd591bea1 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigTest.java @@ -5,13 +5,13 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.start; @@ -25,31 +25,29 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import junit.framework.TestCase; +import org.junit.Assert; +import org.junit.Test; -public class ConfigTest extends TestCase +public class ConfigTest { - private File jettyHomeDir; - private File resourcesDir; - private void assertEquals(String msg, Classpath expected, Classpath actual) { - assertNotNull(msg + " : expected classpath should not be null",expected); - assertNotNull(msg + " : actual classpath should not be null",actual); - assertTrue(msg + " : expected should have an entry",expected.count() >= 1); - assertTrue(msg + " : actual should have an entry",actual.count() >= 1); + Assert.assertNotNull(msg + " : expected classpath should not be null",expected); + Assert.assertNotNull(msg + " : actual classpath should not be null",actual); + Assert.assertTrue(msg + " : expected should have an entry",expected.count() >= 1); + Assert.assertTrue(msg + " : actual should have an entry",actual.count() >= 1); if (expected.count() != actual.count()) { expected.dump(System.err); actual.dump(System.err); - assertEquals(msg + " : count",expected.count(),actual.count()); + Assert.assertEquals(msg + " : count",expected.count(),actual.count()); } List<File> actualEntries = Arrays.asList(actual.getElements()); List<File> expectedEntries = Arrays.asList(expected.getElements()); int len = expectedEntries.size(); - + for (int i = 0; i < len; i++) { File expectedFile = expectedEntries.get(i); @@ -58,18 +56,18 @@ public class ConfigTest extends TestCase { expected.dump(System.err); actual.dump(System.err); - assertEquals(msg + ": entry [" + i + "]",expectedEntries.get(i),actualEntries.get(i)); + Assert.assertEquals(msg + ": entry [" + i + "]",expectedEntries.get(i),actualEntries.get(i)); } } } private void assertEquals(String msg, Collection<String> expected, Collection<String> actual) { - assertTrue(msg + " : expected should have an entry",expected.size() >= 1); - assertEquals(msg + " : size",expected.size(),actual.size()); + Assert.assertTrue(msg + " : expected should have an entry",expected.size() >= 1); + Assert.assertEquals(msg + " : size",expected.size(),actual.size()); for (String expectedVal : expected) { - assertTrue(msg + " : should contain <" + expectedVal + ">",actual.contains(expectedVal)); + Assert.assertTrue(msg + " : should contain <" + expectedVal + ">",actual.contains(expectedVal)); } } @@ -81,12 +79,7 @@ public class ConfigTest extends TestCase private File getJettyHomeDir() { - if (jettyHomeDir == null) - { - jettyHomeDir = new File(getTestResourcesDir(),"jetty.home"); - } - - return jettyHomeDir; + return new File(getTestResourcesDir(),"jetty.home"); } private String getTestableJettyHome() @@ -96,19 +89,15 @@ public class ConfigTest extends TestCase private File getTestResourcesDir() { - if (resourcesDir == null) - { - File src = new File(System.getProperty("user.dir"),"src"); - File test = new File(src,"test"); - resourcesDir = new File(test,"resources"); - } - - return resourcesDir; + File src = new File(System.getProperty("user.dir"),"src"); + File test = new File(src,"test"); + return new File(test,"resources"); } - /** + /* * Test for SUBJECT "/=" for assign canonical path */ + @Test public void testSubjectAssignCanonicalPath() throws IOException { StringBuffer buf = new StringBuffer(); @@ -117,12 +106,13 @@ public class ConfigTest extends TestCase Config cfg = new Config(); cfg.parse(buf); - assertEquals(getTestResourcesDir().getCanonicalPath(),cfg.getProperty("test.resources.dir")); + Assert.assertEquals(getTestResourcesDir().getCanonicalPath(),cfg.getProperty("test.resources.dir")); } - /** + /* * Test for SUBJECT "~=" for assigning Start Properties */ + @Test public void testSubjectAssignStartProperty() throws IOException { StringBuffer buf = new StringBuffer(); @@ -132,13 +122,14 @@ public class ConfigTest extends TestCase Config options = new Config(); options.parse(buf); - assertEquals("foo",options.getProperty("test.jetty.start.text")); - assertEquals("Eatagramovabits",options.getProperty("test.jetty.start.quote")); + Assert.assertEquals("foo",options.getProperty("test.jetty.start.text")); + Assert.assertEquals("Eatagramovabits",options.getProperty("test.jetty.start.quote")); } - /** + /* * Test for SUBJECT "=" for assigning System Properties */ + @Test public void testSubjectAssignSystemProperty() throws IOException { StringBuffer buf = new StringBuffer(); @@ -148,13 +139,14 @@ public class ConfigTest extends TestCase Config options = new Config(); options.parse(buf); - assertEquals("foo",System.getProperty("test.jetty.start.text")); - assertEquals("Eatagramovabits",System.getProperty("test.jetty.start.quote")); + Assert.assertEquals("foo",System.getProperty("test.jetty.start.text")); + Assert.assertEquals("Eatagramovabits",System.getProperty("test.jetty.start.quote")); } - /** + /* * Test for SUBJECT ending with "/**", all jar and zip components in dir (deep, recursive) */ + @Test public void testSubjectComponentDirDeep() throws IOException { StringBuffer buf = new StringBuffer(); @@ -191,9 +183,10 @@ public class ConfigTest extends TestCase assertEquals("Components (Deep)",expected,actual); } - /** + /* * Test for SUBJECT ending with "/*", all jar and zip components in dir (shallow, no recursion) */ + @Test public void testSubjectComponentDirShallow() throws IOException { StringBuffer buf = new StringBuffer(); @@ -225,9 +218,10 @@ public class ConfigTest extends TestCase assertEquals("Components (Shallow)",expected,actual); } - /** + /* * Test for SUBJECT ending with ".class", a Main Class */ + @Test public void testSubjectMainClass() throws IOException { StringBuffer buf = new StringBuffer(); @@ -236,12 +230,13 @@ public class ConfigTest extends TestCase Config options = new Config(); options.parse(buf); - assertEquals("org.eclipse.jetty.xml.XmlConfiguration",options.getMainClassname()); + Assert.assertEquals("org.eclipse.jetty.xml.XmlConfiguration",options.getMainClassname()); } - /** + /* * Test for SUBJECT ending with ".class", a Main Class */ + @Test public void testSubjectMainClassConditionalPropertySet() throws IOException { StringBuffer buf = new StringBuffer(); @@ -252,12 +247,13 @@ public class ConfigTest extends TestCase options.setProperty("start.class","net.company.server.Start"); options.parse(buf); - assertEquals("net.company.server.Start",options.getMainClassname()); + Assert.assertEquals("net.company.server.Start",options.getMainClassname()); } - /** + /* * Test for SUBJECT ending with ".class", a Main Class */ + @Test public void testSubjectMainClassConditionalPropertyUnset() throws IOException { StringBuffer buf = new StringBuffer(); @@ -268,12 +264,13 @@ public class ConfigTest extends TestCase // The "start.class" property is unset. options.parse(buf); - assertEquals("org.eclipse.jetty.xml.XmlConfiguration",options.getMainClassname()); + Assert.assertEquals("org.eclipse.jetty.xml.XmlConfiguration",options.getMainClassname()); } - /** + /* * Test for SUBJECT ending with "/", a simple Classpath Entry */ + @Test public void testSubjectSimpleComponent() throws IOException { StringBuffer buf = new StringBuffer(); @@ -293,9 +290,10 @@ public class ConfigTest extends TestCase assertEquals("Simple Component",expected,actual); } - /** + /* * Test for SUBJECT ending with "/", a simple Classpath Entry */ + @Test public void testSubjectSimpleComponentMultiple() throws IOException { StringBuffer buf = new StringBuffer(); @@ -317,9 +315,10 @@ public class ConfigTest extends TestCase assertEquals("Simple Component",expected,actual); } - /** + /* * Test for SUBJECT ending with "/", a simple Classpath Entry */ + @Test public void testSubjectSimpleComponentNotExists() throws IOException { StringBuffer buf = new StringBuffer(); @@ -340,9 +339,10 @@ public class ConfigTest extends TestCase assertEquals("Simple Component",expected,actual); } - /** + /* * Test for SUBJECT ending with ".xml", an XML Configuration File */ + @Test public void testSubjectXmlConfigAlt() throws IOException { StringBuffer buf = new StringBuffer(); @@ -359,13 +359,14 @@ public class ConfigTest extends TestCase List<String> actual = options.getXmlConfigs(); String expected = new File("src/test/resources/test-alt.xml").getAbsolutePath(); - assertEquals("XmlConfig.size",1,actual.size()); - assertEquals(expected,actual.get(0)); + Assert.assertEquals("XmlConfig.size",1,actual.size()); + Assert.assertEquals(expected,actual.get(0)); } - /** + /* * Test for SUBJECT ending with ".xml", an XML Configuration File */ + @Test public void testSubjectXmlConfigDefault() throws IOException { StringBuffer buf = new StringBuffer(); @@ -380,13 +381,14 @@ public class ConfigTest extends TestCase List<String> actual = options.getXmlConfigs(); String expected = getJettyEtcFile("test-jetty.xml"); - assertEquals("XmlConfig.size",1,actual.size()); - assertEquals(expected,actual.get(0)); + Assert.assertEquals("XmlConfig.size",1,actual.size()); + Assert.assertEquals(expected,actual.get(0)); } - /** + /* * Test for SUBJECT ending with ".xml", an XML Configuration File. */ + @Test public void testSubjectXmlConfigMultiple() throws IOException { StringBuffer buf = new StringBuffer(); @@ -409,9 +411,10 @@ public class ConfigTest extends TestCase assertEquals("Multiple XML Configs",expected,actual); } - /** + /* * Test Section Handling */ + @Test public void testSectionClasspathSingle() throws IOException { StringBuffer buf = new StringBuffer(); @@ -426,12 +429,12 @@ public class ConfigTest extends TestCase options.parse(buf); Classpath defaultClasspath = options.getClasspath(); - assertNotNull("Default Classpath should not be null",defaultClasspath); + Assert.assertNotNull("Default Classpath should not be null",defaultClasspath); Classpath foocp = options.getSectionClasspath("Foo"); - assertNull("Foo Classpath should not exist",foocp); + Assert.assertNull("Foo Classpath should not exist",foocp); Classpath allcp = options.getSectionClasspath("All"); - assertNotNull("Classpath section 'All' should exist",allcp); + Assert.assertNotNull("Classpath section 'All' should exist",allcp); File lib = new File(getJettyHomeDir(),"lib"); @@ -441,10 +444,11 @@ public class ConfigTest extends TestCase assertEquals("Single Classpath Section",expected,allcp); } - - /** + + /* * Test Section Handling */ + @Test public void testSectionClasspathAvailable() throws IOException { StringBuffer buf = new StringBuffer(); @@ -459,12 +463,12 @@ public class ConfigTest extends TestCase options.parse(buf); Classpath defaultClasspath = options.getClasspath(); - assertNotNull("Default Classpath should not be null",defaultClasspath); + Assert.assertNotNull("Default Classpath should not be null",defaultClasspath); Classpath foocp = options.getSectionClasspath("Foo"); - assertNull("Foo Classpath should not exist",foocp); + Assert.assertNull("Foo Classpath should not exist",foocp); Classpath allcp = options.getSectionClasspath("All"); - assertNotNull("Classpath section 'All' should exist",allcp); + Assert.assertNotNull("Classpath section 'All' should exist",allcp); File lib = new File(getJettyHomeDir(),"lib"); @@ -475,9 +479,10 @@ public class ConfigTest extends TestCase assertEquals("Single Classpath Section",expected,allcp); } - /** + /* * Test Section Handling, with multiple defined sections. */ + @Test public void testSectionClasspathMultiples() throws IOException { StringBuffer buf = new StringBuffer(); @@ -506,10 +511,10 @@ public class ConfigTest extends TestCase cfg.parse(buf); Classpath defaultClasspath = cfg.getClasspath(); - assertNotNull("Default Classpath should not be null",defaultClasspath); + Assert.assertNotNull("Default Classpath should not be null",defaultClasspath); Classpath foocp = cfg.getSectionClasspath("Foo"); - assertNull("Foo Classpath should not exist",foocp); + Assert.assertNull("Foo Classpath should not exist",foocp); // Test if entire section list can be fetched Set<String> sections = cfg.getSectionIds(); @@ -527,7 +532,7 @@ public class ConfigTest extends TestCase // Test fetch of specific section by name works Classpath cpAll = cfg.getSectionClasspath("All"); - assertNotNull("Classpath section 'All' should exist",cpAll); + Assert.assertNotNull("Classpath section 'All' should exist",cpAll); File lib = new File(getJettyHomeDir(),"lib"); @@ -539,14 +544,14 @@ public class ConfigTest extends TestCase expectedAll.addComponent(new File(lib,"LOGGING.JAR")); assertEquals("Classpath 'All' Section",expectedAll,cpAll); - + // Test combined classpath fetch of multiple sections works List<String> activated = new ArrayList<String>(); activated.add("server"); activated.add("logging"); - + Classpath cpCombined = cfg.getCombinedClasspath(activated); - + Classpath expectedCombined = new Classpath(); // from default expectedCombined.addComponent(new File(lib,"spec.zip")); @@ -559,17 +564,16 @@ public class ConfigTest extends TestCase // from '*' expectedCombined.addComponent(new File(lib,"io.jar")); expectedCombined.addComponent(new File(lib,"util.jar")); - + assertEquals("Classpath combined 'server,logging'",expectedCombined,cpCombined); } - - + @Test public void testDynamicSection() throws IOException { StringBuffer buf = new StringBuffer(); buf.append("[All,default,=$(jetty.home)/lib/*]\n"); - + String jettyHome = getTestableJettyHome(); Config options = new Config(); @@ -577,32 +581,31 @@ public class ConfigTest extends TestCase options.parse(buf); Classpath defaultClasspath = options.getClasspath(); - assertNotNull("Default Classpath should not be null",defaultClasspath); + Assert.assertNotNull("Default Classpath should not be null",defaultClasspath); Classpath foocp = options.getSectionClasspath("foo"); - assertNotNull("Foo Classpath should not exist",foocp); + Assert.assertNotNull("Foo Classpath should not exist",foocp); Classpath allcp = options.getSectionClasspath("All"); - assertNotNull("Classpath section 'All' should exist",allcp); - + Assert.assertNotNull("Classpath section 'All' should exist",allcp); + Classpath extcp = options.getSectionClasspath("ext"); - assertNotNull("Classpath section 'ext' should exist", extcp); + Assert.assertNotNull("Classpath section 'ext' should exist", extcp); - assertEquals("Deep Classpath Section",0,foocp.count()); + Assert.assertEquals("Deep Classpath Section",0,foocp.count()); - Classpath expected = new Classpath(); File lib = new File(getJettyHomeDir(),"lib"); File ext = new File(lib, "ext"); - expected = new Classpath(); + Classpath expected = new Classpath(); expected.addComponent(new File(ext,"custom-impl.jar")); assertEquals("Single Classpath Section",expected,extcp); - } - + + @Test public void testDeepDynamicSection() throws IOException { StringBuffer buf = new StringBuffer(); buf.append("[All,default,=$(jetty.home)/lib/**]\n"); - + String jettyHome = getTestableJettyHome(); @@ -611,15 +614,15 @@ public class ConfigTest extends TestCase options.parse(buf); Classpath defaultClasspath = options.getClasspath(); - assertNotNull("Default Classpath should not be null",defaultClasspath); + Assert.assertNotNull("Default Classpath should not be null",defaultClasspath); Classpath foocp = options.getSectionClasspath("foo"); - assertNotNull("Foo Classpath should not exist",foocp); + Assert.assertNotNull("Foo Classpath should not exist",foocp); Classpath allcp = options.getSectionClasspath("All"); - assertNotNull("Classpath section 'All' should exist",allcp); - + Assert.assertNotNull("Classpath section 'All' should exist",allcp); + Classpath extcp = options.getSectionClasspath("ext"); - assertNotNull("Classpath section 'ext' should exist", extcp); + Assert.assertNotNull("Classpath section 'ext' should exist", extcp); File lib = new File(getJettyHomeDir(),"lib"); @@ -628,11 +631,10 @@ public class ConfigTest extends TestCase File bar = new File(foo, "bar"); expected.addComponent(new File(bar,"foobar.jar")); assertEquals("Deep Classpath Section",expected,foocp); - + File ext = new File(lib, "ext"); expected = new Classpath(); expected.addComponent(new File(ext,"custom-impl.jar")); assertEquals("Single Classpath Section",expected,extcp); - } } diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/VersionTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/VersionTest.java index 63643e806d..f3a8fee032 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/VersionTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/VersionTest.java @@ -5,27 +5,31 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.start; -import junit.framework.TestCase; +import org.junit.Test; -public class VersionTest extends TestCase +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class VersionTest { + @Test public void testDefaultVersion() { Version version = new Version(); - assertEquals("Default version difference to 0.0.0",0,version.compare(new Version("0.0.0"))); } - + + @Test public void testNewerVersion() { assertIsNewer("0.0.0", "0.0.1"); assertIsNewer("0.1.0", "0.1.1"); @@ -33,6 +37,7 @@ public class VersionTest extends TestCase // assertIsNewer("1.6.0_12", "1.6.0_16"); // JDK version spec? } + @Test public void testOlderVersion() { assertIsOlder("0.0.1", "0.0.0"); assertIsOlder("0.1.1", "0.1.0"); @@ -43,7 +48,6 @@ public class VersionTest extends TestCase { Version vbase = new Version(basever); Version vtest = new Version(testver); - assertTrue("Version [" + testver + "] should be older than [" + basever + "]", vtest.compare(vbase) == -1); } @@ -52,7 +56,6 @@ public class VersionTest extends TestCase { Version vbase = new Version(basever); Version vtest = new Version(testver); - assertTrue("Version [" + testver + "] should be newer than [" + basever + "]", vtest.compare(vbase) == 1); } diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index 6a3f9c5aab..e8801c32a3 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -25,7 +25,7 @@ </goals> <configuration> <instructions> - <Import-Package>org.slf4j;version="[1.5,1.6)";resolution:=optional,*</Import-Package> + <Import-Package>org.slf4j;version="[1.5,1.7)";resolution:=optional,*</Import-Package> </instructions> </configuration> </execution> @@ -60,18 +60,20 @@ </execution> </executions> </plugin> - <!-- Always create the source bundle. the configuration is inherited by the parent pom. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.util.*</onlyAnalyze> + </configuration> </plugin> - </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-util/src/main/config/etc/jetty-logging.xml b/jetty-util/src/main/config/etc/jetty-logging.xml index 09b590abe6..f6e47e6057 100644 --- a/jetty-util/src/main/config/etc/jetty-logging.xml +++ b/jetty-util/src/main/config/etc/jetty-logging.xml @@ -13,7 +13,7 @@ <New id="ServerLog" class="java.io.PrintStream"> <Arg> <New class="org.eclipse.jetty.util.RolloverFileOutputStream"> - <Arg><SystemProperty name="jetty.home" default="."/>/logs/yyyy_mm_dd.stderrout.log</Arg> + <Arg><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.stderrout.log</Arg> <Arg type="boolean">false</Arg> <Arg type="int">90</Arg> <Arg><Call class="java.util.TimeZone" name="getTimeZone"><Arg>GMT</Arg></Call></Arg> diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java index 829b4ef938..aaba131ea3 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java @@ -20,10 +20,8 @@ import java.util.Queue; /* ------------------------------------------------------------ */ /** Queue backed by circular array. * - * This partial Queue implementation (also with {@link #pop()} for stack operation) + * This partial Queue implementation (also with {@link #remove()} for stack operation) * is backed by a growable circular array. - * - * * * @param <E> */ @@ -214,7 +212,7 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E> /* ------------------------------------------------------------ */ /** * Get without synchronization or bounds checking. - * @see get(int) + * @see #get(int) */ public E getUnsafe(int index) { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java index d433996e7c..ce23e549c8 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java @@ -40,7 +40,8 @@ public class AttributesMap implements Attributes { _map=map; } - + + /* ------------------------------------------------------------ */ public AttributesMap(AttributesMap map) { _map=new HashMap<String,Object>(map._map); @@ -117,7 +118,13 @@ public class AttributesMap implements Attributes { _map.clear(); } - + + /* ------------------------------------------------------------ */ + public int size() + { + return _map.size(); + } + /* ------------------------------------------------------------ */ @Override public String toString() @@ -130,5 +137,16 @@ public class AttributesMap implements Attributes { return _map.keySet(); } + + /* ------------------------------------------------------------ */ + public void addAll(Attributes attributes) + { + Enumeration<String> e = attributes.getAttributeNames(); + while (e.hasMoreElements()) + { + String name=e.nextElement(); + setAttribute(name,attributes.getAttribute(name)); + } + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/HostMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/HostMap.java new file mode 100644 index 0000000000..768171561e --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/HostMap.java @@ -0,0 +1,101 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + + +package org.eclipse.jetty.util; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/* ------------------------------------------------------------ */ +/** + */ +public class HostMap<TYPE> extends HashMap<String, TYPE> +{ + /* --------------------------------------------------------------- */ + /** Construct empty HostMap. + */ + public HostMap() + { + super(11); + } + + /* --------------------------------------------------------------- */ + /** Construct empty HostMap. + * + * @param capacity initial capacity + */ + public HostMap(int capacity) + { + super (capacity); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.util.HashMap#put(java.lang.Object, java.lang.Object) + */ + @Override + public TYPE put(String host, TYPE object) + throws IllegalArgumentException + { + return super.put(host, object); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.util.HashMap#get(java.lang.Object) + */ + @Override + public TYPE get(Object key) + { + return super.get(key); + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve a lazy list of map entries associated with specified + * hostname by taking into account the domain suffix matches. + * + * @param host hostname + * @return lazy list of map entries + */ + public Object getLazyMatches(String host) + { + if (host == null) + return LazyList.getList(super.entrySet()); + + int idx = 0; + String domain = host.trim(); + HashSet<String> domains = new HashSet<String>(); + do { + domains.add(domain); + if ((idx = domain.indexOf('.')) > 0) + { + domain = domain.substring(idx+1); + } + } while (idx > 0); + + Object entries = null; + for(Map.Entry<String, TYPE> entry: super.entrySet()) + { + if (domains.contains(entry.getKey())) + { + entries = LazyList.add(entries,entry); + } + } + + return entries; + } + +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java new file mode 100644 index 0000000000..dc9f82e687 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java @@ -0,0 +1,358 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.util; + +import java.util.BitSet; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; + + +/* ------------------------------------------------------------ */ +/** + * Internet address map to object + * <p> + * Internet addresses may be specified as absolute address or as a combination of + * four octet wildcard specifications (a.b.c.d) that are defined as follows. + * </p> + * <pre> + * nnn - an absolute value (0-255) + * mmm-nnn - an inclusive range of absolute values, + * with following shorthand notations: + * nnn- => nnn-255 + * -nnn => 0-nnn + * - => 0-255 + * a,b,... - a list of wildcard specifications + * </pre> + */ +public class IPAddressMap<TYPE> extends HashMap<String, TYPE> +{ + private final HashMap<String,IPAddrPattern> _patterns = new HashMap<String,IPAddrPattern>(); + + /* --------------------------------------------------------------- */ + /** Construct empty IPAddressMap. + */ + public IPAddressMap() + { + super(11); + } + + /* --------------------------------------------------------------- */ + /** Construct empty IPAddressMap. + * + * @param capacity initial capacity + */ + public IPAddressMap(int capacity) + { + super (capacity); + } + + /* ------------------------------------------------------------ */ + /** + * Insert a new internet address into map + * + * @see java.util.HashMap#put(java.lang.Object, java.lang.Object) + */ + @Override + public TYPE put(String addrSpec, TYPE object) + throws IllegalArgumentException + { + if (addrSpec == null || addrSpec.trim().length() == 0) + throw new IllegalArgumentException("Invalid IP address pattern: "+addrSpec); + + String spec = addrSpec.trim(); + if (_patterns.get(spec) == null) + _patterns.put(spec,new IPAddrPattern(spec)); + + return super.put(spec, object); + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve the object mapped to the specified internet address literal + * + * @see java.util.HashMap#get(java.lang.Object) + */ + @Override + public TYPE get(Object key) + { + return super.get(key); + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve the first object that is associated with the specified + * internet address by taking into account the wildcard specifications. + * + * @param addr internet address + * @return associated object + */ + public TYPE match(String addr) + { + Map.Entry<String, TYPE> entry = getMatch(addr); + return entry==null ? null : entry.getValue(); + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve the first map entry that is associated with the specified + * internet address by taking into account the wildcard specifications. + * + * @param addr internet address + * @return map entry associated + */ + public Map.Entry<String, TYPE> getMatch(String addr) + { + if (addr != null) + { + for(Map.Entry<String, TYPE> entry: super.entrySet()) + { + if (_patterns.get(entry.getKey()).match(addr)) + { + return entry; + } + } + } + return null; + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve a lazy list of map entries associated with specified + * internet address by taking into account the wildcard specifications. + * + * @param addr internet address + * @return lazy list of map entries + */ + public Object getLazyMatches(String addr) + { + if (addr == null) + return LazyList.getList(super.entrySet()); + + Object entries = null; + for(Map.Entry<String, TYPE> entry: super.entrySet()) + { + if (_patterns.get(entry.getKey()).match(addr)) + { + entries = LazyList.add(entries,entry); + } + } + return entries; + } + + /* ------------------------------------------------------------ */ + /** + * IPAddrPattern + * + * Represents internet address wildcard. + * Matches the wildcard to provided internet address. + */ + private static class IPAddrPattern + { + private final OctetPattern[] _octets = new OctetPattern[4]; + /* ------------------------------------------------------------ */ + /** + * Create new IPAddrPattern + * + * @param value internet address wildcard specification + * @throws IllegalArgumentException if wildcard specification is invalid + */ + public IPAddrPattern(String value) + throws IllegalArgumentException + { + if (value == null || value.trim().length() == 0) + throw new IllegalArgumentException("Invalid IP address pattern: "+value); + + try + { + StringTokenizer parts = new StringTokenizer(value, "."); + + String part; + for (int idx=0; idx<4; idx++) + { + part = parts.hasMoreTokens() ? parts.nextToken().trim() : "0-255"; + + int len = part.length(); + if (len == 0 && parts.hasMoreTokens()) + throw new IllegalArgumentException("Invalid IP address pattern: "+value); + + _octets[idx] = new OctetPattern(len==0 ? "0-255" : part); + } + } + catch (IllegalArgumentException ex) + { + throw new IllegalArgumentException("Invalid IP address pattern: "+value, ex); + } + } + + /* ------------------------------------------------------------ */ + /** + * Match the specified internet address against the wildcard + * + * @param value internet address + * @return true if specified internet address matches wildcard specification + * + * @throws IllegalArgumentException if specified internet address is invalid + */ + public boolean match(String value) + throws IllegalArgumentException + { + if (value == null || value.trim().length() == 0) + throw new IllegalArgumentException("Invalid IP address: "+value); + + try + { + StringTokenizer parts = new StringTokenizer(value, "."); + + boolean result = true; + for (int idx=0; idx<4; idx++) + { + if (!parts.hasMoreTokens()) + throw new IllegalArgumentException("Invalid IP address: "+value); + + if (!(result &= _octets[idx].match(parts.nextToken()))) + break; + } + return result; + } + catch (IllegalArgumentException ex) + { + throw new IllegalArgumentException("Invalid IP address: "+value, ex); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * OctetPattern + * + * Represents a single octet wildcard. + * Matches the wildcard to the specified octet value. + */ + private static class OctetPattern extends BitSet + { + private final BitSet _mask = new BitSet(256); + + /* ------------------------------------------------------------ */ + /** + * Create new OctetPattern + * + * @param octetSpec octet wildcard specification + * @throws IllegalArgumentException if wildcard specification is invalid + */ + public OctetPattern(String octetSpec) + throws IllegalArgumentException + { + try + { + if (octetSpec != null) + { + String spec = octetSpec.trim(); + if(spec.length() == 0) + { + _mask.set(0,255); + } + else + { + StringTokenizer parts = new StringTokenizer(spec,","); + while (parts.hasMoreTokens()) + { + String part = parts.nextToken().trim(); + if (part.length() > 0) + { + if (part.indexOf('-') < 0) + { + Integer value = Integer.valueOf(part); + _mask.set(value); + } + else + { + int low = 0, high = 255; + + String[] bounds = part.split("-",-2); + if (bounds.length != 2) + { + throw new IllegalArgumentException("Invalid octet spec: "+octetSpec); + } + + if (bounds[0].length() > 0) + { + low = Integer.parseInt(bounds[0]); + } + if (bounds[1].length() > 0) + { + high = Integer.parseInt(bounds[1]); + } + + if (low > high) + { + throw new IllegalArgumentException("Invalid octet spec: "+octetSpec); + } + + _mask.set(low, high+1); + } + } + } + } + } + } + catch (NumberFormatException ex) + { + throw new IllegalArgumentException("Invalid octet spec: "+octetSpec, ex); + } + } + + /* ------------------------------------------------------------ */ + /** + * Match specified octet value against the wildcard + * + * @param value octet value + * @return true if specified octet value matches the wildcard + * @throws IllegalArgumentException if specified octet value is invalid + */ + public boolean match(String value) + throws IllegalArgumentException + { + if (value == null || value.trim().length() == 0) + throw new IllegalArgumentException("Invalid octet: "+value); + + try + { + int number = Integer.parseInt(value); + return match(number); + } + catch (NumberFormatException ex) + { + throw new IllegalArgumentException("Invalid octet: "+value); + } + } + + /* ------------------------------------------------------------ */ + /** + * Match specified octet value against the wildcard + * + * @param number octet value + * @return true if specified octet value matches the wildcard + * @throws IllegalArgumentException if specified octet value is invalid + */ + public boolean match(int number) + throws IllegalArgumentException + { + if (number < 0 || number > 255) + throw new IllegalArgumentException("Invalid octet: "+number); + + return _mask.get(number); + } + } +}
\ No newline at end of file diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/LazyList.java b/jetty-util/src/main/java/org/eclipse/jetty/util/LazyList.java index 6156b9df16..56d16275e6 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/LazyList.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/LazyList.java @@ -51,7 +51,6 @@ import java.util.ListIterator; * An ArrayList of default size is used as the initial LazyList. * * @see java.util.List - * */ public class LazyList implements Cloneable, Serializable @@ -283,7 +282,7 @@ public class LazyList /** Convert a lazylist to an array * @param list The list to convert * @param clazz The class of the array, which may be a primitive type - * @return + * @return array of the lazylist entries passed in */ @SuppressWarnings("unchecked") public static Object toArray(Object list,Class<?> clazz) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java index f464dc4c97..6eb82e4951 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java @@ -283,7 +283,7 @@ public class MultiPartInputStream */ public MultiPartInputStream (InputStream in, String contentType, MultipartConfigElement config) { - _in = in; + _in = new BufferedInputStream(in); _contentType = contentType; _config = config; if (_config == null) @@ -463,11 +463,14 @@ public class MultiPartInputStream // this is not a boundary if(cr) part.write(13); + if(lf) - part.write(10); + part.write(10); + cr=lf=false; if(b>0) part.write(byteBoundary,0,b); + b=-1; part.write(c); } @@ -477,8 +480,10 @@ public class MultiPartInputStream { if(cr) part.write(13); + if(lf) part.write(10); + cr=lf=false; part.write(byteBoundary,0,b); b=-1; @@ -494,9 +499,11 @@ public class MultiPartInputStream } // handle CR LF if(cr) - part.write(13); + part.write(13); + if(lf) part.write(10); + cr=(c==13); lf=(c==10||state==10); if(state==10) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java b/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java index 3d8522e451..d573906979 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java @@ -32,8 +32,8 @@ public abstract class PatternMatcher * Will iterate over the jar names, matching * all those starting with "aaa-" first, then "bbb-". * - * @param pattern - * @param loader + * @param pattern the pattern + * @param uris the uris to test the pattern against * @param isNullInclusive if true, an empty pattern means all names match, if false, none match * @throws Exception */ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java b/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java index 90729a14f1..dfa66bf03e 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.util; +import java.io.IOException; import java.util.NoSuchElementException; import java.util.StringTokenizer; @@ -266,7 +267,7 @@ public class QuotedStringTokenizer * @param s The string to quote. * @return quoted string */ - public static String quote(String s, String delim) + public static String quoteIfNeeded(String s, String delim) { if (s==null) return null; @@ -309,162 +310,19 @@ public class QuotedStringTokenizer } - /* ------------------------------------------------------------ */ - /** Quote a string into a StringBuffer. + /** Quote a string into an Appendable. * The characters ", \, \n, \r, \t, \f and \b are escaped - * @param buf The StringBuffer + * @param buf The Appendable * @param s The String to quote. */ - public static void quote(StringBuffer buf, String s) + public static void quote(Appendable buf, String s) { - synchronized(buf) + try { buf.append('"'); - - int i=0; - loop: - for (;i<s.length();i++) - { - char c = s.charAt(i); - switch(c) - { - case '"': - buf.append(s,0,i); - buf.append("\\\""); - break loop; - case '\\': - buf.append(s,0,i); - buf.append("\\\\"); - break loop; - case '\n': - buf.append(s,0,i); - buf.append("\\n"); - break loop; - case '\r': - buf.append(s,0,i); - buf.append("\\r"); - break loop; - case '\t': - buf.append(s,0,i); - buf.append("\\t"); - break loop; - case '\f': - buf.append(s,0,i); - buf.append("\\f"); - break loop; - case '\b': - buf.append(s,0,i); - buf.append("\\b"); - break loop; - - default: - continue; - } - } - if (i==s.length()) - buf.append(s); - else - { - i++; - for (;i<s.length();i++) - { - char c = s.charAt(i); - switch(c) - { - case '"': - buf.append("\\\""); - continue; - case '\\': - buf.append("\\\\"); - continue; - case '\n': - buf.append("\\n"); - continue; - case '\r': - buf.append("\\r"); - continue; - case '\t': - buf.append("\\t"); - continue; - case '\f': - buf.append("\\f"); - continue; - case '\b': - buf.append("\\b"); - continue; - - default: - buf.append(c); - continue; - } - } - } - - buf.append('"'); - } - - - - } - - - /* ------------------------------------------------------------ */ - /** Quote a string into a StringBuffer. - * The characters ", \, \n, \r, \t, \f and \b are escaped - * @param buf The StringBuffer - * @param s The String to quote. - */ - public static void quote(StringBuilder buf, String s) - { - buf.append('"'); - - int i=0; - loop: - for (;i<s.length();i++) - { - char c = s.charAt(i); - switch(c) - { - case '"': - buf.append(s,0,i); - buf.append("\\\""); - break loop; - case '\\': - buf.append(s,0,i); - buf.append("\\\\"); - break loop; - case '\n': - buf.append(s,0,i); - buf.append("\\n"); - break loop; - case '\r': - buf.append(s,0,i); - buf.append("\\r"); - break loop; - case '\t': - buf.append(s,0,i); - buf.append("\\t"); - break loop; - case '\f': - buf.append(s,0,i); - buf.append("\\f"); - break loop; - case '\b': - buf.append(s,0,i); - buf.append("\\b"); - break loop; - default: - continue; - } - } - if (i==s.length()) - buf.append(s); - else - { - i++; - for (;i<s.length();i++) + for (int i=0;i<s.length();i++) { char c = s.charAt(i); switch(c) @@ -492,187 +350,60 @@ public class QuotedStringTokenizer continue; default: - buf.append(c); - continue; - } - } - } - - buf.append('"'); - } - - - - - - /* ------------------------------------------------------------ */ - /** Quote a string into a StringBuffer. - * The characters ", \, \n, \r, \t, \f, \b are escaped. - * Quotes are forced if any escaped characters are present or there - * is a ", ', space, +, =, ; or % character. - * - * @param buf The StringBuffer - * @param s The String to quote. - */ - public static void quoteIfNeeded(StringBuffer buf, String s) - { - synchronized(buf) - { - int e=-1; - - search: for (int i=0;i<s.length();i++) - { - char c = s.charAt(i); - switch(c) - { - case '"': - case '\\': - case '\n': - case '\r': - case '\t': - case '\f': - case '\b': - case '%': - case '+': - case ' ': - case ';': - case '=': - e=i; - buf.append('"'); - // TODO when 1.4 support is dropped: buf.append(s,0,e); - for (int j=0;j<e;j++) - buf.append(s.charAt(j)); - break search; - - default: - continue; - } - } - - if (e<0) - { - buf.append(s); - return; - } - - for (int i=e;i<s.length();i++) - { - char c = s.charAt(i); - switch(c) - { - case '"': - buf.append("\\\""); - continue; - case '\\': - buf.append("\\\\"); - continue; - case '\n': - buf.append("\\n"); - continue; - case '\r': - buf.append("\\r"); - continue; - case '\t': - buf.append("\\t"); - continue; - case '\f': - buf.append("\\f"); - continue; - case '\b': - buf.append("\\b"); - continue; - - default: - buf.append(c); + if (c<0x10) + { + buf.append("\\u000"); + buf.append(Integer.toString(c,16)); + } + else if (c<=0x1f) + { + buf.append("\\u00"); + buf.append(Integer.toString(c,16)); + } + else + buf.append(c); continue; } } + buf.append('"'); + } + catch(IOException e) + { + throw new RuntimeException(e); } } /* ------------------------------------------------------------ */ - /** Quote a string into a StringBuffer. - * The characters ", \, \n, \r, \t, \f, \b are escaped. - * Quotes are forced if any escaped characters are present or there - * is a ", ', space, + or % character. + /** Quote a string into a StringBuffer only if needed. + * Quotes are forced if any delim characters are present. * - * @param buf The StringBuilder + * @param buf The StringBuffer * @param s The String to quote. + * @param delim String of characters that must be quoted. + * @return true if quoted; */ - public static void quoteIfNeeded(StringBuilder buf, String s) + public static boolean quoteIfNeeded(Appendable buf, String s,String delim) { - int e=-1; - - search: for (int i=0;i<s.length();i++) + for (int i=0;i<s.length();i++) { char c = s.charAt(i); - switch(c) + if (delim.indexOf(c)>=0) { - case '"': - case '\\': - case '\n': - case '\r': - case '\t': - case '\f': - case '\b': - case '%': - case '+': - case ' ': - case ';': - case '=': - e=i; - buf.append('"'); - // TODO when 1.4 support is dropped: buf.append(s,0,e); - for (int j=0;j<e;j++) - buf.append(s.charAt(j)); - break search; - - default: - continue; + quote(buf,s); + return true; } } - - if (e<0) + + try { buf.append(s); - return; + return false; } - - for (int i=e;i<s.length();i++) + catch(IOException e) { - char c = s.charAt(i); - switch(c) - { - case '"': - buf.append("\\\""); - continue; - case '\\': - buf.append("\\\\"); - continue; - case '\n': - buf.append("\\n"); - continue; - case '\r': - buf.append("\\r"); - continue; - case '\t': - buf.append("\\t"); - continue; - case '\f': - buf.append("\\f"); - continue; - case '\b': - buf.append("\\b"); - continue; - - default: - buf.append(c); - continue; - } + throw new RuntimeException(e); } - buf.append('"'); - } /* ------------------------------------------------------------ */ @@ -720,6 +451,15 @@ public class QuotedStringTokenizer case 'b': b.append('\b'); break; + case '\\': + b.append('\\'); + break; + case '/': + b.append('/'); + break; + case '"': + b.append('"'); + break; case 'u': b.append((char)( (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<24)+ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java index 77dc44664e..0cacc83b11 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java @@ -120,7 +120,7 @@ public class Scanner /** * Get the location of the directory to scan - * @return + * @return the first directory (of {@link #getScanDirs()} being scanned) * @deprecated use getScanDirs() instead */ @Deprecated @@ -160,7 +160,7 @@ public class Scanner /** * Get any filter applied to files in the scan dir. - * @return + * @return the filename filter */ public FilenameFilter getFilenameFilter () { @@ -310,7 +310,6 @@ public class Scanner /** * Recursively scan all files in the designated directories. - * @return Map of name of file to last modified time */ public synchronized void scanFiles () { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index 5c508eb368..5c279c094c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.util; @@ -25,20 +25,20 @@ import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ -/** TYPE Utilities. +/** + * TYPE Utilities. * Provides various static utiltiy methods for manipulating types and their * string representations. * * @since Jetty 4.1 - * */ public class TypeUtil { public static int CR = '\015'; public static int LF = '\012'; - + /* ------------------------------------------------------------ */ - private static final HashMap name2Class=new HashMap(); + private static final HashMap<String, Class> name2Class=new HashMap<String, Class>(); static { name2Class.put("boolean",java.lang.Boolean.TYPE); @@ -50,7 +50,7 @@ public class TypeUtil name2Class.put("long",java.lang.Long.TYPE); name2Class.put("short",java.lang.Short.TYPE); name2Class.put("void",java.lang.Void.TYPE); - + name2Class.put("java.lang.Boolean.TYPE",java.lang.Boolean.TYPE); name2Class.put("java.lang.Byte.TYPE",java.lang.Byte.TYPE); name2Class.put("java.lang.Character.TYPE",java.lang.Character.TYPE); @@ -84,9 +84,9 @@ public class TypeUtil name2Class.put("String",java.lang.String.class); name2Class.put("java.lang.String",java.lang.String.class); } - + /* ------------------------------------------------------------ */ - private static final HashMap class2Name=new HashMap(); + private static final HashMap<Class, String> class2Name=new HashMap<Class, String>(); static { class2Name.put(java.lang.Boolean.TYPE,"boolean"); @@ -107,19 +107,19 @@ public class TypeUtil class2Name.put(java.lang.Integer.class,"java.lang.Integer"); class2Name.put(java.lang.Long.class,"java.lang.Long"); class2Name.put(java.lang.Short.class,"java.lang.Short"); - + class2Name.put(null,"void"); class2Name.put(java.lang.String.class,"java.lang.String"); } - + /* ------------------------------------------------------------ */ - private static final HashMap class2Value=new HashMap(); + private static final HashMap<Class, Method> class2Value=new HashMap<Class, Method>(); static { try { Class[] s ={java.lang.String.class}; - + class2Value.put(java.lang.Boolean.TYPE, java.lang.Boolean.class.getMethod("valueOf",s)); class2Value.put(java.lang.Byte.TYPE, @@ -157,53 +157,15 @@ public class TypeUtil } /* ------------------------------------------------------------ */ - private static Class[] stringArg = { java.lang.String.class }; - - /* ------------------------------------------------------------ */ - private static int intCacheSize = 600; - private static Integer[] integerCache = new Integer[intCacheSize]; - private static String[] integerStrCache = new String[intCacheSize]; - private static Integer minusOne = new Integer(-1); - private static int longCacheSize = 64; - private static Long[] longCache = new Long[longCacheSize]; - private static Long minusOneL = new Long(-1); - - public static void setIntCacheSize(int size) - { - if (size > intCacheSize) { - Integer[] intCache = new Integer[size]; - System.arraycopy(integerCache,0,intCache,0,intCacheSize); - - String [] strCache = new String[size]; - System.arraycopy(integerStrCache,0,strCache,0,intCacheSize); - - intCacheSize = size; - integerCache = intCache; - integerStrCache = strCache; - } - } - - public static void setLongCacheSize(int size) - { - if (size > longCacheSize) { - Long[] lnCache = new Long[size]; - System.arraycopy(longCache,0,lnCache,0,longCacheSize); - - longCacheSize = size; - longCache = lnCache; - } - } - - /* ------------------------------------------------------------ */ /** Class from a canonical name for a type. * @param name A class or type name. * @return A class , which may be a primitive TYPE field.. */ public static Class fromName(String name) { - return (Class)name2Class.get(name); + return name2Class.get(name); } - + /* ------------------------------------------------------------ */ /** Canonical name for a type. * @param type A class , which may be a primitive TYPE field. @@ -211,9 +173,9 @@ public class TypeUtil */ public static String toName(Class type) { - return (String)class2Name.get(type); + return class2Name.get(type); } - + /* ------------------------------------------------------------ */ /** Convert String value to instance. * @param type The class of the instance, which may be a primitive TYPE field. @@ -226,17 +188,17 @@ public class TypeUtil { if (type.equals(java.lang.String.class)) return value; - - Method m = (Method)class2Value.get(type); + + Method m = class2Value.get(type); if (m!=null) - return m.invoke(null,new Object[] {value}); + return m.invoke(null, value); if (type.equals(java.lang.Character.TYPE) || type.equals(java.lang.Character.class)) return new Character(value.charAt(0)); - Constructor c = type.getConstructor(stringArg); - return c.newInstance(new Object[] {value}); + Constructor c = type.getConstructor(java.lang.String.class); + return c.newInstance(value); } catch(NoSuchMethodException e) { @@ -258,7 +220,7 @@ public class TypeUtil } return null; } - + /* ------------------------------------------------------------ */ /** Convert String value to instance. * @param type classname or type (eg int) @@ -269,72 +231,6 @@ public class TypeUtil { return valueOf(fromName(type),value); } - - /* ------------------------------------------------------------ */ - /** Convert int to Integer using cache. - */ - public static Integer newInteger(int i) - { - if (i>=0 && i<intCacheSize) - { - if (integerCache[i]==null) - integerCache[i]=new Integer(i); - return integerCache[i]; - } - else if (i==-1) - return minusOne; - return new Integer(i); - } - - /* ------------------------------------------------------------ */ - /** Convert int to Integer using cache. - */ - public static Long newLong(long i) - { - if (i>=0 && i<longCacheSize) - { - if (longCache[(int)i]==null) - longCache[(int)i]=new Long(i); - return longCache[(int)i]; - } - else if (i==-1) - return minusOneL; - return new Long(i); - } - - - /* ------------------------------------------------------------ */ - /** Convert int to String using cache. - */ - public static String toString(int i) - { - if (i>=0 && i<intCacheSize) - { - if (integerStrCache[i]==null) - integerStrCache[i]=Integer.toString(i); - return integerStrCache[i]; - } - else if (i==-1) - return "-1"; - return Integer.toString(i); - } - - /* ------------------------------------------------------------ */ - /** Convert long to String using cache. - */ - public static String toString(long i) - { - if (i>=0 && i<intCacheSize) - { - if (integerStrCache[(int)i]==null) - integerStrCache[(int)i]=Long.toString(i); - return integerStrCache[(int)i]; - } - else if (i==-1) - return "-1"; - return Long.toString(i); - } - /* ------------------------------------------------------------ */ /** Parse an int from a substring. @@ -343,7 +239,8 @@ public class TypeUtil * @param offset Offset within string * @param length Length of integer or -1 for remainder of string * @param base base of the integer - * @exception NumberFormatException + * @return the parsed integer + * @throws NumberFormatException if the string cannot be parsed */ public static int parseInt(String s, int offset, int length, int base) throws NumberFormatException @@ -356,7 +253,7 @@ public class TypeUtil for (int i=0;i<length;i++) { char c=s.charAt(offset+i); - + int digit=c-'0'; if (digit<0 || digit>=base || digit>=10) { @@ -378,7 +275,8 @@ public class TypeUtil * @param offset Offset within string * @param length Length of integer or -1 for remainder of string * @param base base of the integer - * @exception NumberFormatException + * @return the parsed integer + * @throws NumberFormatException if the array cannot be parsed into an integer */ public static int parseInt(byte[] b, int offset, int length, int base) throws NumberFormatException @@ -391,7 +289,7 @@ public class TypeUtil for (int i=0;i<length;i++) { char c=(char)(0xff&b[offset+i]); - + int digit=c-'0'; if (digit<0 || digit>=base || digit>=10) { @@ -419,9 +317,9 @@ public class TypeUtil public static String toString(byte[] bytes, int base) { StringBuilder buf = new StringBuilder(); - for (int i=0;i<bytes.length;i++) + for (byte b : bytes) { - int bi=0xff&bytes[i]; + int bi=0xff&b; int c='0'+(bi/base)%base; if (c>'9') c= 'a'+(c-'0'-10); @@ -435,7 +333,7 @@ public class TypeUtil } /* ------------------------------------------------------------ */ - /** + /** * @param b An ASCII encoded character 0-9 a-f A-F * @return The byte value of the character 0-16. */ @@ -448,41 +346,35 @@ public class TypeUtil } /* ------------------------------------------------------------ */ - public static void toHex(byte b,StringBuilder buf) - { - int bi=0xff&b; - int c='0'+(bi/16)%16; - if (c>'9') - c= 'A'+(c-'0'-10); - buf.append((char)c); - c='0'+bi%16; - if (c>'9') - c= 'A'+(c-'0'-10); - buf.append((char)c); - } - - /* ------------------------------------------------------------ */ - public static String toHexString(byte[] b) - { - StringBuilder buf = new StringBuilder(); - for (int i=0;i<b.length;i++) + public static void toHex(byte b,Appendable buf) + { + try { - int bi=0xff&b[i]; + int bi=0xff&b; int c='0'+(bi/16)%16; if (c>'9') c= 'A'+(c-'0'-10); buf.append((char)c); c='0'+bi%16; if (c>'9') - c= 'a'+(c-'0'-10); + c= 'A'+(c-'0'-10); buf.append((char)c); } - return buf.toString(); + catch(IOException e) + { + throw new RuntimeException(e); + } + } + + /* ------------------------------------------------------------ */ + public static String toHexString(byte[] b) + { + return toHexString(b, 0, b.length); } - + /* ------------------------------------------------------------ */ public static String toHexString(byte[] b,int offset,int length) - { + { StringBuilder buf = new StringBuilder(); for (int i=offset;i<offset+length;i++) { @@ -498,10 +390,10 @@ public class TypeUtil } return buf.toString(); } - + /* ------------------------------------------------------------ */ public static byte[] fromHexString(String s) - { + { if (s.length()%2!=0) throw new IllegalArgumentException(s); byte[] array = new byte[s.length()/2]; @@ -509,10 +401,10 @@ public class TypeUtil { int b = Integer.parseInt(s.substring(i*2,i*2+2),16); array[i]=(byte)(0xff&b); - } + } return array; } - + public static void dump(Class c) { @@ -529,31 +421,31 @@ public class TypeUtil cl = cl.getParent(); } } - + /* ------------------------------------------------------------ */ public static byte[] readLine(InputStream in) throws IOException { byte[] buf = new byte[256]; - + int i=0; int loops=0; int ch=0; - + while (true) { ch=in.read(); if (ch<0) break; loops++; - + // skip a leading LF's if (loops==1 && ch==LF) continue; - + if (ch==CR || ch==LF) break; - + if (i>=buf.length) { byte[] old_buf=buf; @@ -562,10 +454,10 @@ public class TypeUtil } buf[i++]=(byte)ch; } - + if (ch==-1 && i==0) return null; - + // skip a trailing LF if it exists if (ch==CR && in.available()>=1 && in.markSupported()) { @@ -578,10 +470,10 @@ public class TypeUtil byte[] old_buf=buf; buf=new byte[i]; System.arraycopy(old_buf, 0, buf, 0, i); - + return buf; } - + public static URL jarFor(String className) { try diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java index 37f8486b33..6b5729363c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java @@ -39,7 +39,6 @@ import java.util.Map; * get operations are not protected from concurrent updates. * * @see java.net.URLEncoder - * */ public class UrlEncoded extends MultiMap { @@ -239,7 +238,10 @@ public class UrlEncoded extends MultiMap /* -------------------------------------------------------------- */ /** Decoded parameters to Map. - * @param data the byte[] containing the encoded parameters + * @param raw the byte[] containing the encoded parameters + * @param offset the offset within raw to decode from + * @param length the length of the section to decode + * @param map the {@link MultiMap} to populate */ public static void decodeUtf8To(byte[] raw,int offset, int length, MultiMap map) { @@ -248,7 +250,11 @@ public class UrlEncoded extends MultiMap /* -------------------------------------------------------------- */ /** Decoded parameters to Map. - * @param data the byte[] containing the encoded parameters + * @param raw the byte[] containing the encoded parameters + * @param offset the offset within raw to decode from + * @param length the length of the section to decode + * @param map the {@link MultiMap} to populate + * @param buffer the buffer to decode into */ public static void decodeUtf8To(byte[] raw,int offset, int length, MultiMap map,Utf8StringBuilder buffer) { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ajax/JSON.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ajax/JSON.java index 6cb9a8d40a..7c9a15371c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ajax/JSON.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ajax/JSON.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.util.ajax; @@ -31,10 +31,14 @@ import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; -/** JSON Parser and Generator. - * - * <p>This class provides some static methods to convert POJOs to and from JSON - * notation. The mapping from JSON to java is:<pre> +/** + * JSON Parser and Generator. + * + * <p> + * This class provides some static methods to convert POJOs to and from JSON + * notation. The mapping from JSON to java is: + * + * <pre> * object ==> Map * array ==> Object[] * number ==> Double or Long @@ -42,8 +46,12 @@ import org.eclipse.jetty.util.log.Log; * null ==> null * bool ==> Boolean * </pre> - * </p><p> - * The java to JSON mapping is:<pre> + * + * </p> + * <p> + * The java to JSON mapping is: + * + * <pre> * String --> string * Number --> number * Map --> object @@ -53,36 +61,43 @@ import org.eclipse.jetty.util.log.Log; * Boolean--> boolean * Object --> string (dubious!) * </pre> - * </p><p> - * The interface {@link JSON.Convertible} may be implemented by classes that wish to externalize and - * initialize specific fields to and from JSON objects. Only directed acyclic graphs of objects are supported. + * * </p> * <p> - * The interface {@link JSON.Generator} may be implemented by classes that know how to render themselves as JSON and - * the {@link #toString(Object)} method will use {@link JSON.Generator#addJSON(StringBuffer)} to generate the JSON. - * The class {@link JSON.Literal} may be used to hold pre-gnerated JSON object. + * The interface {@link JSON.Convertible} may be implemented by classes that + * wish to externalize and initialize specific fields to and from JSON objects. + * Only directed acyclic graphs of objects are supported. + * </p> * <p> - * The interface {@link Convertor} may be implemented to provide static convertors for objects that may be registered - * with {@link #registerConvertor(Class, org.eclipse.jetty.util.ajax.JSON.Convertor)}. These convertors are looked up by class, interface and - * super class by {@link #getConvertor(Class)}. + * The interface {@link JSON.Generator} may be implemented by classes that know + * how to render themselves as JSON and the {@link #toString(Object)} method + * will use {@link JSON.Generator#addJSON(Appendable)} to generate the JSON. + * The class {@link JSON.Literal} may be used to hold pre-generated JSON object. + * <p> + * The interface {@link JSON.Convertor} may be implemented to provide static + * convertors for objects that may be registered with + * {@link #registerConvertor(Class, org.eclipse.jetty.util.ajax.JSON.Convertor)} + * . These convertors are looked up by class, interface and super class by + * {@link #getConvertor(Class)}. * </p> - * + * * */ public class JSON { public final static JSON DEFAULT = new JSON(); - private Map<String,Convertor> _convertors=new ConcurrentHashMap<String,Convertor>(); - private int _stringBufferSize=256; - + private Map<String, Convertor> _convertors = new ConcurrentHashMap<String, Convertor>(); + private int _stringBufferSize = 1024; + public JSON() { } - + /* ------------------------------------------------------------ */ /** - * @return the initial stringBuffer size to use when creating JSON strings (default 256) + * @return the initial stringBuffer size to use when creating JSON strings + * (default 1024) */ public int getStringBufferSize() { @@ -91,18 +106,23 @@ public class JSON /* ------------------------------------------------------------ */ /** - * @param stringBufferSize the initial stringBuffer size to use when creating JSON strings (default 256) + * @param stringBufferSize + * the initial stringBuffer size to use when creating JSON + * strings (default 1024) */ public void setStringBufferSize(int stringBufferSize) { - _stringBufferSize=stringBufferSize; + _stringBufferSize = stringBufferSize; } /* ------------------------------------------------------------ */ /** * Register a {@link Convertor} for a class or interface. - * @param forClass The class or interface that the convertor applies to - * @param convertor the convertor + * + * @param forClass + * The class or interface that the convertor applies to + * @param convertor + * the convertor */ public static void registerConvertor(Class forClass, Convertor convertor) { @@ -124,39 +144,31 @@ public class JSON /* ------------------------------------------------------------ */ public static String toString(Object object) { - StringBuffer buffer=new StringBuffer(DEFAULT.getStringBufferSize()); - synchronized (buffer) - { - DEFAULT.append(buffer,object); - return buffer.toString(); - } + StringBuilder buffer = new StringBuilder(DEFAULT.getStringBufferSize()); + DEFAULT.append(buffer,object); + return buffer.toString(); } /* ------------------------------------------------------------ */ public static String toString(Map object) { - StringBuffer buffer=new StringBuffer(DEFAULT.getStringBufferSize()); - synchronized (buffer) - { - DEFAULT.appendMap(buffer,object); - return buffer.toString(); - } + StringBuilder buffer = new StringBuilder(DEFAULT.getStringBufferSize()); + DEFAULT.appendMap(buffer,object); + return buffer.toString(); } /* ------------------------------------------------------------ */ public static String toString(Object[] array) { - StringBuffer buffer=new StringBuffer(DEFAULT.getStringBufferSize()); - synchronized (buffer) - { - DEFAULT.appendArray(buffer,array); - return buffer.toString(); - } + StringBuilder buffer = new StringBuilder(DEFAULT.getStringBufferSize()); + DEFAULT.appendArray(buffer,array); + return buffer.toString(); } /* ------------------------------------------------------------ */ /** - * @param s String containing JSON object or array. + * @param s + * String containing JSON object or array. * @return A Map, Object array or primitive array parsed from the JSON. */ public static Object parse(String s) @@ -166,8 +178,10 @@ public class JSON /* ------------------------------------------------------------ */ /** - * @param s String containing JSON object or array. - * @param stripOuterComment If true, an outer comment around the JSON is ignored. + * @param s + * String containing JSON object or array. + * @param stripOuterComment + * If true, an outer comment around the JSON is ignored. * @return A Map, Object array or primitive array parsed from the JSON. */ public static Object parse(String s, boolean stripOuterComment) @@ -177,7 +191,8 @@ public class JSON /* ------------------------------------------------------------ */ /** - * @param in Reader containing JSON object or array. + * @param in + * Reader containing JSON object or array. * @return A Map, Object array or primitive array parsed from the JSON. */ public static Object parse(Reader in) throws IOException @@ -187,8 +202,10 @@ public class JSON /* ------------------------------------------------------------ */ /** - * @param s Stream containing JSON object or array. - * @param stripOuterComment If true, an outer comment around the JSON is ignored. + * @param in + * Reader containing JSON object or array. + * @param stripOuterComment + * If true, an outer comment around the JSON is ignored. * @return A Map, Object array or primitive array parsed from the JSON. */ public static Object parse(Reader in, boolean stripOuterComment) throws IOException @@ -199,7 +216,8 @@ public class JSON /* ------------------------------------------------------------ */ /** * @deprecated use {@link #parse(Reader)} - * @param in Reader containing JSON object or array. + * @param in + * Reader containing JSON object or array. * @return A Map, Object array or primitive array parsed from the JSON. */ @Deprecated @@ -211,8 +229,10 @@ public class JSON /* ------------------------------------------------------------ */ /** * @deprecated use {@link #parse(Reader, boolean)} - * @param s Stream containing JSON object or array. - * @param stripOuterComment If true, an outer comment around the JSON is ignored. + * @param in + * Stream containing JSON object or array. + * @param stripOuterComment + * If true, an outer comment around the JSON is ignored. * @return A Map, Object array or primitive array parsed from the JSON. */ @Deprecated @@ -222,23 +242,26 @@ public class JSON } /* ------------------------------------------------------------ */ - /** Convert Object to JSON - * @param object The object to convert + /** + * Convert Object to JSON + * + * @param object + * The object to convert * @return The JSON String */ public String toJSON(Object object) { - StringBuffer buffer=new StringBuffer(getStringBufferSize()); - synchronized (buffer) - { - append(buffer,object); - return buffer.toString(); - } + StringBuilder buffer = new StringBuilder(getStringBufferSize()); + append(buffer,object); + return buffer.toString(); } /* ------------------------------------------------------------ */ - /** Convert JSON to Object - * @param json The json to convert + /** + * Convert JSON to Object + * + * @param json + * The json to convert * @return The object */ public Object fromJSON(String json) @@ -247,53 +270,90 @@ public class JSON return parse(source); } + @Deprecated + public void append(StringBuffer buffer, Object object) + { + append((Appendable)buffer,object); + } + /* ------------------------------------------------------------ */ /** * Append object as JSON to string buffer. + * * @param buffer + * the buffer to append to * @param object + * the object to append */ - public void append(StringBuffer buffer, Object object) + public void append(Appendable buffer, Object object) { - if (object==null) - buffer.append("null"); - else if (object instanceof Convertible) - appendJSON(buffer,(Convertible)object); - else if (object instanceof Generator) - appendJSON(buffer,(Generator)object); - else if (object instanceof Map) - appendMap(buffer,(Map)object); - else if (object instanceof Collection) - appendArray(buffer,(Collection)object); - else if (object.getClass().isArray()) - appendArray(buffer,object); - else if (object instanceof Number) - appendNumber(buffer,(Number)object); - else if (object instanceof Boolean) - appendBoolean(buffer,(Boolean)object); - else if (object instanceof Character) - appendString(buffer,object.toString()); - else if (object instanceof String) - appendString(buffer,(String)object); - else + try { - Convertor convertor=getConvertor(object.getClass()); - if (convertor!=null) - appendJSON(buffer,convertor,object); - else + if (object == null) + buffer.append("null"); + else if (object instanceof Convertible) + appendJSON(buffer,(Convertible)object); + else if (object instanceof Generator) + appendJSON(buffer,(Generator)object); + else if (object instanceof Map) + appendMap(buffer,(Map)object); + else if (object instanceof Collection) + appendArray(buffer,(Collection)object); + else if (object.getClass().isArray()) + appendArray(buffer,object); + else if (object instanceof Number) + appendNumber(buffer,(Number)object); + else if (object instanceof Boolean) + appendBoolean(buffer,(Boolean)object); + else if (object instanceof Character) appendString(buffer,object.toString()); + else if (object instanceof String) + appendString(buffer,(String)object); + else + { + Convertor convertor = getConvertor(object.getClass()); + if (convertor != null) + appendJSON(buffer,convertor,object); + else + appendString(buffer,object.toString()); + } + } + catch (IOException e) + { + throw new RuntimeException(e); } } /* ------------------------------------------------------------ */ + @Deprecated public void appendNull(StringBuffer buffer) { - buffer.append("null"); + appendNull((Appendable)buffer); } /* ------------------------------------------------------------ */ + public void appendNull(Appendable buffer) + { + try + { + buffer.append("null"); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + /* ------------------------------------------------------------ */ + @Deprecated public void appendJSON(final StringBuffer buffer, final Convertor convertor, final Object object) { + appendJSON((Appendable)buffer,convertor,object); + } + + /* ------------------------------------------------------------ */ + public void appendJSON(final Appendable buffer, final Convertor convertor, final Object object) + { appendJSON(buffer,new Convertible() { public void fromJSON(Map object) @@ -308,183 +368,206 @@ public class JSON } /* ------------------------------------------------------------ */ + @Deprecated public void appendJSON(final StringBuffer buffer, Convertible converter) { - final char[] c= - { '{' }; - converter.toJSON(new Output() - { - public void add(Object obj) - { - if (c[0]==0) - throw new IllegalStateException(); - append(buffer,obj); - c[0]=0; - } + appendJSON((StringBuffer)buffer,converter); + } - public void addClass(Class type) - { - if (c[0]==0) - throw new IllegalStateException(); - buffer.append(c); - buffer.append("\"class\":"); - append(buffer,type.getName()); - c[0]=','; - } + /* ------------------------------------------------------------ */ + public void appendJSON(final Appendable buffer, Convertible converter) + { + ConvertableOutput out=new ConvertableOutput(buffer); + converter.toJSON(out); + out.complete(); + } - public void add(String name, Object value) - { - if (c[0]==0) - throw new IllegalStateException(); - buffer.append(c); - QuotedStringTokenizer.quote(buffer,name); - buffer.append(':'); - append(buffer,value); - c[0]=','; - } + /* ------------------------------------------------------------ */ + @Deprecated + public void appendJSON(StringBuffer buffer, Generator generator) + { + generator.addJSON(buffer); + } - public void add(String name, double value) - { - if (c[0]==0) - throw new IllegalStateException(); - buffer.append(c); - QuotedStringTokenizer.quote(buffer,name); - buffer.append(':'); - appendNumber(buffer,new Double(value)); - c[0]=','; - } + /* ------------------------------------------------------------ */ + public void appendJSON(Appendable buffer, Generator generator) + { + generator.addJSON(buffer); + } - public void add(String name, long value) + /* ------------------------------------------------------------ */ + @Deprecated + public void appendMap(StringBuffer buffer, Map<?,?> map) + { + appendMap((Appendable)buffer,map); + } + + /* ------------------------------------------------------------ */ + public void appendMap(Appendable buffer, Map<?,?> map) + { + try + { + if (map == null) { - if (c[0]==0) - throw new IllegalStateException(); - buffer.append(c); - QuotedStringTokenizer.quote(buffer,name); - buffer.append(':'); - appendNumber(buffer,TypeUtil.newLong(value)); - c[0]=','; + appendNull(buffer); + return; } - public void add(String name, boolean value) + buffer.append('{'); + Iterator<?> iter = map.entrySet().iterator(); + while (iter.hasNext()) { - if (c[0]==0) - throw new IllegalStateException(); - buffer.append(c); - QuotedStringTokenizer.quote(buffer,name); + Map.Entry<?,?> entry = (Map.Entry<?,?>)iter.next(); + QuotedStringTokenizer.quote(buffer,entry.getKey().toString()); buffer.append(':'); - appendBoolean(buffer,value?Boolean.TRUE:Boolean.FALSE); - c[0]=','; + append(buffer,entry.getValue()); + if (iter.hasNext()) + buffer.append(','); } - }); - if (c[0]=='{') - buffer.append("{}"); - else if (c[0]!=0) - buffer.append("}"); + buffer.append('}'); + } + catch (IOException e) + { + throw new RuntimeException(e); + } } /* ------------------------------------------------------------ */ - public void appendJSON(StringBuffer buffer, Generator generator) + @Deprecated + public void appendArray(StringBuffer buffer, Collection collection) { - generator.addJSON(buffer); + appendArray((Appendable)buffer,collection); } /* ------------------------------------------------------------ */ - public void appendMap(StringBuffer buffer, Map object) + public void appendArray(Appendable buffer, Collection collection) { - if (object==null) + try { - appendNull(buffer); - return; - } + if (collection == null) + { + appendNull(buffer); + return; + } + + buffer.append('['); + Iterator iter = collection.iterator(); + boolean first = true; + while (iter.hasNext()) + { + if (!first) + buffer.append(','); - buffer.append('{'); - Iterator iter=object.entrySet().iterator(); - while (iter.hasNext()) + first = false; + append(buffer,iter.next()); + } + + buffer.append(']'); + } + catch (IOException e) { - Map.Entry entry=(Map.Entry)iter.next(); - QuotedStringTokenizer.quote(buffer,entry.getKey().toString()); - buffer.append(':'); - append(buffer,entry.getValue()); - if (iter.hasNext()) - buffer.append(','); + throw new RuntimeException(e); } + } - buffer.append('}'); + /* ------------------------------------------------------------ */ + @Deprecated + public void appendArray(StringBuffer buffer, Object array) + { + appendArray((Appendable)buffer,array); } /* ------------------------------------------------------------ */ - public void appendArray(StringBuffer buffer, Collection collection) + public void appendArray(Appendable buffer, Object array) { - if (collection==null) + try { - appendNull(buffer); - return; - } + if (array == null) + { + appendNull(buffer); + return; + } - buffer.append('['); - Iterator iter=collection.iterator(); - boolean first=true; - while (iter.hasNext()) - { - if (!first) - buffer.append(','); + buffer.append('['); + int length = Array.getLength(array); - first=false; - append(buffer,iter.next()); + for (int i = 0; i < length; i++) + { + if (i != 0) + buffer.append(','); + append(buffer,Array.get(array,i)); + } + + buffer.append(']'); } + catch (IOException e) + { + throw new RuntimeException(e); + } + } - buffer.append(']'); + /* ------------------------------------------------------------ */ + @Deprecated + public void appendBoolean(StringBuffer buffer, Boolean b) + { + appendBoolean((Appendable)buffer,b); } /* ------------------------------------------------------------ */ - public void appendArray(StringBuffer buffer, Object array) + public void appendBoolean(Appendable buffer, Boolean b) { - if (array==null) + try { - appendNull(buffer); - return; + if (b == null) + { + appendNull(buffer); + return; + } + buffer.append(b.booleanValue()?"true":"false"); } - - buffer.append('['); - int length=Array.getLength(array); - - for (int i=0; i<length; i++) + catch (IOException e) { - if (i!=0) - buffer.append(','); - append(buffer,Array.get(array,i)); + throw new RuntimeException(e); } - - buffer.append(']'); } /* ------------------------------------------------------------ */ - public void appendBoolean(StringBuffer buffer, Boolean b) + @Deprecated + public void appendNumber(StringBuffer buffer, Number number) { - if (b==null) - { - appendNull(buffer); - return; - } - buffer.append(b.booleanValue()?"true":"false"); + appendNumber((Appendable)buffer,number); } /* ------------------------------------------------------------ */ - public void appendNumber(StringBuffer buffer, Number number) + public void appendNumber(Appendable buffer, Number number) { - if (number==null) + try { - appendNull(buffer); - return; + if (number == null) + { + appendNull(buffer); + return; + } + buffer.append(String.valueOf(number)); + } + catch (IOException e) + { + throw new RuntimeException(e); } - buffer.append(number); } /* ------------------------------------------------------------ */ + @Deprecated public void appendString(StringBuffer buffer, String string) { - if (string==null) + appendString((Appendable)buffer,string); + } + + /* ------------------------------------------------------------ */ + public void appendString(Appendable buffer, String string) + { + if (string == null) { appendNull(buffer); return; @@ -492,19 +575,19 @@ public class JSON QuotedStringTokenizer.quote(buffer,string); } - + // Parsing utilities /* ------------------------------------------------------------ */ - protected String toString(char[] buffer,int offset,int length) + protected String toString(char[] buffer, int offset, int length) { return new String(buffer,offset,length); } /* ------------------------------------------------------------ */ - protected Map<String,Object> newMap() + protected Map<String, Object> newMap() { - return new HashMap<String,Object>(); + return new HashMap<String, Object>(); } /* ------------------------------------------------------------ */ @@ -526,13 +609,13 @@ public class JSON } /* ------------------------------------------------------------ */ - protected Object convertTo(Class type,Map map) + protected Object convertTo(Class type, Map map) { - if (type!=null&&Convertible.class.isAssignableFrom(type)) + if (type != null && Convertible.class.isAssignableFrom(type)) { try { - Convertible conv=(Convertible)type.newInstance(); + Convertible conv = (Convertible)type.newInstance(); conv.fromJSON(map); return conv; } @@ -542,20 +625,22 @@ public class JSON } } - Convertor convertor=getConvertor(type); - if (convertor!=null) + Convertor convertor = getConvertor(type); + if (convertor != null) { return convertor.fromJSON(map); } return map; } - /* ------------------------------------------------------------ */ /** * Register a {@link Convertor} for a class or interface. - * @param forClass The class or interface that the convertor applies to - * @param convertor the convertor + * + * @param forClass + * The class or interface that the convertor applies to + * @param convertor + * the convertor */ public void addConvertor(Class forClass, Convertor convertor) { @@ -566,28 +651,31 @@ public class JSON /** * Lookup a convertor for a class. * <p> - * If no match is found for the class, then the interfaces for the class are tried. If still no - * match is found, then the super class and it's interfaces are tried recursively. - * @param forClass The class - * @return a {@link Convertor} or null if none were found. + * If no match is found for the class, then the interfaces for the class are + * tried. If still no match is found, then the super class and it's + * interfaces are tried recursively. + * + * @param forClass + * The class + * @return a {@link JSON.Convertor} or null if none were found. */ protected Convertor getConvertor(Class forClass) { - Class cls=forClass; - Convertor convertor=_convertors.get(cls.getName()); - if (convertor==null && this!=DEFAULT) - convertor=DEFAULT.getConvertor(cls); - - while (convertor==null&&cls!=null&&cls!=Object.class) + Class cls = forClass; + Convertor convertor = _convertors.get(cls.getName()); + if (convertor == null && this != DEFAULT) + convertor = DEFAULT.getConvertor(cls); + + while (convertor == null && cls != null && cls != Object.class) { - Class[] ifs=cls.getInterfaces(); - int i=0; - while (convertor==null&&ifs!=null&&i<ifs.length) - convertor=_convertors.get(ifs[i++].getName()); - if (convertor==null) + Class[] ifs = cls.getInterfaces(); + int i = 0; + while (convertor == null && ifs != null && i < ifs.length) + convertor = _convertors.get(ifs[i++].getName()); + if (convertor == null) { - cls=cls.getSuperclass(); - convertor=_convertors.get(cls.getName()); + cls = cls.getSuperclass(); + convertor = _convertors.get(cls.getName()); } } return convertor; @@ -595,92 +683,96 @@ public class JSON /* ------------------------------------------------------------ */ /** - * Register a {@link Convertor} for a named class or interface. - * @param name name of a class or an interface that the convertor applies to - * @param convertor the convertor + * Register a {@link JSON.Convertor} for a named class or interface. + * + * @param name + * name of a class or an interface that the convertor applies to + * @param convertor + * the convertor */ public void addConvertorFor(String name, Convertor convertor) { _convertors.put(name,convertor); - } + } /* ------------------------------------------------------------ */ /** * Lookup a convertor for a named class. * - * @param name name of the class - * @return a {@link Convertor} or null if none were found. + * @param name + * name of the class + * @return a {@link JSON.Convertor} or null if none were found. */ public Convertor getConvertorFor(String name) { - String clsName=name; - Convertor convertor=_convertors.get(clsName); - if (convertor==null && this!=DEFAULT) - convertor=DEFAULT.getConvertorFor(clsName); + String clsName = name; + Convertor convertor = _convertors.get(clsName); + if (convertor == null && this != DEFAULT) + convertor = DEFAULT.getConvertorFor(clsName); return convertor; - } + } /* ------------------------------------------------------------ */ public Object parse(Source source, boolean stripOuterComment) { - int comment_state=0; // 0=no comment, 1="/", 2="/*", 3="/* *" -1="//" + int comment_state = 0; // 0=no comment, 1="/", 2="/*", 3="/* *" -1="//" if (!stripOuterComment) return parse(source); - - int strip_state=1; // 0=no strip, 1=wait for /*, 2= wait for */ - Object o=null; + int strip_state = 1; // 0=no strip, 1=wait for /*, 2= wait for */ + + Object o = null; while (source.hasNext()) { - char c=source.peek(); + char c = source.peek(); // handle // or /* comment - if (comment_state==1) + if (comment_state == 1) { switch (c) { case '/': - comment_state=-1; + comment_state = -1; break; case '*': - comment_state=2; - if (strip_state==1) + comment_state = 2; + if (strip_state == 1) { - comment_state=0; - strip_state=2; + comment_state = 0; + strip_state = 2; } } } // handle /* */ comment - else if (comment_state>1) + else if (comment_state > 1) { switch (c) { case '*': - comment_state=3; + comment_state = 3; break; case '/': - if (comment_state==3) + if (comment_state == 3) { - comment_state=0; - if (strip_state==2) + comment_state = 0; + if (strip_state == 2) return o; } else - comment_state=2; + comment_state = 2; break; default: - comment_state=2; + comment_state = 2; } } // handle // comment - else if (comment_state<0) + else if (comment_state < 0) { switch (c) { case '\r': case '\n': - comment_state=0; + comment_state = 0; default: break; } @@ -690,72 +782,71 @@ public class JSON { if (!Character.isWhitespace(c)) { - if (c=='/') - comment_state=1; - else if (c=='*') - comment_state=3; - else if (o==null) + if (c == '/') + comment_state = 1; + else if (c == '*') + comment_state = 3; + else if (o == null) { - o=parse(source); + o = parse(source); continue; } } } - + source.next(); } return o; } - /* ------------------------------------------------------------ */ public Object parse(Source source) { - int comment_state=0; // 0=no comment, 1="/", 2="/*", 3="/* *" -1="//" + int comment_state = 0; // 0=no comment, 1="/", 2="/*", 3="/* *" -1="//" while (source.hasNext()) { - char c=source.peek(); + char c = source.peek(); // handle // or /* comment - if (comment_state==1) + if (comment_state == 1) { switch (c) { case '/': - comment_state=-1; + comment_state = -1; break; case '*': - comment_state=2; + comment_state = 2; } } // handle /* */ comment - else if (comment_state>1) + else if (comment_state > 1) { switch (c) { case '*': - comment_state=3; + comment_state = 3; break; case '/': - if (comment_state==3) - comment_state=0; + if (comment_state == 3) + comment_state = 0; else - comment_state=2; + comment_state = 2; break; default: - comment_state=2; + comment_state = 2; } } // handle // comment - else if (comment_state<0) + else if (comment_state < 0) { switch (c) { case '\r': case '\n': - comment_state=0; + comment_state = 0; break; default: break; @@ -790,9 +881,9 @@ public class JSON case 'N': complete("NaN",source); return null; - + case '/': - comment_state=1; + comment_state = 1; break; default: @@ -800,7 +891,7 @@ public class JSON return parseNumber(source); else if (Character.isWhitespace(c)) break; - return handleUnknown(source, c); + return handleUnknown(source,c); } } source.next(); @@ -812,47 +903,47 @@ public class JSON /* ------------------------------------------------------------ */ protected Object handleUnknown(Source source, char c) { - throw new IllegalStateException("unknown char '"+c+"'("+(int)c+") in "+source); + throw new IllegalStateException("unknown char '" + c + "'(" + (int)c + ") in " + source); } /* ------------------------------------------------------------ */ protected Object parseObject(Source source) { - if (source.next()!='{') + if (source.next() != '{') throw new IllegalStateException(); - Map<String,Object> map=newMap(); + Map<String, Object> map = newMap(); - char next=seekTo("\"}",source); + char next = seekTo("\"}",source); while (source.hasNext()) { - if (next=='}') + if (next == '}') { source.next(); break; } - String name=parseString(source); + String name = parseString(source); seekTo(':',source); source.next(); - Object value=contextFor(name).parse(source); + Object value = contextFor(name).parse(source); map.put(name,value); seekTo(",}",source); - next=source.next(); - if (next=='}') + next = source.next(); + if (next == '}') break; else - next=seekTo("\"}",source); + next = seekTo("\"}",source); } - String classname=(String)map.get("class"); - if (classname!=null) + String classname = (String)map.get("class"); + if (classname != null) { try { - Class c=Loader.loadClass(JSON.class,classname); + Class c = Loader.loadClass(JSON.class,classname); return convertTo(c,map); } catch (ClassNotFoundException e) @@ -862,26 +953,26 @@ public class JSON } return map; } - + /* ------------------------------------------------------------ */ protected Object parseArray(Source source) { - if (source.next()!='[') + if (source.next() != '[') throw new IllegalStateException(); - int size=0; - ArrayList list=null; - Object item=null; - boolean coma=true; + int size = 0; + ArrayList list = null; + Object item = null; + boolean coma = true; while (source.hasNext()) { - char c=source.peek(); + char c = source.peek(); switch (c) { case ']': source.next(); - switch(size) + switch (size) { case 0: return newArray(0); @@ -896,7 +987,7 @@ public class JSON case ',': if (coma) throw new IllegalStateException(); - coma=true; + coma = true; source.next(); break; @@ -905,22 +996,22 @@ public class JSON source.next(); else { - coma=false; - if (size++==0) - item=contextForArray().parse(source); - else if (list==null) + coma = false; + if (size++ == 0) + item = contextForArray().parse(source); + else if (list == null) { - list=new ArrayList(); + list = new ArrayList(); list.add(item); - item=contextForArray().parse(source); + item = contextForArray().parse(source); list.add(item); - item=null; + item = null; } else { - item=contextForArray().parse(source); + item = contextForArray().parse(source); list.add(item); - item=null; + item = null; } } } @@ -929,169 +1020,160 @@ public class JSON throw new IllegalStateException("unexpected end of array"); } - /* ------------------------------------------------------------ */ protected String parseString(Source source) { - if (source.next()!='"') + if (source.next() != '"') throw new IllegalStateException(); - boolean escape=false; + boolean escape = false; + + StringBuilder b = null; + final char[] scratch = source.scratchBuffer(); - StringBuffer b=null; - final char[] scratch=source.scratchBuffer(); - - if (scratch!=null) + if (scratch != null) { - int i=0; + int i = 0; while (source.hasNext()) { - if(i>=scratch.length) + if (i >= scratch.length) { // we have filled the scratch buffer, so we must // use the StringBuffer for a large string - b=new StringBuffer(scratch.length*2); + b = new StringBuilder(scratch.length * 2); b.append(scratch,0,i); break; } - char c=source.next(); + char c = source.next(); if (escape) { - escape=false; + escape = false; switch (c) { case '"': - scratch[i++]='"'; + scratch[i++] = '"'; break; case '\\': - scratch[i++]='\\'; + scratch[i++] = '\\'; break; case '/': - scratch[i++]='/'; + scratch[i++] = '/'; break; case 'b': - scratch[i++]='\b'; + scratch[i++] = '\b'; break; case 'f': - scratch[i++]='\f'; + scratch[i++] = '\f'; break; case 'n': - scratch[i++]='\n'; + scratch[i++] = '\n'; break; case 'r': - scratch[i++]='\r'; + scratch[i++] = '\r'; break; case 't': - scratch[i++]='\t'; + scratch[i++] = '\t'; break; case 'u': - char uc=(char)((TypeUtil.convertHexDigit((byte)source.next())<<12)+ - (TypeUtil.convertHexDigit((byte)source.next())<<8)+ - (TypeUtil.convertHexDigit((byte)source.next())<<4)+ - (TypeUtil.convertHexDigit((byte)source.next()))); - scratch[i++]=uc; + char uc = (char)((TypeUtil.convertHexDigit((byte)source.next()) << 12) + (TypeUtil.convertHexDigit((byte)source.next()) << 8) + + (TypeUtil.convertHexDigit((byte)source.next()) << 4) + (TypeUtil.convertHexDigit((byte)source.next()))); + scratch[i++] = uc; break; default: - scratch[i++]=c; + scratch[i++] = c; } } - else if (c=='\\') + else if (c == '\\') { - escape=true; + escape = true; continue; } - else if (c=='\"') + else if (c == '\"') { // Return string that fits within scratch buffer return toString(scratch,0,i); } else - scratch[i++]=c; + scratch[i++] = c; } - + // Missing end quote, but return string anyway ? - if (b==null) + if (b == null) return toString(scratch,0,i); } else - b=new StringBuffer(getStringBufferSize()); - - + b = new StringBuilder(getStringBufferSize()); + // parse large string into string buffer - synchronized (b) + final StringBuilder builder=b; + while (source.hasNext()) { - while (source.hasNext()) - { - char c=source.next(); + char c = source.next(); - if (escape) - { - escape=false; - switch (c) - { - case '"': - b.append('"'); - break; - case '\\': - b.append('\\'); - break; - case '/': - b.append('/'); - break; - case 'b': - b.append('\b'); - break; - case 'f': - b.append('\f'); - break; - case 'n': - b.append('\n'); - break; - case 'r': - b.append('\r'); - break; - case 't': - b.append('\t'); - break; - case 'u': - char uc=(char)((TypeUtil.convertHexDigit((byte)source.next())<<12)+ - (TypeUtil.convertHexDigit((byte)source.next())<<8)+ - (TypeUtil.convertHexDigit((byte)source.next())<<4)+ - (TypeUtil.convertHexDigit((byte)source.next()))); - b.append(uc); - break; - default: - b.append(c); - } - } - else if (c=='\\') + if (escape) + { + escape = false; + switch (c) { - escape=true; - continue; + case '"': + builder.append('"'); + break; + case '\\': + builder.append('\\'); + break; + case '/': + builder.append('/'); + break; + case 'b': + builder.append('\b'); + break; + case 'f': + builder.append('\f'); + break; + case 'n': + builder.append('\n'); + break; + case 'r': + builder.append('\r'); + break; + case 't': + builder.append('\t'); + break; + case 'u': + char uc = (char)((TypeUtil.convertHexDigit((byte)source.next()) << 12) + (TypeUtil.convertHexDigit((byte)source.next()) << 8) + + (TypeUtil.convertHexDigit((byte)source.next()) << 4) + (TypeUtil.convertHexDigit((byte)source.next()))); + builder.append(uc); + break; + default: + builder.append(c); } - else if (c=='\"') - break; - else - b.append(c); } - - return b.toString(); + else if (c == '\\') + { + escape = true; + continue; + } + else if (c == '\"') + break; + else + builder.append(c); } + return builder.toString(); } /* ------------------------------------------------------------ */ public Number parseNumber(Source source) { - boolean minus=false; - long number=0; - StringBuilder buffer=null; + boolean minus = false; + long number = 0; + StringBuilder buffer = null; longLoop: while (source.hasNext()) { - char c=source.peek(); + char c = source.peek(); switch (c) { case '0': @@ -1104,68 +1186,66 @@ public class JSON case '7': case '8': case '9': - number=number*10+(c-'0'); + number = number * 10 + (c - '0'); source.next(); break; case '-': case '+': - if (number!=0) + if (number != 0) throw new IllegalStateException("bad number"); - minus=true; + minus = true; source.next(); break; case '.': case 'e': case 'E': - buffer=new StringBuilder(16); - if(minus) + buffer = new StringBuilder(16); + if (minus) buffer.append('-'); buffer.append(number); buffer.append(c); source.next(); break longLoop; - default: break longLoop; } } - if (buffer==null) - return TypeUtil.newLong(minus?-1*number:number); - + if (buffer == null) + return minus ? -1 * number : number; - doubleLoop: while (source.hasNext()) + doubleLoop: while (source.hasNext()) + { + char c = source.peek(); + switch (c) { - char c=source.peek(); - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - case '.': - case '+': - case 'e': - case 'E': - buffer.append(c); - source.next(); - break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + case '.': + case '+': + case 'e': + case 'E': + buffer.append(c); + source.next(); + break; - default: - break doubleLoop; - } + default: + break doubleLoop; } - return new Double(buffer.toString()); + } + return new Double(buffer.toString()); } @@ -1174,16 +1254,16 @@ public class JSON { while (source.hasNext()) { - char c=source.peek(); - if (c==seek) + char c = source.peek(); + if (c == seek) return; if (!Character.isWhitespace(c)) - throw new IllegalStateException("Unexpected '"+c+" while seeking '"+seek+"'"); + throw new IllegalStateException("Unexpected '" + c + " while seeking '" + seek + "'"); source.next(); } - throw new IllegalStateException("Expected '"+seek+"'"); + throw new IllegalStateException("Expected '" + seek + "'"); } /* ------------------------------------------------------------ */ @@ -1191,35 +1271,157 @@ public class JSON { while (source.hasNext()) { - char c=source.peek(); - if (seek.indexOf(c)>=0) + char c = source.peek(); + if (seek.indexOf(c) >= 0) { return c; } if (!Character.isWhitespace(c)) - throw new IllegalStateException("Unexpected '"+c+"' while seeking one of '"+seek+"'"); + throw new IllegalStateException("Unexpected '" + c + "' while seeking one of '" + seek + "'"); source.next(); } - throw new IllegalStateException("Expected one of '"+seek+"'"); + throw new IllegalStateException("Expected one of '" + seek + "'"); } /* ------------------------------------------------------------ */ protected static void complete(String seek, Source source) { - int i=0; - while (source.hasNext()&&i<seek.length()) + int i = 0; + while (source.hasNext() && i < seek.length()) { - char c=source.next(); - if (c!=seek.charAt(i++)) - throw new IllegalStateException("Unexpected '"+c+" while seeking \""+seek+"\""); + char c = source.next(); + if (c != seek.charAt(i++)) + throw new IllegalStateException("Unexpected '" + c + " while seeking \"" + seek + "\""); } - if (i<seek.length()) - throw new IllegalStateException("Expected \""+seek+"\""); + if (i < seek.length()) + throw new IllegalStateException("Expected \"" + seek + "\""); } + private final class ConvertableOutput implements Output + { + private final Appendable _buffer; + char c = '{'; + + private ConvertableOutput(Appendable buffer) + { + _buffer = buffer; + } + + public void complete() + { + try + { + if (c == '{') + _buffer.append("{}"); + else if (c != 0) + _buffer.append("}"); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void add(Object obj) + { + if (c == 0) + throw new IllegalStateException(); + append(_buffer,obj); + c = 0; + } + + public void addClass(Class type) + { + try + { + if (c == 0) + throw new IllegalStateException(); + _buffer.append(c); + _buffer.append("\"class\":"); + append(_buffer,type.getName()); + c = ','; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void add(String name, Object value) + { + try + { + if (c == 0) + throw new IllegalStateException(); + _buffer.append(c); + QuotedStringTokenizer.quote(_buffer,name); + _buffer.append(':'); + append(_buffer,value); + c = ','; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void add(String name, double value) + { + try + { + if (c == 0) + throw new IllegalStateException(); + _buffer.append(c); + QuotedStringTokenizer.quote(_buffer,name); + _buffer.append(':'); + appendNumber(_buffer,new Double(value)); + c = ','; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void add(String name, long value) + { + try + { + if (c == 0) + throw new IllegalStateException(); + _buffer.append(c); + QuotedStringTokenizer.quote(_buffer,name); + _buffer.append(':'); + appendNumber(_buffer, value); + c = ','; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void add(String name, boolean value) + { + try + { + if (c == 0) + throw new IllegalStateException(); + _buffer.append(c); + QuotedStringTokenizer.quote(_buffer,name); + _buffer.append(':'); + appendBoolean(_buffer,value?Boolean.TRUE:Boolean.FALSE); + c = ','; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + } /* ------------------------------------------------------------ */ public interface Source @@ -1229,7 +1431,7 @@ public class JSON char next(); char peek(); - + char[] scratchBuffer(); } @@ -1242,14 +1444,14 @@ public class JSON public StringSource(String s) { - string=s; + string = s; } public boolean hasNext() { - if (index<string.length()) + if (index < string.length()) return true; - scratch=null; + scratch = null; return false; } @@ -1262,17 +1464,17 @@ public class JSON { return string.charAt(index); } - + @Override public String toString() { - return string.substring(0,index)+"|||"+string.substring(index); + return string.substring(0,index) + "|||" + string.substring(index); } public char[] scratchBuffer() { - if (scratch==null) - scratch=new char[string.length()]; + if (scratch == null) + scratch = new char[string.length()]; return scratch; } } @@ -1281,26 +1483,26 @@ public class JSON public static class ReaderSource implements Source { private Reader _reader; - private int _next=-1; + private int _next = -1; private char[] scratch; public ReaderSource(Reader r) { - _reader=r; + _reader = r; } - + public void setReader(Reader reader) { - _reader=reader; - _next=-1; + _reader = reader; + _next = -1; } public boolean hasNext() { getNext(); - if (_next<0) + if (_next < 0) { - scratch=null; + scratch = null; return false; } return true; @@ -1309,8 +1511,8 @@ public class JSON public char next() { getNext(); - char c=(char)_next; - _next=-1; + char c = (char)_next; + _next = -1; return c; } @@ -1322,11 +1524,11 @@ public class JSON private void getNext() { - if (_next<0) + if (_next < 0) { try { - _next=_reader.read(); + _next = _reader.read(); } catch (IOException e) { @@ -1337,15 +1539,15 @@ public class JSON public char[] scratchBuffer() { - if (scratch==null) - scratch=new char[1024]; + if (scratch == null) + scratch = new char[1024]; return scratch; } } /* ------------------------------------------------------------ */ - /** + /** * JSON Output class for use by {@link Convertible}. */ public interface Output @@ -1365,16 +1567,16 @@ public class JSON /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ - /** JSON Convertible object. - * Object can implement this interface in a similar way to the - * {@link Externalizable} interface is used to allow classes to + /** + * JSON Convertible object. Object can implement this interface in a similar + * way to the {@link Externalizable} interface is used to allow classes to * provide their own serialization mechanism. * <p> - * A JSON.Convertible object may be written to a JSONObject - * or initialized from a Map of field names to values. + * A JSON.Convertible object may be written to a JSONObject or initialized + * from a Map of field names to values. * <p> - * If the JSON is to be convertible back to an Object, then - * the method {@link Output#addClass(Class)} must be called from within toJSON() + * If the JSON is to be convertible back to an Object, then the method + * {@link Output#addClass(Class)} must be called from within toJSON() * */ public interface Convertible @@ -1385,13 +1587,16 @@ public class JSON } /* ------------------------------------------------------------ */ - /** Static JSON Convertor. + /** + * Static JSON Convertor. * <p> - * may be implemented to provide static convertors for objects that may be registered - * with {@link JSON#registerConvertor(Class, org.eclipse.jetty.util.ajax.JSON.Convertor). - * These convertors are looked up by class, interface and - * super class by {@link JSON#getConvertor(Class)}. Convertors should be used when the - * classes to be converted cannot implement {@link Convertible} or {@link Generator}. + * may be implemented to provide static convertors for objects that may be + * registered with + * {@link JSON#registerConvertor(Class, org.eclipse.jetty.util.ajax.JSON.Convertor)} + * . These convertors are looked up by class, interface and super class by + * {@link JSON#getConvertor(Class)}. Convertors should be used when the + * classes to be converted cannot implement {@link Convertible} or + * {@link Generator}. */ public interface Convertor { @@ -1401,34 +1606,39 @@ public class JSON } /* ------------------------------------------------------------ */ - /** JSON Generator. - * A class that can add it's JSON representation directly to a StringBuffer. - * This is useful for object instances that are frequently converted and wish to - * avoid multiple Conversions + /** + * JSON Generator. A class that can add it's JSON representation directly to + * a StringBuffer. This is useful for object instances that are frequently + * converted and wish to avoid multiple Conversions */ public interface Generator { - public void addJSON(StringBuffer buffer); + public void addJSON(Appendable buffer); } /* ------------------------------------------------------------ */ - /** A Literal JSON generator - * A utility instance of {@link JSON.Generator} that holds a pre-generated string on JSON text. + /** + * A Literal JSON generator A utility instance of {@link JSON.Generator} + * that holds a pre-generated string on JSON text. */ public static class Literal implements Generator { private String _json; /* ------------------------------------------------------------ */ - /** Construct a literal JSON instance for use by {@link JSON#toString(Object)}. - * If {@link Log#isDebugEnabled()} is true, the JSON will be parsed to check validity - * @param json A literal JSON string. + /** + * Construct a literal JSON instance for use by + * {@link JSON#toString(Object)}. If {@link Log#isDebugEnabled()} is + * true, the JSON will be parsed to check validity + * + * @param json + * A literal JSON string. */ public Literal(String json) { if (Log.isDebugEnabled()) parse(json); - _json=json; + _json = json; } @Override @@ -1437,9 +1647,16 @@ public class JSON return _json; } - public void addJSON(StringBuffer buffer) + public void addJSON(Appendable buffer) { - buffer.append(_json); + try + { + buffer.append(_json); + } + catch(IOException e) + { + throw new RuntimeException(e); + } } } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java index dd657bb3cb..d9d21cbce1 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java @@ -211,5 +211,12 @@ public abstract class AbstractLifeCycle implements LifeCycle } } - + public static abstract class AbstractLifeCycleListener implements LifeCycle.Listener + { + public void lifeCycleFailure(LifeCycle event, Throwable cause) {} + public void lifeCycleStarted(LifeCycle event) {} + public void lifeCycleStarting(LifeCycle event) {} + public void lifeCycleStopped(LifeCycle event) {} + public void lifeCycleStopping(LifeCycle event) {} + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java index eb2a13ef30..29681f30d6 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java @@ -34,9 +34,6 @@ import org.eclipse.jetty.util.log.Log; * this.bars=bars; * } * </pre> - * - * - * */ public class Container { @@ -73,7 +70,7 @@ public class Container * @param oldChild The previous value of the child. If this is non null and differs from <code>child</code>, then a remove event is generated. * @param child The current child. If this is non null and differs from <code>oldChild</code>, then an add event is generated. * @param relationship The name of the relationship - * @param addRemoveBean If true add/remove is called for the new/old children as well as the relationships + * @param addRemove If true add/remove is called for the new/old children as well as the relationships */ public synchronized void update(Object parent, Object oldChild, final Object child, String relationship,boolean addRemove) { @@ -112,7 +109,7 @@ public class Container * This array is modified and children that remain in the new children array are nulled out of the old children array. * @param children The current array of children. An add event is generated for any child in this array but not in the <code>oldChildren</code> array. * @param relationship The name of the relationship - * @param addRemoveBean If true add/remove is called for the new/old children as well as the relationships + * @param addRemove If true add/remove is called for the new/old children as well as the relationships */ public synchronized void update(Object parent, Object[] oldChildren, final Object[] children, String relationship, boolean addRemove) { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java index 99f6edf7ca..19ecf11039 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java @@ -22,12 +22,12 @@ import java.util.logging.Level; * <p> * Implementation of Jetty {@link Logger} based on {@link java.util.logging.Logger}. * </p> - * + * * <p> * Honors the standard jetty system property <code>"org.eclipse.jetty.util.log.DEBUG"</code> to set logger into debug * mode (defaults to false, set to "true" to enable) * </p> - * + * * <p> * You can also set the logger level using <a href="http://java.sun.com/j2se/1.5.0/docs/guide/logging/overview.html"> * standard java.util.logging configuration</a> against the name <code>"org.eclipse.jetty.util.log"</code>. @@ -46,44 +46,42 @@ public class JavaUtilLog implements Logger { _logger = java.util.logging.Logger.getLogger(name); if (Boolean.getBoolean("org.eclipse.jetty.util.log.DEBUG")) - { _logger.setLevel(Level.FINE); - } } - + public String getName() { return _logger.getName(); } - public void debug(String msg) + public void warn(String msg, Object... args) { - _logger.log(Level.FINE,msg); + _logger.log(Level.WARNING, format(msg, args)); } - public void debug(String msg, Throwable th) + public void warn(Throwable thrown) { - _logger.log(Level.FINE,msg,th); + warn("", thrown); } - public void debug(String msg, Object arg0, Object arg1) + public void warn(String msg, Throwable thrown) { - _logger.log(Level.FINE,format(msg,arg0,arg1)); + _logger.log(Level.WARNING, msg, thrown); } - public Logger getLogger(String name) + public void info(String msg, Object... args) { - return new JavaUtilLog(name); + _logger.log(Level.INFO, format(msg, args)); } - public void info(String msg) + public void info(Throwable thrown) { - _logger.log(Level.INFO,msg); + info("", thrown); } - public void info(String msg, Object arg0, Object arg1) + public void info(String msg, Throwable thrown) { - _logger.log(Level.INFO,format(msg,arg0,arg1)); + _logger.log(Level.INFO, msg, thrown); } public boolean isDebugEnabled() @@ -96,30 +94,50 @@ public class JavaUtilLog implements Logger _logger.setLevel(Level.FINE); } - public void warn(String msg) + public void debug(String msg, Object... args) { - _logger.log(Level.WARNING,msg); + _logger.log(Level.FINE, format(msg, args)); } - public void warn(String msg, Object arg0, Object arg1) + public void debug(Throwable thrown) { - _logger.log(Level.WARNING,format(msg,arg0,arg1)); + debug("", thrown); } - public void warn(String msg, Throwable th) + public void debug(String msg, Throwable thrown) { - _logger.log(Level.WARNING,msg,th); + _logger.log(Level.FINE, msg, thrown); } - private String format(String msg, Object arg0, Object arg1) + public Logger getLogger(String name) { - int i0 = msg.indexOf("{}"); - int i1 = i0 < 0?-1:msg.indexOf("{}",i0 + 2); + return new JavaUtilLog(name); + } - if (arg1 != null && i1 >= 0) - msg = msg.substring(0,i1) + arg1 + msg.substring(i1 + 2); - if (arg0 != null && i0 >= 0) - msg = msg.substring(0,i0) + arg0 + msg.substring(i0 + 2); - return msg; + private String format(String msg, Object... args) + { + msg = String.valueOf(msg); // Avoids NPE + String braces = "{}"; + StringBuilder builder = new StringBuilder(); + int start = 0; + for (Object arg : args) + { + int bracesIndex = msg.indexOf(braces, start); + if (bracesIndex < 0) + { + builder.append(msg.substring(start)); + builder.append(" "); + builder.append(arg); + start = msg.length(); + } + else + { + builder.append(msg.substring(start, bracesIndex)); + builder.append(String.valueOf(arg)); + start = bracesIndex + braces.length(); + } + } + builder.append(msg.substring(start)); + return builder.toString(); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java index 775fcd54a1..2adca11192 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java @@ -4,25 +4,24 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.util.log; + import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import org.eclipse.jetty.util.Loader; - - -/*-----------------------------------------------------------------------*/ -/** Logging. - * This class provides a static logging interface. If an instance of the +/** + * Logging. + * This class provides a static logging interface. If an instance of the * org.slf4j.Logger class is found on the classpath, the static log methods * are directed to a slf4j logger for "org.eclipse.log". Otherwise the logs * are directed to stderr. @@ -30,62 +29,55 @@ import org.eclipse.jetty.util.Loader; * The "org.eclipse.jetty.util.log.class" system property can be used * to select a specific logging implementation. * <p> - * If the system property org.eclipse.jetty.util.log.IGNORED is set, + * If the system property org.eclipse.jetty.util.log.IGNORED is set, * then ignored exceptions are logged in detail. - * + * * @see StdErrLog * @see Slf4jLog */ -public class Log -{ - private static final String[] __nestedEx = - {"getTargetException","getTargetError","getException","getRootCause"}; - /*-------------------------------------------------------------------*/ - private static final Class[] __noArgs=new Class[0]; +public class Log +{ public final static String EXCEPTION= "EXCEPTION "; public final static String IGNORED= "IGNORED"; - public final static String IGNORED_FMT= "IGNORED: {}"; - public final static String NOT_IMPLEMENTED= "NOT IMPLEMENTED "; - + public static String __logClass; public static boolean __ignored; - + static { - AccessController.doPrivileged(new PrivilegedAction<Boolean>() + AccessController.doPrivileged(new PrivilegedAction<Object>() + { + public Object run() { - public Boolean run() - { - __logClass = System.getProperty("org.eclipse.jetty.util.log.class","org.eclipse.jetty.util.log.Slf4jLog"); - __ignored = Boolean.parseBoolean(System.getProperty("org.eclipse.jetty.util.log.IGNORED","false")); - return true; - } - }); + __logClass = System.getProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.Slf4jLog"); + __ignored = Boolean.parseBoolean(System.getProperty("org.eclipse.jetty.util.log.IGNORED", "false")); + return null; + } + }); } - + private static Logger __log; - private static boolean _initialized; - + private static boolean __initialized; + public static boolean initialized() { - if (__log!=null) + if (__log != null) return true; - + synchronized (Log.class) { - if (_initialized) - return __log!=null; - _initialized=true; + if (__initialized) + return __log != null; + __initialized = true; } - - Class log_class=null; + try { - log_class=Loader.loadClass(Log.class, __logClass); - if (__log==null || !__log.getClass().equals(log_class)) + Class log_class = Loader.loadClass(Log.class, __logClass); + if (__log == null || !__log.getClass().equals(log_class)) { - __log=(Logger) log_class.newInstance(); - __log.info("Logging to {} via {}",__log,log_class.getName()); + __log = (Logger)log_class.newInstance(); + __log.debug("Logging to {} via {}", __log, log_class.getName()); } } catch(NoClassDefFoundError e) @@ -97,34 +89,34 @@ public class Log initStandardLogging(e); } - return __log!=null; + return __log != null; } - private static void initStandardLogging(Throwable e) + private static void initStandardLogging(Throwable e) { Class log_class; if(e != null && __ignored) e.printStackTrace(); - if (__log==null) + if (__log == null) { - log_class= StdErrLog.class; - __log=new StdErrLog(); - __log.info("Logging to {} via {}",__log,log_class.getName()); + log_class = StdErrLog.class; + __log = new StdErrLog(); + __log.debug("Logging to {} via {}", __log, log_class.getName()); } } public static void setLog(Logger log) { - Log.__log=log; + Log.__log = log; } - + public static Logger getLog() { initialized(); return __log; } - + /** * Set Log to parent Logger. * <p> @@ -132,12 +124,12 @@ public class Log * call {@link #getLogger(String)} on it and construct a {@link LoggerLog} instance * as this Log's Logger, so that logging is delegated to the parent Log. * <p> - * This should be used if a webapp is using Log, but wishes the logging to be + * This should be used if a webapp is using Log, but wishes the logging to be * directed to the containers log. * <p> * If there is not parent Log, then this call is equivalent to<pre> * Log.setLog(Log.getLogger(name)); - * </pre> + * </pre> * @param name Logger name */ public static void setLogToParent(String name) @@ -148,161 +140,137 @@ public class Log try { Class<?> uberlog = loader.getParent().loadClass("org.eclipse.jetty.util.log.Log"); - Method getLogger=uberlog.getMethod("getLogger",new Class[]{String.class}); + Method getLogger = uberlog.getMethod("getLogger", new Class[]{String.class}); Object logger = getLogger.invoke(null,name); setLog(new LoggerLog(logger)); - return; } catch (Exception e) { e.printStackTrace(); - } + } + } + else + { + setLog(getLogger(name)); } - - setLog(getLogger(name)); } - + public static void debug(Throwable th) - { + { if (!isDebugEnabled()) return; - __log.debug(EXCEPTION,th); - unwind(th); + __log.debug(EXCEPTION, th); } public static void debug(String msg) { if (!initialized()) return; - - __log.debug(msg,null,null); + __log.debug(msg); } - - public static void debug(String msg,Object arg) + + public static void debug(String msg, Object arg) { if (!initialized()) return; - __log.debug(msg,arg,null); + __log.debug(msg, arg); } - - public static void debug(String msg,Object arg0, Object arg1) + + public static void debug(String msg, Object arg0, Object arg1) { if (!initialized()) return; - __log.debug(msg,arg0,arg1); + __log.debug(msg, arg0, arg1); } - - /* ------------------------------------------------------------ */ + /** * Ignore an exception unless trace is enabled. * This works around the problem that log4j does not support the trace level. + * @param thrown the Throwable to ignore */ - public static void ignore(Throwable th) + public static void ignore(Throwable thrown) { if (!initialized()) return; if (__ignored) { - __log.warn(IGNORED,th); - unwind(th); + __log.warn(IGNORED, thrown); } } - + public static void info(String msg) { if (!initialized()) return; - __log.info(msg,null,null); + __log.info(msg); } - - public static void info(String msg,Object arg) + + public static void info(String msg, Object arg) { if (!initialized()) return; - __log.info(msg,arg,null); + __log.info(msg, arg); } - - public static void info(String msg,Object arg0, Object arg1) + + public static void info(String msg, Object arg0, Object arg1) { if (!initialized()) return; - __log.info(msg,arg0,arg1); + __log.info(msg, arg0, arg1); } - + public static boolean isDebugEnabled() { if (!initialized()) return false; return __log.isDebugEnabled(); } - + public static void warn(String msg) { if (!initialized()) return; - __log.warn(msg,null,null); + __log.warn(msg); } - - public static void warn(String msg,Object arg) + + public static void warn(String msg, Object arg) { if (!initialized()) return; - __log.warn(msg,arg,null); + __log.warn(msg, arg); } - - public static void warn(String msg,Object arg0, Object arg1) + + public static void warn(String msg, Object arg0, Object arg1) { if (!initialized()) return; - __log.warn(msg,arg0,arg1); + __log.warn(msg, arg0, arg1); } - + public static void warn(String msg, Throwable th) { if (!initialized()) return; - __log.warn(msg,th); - unwind(th); + __log.warn(msg, th); } public static void warn(Throwable th) { if (!initialized()) return; - __log.warn(EXCEPTION,th); - unwind(th); + __log.warn(EXCEPTION, th); } - /** Obtain a named Logger. + /** * Obtain a named Logger or the default Logger if null is passed. + * @param name the Logger name + * @return the Logger with the given name */ public static Logger getLogger(String name) { if (!initialized()) return null; - - if (name==null) - return __log; - return __log.getLogger(name); - } - private static void unwind(Throwable th) - { - if (th==null) - return; - for (int i=0;i<__nestedEx.length;i++) - { - try - { - Method get_target = th.getClass().getMethod(__nestedEx[i],__noArgs); - Throwable th2=(Throwable)get_target.invoke(th,(Object[])null); - if (th2!=null && th2!=th) - warn("Nested in "+th+":",th2); - } - catch(Exception ignore){} - } + return name == null ? __log : __log.getLogger(name); } - - } - diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Logger.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Logger.java index 72eab7dc9b..d96c04012a 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Logger.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Logger.java @@ -4,39 +4,99 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.util.log; -/** Logging Facade - * A simple logging facade that is intended simply to capture the style - * of logging as used by Jetty. - * +/** + * A simple logging facade that is intended simply to capture the style of logging as used by Jetty. */ public interface Logger { + /** + * @return the name of this logger + */ + public String getName(); + + /** + * Formats and logs at warn level. + * @param msg the formatting string + * @param args the optional arguments + */ + public void warn(String msg, Object... args); + + /** + * Logs the given Throwable information at warn level + * @param thrown the Throwable to log + */ + public void warn(Throwable thrown); + + /** + * Logs the given message at warn level, with Throwable information. + * @param msg the message to log + * @param thrown the Throwable to log + */ + public void warn(String msg, Throwable thrown); + + /** + * Formats and logs at info level. + * @param msg the formatting string + * @param args the optional arguments + */ + public void info(String msg, Object... args); + + /** + * Logs the given Throwable information at info level + * @param thrown the Throwable to log + */ + public void info(Throwable thrown); + + /** + * Logs the given message at info level, with Throwable information. + * @param msg the message to log + * @param thrown the Throwable to log + */ + public void info(String msg, Throwable thrown); + + /** + * @return whether the debug level is enabled + */ public boolean isDebugEnabled(); - /** Mutator used to turn debug on programatically. - * Implementations operation in which case an appropriate - * warning message shall be generated. + /** + * Mutator used to turn debug on programmatically. + * @param enabled whether to enable the debug level */ public void setDebugEnabled(boolean enabled); - public void info(String msg); - public void info(String msg,Object arg0, Object arg1); - public void debug(String msg); - public void debug(String msg,Throwable th); - public void debug(String msg,Object arg0, Object arg1); - public void warn(String msg); - public void warn(String msg,Object arg0, Object arg1); - public void warn(String msg, Throwable th); + /** + * Formats and logs at debug level. + * @param msg the formatting string + * @param args the optional arguments + */ + public void debug(String msg, Object... args); + + /** + * Logs the given Throwable information at debug level + * @param thrown the Throwable to log + */ + public void debug(Throwable thrown); + + /** + * Logs the given message at debug level, with Throwable information. + * @param msg the message to log + * @param thrown the Throwable to log + */ + public void debug(String msg, Throwable thrown); + + /** + * @param name the name of the logger + * @return a logger with the given name + */ public Logger getLogger(String name); - - public String getName(); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/LoggerLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/LoggerLog.java index a476c16d67..6eef7bfa39 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/LoggerLog.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/LoggerLog.java @@ -4,124 +4,106 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.util.log; import java.lang.reflect.Method; +/** + * + */ public class LoggerLog implements Logger { - boolean _debug; - Object _logger; - Method _debugMT; - Method _debugMAA; - Method _infoMAA; - Method _warnMT; - Method _warnMAA; - Method _isDebugEnabled; - Method _setDebugEnabledE; - Method _getLoggerN; - + private final Object _logger; + private final Method _debugMT; + private final Method _debugMAA; + private final Method _infoMT; + private final Method _infoMAA; + private final Method _warnMT; + private final Method _warnMAA; + private final Method _setDebugEnabledE; + private final Method _getLoggerN; + private final Method _getName; + private volatile boolean _debug; + public LoggerLog(Object logger) { try { - _logger=logger; - Class<?> lc=logger.getClass(); - _debugMT=lc.getMethod("debug",new Class[]{String.class,Throwable.class}); - _debugMAA=lc.getMethod("debug",new Class[]{String.class,Object.class,Object.class}); - _infoMAA=lc.getMethod("info",new Class[]{String.class,Object.class,Object.class}); - _warnMT=lc.getMethod("warn",new Class[]{String.class,Throwable.class}); - _warnMAA=lc.getMethod("warn",new Class[]{String.class,Object.class,Object.class}); - _isDebugEnabled=lc.getMethod("isDebugEnabled",new Class[]{}); - _setDebugEnabledE=lc.getMethod("setDebugEnabled",new Class[]{Boolean.TYPE}); - _getLoggerN=lc.getMethod("getLogger",new Class[]{String.class}); - - _debug=((Boolean)_isDebugEnabled.invoke(_logger,(Object[])null)).booleanValue(); - } - catch(Exception e) + _logger = logger; + Class<?> lc = logger.getClass(); + _debugMT = lc.getMethod("debug", new Class[]{String.class, Throwable.class}); + _debugMAA = lc.getMethod("debug", new Class[]{String.class, Object[].class}); + _infoMT = lc.getMethod("info", new Class[]{String.class, Throwable.class}); + _infoMAA = lc.getMethod("info", new Class[]{String.class, Object[].class}); + _warnMT = lc.getMethod("warn", new Class[]{String.class, Throwable.class}); + _warnMAA = lc.getMethod("warn", new Class[]{String.class, Object[].class}); + Method _isDebugEnabled = lc.getMethod("isDebugEnabled"); + _setDebugEnabledE = lc.getMethod("setDebugEnabled", new Class[]{Boolean.TYPE}); + _getLoggerN = lc.getMethod("getLogger", new Class[]{String.class}); + _getName = lc.getMethod("getName"); + + _debug = (Boolean)_isDebugEnabled.invoke(_logger); + } + catch(Exception x) { - e.printStackTrace(); - throw new IllegalStateException(e); + throw new IllegalStateException(x); } } - public String getName() { - return _logger.toString(); - } - - public void debug(String msg, Throwable th) - { - if (_debug) + try { - try - { - _debugMT.invoke(_logger,msg,th); - } - catch (Exception e) - { - e.printStackTrace(); - } + return (String)_getName.invoke(_logger); + } + catch (Exception e) + { + e.printStackTrace(); + return null; } } - public void debug(String msg) + public void warn(String msg, Object... args) { - if (_debug) + try { - try - { - _debugMAA.invoke(_logger,msg,null,null); - } - catch (Exception e) - { - e.printStackTrace(); - } + _warnMAA.invoke(_logger, args); + } + catch (Exception e) + { + e.printStackTrace(); } } - public void debug(String msg, Object arg0, Object arg1) + public void warn(Throwable thrown) { - if (_debug) - { - try - { - _debugMAA.invoke(_logger,msg,arg0,arg1); - } - catch (Exception e) - { - e.printStackTrace(); - } - } + warn("", thrown); } - public Logger getLogger(String name) + public void warn(String msg, Throwable thrown) { try { - Object logger=_getLoggerN.invoke(_logger,name); - return new LoggerLog(logger); + _warnMT.invoke(_logger, msg, thrown); } catch (Exception e) { e.printStackTrace(); } - return this; } - public void info(String msg) + public void info(String msg, Object... args) { try { - _infoMAA.invoke(_logger,msg,null,null); + _infoMAA.invoke(_logger, args); } catch (Exception e) { @@ -129,11 +111,16 @@ public class LoggerLog implements Logger } } - public void info(String msg, Object arg0, Object arg1) + public void info(Throwable thrown) + { + info("", thrown); + } + + public void info(String msg, Throwable thrown) { try { - _infoMAA.invoke(_logger,msg,arg0,arg1); + _infoMT.invoke(_logger, msg, thrown); } catch (Exception e) { @@ -150,21 +137,23 @@ public class LoggerLog implements Logger { try { - _setDebugEnabledE.invoke(_logger,enabled); - _debug=enabled; + _setDebugEnabledE.invoke(_logger, enabled); + _debug = enabled; } catch (Exception e) { e.printStackTrace(); } - } - public void warn(String msg) + public void debug(String msg, Object... args) { + if (!_debug) + return; + try { - _warnMAA.invoke(_logger,msg,null,null); + _debugMAA.invoke(_logger, args); } catch (Exception e) { @@ -172,11 +161,19 @@ public class LoggerLog implements Logger } } - public void warn(String msg, Object arg0, Object arg1) + public void debug(Throwable thrown) { + debug("", thrown); + } + + public void debug(String msg, Throwable th) + { + if (!_debug) + return; + try { - _warnMAA.invoke(_logger,msg,arg0,arg1); + _debugMT.invoke(_logger, msg, th); } catch (Exception e) { @@ -184,16 +181,17 @@ public class LoggerLog implements Logger } } - public void warn(String msg, Throwable th) + public Logger getLogger(String name) { try { - _warnMT.invoke(_logger,msg,th); + Object logger=_getLoggerN.invoke(_logger, name); + return new LoggerLog(logger); } catch (Exception e) { e.printStackTrace(); + return this; } } - } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Slf4jLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Slf4jLog.java index a62b62824b..7df5c9fd08 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Slf4jLog.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Slf4jLog.java @@ -4,144 +4,100 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.util.log; - -/* ------------------------------------------------------------ */ -/** Slf4jLog Logger - * +/** + * Slf4jLog Logger */ public class Slf4jLog implements Logger { - private org.slf4j.Logger _logger; - + private final org.slf4j.Logger _logger; public Slf4jLog() throws Exception { this("org.eclipse.jetty.util.log"); } - + public Slf4jLog(String name) { _logger = org.slf4j.LoggerFactory.getLogger( name ); } - + public String getName() { return _logger.getName(); } - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doDebug(java.lang.String) - */ - public void debug(String msg) + + public void warn(String msg, Object... args) { - _logger.debug(msg); + _logger.warn(msg, args); } - - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doDebug(java.lang.String, java.lang.Object, java.lang.Object) - */ - public void debug(String msg, Object arg0, Object arg1) + + public void warn(Throwable thrown) { - _logger.debug(msg, arg0, arg1); + warn("", thrown); } - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doDebug(java.lang.String, java.lang.Throwable) - */ - public void debug(String msg, Throwable th) + public void warn(String msg, Throwable thrown) { - _logger.debug(msg, th); + _logger.warn(msg, thrown); } - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doDebugEnabled() - */ - public boolean isDebugEnabled() + public void info(String msg, Object... args) { - return _logger.isDebugEnabled(); + _logger.info(msg, args); } - - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doInfo(java.lang.String) - */ - public void info(String msg) + public void info(Throwable thrown) { - _logger.info(msg); + info("", thrown); } - - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doInfo(java.lang.String, java.lang.Object, java.lang.Object) - */ - public void info(String msg, Object arg0, Object arg1) + + public void info(String msg, Throwable thrown) { - _logger.info(msg, arg0, arg1); + _logger.info(msg, thrown); } - - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doWarn(java.lang.String) - */ - public void warn(String msg) + public void debug(String msg, Object... args) { - _logger.warn(msg); + _logger.debug(msg, args); } - - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doWarn(java.lang.String, java.lang.Object, java.lang.Object) - */ - public void warn(String msg, Object arg0, Object arg1) + + public void debug(Throwable thrown) { - _logger.warn(msg, arg0, arg1); + debug("", thrown); } - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.log.Log#doWarn(java.lang.String, java.lang.Throwable) - */ - public void warn(String msg, Throwable th) + public void debug(String msg, Throwable thrown) { + _logger.debug(msg, thrown); + } - if (th instanceof RuntimeException || th instanceof Error) - _logger.error(msg, th); - else - _logger.warn(msg,th); + public boolean isDebugEnabled() + { + return _logger.isDebugEnabled(); + } + public void setDebugEnabled(boolean enabled) + { + warn("setDebugEnabled not implemented",null,null); } - /* ------------------------------------------------------------ */ public Logger getLogger(String name) { return new Slf4jLog(name); - } - /* ------------------------------------------------------------ */ @Override public String toString() { return _logger.toString(); } - - /* ------------------------------------------------------------ */ - public void setDebugEnabled(boolean enabled) - { - warn("setDebugEnabled not implemented",null,null); - } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java index 58bf8df615..788bc081d8 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.util.log; @@ -17,76 +17,82 @@ import java.security.AccessControlException; import org.eclipse.jetty.util.DateCache; -/*-----------------------------------------------------------------------*/ -/** StdErr Logging. - * This implementation of the Logging facade sends all logs to StdErr with minimal formatting. - * - * If the system property "org.eclipse.jetty.util.log.DEBUG" is set, - * then debug logs are printed if stderr is being used. +/** + * StdErr Logging. This implementation of the Logging facade sends all logs to + * StdErr with minimal formatting. * <p> - * For named debuggers, the system property name+".DEBUG" is checked. If it is not not set, then + * If the system property "org.eclipse.jetty.util.log.DEBUG" is set, then debug + * logs are printed if stderr is being used. For named debuggers, the system + * property name+".DEBUG" is checked. If it is not not set, then * "org.eclipse.jetty.util.log.DEBUG" is used as the default. + * <p> + * If the system property "org.eclipse.jetty.util.log.SOURCE" is set, then the + * source method/file of a log is logged. For named debuggers, the system + * property name+".SOURCE" is checked. If it is not not set, then + * "org.eclipse.jetty.util.log.SOURCE" is used as the default. * */ public class StdErrLog implements Logger -{ +{ private static DateCache _dateCache; - - private final static String LN = System.getProperty("line.separator"); - private final static boolean __debug = - Boolean.parseBoolean(System.getProperty("org.eclipse.jetty.util.log.DEBUG",System.getProperty("org.eclipse.jetty.util.log.stderr.DEBUG","false"))); - private boolean _debug = __debug; - private final String _name; - private boolean _hideStacks=false; - StringBuilder _buffer = new StringBuilder(); - + + private final static boolean __debug = Boolean.parseBoolean( + System.getProperty("org.eclipse.jetty.util.log.DEBUG", + System.getProperty("org.eclipse.jetty.util.log.stderr.DEBUG", "false"))); + private final static boolean __source = Boolean.parseBoolean( + System.getProperty("org.eclipse.jetty.util.log.SOURCE", + System.getProperty("org.eclipse.jetty.util.log.stderr.SOURCE", "false"))); + static { try { - _dateCache=new DateCache("yyyy-MM-dd HH:mm:ss"); + _dateCache = new DateCache("yyyy-MM-dd HH:mm:ss"); } - catch(Exception e) + catch (Exception x) { - e.printStackTrace(); + x.printStackTrace(); } - } - + + private boolean _debug = __debug; + private boolean _source = __source; + private final String _name; + private boolean _hideStacks = false; + public StdErrLog() { this(null); } - + public StdErrLog(String name) - { - this._name=name==null?"":name; + { + this._name = name == null ? "" : name; try { - _debug = Boolean.parseBoolean(System.getProperty(_name + ".DEBUG",Boolean.toString(__debug))); + _debug = Boolean.parseBoolean(System.getProperty(_name + ".DEBUG", Boolean.toString(_debug))); } catch (AccessControlException ace) { _debug = __debug; } + + try + { + _source = Boolean.parseBoolean(System.getProperty(_name + ".SOURCE", Boolean.toString(_source))); + } + catch (AccessControlException ace) + { + _source = __source; + } } - + public String getName() { return _name; } - - public boolean isDebugEnabled() - { - return _debug; - } - - public void setDebugEnabled(boolean enabled) - { - _debug=enabled; - } - + public boolean isHideStacks() { return _hideStacks; @@ -97,227 +103,226 @@ public class StdErrLog implements Logger _hideStacks = hideStacks; } - public void info(String msg) + /* ------------------------------------------------------------ */ + /** Is the source of a log, logged + * @return true if the class, method, file and line number of a log is logged. + */ + public boolean isSource() { - String d=_dateCache.now(); - int ms=_dateCache.lastMs(); - synchronized(_buffer) - { - tag(d,ms,":INFO:"); - format(msg); - System.err.println(_buffer.toString()); - } + return _source; } - public void info(String msg,Object arg0, Object arg1) + /* ------------------------------------------------------------ */ + /** Set if a log source is logged. + * @param source true if the class, method, file and line number of a log is logged. + */ + public void setSource(boolean source) { - String d=_dateCache.now(); - int ms=_dateCache.lastMs(); - synchronized(_buffer) - { - tag(d,ms,":INFO:"); - format(msg,arg0,arg1); - System.err.println(_buffer.toString()); - } + _source = source; } - - public void debug(String msg,Throwable th) + + public void warn(String msg, Object... args) { - if (_debug) - { - String d=_dateCache.now(); - int ms=_dateCache.lastMs(); - synchronized(_buffer) - { - tag(d,ms,":DBUG:"); - format(msg); - if (_hideStacks) - format(th.toString()); - else - format(th); - System.err.println(_buffer.toString()); - } - } + StringBuilder buffer = new StringBuilder(64); + format(buffer, ":WARN:", msg, args); + System.err.println(buffer); } - - public void debug(String msg) + + public void warn(Throwable thrown) { - if (_debug) - { - String d=_dateCache.now(); - int ms=_dateCache.lastMs(); - synchronized(_buffer) - { - tag(d,ms,":DBUG:"); - format(msg); - System.err.println(_buffer.toString()); - } - } + warn("", thrown); } - - public void debug(String msg,Object arg0, Object arg1) + + public void warn(String msg, Throwable thrown) { - if (_debug) - { - String d=_dateCache.now(); - int ms=_dateCache.lastMs(); - synchronized(_buffer) - { - tag(d,ms,":DBUG:"); - format(msg,arg0,arg1); - System.err.println(_buffer.toString()); - } - } + StringBuilder buffer = new StringBuilder(64); + format(buffer, ":WARN:", msg, thrown); + System.err.println(buffer); } - - public void warn(String msg) + + public void info(String msg, Object... args) { - String d=_dateCache.now(); - int ms=_dateCache.lastMs(); - synchronized(_buffer) - { - tag(d,ms,":WARN:"); - format(msg); - System.err.println(_buffer.toString()); - } + StringBuilder buffer = new StringBuilder(64); + format(buffer, ":INFO:", msg, args); + System.err.println(buffer); } - - public void warn(String msg,Object arg0, Object arg1) + + public void info(Throwable thrown) { - String d=_dateCache.now(); - int ms=_dateCache.lastMs(); - synchronized(_buffer) - { - tag(d,ms,":WARN:"); - format(msg,arg0,arg1); - System.err.println(_buffer.toString()); - } + info("", thrown); } - - public void warn(String msg, Throwable th) + + public void info(String msg, Throwable thrown) { - String d=_dateCache.now(); - int ms=_dateCache.lastMs(); - synchronized(_buffer) - { - tag(d,ms,":WARN:"); - format(msg); - if (_hideStacks) - format(th.toString()); - else - format(th); - System.err.println(_buffer.toString()); - } + StringBuilder buffer = new StringBuilder(64); + format(buffer, ":INFO:", msg, thrown); + System.err.println(buffer); + } + + public boolean isDebugEnabled() + { + return _debug; } - - private void tag(String d,int ms,String tag) + public void setDebugEnabled(boolean enabled) { - _buffer.setLength(0); - _buffer.append(d); - if (ms>99) - _buffer.append('.'); - else if (ms>9) - _buffer.append(".0"); + _debug = enabled; + } + + public void debug(String msg, Object... args) + { + if (!_debug) + return; + StringBuilder buffer = new StringBuilder(64); + format(buffer, ":DBUG:", msg, args); + System.err.println(buffer); + } + + public void debug(Throwable thrown) + { + debug("", thrown); + } + + public void debug(String msg, Throwable thrown) + { + if (!_debug) + return; + StringBuilder buffer = new StringBuilder(64); + format(buffer, ":DBUG:", msg, thrown); + System.err.println(buffer); + } + + private void format(StringBuilder buffer, String level, String msg, Object... args) + { + String d = _dateCache.now(); + int ms = _dateCache.lastMs(); + tag(buffer, d, ms, level); + format(buffer, msg, args); + } + + private void format(StringBuilder buffer, String level, String msg, Throwable thrown) + { + format(buffer, level, msg); + if (isHideStacks()) + format(buffer, String.valueOf(thrown)); else - _buffer.append(".00"); - _buffer.append(ms).append(tag).append(_name).append(':'); + format(buffer, thrown); } - - private void format(String msg, Object arg0, Object arg1) + + private void tag(StringBuilder buffer, String d, int ms, String tag) { - int i0=msg==null?-1:msg.indexOf("{}"); - int i1=i0<0?-1:msg.indexOf("{}",i0+2); - - if (i0>=0) + buffer.setLength(0); + buffer.append(d); + if (ms > 99) + buffer.append('.'); + else if (ms > 9) + buffer.append(".0"); + else + buffer.append(".00"); + buffer.append(ms).append(tag).append(_name).append(':'); + if (_source) { - format(msg.substring(0,i0)); - format(String.valueOf(arg0==null?"null":arg0)); - - if (i1>=0) + Throwable source = new Throwable(); + StackTraceElement[] frames = source.getStackTrace(); + for (int i=0;i<frames.length;i++) { - format(msg.substring(i0+2,i1)); - format(String.valueOf(arg1==null?"null":arg1)); - format(msg.substring(i1+2)); - } - else - { - format(msg.substring(i0+2)); - if (arg1!=null) - { - _buffer.append(' '); - format(String.valueOf(arg1)); - } + final StackTraceElement frame = frames[i]; + String clazz = frame.getClassName(); + if (clazz.equals(StdErrLog.class.getName())|| clazz.equals(Log.class.getName())) + continue; + if (clazz.startsWith("org.eclipse.jetty.")) + buffer.append("o.e.j.").append(clazz,18,clazz.length()); + else + buffer.append(clazz); + buffer.append('#').append(frame.getMethodName()); + if (frame.getFileName()!=null) + buffer.append('(').append(frame.getFileName()).append(':').append(frame.getLineNumber()).append(')'); + buffer.append(':'); + break; } } - else + } + + private void format(StringBuilder builder, String msg, Object... args) + { + msg = String.valueOf(msg); // Avoids NPE + String braces = "{}"; + int start = 0; + for (Object arg : args) { - format(msg); - if (arg0!=null) + int bracesIndex = msg.indexOf(braces, start); + if (bracesIndex < 0) { - _buffer.append(' '); - format(String.valueOf(arg0)); + escape(builder, msg.substring(start)); + builder.append(" "); + builder.append(arg); + start = msg.length(); } - if (arg1!=null) + else { - _buffer.append(' '); - format(String.valueOf(arg1)); + escape(builder, msg.substring(start, bracesIndex)); + builder.append(String.valueOf(arg)); + start = bracesIndex + braces.length(); } } + escape(builder, msg.substring(start)); } - - private void format(String msg) + + private void escape(StringBuilder builder, String string) { - if (msg == null) - _buffer.append("null"); - else - for (int i=0;i<msg.length();i++) + for (int i = 0; i < string.length(); ++i) + { + char c = string.charAt(i); + if (Character.isISOControl(c)) { - char c=msg.charAt(i); - if (Character.isISOControl(c)) - { - if (c=='\n') - _buffer.append('|'); - else if (c=='\r') - _buffer.append('<'); - else - _buffer.append('?'); - } + if (c == '\n') + builder.append('|'); + else if (c == '\r') + builder.append('<'); else - _buffer.append(c); + builder.append('?'); } + else + builder.append(c); + } } - - private void format(Throwable th) + + private void format(StringBuilder buffer, Throwable thrown) { - if (th == null) - _buffer.append("null"); + if (thrown == null) + { + buffer.append("null"); + } else { - _buffer.append('\n'); - format(th.toString()); - StackTraceElement[] elements = th.getStackTrace(); - for (int i=0;elements!=null && i<elements.length;i++) + buffer.append('\n'); + format(buffer, thrown.toString()); + StackTraceElement[] elements = thrown.getStackTrace(); + for (int i = 0; elements != null && i < elements.length; i++) { - _buffer.append("\n\tat "); - format(elements[i].toString()); + buffer.append("\n\tat "); + format(buffer, elements[i].toString()); + } + + Throwable cause = thrown.getCause(); + if (cause!=null && cause!=thrown) + { + buffer.append("\nCaused by: "); + format(buffer,cause); } } } - + public Logger getLogger(String name) { - if ((name==null && this._name==null) || - (name!=null && name.equals(this._name))) + if ((name == null && this._name == null) || (name != null && name.equals(this._name))) return this; - return new StdErrLog(_name==null||_name.length()==0?name:_name+"."+name); + return new StdErrLog(_name == null || _name.length() == 0?name:_name + "." + name); } - + @Override public String toString() { - return "StdErrLog:"+_name+":DEBUG="+_debug; + return "StdErrLog:" + _name + ":DEBUG=" + _debug; } - } - diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java index aa97c53505..dc933bafb7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java @@ -315,7 +315,7 @@ class JarFileResource extends JarResource * Take a Resource that possibly might use URLConnection caching * and turn it into one that doesn't. * @param resource - * @return + * @return the non-caching resource */ public static Resource getNonCachingResource (Resource resource) { @@ -331,9 +331,9 @@ class JarFileResource extends JarResource /** * Check if this jar:file: resource is contained in the - * named resource. Eg jar:file:///a/b/c/foo.jar!/x.html isContainedIn file:///a/b/c/foo.jar + * named resource. Eg <code>jar:file:///a/b/c/foo.jar!/x.html</code> isContainedIn <code>file:///a/b/c/foo.jar</code> * @param resource - * @return + * @return true if resource is contained in the named resource * @throws MalformedURLException */ @Override diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java index 6c8b41695f..44e8ba6916 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java @@ -34,10 +34,8 @@ import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ -/** Abstract resource class. - * - * - * +/** + * Abstract resource class. */ public abstract class Resource implements Serializable { @@ -259,13 +257,13 @@ public abstract class Resource implements Serializable /* ------------------------------------------------------------ */ /** Find a classpath resource. - * The {@java.lang.Class#getResource} method is used to lookup the resource. If it is not + * The {@link java.lang.Class#getResource(String)} method is used to lookup the resource. If it is not * found, then the {@link Loader#getResource(Class, String, boolean)} method is used. * If it is still not found, then {@link ClassLoader#getSystemResource(String)} is used. - * Unlike {@link #getSystemResource} this method does not check for normal resources. - * @param name The relative name of the resouce + * Unlike {@link ClassLoader#getSystemResource(String)} this method does not check for normal resources. + * @param name The relative name of the resource * @param useCaches True if URL caches are to be used. - * @param checkParents True if forced searching of parent classloaders is performed to work around + * @param checkParents True if forced searching of parent Classloaders is performed to work around * loaders with inverted priorities * @return Resource or null */ @@ -491,7 +489,7 @@ public abstract class Resource implements Serializable buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n"); } - String defangedBase = defangURI(base); + String encodedBase = hrefEncodeURI(base); DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); @@ -500,7 +498,7 @@ public abstract class Resource implements Serializable Resource item = addPath(ls[i]); buf.append("\n<TR><TD><A HREF=\""); - String path=URIUtil.addPaths(defangedBase,URIUtil.encodePath(ls[i])); + String path=URIUtil.addPaths(encodedBase,URIUtil.encodePath(ls[i])); buf.append(path); @@ -524,38 +522,36 @@ public abstract class Resource implements Serializable } /** - * Defang any characters that could break the URI string in an HREF. + * Encode any characters that could break the URI string in an HREF. * Such as <a href="/path/to;<script>Window.alert("XSS"+'%20'+"here");</script>">Link</a> * * The above example would parse incorrectly on various browsers as the "<" or '"' characters * would end the href attribute value string prematurely. * - * @param raw the raw text to defang. + * @param raw the raw text to encode. * @return the defanged text. */ - private static String defangURI(String raw) + private static String hrefEncodeURI(String raw) { StringBuffer buf = null; - - if (buf==null) + + loop: + for (int i=0;i<raw.length();i++) { - for (int i=0;i<raw.length();i++) + char c=raw.charAt(i); + switch(c) { - char c=raw.charAt(i); - switch(c) - { - case '\'': - case '"': - case '<': - case '>': - buf=new StringBuffer(raw.length()<<1); - break; - } + case '\'': + case '"': + case '<': + case '>': + buf=new StringBuffer(raw.length()<<1); + break loop; } - if (buf==null) - return raw; } - + if (buf==null) + return raw; + for (int i=0;i<raw.length();i++) { char c=raw.charAt(i); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java index 7ff50cfe63..8d55ee2f3f 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java @@ -114,6 +114,10 @@ public class ResourceCollection extends Resource throw new IllegalArgumentException(_resources[i] + " is not an existing directory."); } } + catch(IllegalArgumentException e) + { + throw e; + } catch(Exception e) { throw new RuntimeException(e); @@ -458,12 +462,9 @@ public class ResourceCollection extends Resource public String toString() { if(_resources==null) - return ""; + return "[]"; - StringBuilder buffer = new StringBuilder(); - for(Resource r : _resources) - buffer.append(r.toString()).append(';'); - return buffer.toString(); + return String.valueOf(Arrays.asList(_resources)); } /* ------------------------------------------------------------ */ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java index 98006e5a6f..8c9b33d310 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java @@ -46,7 +46,7 @@ public class CounterStatistic /* ------------------------------------------------------------ */ /** - * @param delta + * @param delta the amount to add to the count */ public void add(final long delta) { @@ -64,7 +64,7 @@ public class CounterStatistic /* ------------------------------------------------------------ */ /** - * @param delta + * @param delta the amount to subtract the count by. */ public void subtract(final long delta) { @@ -89,7 +89,7 @@ public class CounterStatistic /* ------------------------------------------------------------ */ /** - * @return + * @return max value */ public long getMax() { @@ -98,7 +98,7 @@ public class CounterStatistic /* ------------------------------------------------------------ */ /** - * @return + * @return current value */ public long getCurrent() { @@ -107,7 +107,7 @@ public class CounterStatistic /* ------------------------------------------------------------ */ /** - * @return + * @return total value */ public long getTotal() { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java index cc0edea8db..fbdb422b0b 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java @@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicLong; * deviation of continuous sequence of samples. * <p> * Calculates estimates of mean, variance, and standard deviation - * characteristics of a sample using a non synchronised + * characteristics of a sample using a non synchronized * approximation of the on-line algorithm presented * in Donald Knuth's Art of Computer Programming, Volume 2, * Seminumerical Algorithms, 3rd edition, page 232, @@ -73,7 +73,7 @@ public class SampleStatistic /* ------------------------------------------------------------ */ /** - * @return + * @return the max value */ public long getMax() { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java index 32bc92e1cf..c00a3cb1fe 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java @@ -27,12 +27,10 @@ import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ -/** Jetty ThreadPool using java 5 ThreadPoolExecutor +/** + * Jetty ThreadPool using java 5 ThreadPoolExecutor * This class wraps a {@link ExecutorService} as a {@link ThreadPool} and - * {@link LifeCycle} interfaces so that it may be used by the Jetty {@link org.eclipse.jetty.Server} - * - * - * + * {@link LifeCycle} interfaces so that it may be used by the Jetty <code>org.eclipse.jetty.server.Server</code> */ public class ExecutorThreadPool extends AbstractLifeCycle implements ThreadPool, LifeCycle { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java index a543363130..6c89832e70 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java @@ -28,7 +28,6 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.log.Log; - public class QueuedThreadPool extends AbstractLifeCycle implements ThreadPool, Executor { private final AtomicInteger _threadsStarted = new AtomicInteger(); @@ -47,7 +46,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements ThreadPool, E private int _maxStopTime=100; /* ------------------------------------------------------------------- */ - /* Construct + /** Construct */ public QueuedThreadPool() { @@ -55,7 +54,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements ThreadPool, E } /* ------------------------------------------------------------------- */ - /* Construct + /** Construct */ public QueuedThreadPool(int maxThreads) { @@ -64,7 +63,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements ThreadPool, E } /* ------------------------------------------------------------------- */ - /* Construct + /** Construct */ public QueuedThreadPool(BlockingQueue<Runnable> jobQ) { @@ -508,7 +507,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements ThreadPool, E /** * @param id The thread ID to stop. * @return true if the thread was found and stopped. - * @Deprecated Use {@link #interruptThread(long)} in preference + * @deprecated Use {@link #interruptThread(long)} in preference */ @SuppressWarnings("deprecation") public boolean stopThread(long id) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ShutdownThread.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ShutdownThread.java index bae25570e6..ebf3096fff 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ShutdownThread.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ShutdownThread.java @@ -35,6 +35,7 @@ public class ShutdownThread extends Thread { private static final ShutdownThread _thread = new ShutdownThread(); + private boolean _hooked; private final List<LifeCycle> _lifeCycles = new CopyOnWriteArrayList<LifeCycle>(); /* ------------------------------------------------------------ */ @@ -45,14 +46,44 @@ public class ShutdownThread extends Thread */ private ShutdownThread() { - Runtime.getRuntime().addShutdownHook(this); } - + + /* ------------------------------------------------------------ */ + private synchronized void hook() + { + try + { + if (!_hooked) + Runtime.getRuntime().addShutdownHook(this); + _hooked=true; + } + catch(Exception e) + { + Log.ignore(e); + Log.info("shutdown already commenced"); + } + } + + /* ------------------------------------------------------------ */ + private synchronized void unhook() + { + try + { + _hooked=false; + Runtime.getRuntime().removeShutdownHook(this); + } + catch(Exception e) + { + Log.ignore(e); + Log.info("shutdown already commenced"); + } + } + /* ------------------------------------------------------------ */ /** * Returns the instance of the singleton * - * @return + * @return the singleton instance of the {@link ShutdownThread} */ public static ShutdownThread getInstance() { @@ -63,18 +94,24 @@ public class ShutdownThread extends Thread public static synchronized void register(LifeCycle... lifeCycles) { _thread._lifeCycles.addAll(Arrays.asList(lifeCycles)); + if (_thread._lifeCycles.size()>0) + _thread.hook(); } /* ------------------------------------------------------------ */ public static synchronized void register(int index, LifeCycle... lifeCycles) { _thread._lifeCycles.addAll(index,Arrays.asList(lifeCycles)); + if (_thread._lifeCycles.size()>0) + _thread.hook(); } /* ------------------------------------------------------------ */ public static synchronized void deregister(LifeCycle lifeCycle) { _thread._lifeCycles.remove(lifeCycle); + if (_thread._lifeCycles.size()==0) + _thread.unhook(); } /* ------------------------------------------------------------ */ @@ -93,11 +130,4 @@ public class ShutdownThread extends Thread } } } - - /* ------------------------------------------------------------ */ - protected Object readResolve() - throws ObjectStreamException - { - return _thread; - } -}
\ No newline at end of file +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Timeout.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Timeout.java index e2220840c7..c1aabe11d1 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Timeout.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Timeout.java @@ -23,10 +23,7 @@ import org.eclipse.jetty.util.log.Log; * is changed, this affects all scheduled tasks. * <p> * The nested class Task should be extended by users of this class to obtain call back notification of - * expiries. - * - * - * + * expires. */ public class Timeout { @@ -91,7 +88,7 @@ public class Timeout * expired Task, but without calling it's {@link Task#expire()} or * {@link Task#expired()} methods. * - * @returns the next expired task or null. + * @return the next expired task or null. */ public Task expired() { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ArrayQueueTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ArrayQueueTest.java index f79c618564..028208bd32 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ArrayQueueTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ArrayQueueTest.java @@ -13,11 +13,16 @@ package org.eclipse.jetty.util; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -public class ArrayQueueTest extends TestCase +import org.junit.Test; + + +public class ArrayQueueTest { - + @Test public void testWrap() throws Exception { ArrayQueue<String> queue = new ArrayQueue<String>(3,3); @@ -63,6 +68,7 @@ public class ArrayQueueTest extends TestCase } + @Test public void testRemove() throws Exception { ArrayQueue<String> queue = new ArrayQueue<String>(3,3); @@ -82,6 +88,7 @@ public class ArrayQueueTest extends TestCase assertEquals(i+"!",queue.get(i)); } + @Test public void testGrow() throws Exception { ArrayQueue<String> queue = new ArrayQueue<String>(3,5); @@ -123,10 +130,9 @@ public class ArrayQueueTest extends TestCase for (int i=0;i<12;i++) queue.add(""+('a'+i)); assertEquals(13,queue.getCapacity()); - - } + @Test public void testFullEmpty() throws Exception { ArrayQueue<String> queue = new ArrayQueue<String>(2); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/BlockingArrayQueueTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/BlockingArrayQueueTest.java index a7ae482adc..7daee8f5c5 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/BlockingArrayQueueTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/BlockingArrayQueueTest.java @@ -13,17 +13,22 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.util.HashSet; import java.util.Random; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; +import org.junit.Test; + -public class BlockingArrayQueueTest extends TestCase +public class BlockingArrayQueueTest { + @Test public void testWrap() throws Exception { BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3); @@ -66,6 +71,7 @@ public class BlockingArrayQueueTest extends TestCase } + @Test public void testRemove() throws Exception { BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3,3); @@ -85,6 +91,7 @@ public class BlockingArrayQueueTest extends TestCase assertEquals(i+"!",queue.get(i)); } + @Test public void testGrow() throws Exception { BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3,2); @@ -128,11 +135,9 @@ public class BlockingArrayQueueTest extends TestCase s+=2; c+=2; } - - - } + @Test public void testTake() throws Exception { final String[] data=new String[4]; @@ -178,6 +183,7 @@ public class BlockingArrayQueueTest extends TestCase volatile boolean _running; + @Test public void testConcurrentAccess() throws Exception { final int THREADS=50; @@ -306,9 +312,5 @@ public class BlockingArrayQueueTest extends TestCase HashSet<Integer> consSet = new HashSet<Integer>(consumed); assertEquals(prodSet,consSet); - - - - } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java index e49eff036e..15284fd249 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java @@ -13,37 +13,23 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.util.Locale; import java.util.TimeZone; -import junit.framework.TestSuite; +import org.junit.Test; /* ------------------------------------------------------------ */ /** Util meta Tests. * */ -public class DateCacheTest extends junit.framework.TestCase +public class DateCacheTest { - public DateCacheTest(String name) - { - super(name); - } - - public static junit.framework.Test suite() { - TestSuite suite = new TestSuite(DateCacheTest.class); - return suite; - } - - /* ------------------------------------------------------------ */ - /** main. - */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - /* ------------------------------------------------------------ */ + @Test public void testDateCache() throws Exception { //@WAS: Test t = new Test("org.eclipse.jetty.util.DateCache"); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java new file mode 100644 index 0000000000..f1ade99091 --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java @@ -0,0 +1,172 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + + +public class IPAddressMapTest +{ + @Test + public void testOneAddress() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.5.2.1","1"); + + assertNotNull(map.match("10.5.2.1")); + + assertNull(map.match("101.5.2.1")); + assertNull(map.match("10.15.2.1")); + assertNull(map.match("10.5.22.1")); + assertNull(map.match("10.5.2.0")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testOneRange() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("1-15.16-31.32-63.64-127","1"); + + assertNotNull(map.match("7.23.39.71")); + assertNotNull(map.match("1.16.32.64")); + assertNotNull(map.match("15.31.63.127")); + + assertNull(map.match("16.32.64.128")); + assertNull(map.match("1.16.32.63")); + assertNull(map.match("1.16.31.64")); + assertNull(map.match("1.15.32.64")); + assertNull(map.match("0.16.32.64")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testOneMissing() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.5.2.","1"); + + assertNotNull(map.match("10.5.2.0")); + assertNotNull(map.match("10.5.2.128")); + assertNotNull(map.match("10.5.2.255")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testTwoMissing() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.5.","1"); + + assertNotNull(map.match("10.5.2.0")); + assertNotNull(map.match("10.5.2.128")); + assertNotNull(map.match("10.5.2.255")); + assertNotNull(map.match("10.5.0.1")); + assertNotNull(map.match("10.5.128.1")); + assertNotNull(map.match("10.5.255.1")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testThreeMissing() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.","1"); + + assertNotNull(map.match("10.5.2.0")); + assertNotNull(map.match("10.5.2.128")); + assertNotNull(map.match("10.5.2.255")); + assertNotNull(map.match("10.5.0.1")); + assertNotNull(map.match("10.5.128.1")); + assertNotNull(map.match("10.5.255.1")); + assertNotNull(map.match("10.0.1.1")); + assertNotNull(map.match("10.128.1.1")); + assertNotNull(map.match("10.255.1.1")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testOneMixed() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("0-15,21.10,16-31.0-15,32-63.-95,128-","1"); + + assertNotNull(map.match("7.23.39.46")); + assertNotNull(map.match("10.20.10.150")); + assertNotNull(map.match("21.10.32.255")); + assertNotNull(map.match("21.10.15.0")); + + assertNull(map.match("16.15.20.100")); + assertNull(map.match("15.10.63.100")); + assertNull(map.match("15.10.64.128")); + assertNull(map.match("15.11.32.95")); + assertNull(map.match("16.31.63.128")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testManyMixed() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.5.2.1","1"); + map.put("1-15.16-31.32-63.64-127","2"); + map.put("1-15,21.10,16-31.0-15,32-63.-55,195-","3"); + map.put("44.99.99.","4"); + map.put("55.99.","5"); + map.put("66.","6"); + + assertEquals("1", map.match("10.5.2.1")); + + assertEquals("2", map.match("7.23.39.71")); + assertEquals("2", map.match("1.16.32.64")); + assertEquals("2", map.match("15.31.63.127")); + + assertEquals("3", map.match("7.23.39.46")); + assertEquals("3", map.match("10.20.10.200")); + assertEquals("3", map.match("21.10.32.255")); + assertEquals("3", map.match("21.10.15.0")); + + assertEquals("4", map.match("44.99.99.0")); + assertEquals("5", map.match("55.99.128.1")); + assertEquals("6", map.match("66.255.1.1")); + + assertNull(map.match("101.5.2.1")); + assertNull(map.match("10.15.2.1")); + assertNull(map.match("10.5.22.1")); + assertNull(map.match("10.5.2.0")); + + assertNull(map.match("16.32.64.96")); + assertNull(map.match("1.16.32.194")); + assertNull(map.match("1.16.31.64")); + assertNull(map.match("1.15.32.64")); + assertNull(map.match("0.16.32.64")); + + assertNull(map.match("16.15.20.100")); + assertNull(map.match("15.10.63.100")); + assertNull(map.match("15.10.64.128")); + assertNull(map.match("15.11.32.95")); + assertNull(map.match("16.31.63.128")); + } +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/LazyListTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/LazyListTest.java index 4f1613e6e4..93716a4a74 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/LazyListTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/LazyListTest.java @@ -13,32 +13,28 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; -import junit.framework.TestCase; +import org.junit.Test; + /** * * */ -public class LazyListTest extends TestCase +public class LazyListTest { - - /** - * Constructor for LazyListTest. - * @param arg0 - */ - public LazyListTest(String arg0) - { - super(arg0); - } - /* * Test for Object add(Object, Object) */ + @Test public void testAddObjectObject() { Object list=null; @@ -79,6 +75,7 @@ public class LazyListTest extends TestCase /* * Test for Object add(Object, int, Object) */ + @Test public void testAddObjectintObject() { Object list=null; @@ -100,7 +97,7 @@ public class LazyListTest extends TestCase assertTrue(list instanceof List); } - + @Test public void testAddCollection() { ArrayList l=new ArrayList(); @@ -118,6 +115,7 @@ public class LazyListTest extends TestCase assertEquals("b",LazyList.get(list,3)); } + @Test public void testEnsureSize() { assertTrue(LazyList.ensureSize(null,10)!=null); @@ -134,6 +132,7 @@ public class LazyListTest extends TestCase /* * Test for Object remove(Object, Object) */ + @Test public void testRemoveObjectObject() { Object list=null; @@ -166,6 +165,7 @@ public class LazyListTest extends TestCase /* * Test for Object remove(Object, int) */ + @Test public void testRemoveObjectint() { Object list=null; @@ -197,6 +197,7 @@ public class LazyListTest extends TestCase /* * Test for List getList(Object) */ + @Test public void testGetListObject() { assertEquals(0,LazyList.getList(null).size()); @@ -211,12 +212,14 @@ public class LazyListTest extends TestCase /* * Test for List getList(Object, boolean) */ + @Test public void testGetListObjectboolean() { assertEquals(0,LazyList.getList(null,false).size()); assertEquals(null,LazyList.getList(null,true)); } + @Test public void testToStringArray() { assertEquals(0,LazyList.toStringArray(null).length); @@ -237,6 +240,7 @@ public class LazyListTest extends TestCase } + @Test public void testSize() { ArrayList l=new ArrayList(); @@ -249,6 +253,7 @@ public class LazyListTest extends TestCase assertEquals(2,LazyList.size(l)); } + @Test public void testGet() { testAddObjectObject(); @@ -274,6 +279,7 @@ public class LazyListTest extends TestCase } } + @Test public void testContains() { ArrayList l=new ArrayList(); @@ -289,8 +295,7 @@ public class LazyListTest extends TestCase } - - + @Test public void testIterator() { ArrayList l=new ArrayList(); @@ -312,6 +317,7 @@ public class LazyListTest extends TestCase assertFalse(i.hasNext()); } + @Test public void testListIterator() { ArrayList l=new ArrayList(); @@ -341,6 +347,7 @@ public class LazyListTest extends TestCase assertEquals("a",i.previous()); } + @Test public void testCloneToString() { ArrayList l=new ArrayList(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiExceptionTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiExceptionTest.java index 8bbc66aa99..7777a6779a 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiExceptionTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiExceptionTest.java @@ -3,9 +3,16 @@ package org.eclipse.jetty.util; import java.io.IOException; import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -public class MultiExceptionTest extends TestCase +import org.junit.Test; + + +public class MultiExceptionTest { + @Test public void testEmpty() throws Exception { MultiException me = new MultiException(); @@ -16,6 +23,7 @@ public class MultiExceptionTest extends TestCase me.ifExceptionThrowRuntime(); } + @Test public void testOne() throws Exception { MultiException me = new MultiException(); @@ -69,6 +77,7 @@ public class MultiExceptionTest extends TestCase } } + @Test public void testTwo() throws Exception { MultiException me = new MultiException(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java index b3b4f1d392..b4835a48bd 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java @@ -34,16 +34,16 @@ public class MultiPartInputStreamTest extends TestCase { protected String _contentType = "multipart/form-data, boundary=AaB03x"; protected String _multi = - "--AaB03x\n"+ - "content-disposition: form-data; name=\"field1\"\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"\r\n"+ "\r\n"+ - "Joe Blow\n"+ - "--AaB03x\n"+ - "content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\n"+ - "Content-Type: text/plain\n"+ + "Joe Blow\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+ + "Content-Type: text/plain\r\n"+ "\r\n"+ - "000000000000000000000000000000000000000000000000000\n"+ - "--AaB03x--"; + "000000000000000000000000000000000000000000000000000\r\n"+ + "--AaB03x--\r\n"; protected String _dirname = System.getProperty("java.io.tmpdir")+File.separator+"myfiles-"+System.currentTimeMillis(); @@ -112,7 +112,7 @@ public class MultiPartInputStreamTest extends TestCase throws Exception { MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); - MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), _contentType, config); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/QuotedStringTokenizerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/QuotedStringTokenizerTest.java index 8c2253163a..7048e9b1ee 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/QuotedStringTokenizerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/QuotedStringTokenizerTest.java @@ -13,27 +13,23 @@ package org.eclipse.jetty.util; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + /** * * */ -public class QuotedStringTokenizerTest extends TestCase +public class QuotedStringTokenizerTest { - - /** - * Constructor for QuotedStringTokenizerTest. - * @param arg0 - */ - public QuotedStringTokenizerTest(String arg0) - { - super(arg0); - } - /* * Test for String nextToken() */ + @Test public void testTokenizer0() { QuotedStringTokenizer tok = @@ -44,6 +40,7 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String nextToken() */ + @Test public void testTokenizer1() { QuotedStringTokenizer tok = @@ -55,6 +52,7 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String nextToken() */ + @Test public void testTokenizer2() { QuotedStringTokenizer tok = @@ -70,6 +68,7 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String nextToken() */ + @Test public void testTokenizer3() { QuotedStringTokenizer tok; @@ -91,6 +90,7 @@ public class QuotedStringTokenizerTest extends TestCase checkTok(tok,true,true); } + @Test public void testQuote() { StringBuffer buf = new StringBuffer(); @@ -108,11 +108,11 @@ public class QuotedStringTokenizerTest extends TestCase assertEquals("\"abcefg\\\"\"",buf.toString()); buf.setLength(0); - QuotedStringTokenizer.quoteIfNeeded(buf,"abc \n efg"); + QuotedStringTokenizer.quoteIfNeeded(buf,"abc \n efg","\"\\\n\r\t\f\b%+ ;="); assertEquals("\"abc \\n efg\"",buf.toString()); buf.setLength(0); - QuotedStringTokenizer.quoteIfNeeded(buf,"abcefg"); + QuotedStringTokenizer.quoteIfNeeded(buf,"abcefg","\"\\\n\r\t\f\b%+ ;="); assertEquals("abcefg",buf.toString()); } @@ -120,6 +120,7 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String nextToken() */ + @Test public void testTokenizer4() { QuotedStringTokenizer tok = new QuotedStringTokenizer("abc'def,ghi'jkl",","); @@ -150,21 +151,24 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String quote(String, String) */ + @Test public void testQuoteString() { - assertEquals("abc",QuotedStringTokenizer.quote("abc", " ,")); - assertEquals("\"a c\"",QuotedStringTokenizer.quote("a c", " ,")); - assertEquals("\"a'c\"",QuotedStringTokenizer.quote("a'c", " ,")); - assertEquals("\"a\\n\\r\\t\"",QuotedStringTokenizer.quote("a\n\r\t")); + assertEquals("abc",QuotedStringTokenizer.quoteIfNeeded("abc", " ,")); + assertEquals("\"a c\"",QuotedStringTokenizer.quoteIfNeeded("a c", " ,")); + assertEquals("\"a'c\"",QuotedStringTokenizer.quoteIfNeeded("a'c", " ,")); + assertEquals("\"a\\n\\r\\t\"",QuotedStringTokenizer.quote("a\n\r\t")); + assertEquals("\"\\u0000\\u001f\"",QuotedStringTokenizer.quote("\u0000\u001f")); } - + @Test public void testUnquote() { assertEquals("abc",QuotedStringTokenizer.unquote("abc")); assertEquals("a\"c",QuotedStringTokenizer.unquote("\"a\\\"c\"")); assertEquals("a'c",QuotedStringTokenizer.unquote("\"a'c\"")); assertEquals("a\n\r\t",QuotedStringTokenizer.unquote("\"a\\n\\r\\t\"")); + assertEquals("\u0000\u001f ",QuotedStringTokenizer.unquote("\"\u0000\u001f\u0020\"")); } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java index ce27d67600..5f0c075f98 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java @@ -13,6 +13,10 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; @@ -20,37 +24,28 @@ import java.io.ObjectOutputStream; import java.util.Map; import java.util.Set; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; /** * * */ -public class StringMapTest extends TestCase +public class StringMapTest { StringMap m0; StringMap m1; StringMap m5; StringMap m5i; - /** - * Constructor for StringMapTest. - * @param arg0 - */ - public StringMapTest(String arg0) - { - super(arg0); - } - /* * @see TestCase#setUp() */ - @Override - protected void setUp() throws Exception + + @Before + public void setUp() throws Exception { - super.setUp(); - m0=new StringMap(); m1=new StringMap(false); m1.put("abc", "0"); @@ -70,15 +65,7 @@ public class StringMapTest extends TestCase m5i.put("bbb", null); } - /* - * @see TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - } - + @Test public void testSize() { assertEquals(0, m0.size()); @@ -96,6 +83,7 @@ public class StringMapTest extends TestCase assertEquals(5, m5i.size()); } + @Test public void testIsEmpty() { assertTrue(m0.isEmpty()); @@ -104,6 +92,7 @@ public class StringMapTest extends TestCase assertFalse(m5i.isEmpty()); } + @Test public void testClear() { m0.clear(); @@ -123,6 +112,7 @@ public class StringMapTest extends TestCase /* * Test for Object put(Object, Object) */ + @Test public void testPutGet() { assertEquals("2",m5.get("abc")); @@ -146,11 +136,10 @@ public class StringMapTest extends TestCase } - - /* * Test for Map.Entry getEntry(String, int, int) */ + @Test public void testGetEntryStringintint() { Map.Entry entry; @@ -187,6 +176,7 @@ public class StringMapTest extends TestCase /* * Test for Map.Entry getEntry(char[], int, int) */ + @Test public void testGetEntrycharArrayintint() { char[] xabcyz = {'x','a','b','c','y','z'}; @@ -210,6 +200,7 @@ public class StringMapTest extends TestCase /* * Test for Object remove(Object) */ + @Test public void testRemove() { m0.remove("abc"); @@ -230,10 +221,10 @@ public class StringMapTest extends TestCase assertEquals(null,m5i.get(null)); } - /* * Test for Set entrySet() */ + @Test public void testEntrySet() { Set es0=m0.entrySet(); @@ -247,6 +238,7 @@ public class StringMapTest extends TestCase /* * Test for boolean containsKey(Object) */ + @Test public void testContainsKey() { assertTrue(m5.containsKey("abc")); @@ -260,6 +252,7 @@ public class StringMapTest extends TestCase assertTrue(m5i.containsKey("ABC")); } + @Test public void testWriteExternal() throws Exception { @@ -288,6 +281,7 @@ public class StringMapTest extends TestCase } + @Test public void testToString() { assertEquals("{}",m0.toString()); @@ -295,7 +289,7 @@ public class StringMapTest extends TestCase assertTrue(m5.toString().indexOf("abc=2")>0); } - + @Test public void testIgnoreCase() { StringMap map = new StringMap(true); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java index 10d2a51bdb..52d9f8fb9a 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java @@ -13,43 +13,20 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; -import junit.framework.TestCase; /** * * */ -public class StringUtilTest extends TestCase +public class StringUtilTest { - - /** - * Constructor for StringUtilTest. - * @param arg0 - */ - public StringUtilTest(String arg0) - { - super(arg0); - } - - /* - * @see TestCase#setUp() - */ - @Override - protected void setUp() throws Exception - { - super.setUp(); - } - - /* - * @see TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - } - + @Test public void testAsciiToLowerCase() { String lc="\u0690bc def 1\u06903"; @@ -57,6 +34,7 @@ public class StringUtilTest extends TestCase assertTrue(StringUtil.asciiToLowerCase(lc)==lc); } + @Test public void testStartsWithIgnoreCase() { @@ -74,6 +52,7 @@ public class StringUtilTest extends TestCase assertFalse(StringUtil.startsWithIgnoreCase("\u0690", "xyz")); } + @Test public void testEndsWithIgnoreCase() { assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcd\u0690f\u0690", "\u0690f\u0690")); @@ -90,6 +69,7 @@ public class StringUtilTest extends TestCase assertFalse(StringUtil.endsWithIgnoreCase("\u0690", "xyz")); } + @Test public void testIndexFrom() { assertEquals(StringUtil.indexFrom("\u0690bcd", "xyz"),-1); @@ -98,6 +78,7 @@ public class StringUtilTest extends TestCase assertEquals(StringUtil.indexFrom("\u0690bcd", "dxy"),3); } + @Test public void testReplace() { String s="\u0690bc \u0690bc \u0690bc"; @@ -109,6 +90,7 @@ public class StringUtilTest extends TestCase } + @Test public void testUnquote() { String uq =" not quoted "; @@ -120,6 +102,7 @@ public class StringUtilTest extends TestCase } + @Test public void testNonNull() { String nn=""; @@ -130,12 +113,14 @@ public class StringUtilTest extends TestCase /* * Test for boolean equals(String, char[], int, int) */ + @Test public void testEqualsStringcharArrayintint() { assertTrue(StringUtil.equals("\u0690bc", new char[] {'x','\u0690','b','c','z'},1,3)); assertFalse(StringUtil.equals("axc", new char[] {'x','a','b','c','z'},1,3)); } + @Test public void testAppend() { StringBuilder buf = new StringBuilder(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/TestIntrospectionUtil.java b/jetty-util/src/test/java/org/eclipse/jetty/util/TestIntrospectionUtil.java index 91ed6f3acf..e85ee76a16 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/TestIntrospectionUtil.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/TestIntrospectionUtil.java @@ -13,35 +13,40 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import java.lang.reflect.Field; import java.lang.reflect.Method; -import junit.framework.TestCase; +import org.junit.BeforeClass; +import org.junit.Test; + /** * TestInjection * * */ -public class TestIntrospectionUtil extends TestCase +public class TestIntrospectionUtil { - public final Class[] __INTEGER_ARG = new Class[] {Integer.class}; - Field privateAField; - Field protectedAField; - Field publicAField; - Field defaultAField; - Field privateBField; - Field protectedBField; - Field publicBField; - Field defaultBField; - Method privateCMethod; - Method protectedCMethod; - Method publicCMethod; - Method defaultCMethod; - Method privateDMethod; - Method protectedDMethod; - Method publicDMethod; - Method defaultDMethod; + public final static Class[] __INTEGER_ARG = new Class[] {Integer.class}; + static Field privateAField; + static Field protectedAField; + static Field publicAField; + static Field defaultAField; + static Field privateBField; + static Field protectedBField; + static Field publicBField; + static Field defaultBField; + static Method privateCMethod; + static Method protectedCMethod; + static Method publicCMethod; + static Method defaultCMethod; + static Method privateDMethod; + static Method protectedDMethod; + static Method publicDMethod; + static Method defaultDMethod; public class ServletA { @@ -75,8 +80,8 @@ public class TestIntrospectionUtil extends TestCase void setDefaultD(Integer d) {} } - @Override - public void setUp() + @BeforeClass + public static void setUp() throws Exception { privateAField = ServletA.class.getDeclaredField("privateA"); @@ -97,7 +102,7 @@ public class TestIntrospectionUtil extends TestCase defaultDMethod = ServletD.class.getDeclaredMethod("setDefaultD", __INTEGER_ARG); } - + @Test public void testFieldPrivate () throws Exception { @@ -117,6 +122,7 @@ public class TestIntrospectionUtil extends TestCase } } + @Test public void testFieldProtected() throws Exception { @@ -129,6 +135,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(f, protectedAField); } + @Test public void testFieldPublic() throws Exception { @@ -141,6 +148,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(f, publicAField); } + @Test public void testFieldDefault() throws Exception { @@ -153,6 +161,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(f, defaultAField); } + @Test public void testMethodPrivate () throws Exception { @@ -172,6 +181,7 @@ public class TestIntrospectionUtil extends TestCase } } + @Test public void testMethodProtected () throws Exception { @@ -184,6 +194,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(m, protectedCMethod); } + @Test public void testMethodPublic () throws Exception { @@ -196,6 +207,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(m, publicCMethod); } + @Test public void testMethodDefault () throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URITest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URITest.java index 80624ebf07..79f350ff1c 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/URITest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URITest.java @@ -13,34 +13,19 @@ package org.eclipse.jetty.util; -import junit.framework.TestSuite; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; /* ------------------------------------------------------------ */ /** Util meta Tests. * */ -public class URITest extends junit.framework.TestCase +public class URITest { - public URITest(String name) - { - super(name); - } - - public static junit.framework.Test suite() { - TestSuite suite = new TestSuite(URITest.class); - return suite; - } - - /* ------------------------------------------------------------ */ - /** main. - */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - /* ------------------------------------------------------------ */ + @Test public void testEncodePath() { // test basic encode/decode @@ -63,6 +48,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testDecodePath() { assertEquals("foo%23;,:=b a r",URIUtil.decodePath("foo%2523%3b%2c:%3db%20a%20r")); @@ -72,6 +58,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testAddPaths() { assertEquals("null+null", URIUtil.addPaths(null,null),null); @@ -161,6 +148,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testCompactPath() { assertEquals("/foo/bar", URIUtil.compactPath("/foo/bar")); @@ -174,6 +162,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testParentPath() { assertEquals("parent /aaa/bbb/","/aaa/", URIUtil.parentPath("/aaa/bbb/")); @@ -186,6 +175,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testCanonicalPath() { String[][] canonical = diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java index 43d7a5d9f1..bee8052f4d 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java @@ -13,38 +13,23 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayInputStream; import java.io.UnsupportedEncodingException; -import junit.framework.TestSuite; +import org.junit.Test; /* ------------------------------------------------------------ */ /** Util meta Tests. * */ -public class URLEncodedTest extends junit.framework.TestCase +public class URLEncodedTest { - public URLEncodedTest(String name) - { - super(name); - } - - public static junit.framework.Test suite() { - TestSuite suite = new TestSuite(URLEncodedTest.class); - return suite; - } - - /* ------------------------------------------------------------ */ - /** main. - */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - - /* -------------------------------------------------------------- */ + @Test public void testUrlEncoded() throws UnsupportedEncodingException { @@ -147,6 +132,7 @@ public class URLEncodedTest extends junit.framework.TestCase /* -------------------------------------------------------------- */ + @Test public void testUrlEncodedStream() throws Exception { @@ -185,6 +171,7 @@ public class URLEncodedTest extends junit.framework.TestCase } /* -------------------------------------------------------------- */ + @Test public void testUtf8() throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java index 2b65d76185..8601e6205f 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java @@ -13,10 +13,14 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; -public class Utf8StringBufferTest extends junit.framework.TestCase -{ +public class Utf8StringBufferTest +{ public void testUtfStringBuffer() throws Exception { @@ -30,6 +34,7 @@ public class Utf8StringBufferTest extends junit.framework.TestCase } + @Test public void testShort() throws Exception { @@ -49,6 +54,7 @@ public class Utf8StringBufferTest extends junit.framework.TestCase } } + @Test public void testLong() throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java index 4a20865f4b..6240218945 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java @@ -13,10 +13,15 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; -public class Utf8StringBuilderTest extends junit.framework.TestCase -{ +public class Utf8StringBuilderTest +{ + @Test public void testUtfStringBuilder() throws Exception { @@ -29,6 +34,7 @@ public class Utf8StringBuilderTest extends junit.framework.TestCase assertTrue(buffer.toString().endsWith("jetty")); } + @Test public void testShort() throws Exception { @@ -48,6 +54,7 @@ public class Utf8StringBuilderTest extends junit.framework.TestCase } } + @Test public void testLong() throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java index aea0c8f8c3..c4d78105c3 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java @@ -13,14 +13,18 @@ package org.eclipse.jetty.util.ajax; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; /** * Test to convert POJOs to JSON and vice versa with automatic convertor creation. */ -public class JSONPojoConvertorFactoryTest extends TestCase { - +public class JSONPojoConvertorFactoryTest +{ + @Test public void testFoo() { JSON jsonOut = new JSON(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java index 3f193ba280..4fdd24cbda 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java @@ -13,15 +13,20 @@ package org.eclipse.jetty.util.ajax; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + + /** * Test to converts POJOs to JSON and vice versa. - * - * - * */ -public class JSONPojoConvertorTest extends TestCase +public class JSONPojoConvertorTest { + @Test public void testFoo() { JSON json = new JSON(); @@ -66,6 +71,7 @@ public class JSONPojoConvertorTest extends TestCase assertEquals(Color.Green,br.getColor()); } + @Test public void testExclude() { JSON json = new JSON(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java index 0b77acc962..851e729fdf 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java @@ -12,6 +12,10 @@ // ======================================================================== package org.eclipse.jetty.util.ajax; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.StringReader; import java.lang.reflect.Array; import java.math.BigDecimal; @@ -21,12 +25,13 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; -import junit.framework.TestCase; - import org.eclipse.jetty.util.DateCache; import org.eclipse.jetty.util.ajax.JSON.Output; +import org.junit.BeforeClass; +import org.junit.Test; + -public class JSONTest extends TestCase +public class JSONTest { String test="\n\n\n\t\t "+ "// ignore this ,a [ \" \n"+ @@ -45,6 +50,17 @@ public class JSONTest extends TestCase "\"undefined\": undefined," + "}"; + /* ------------------------------------------------------------ */ + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + @BeforeClass + public static void setUp() throws Exception + { + JSON.registerConvertor(Gadget.class,new JSONObjectConvertor(false)); + } + + @Test public void testToString() { HashMap map = new HashMap(); @@ -94,26 +110,16 @@ public class JSONTest extends TestCase gadget.setWoggles(new Woggle[]{w0,w1}); s = JSON.toString(new Gadget[]{gadget}); + System.out.println(s); assertTrue(s.startsWith("[")); assertTrue(s.indexOf("\"modulated\":false")>=0); assertTrue(s.indexOf("\"shields\":42")>=0); assertTrue(s.indexOf("\"name\":\"woggle0\"")>=0); assertTrue(s.indexOf("\"name\":\"woggle1\"")>=0); - - } - - - - /* ------------------------------------------------------------ */ - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - protected void setUp() throws Exception - { - JSON.registerConvertor(Gadget.class,new JSONObjectConvertor(false)); } /* ------------------------------------------------------------ */ + @Test public void testParse() { Map map = (Map)JSON.parse(test); @@ -134,6 +140,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testParseReader() throws Exception { Map map = (Map)JSON.parse(new StringReader(test)); @@ -149,6 +156,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testStripComment() { String test="\n\n\n\t\t "+ @@ -171,6 +179,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testQuote() { String test="\"abc123|\\\"|\\\\|\\/|\\b|\\f|\\n|\\r|\\t|\\uaaaa|\""; @@ -180,6 +189,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testBigDecimal() { Object obj = JSON.parse("1.0E7"); @@ -189,6 +199,16 @@ public class JSONTest extends TestCase obj = Array.get(JSON.parse(string),0); assertTrue(obj instanceof Double); } + + + /* ------------------------------------------------------------ */ + @Test + public void testZeroByte() + { + String withzero="\u0000"; + String json = JSON.toString(withzero); + System.err.println(json); + } /* ------------------------------------------------------------ */ public static class Gadget @@ -247,6 +267,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testConvertor() { // test case#1 - force timezone to GMT @@ -316,6 +337,7 @@ public class JSONTest extends TestCase enum Color { Red, Green, Blue }; + @Test public void testEnumConvertor() { JSON json = new JSON(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java index 528c9241d3..9bc149c1f5 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java @@ -13,34 +13,20 @@ package org.eclipse.jetty.util.component; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; -import junit.textui.TestRunner; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.StdErrLog; +import org.junit.Test; -public class LifeCycleListenerTest extends TestCase + +public class LifeCycleListenerTest { static Exception cause = new Exception("expected test exception"); - public LifeCycleListenerTest(String name) - { - super(name); - } - - public static void main(String[] args) - { - TestRunner.run(suite()); - } - - public static Test suite() - { - TestSuite suite = new TestSuite(LifeCycleListenerTest.class); - return suite; - } - + @Test public void testStart() throws Exception { TestLifeCycle lifecycle = new TestLifeCycle(); @@ -78,6 +64,7 @@ public class LifeCycleListenerTest extends TestCase assertTrue("The lifecycle state is not started",lifecycle.isStarted()); } + @Test public void testStop() throws Exception { TestLifeCycle lifecycle = new TestLifeCycle(); @@ -126,6 +113,7 @@ public class LifeCycleListenerTest extends TestCase } + @Test public void testRemoveLifecycleListener () throws Exception { @@ -178,7 +166,7 @@ public class LifeCycleListenerTest extends TestCase - private class TestListener implements LifeCycle.Listener + private class TestListener extends AbstractLifeCycle.AbstractLifeCycleListener { private boolean failure = false; diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/log/LogTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/log/LogTest.java index a200721ffb..957eaee595 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/log/LogTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/log/LogTest.java @@ -13,26 +13,31 @@ package org.eclipse.jetty.util.log; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import junit.framework.TestCase; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + -public class LogTest extends TestCase +public class LogTest { - PrintStream _orig= System.err; - ByteArrayOutputStream _out = new ByteArrayOutputStream(); - PrintStream _pout = new PrintStream(_out); + static PrintStream _orig= System.err; + static ByteArrayOutputStream _out = new ByteArrayOutputStream(); + static PrintStream _pout = new PrintStream(_out); - @Override - public void setUp() + @BeforeClass + public static void setUp() { System.setErr(_pout); } - @Override - public void tearDown() + @AfterClass + public static void tearDown() { System.setErr(_orig); } @@ -64,6 +69,7 @@ public class LogTest extends TestCase assertTrue(false); } + @Test public void testStdErrLogFormat() { StdErrLog log = new StdErrLog("test"); @@ -90,6 +96,7 @@ public class LogTest extends TestCase logContains("INFO:test:testing"); } + @Test public void testStdErrLogDebug() { StdErrLog log = new StdErrLog("xxx"); @@ -109,6 +116,7 @@ public class LogTest extends TestCase logNotContains("YOU SHOULD NOT SEE THIS!"); } + @Test public void testStdErrLogName() { StdErrLog log = new StdErrLog("test"); @@ -119,6 +127,7 @@ public class LogTest extends TestCase } + @Test public void testStdErrThrowable() { Throwable th = new Throwable("Message"); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/log/StdErrLogTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/log/StdErrLogTest.java index bdda51facd..2a0ffcf005 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/log/StdErrLogTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/log/StdErrLogTest.java @@ -4,7 +4,7 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php @@ -18,43 +18,44 @@ import junit.framework.TestCase; /** * @author mgorovoy * */ -public class StdErrLogTest extends TestCase +public class StdErrLogTest extends TestCase { public void testNullValues() { StdErrLog log = new StdErrLog(); log.setDebugEnabled(true); - + log.setHideStacks(true); + try { log.info("Testing info(msg,null,null) - {} {}",null,null); log.info("Testing info(msg,null,null) - {}",null,null); log.info("Testing info(msg,null,null)",null,null); log.info(null,"- Testing","info(null,arg0,arg1)"); log.info(null,null,null); - + log.debug("Testing debug(msg,null,null) - {} {}",null,null); log.debug("Testing debug(msg,null,null) - {}",null,null); log.debug("Testing debug(msg,null,null)",null,null); log.debug(null,"- Testing","debug(null,arg0,arg1)"); log.debug(null,null,null); - - log.debug("Testing debug(msg,null)",null); + + log.debug("Testing debug(msg,null)"); log.debug(null,new Throwable("IGNORE::Testing debug(null,thrw)").fillInStackTrace()); - + log.warn("Testing warn(msg,null,null) - {} {}",null,null); log.warn("Testing warn(msg,null,null) - {}",null,null); log.warn("Testing warn(msg,null,null)",null,null); log.warn(null,"- Testing","warn(msg,arg0,arg1)"); log.warn(null,null,null); - - log.warn("Testing warn(msg,null)",null); + + log.warn("Testing warn(msg,null)"); log.warn(null,new Throwable("IGNORE::Testing warn(msg,thrw)").fillInStackTrace()); } catch (NullPointerException npe) { - assertTrue("NullPointerException in StdErrLog.", false); System.err.println(npe); npe.printStackTrace(); + assertTrue("NullPointerException in StdErrLog.", false); } } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceCollectionTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceCollectionTest.java index 9317e51c39..7bc940bbac 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceCollectionTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceCollectionTest.java @@ -18,10 +18,20 @@ import java.io.File; import java.io.InputStreamReader; import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -public class ResourceCollectionTest extends TestCase +import org.junit.Test; +import org.junit.BeforeClass; +import org.junit.AfterClass; + +public class ResourceCollectionTest { + @Test public void testMutlipleSources1() throws Exception { ResourceCollection rc1 = new ResourceCollection(new String[]{ @@ -47,6 +57,7 @@ public class ResourceCollectionTest extends TestCase System.err.println(s); } + @Test public void testMergedDir() throws Exception { ResourceCollection rc = new ResourceCollection(new String[]{ @@ -63,6 +74,7 @@ public class ResourceCollectionTest extends TestCase assertEquals("3 - three", getContent(rc, "3.txt")); } + @Test public void testCopyTo() throws Exception { ResourceCollection rc = new ResourceCollection(new String[]{ diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java index 19f505efc4..6eadcb76c4 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java @@ -13,6 +13,10 @@ package org.eclipse.jetty.util.resource; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FilePermission; @@ -24,8 +28,11 @@ import java.util.jar.JarInputStream; import junit.framework.TestSuite; import org.eclipse.jetty.util.IO; +import org.junit.BeforeClass; +import org.junit.Test; -public class ResourceTest extends junit.framework.TestCase + +public class ResourceTest { public static String __userDir = System.getProperty("basedir", "."); @@ -36,7 +43,7 @@ public class ResourceTest extends junit.framework.TestCase private static final boolean DIR=true; private static final boolean EXISTS=true; - class Data + static class Data { Resource resource; String test; @@ -93,27 +100,10 @@ public class ResourceTest extends junit.framework.TestCase } public static Data[] data; - - public ResourceTest(String name) - { - super(name); - } - - /* ------------------------------------------------------------ */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - - /* ------------------------------------------------------------ */ - public static junit.framework.Test suite() - { - return new TestSuite(ResourceTest.class); - } /* ------------------------------------------------------------ */ - @Override - protected void setUp() + @BeforeClass + public static void setUp() throws Exception { if (data!=null) @@ -189,16 +179,8 @@ public class ResourceTest extends junit.framework.TestCase } - - /* ------------------------------------------------------------ */ - @Override - protected void tearDown() - throws Exception - { - } - - /* ------------------------------------------------------------ */ + @Test public void testResourceExists() { for (int i=0;i<data.length;i++) @@ -211,6 +193,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testResourceDir() { for (int i=0;i<data.length;i++) @@ -223,6 +206,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testResourceContent() throws Exception { @@ -238,6 +222,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testEncoding() throws Exception { Resource r =Resource.newResource("/tmp/a file with,spe#ials/"); @@ -246,6 +231,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testJarFile() throws Exception { @@ -256,9 +242,9 @@ public class ResourceTest extends junit.framework.TestCase JarInputStream jin = new JarInputStream(is); assertNotNull(is); assertNotNull(jin); - } + @Test public void testJarFileIsContainedIn () throws Exception { @@ -276,6 +262,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testJarFileCopyToDirectoryTraversal () throws Exception { String s = "jar:"+__userURL+"TestData/extract.zip!/"; @@ -333,6 +320,7 @@ public class ResourceTest extends junit.framework.TestCase /** * Test a class path resource for existence. */ + @Test public void testClassPathResourceClassRelative() { final String classPathName="Resource.class"; @@ -351,6 +339,7 @@ public class ResourceTest extends junit.framework.TestCase /** * Test a class path resource for existence. */ + @Test public void testClassPathResourceClassAbsolute() { final String classPathName="/org/eclipse/jetty/util/resource/Resource.class"; @@ -369,6 +358,7 @@ public class ResourceTest extends junit.framework.TestCase /** * Test a class path resource for directories. */ + @Test public void testClassPathResourceDirectory() throws Exception { final String classPathName="/"; @@ -390,6 +380,7 @@ public class ResourceTest extends junit.framework.TestCase /** * Test a class path resource for a file. */ + @Test public void testClassPathResourceFile() throws Exception { final String fileName="resource.txt"; diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/SampleStatisticTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/SampleStatisticTest.java index 3031aefcb8..14be1dd65f 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/SampleStatisticTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/SampleStatisticTest.java @@ -1,12 +1,13 @@ package org.eclipse.jetty.util.statistic; -import org.eclipse.jetty.util.statistic.SampleStatistic; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -import junit.framework.TestCase; +import org.junit.Test; /* ------------------------------------------------------------ */ -public class SampleStatisticTest extends TestCase +public class SampleStatisticTest { private static long[][] data = { @@ -26,6 +27,7 @@ public class SampleStatisticTest extends TestCase }; + @Test public void testData() throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java index a8910eb342..59cd536b9f 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java @@ -11,14 +11,17 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== - package org.eclipse.jetty.util.thread; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.util.concurrent.atomic.AtomicInteger; -import junit.framework.TestCase; +import org.junit.Test; + -public class QueuedThreadPoolTest extends TestCase +public class QueuedThreadPoolTest { final AtomicInteger _jobs=new AtomicInteger(); volatile long _sleep=100; @@ -44,6 +47,7 @@ public class QueuedThreadPoolTest extends TestCase + @Test public void testThreadPool() throws Exception { _sleep=100; @@ -129,6 +133,7 @@ public class QueuedThreadPoolTest extends TestCase tp.stop(); } + @Test public void testShrink() throws Exception { Runnable job = new Runnable() @@ -184,6 +189,7 @@ public class QueuedThreadPoolTest extends TestCase } + @Test public void testMaxStopTime() throws Exception { _sleep=100; diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java index 11eccd5b15..ceca63281b 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java @@ -13,11 +13,15 @@ package org.eclipse.jetty.util.thread; +import static org.junit.Assert.assertEquals; + import java.util.concurrent.atomic.AtomicIntegerArray; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; + -public class TimeoutTest extends TestCase +public class TimeoutTest { private boolean _stress=Boolean.getBoolean("STRESS"); @@ -29,11 +33,9 @@ public class TimeoutTest extends TestCase /* * @see junit.framework.TestCase#setUp() */ - @Override - protected void setUp() throws Exception + @Before + public void setUp() throws Exception { - super.setUp(); - timeout=new Timeout(lock); tasks= new Timeout.Task[10]; @@ -47,17 +49,7 @@ public class TimeoutTest extends TestCase } /* ------------------------------------------------------------ */ - /* - * @see junit.framework.TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - } - - - /* ------------------------------------------------------------ */ + @Test public void testExpiry() { timeout.setDuration(200); @@ -71,6 +63,7 @@ public class TimeoutTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testCancel() { timeout.setDuration(200); @@ -89,6 +82,7 @@ public class TimeoutTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testTouch() { timeout.setDuration(200); @@ -112,6 +106,7 @@ public class TimeoutTest extends TestCase /* ------------------------------------------------------------ */ + @Test public void testDelay() { Timeout.Task task = new Timeout.Task(); @@ -134,6 +129,7 @@ public class TimeoutTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testStress() throws Exception { if ( !_stress ) diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index cde62c1de1..1ae874368b 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -13,32 +13,22 @@ </properties> <build> <resources> - <resource><directory>src/main/resources</directory></resource> - <resource><directory>target/generated-resources</directory></resource> + <resource> + <directory>src/main/resources</directory> + </resource> + <resource> + <directory>src/main/config/etc</directory> + <targetPath>org/eclipse/jetty/webapp</targetPath> + <filtering>false</filtering> + <includes> + <include>webdefault.xml</include> + </includes> + </resource> </resources> <plugins> <plugin> - <artifactId>maven-antrun-plugin</artifactId> - <executions> - <execution> - <phase>generate-resources</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <tasks> - <copy failonerror="true" file="${basedir}/src/main/config/etc/webdefault.xml" toFile="${project.build.directory}/generated-resources/org/eclipse/jetty/webapp/webdefault.xml" /> - </tasks> - </configuration> - </execution> - </executions> - </plugin> - - <plugin> - <groupId>org.apache.maven.plugins - </groupId> - <artifactId>maven-assembly-plugin - </artifactId> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <phase>package</phase> @@ -71,8 +61,7 @@ <!-- Required for OSGI --> - <groupId>org.apache.maven.plugins - </groupId> + <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> @@ -82,10 +71,12 @@ </archive> </configuration> </plugin> - <!-- always include sources since jetty-xbean makes use of them --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.webapp.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> @@ -98,12 +89,13 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-servlet</artifactId> - <version>${project.version}</version> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + <version>${project.version}</version> </dependency> </dependencies> </project> diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java new file mode 100644 index 0000000000..a7c2185fb6 --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java @@ -0,0 +1,262 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + + +package org.eclipse.jetty.webapp; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.StringTokenizer; + + +/* ------------------------------------------------------------ */ +/** + * ClasspathPattern performs sequential pattern matching of a class name + * against an internal array of classpath pattern entries. + * + * When an entry starts with '-' (minus), reverse matching is performed. + * When an entry ends with '.' (period), prefix matching is performed. + * + * When class is initialized from a classpath pattern string, entries + * in this string should be separated by ':' (semicolon) or ',' (comma). + */ + +public class ClasspathPattern +{ + private class Entry + { + public String classpath = null; + public boolean result = false; + public boolean partial = false; + } + + private ArrayList<String> _patterns = null; + private ArrayList<Entry> _entries = null; + + public ClasspathPattern(String[] patterns) + { + setPatterns(patterns); + } + + public ClasspathPattern(String pattern) + { + setPattern(pattern); + } + + /* ------------------------------------------------------------ */ + /** + * Create a new instance from a String array of classpath patterns + * + * @param patterns array of classpath patterns + * @return new instance + */ + public static ClasspathPattern fromArray(String[] patterns) + { + return new ClasspathPattern(patterns); + } + + /* ------------------------------------------------------------ */ + /** + * Create a new instance from a classpath pattern sring + * + * @param patterns classpath pattern string + * @return new instance + */ + public static ClasspathPattern fromString(String patterns) + { + return new ClasspathPattern(patterns); + } + + /* ------------------------------------------------------------ */ + /** + * Initialize the matcher by parsing each classpath pattern in an array + * + * @param patterns array of classpath patterns + */ + private void setPatterns(String[] patterns) + { + if (patterns == null) + { + _patterns = null; + _entries = null; + } + else + { + _patterns = new ArrayList<String>(); + _entries = new ArrayList<Entry>(); + } + + if (_patterns != null) { + Entry entry = null; + for (String pattern : patterns) + { + entry = createEntry(pattern); + if (entry != null) { + _patterns.add(pattern); + _entries.add(entry); + } + } + } + } + + /* ------------------------------------------------------------ */ + /** + * Initialize the matcher by parsing each classpath pattern in an array + * + * @param patterns array of classpath patterns + */ + private void addPatterns(String[] patterns) + { + if (patterns != null) + { + if (_patterns == null) + { + setPatterns(patterns); + } + else + { + Entry entry = null; + for (String pattern : patterns) + { + entry = createEntry(pattern); + if (entry != null) { + _patterns.add(pattern); + _entries.add(entry); + } + } + } + } + } + + /* ------------------------------------------------------------ */ + /** + * Create an entry object containing information about + * a single classpath pattern + * + * @param pattern single classpath pattern + * @return corresponding Entry object + */ + private Entry createEntry(String pattern) + { + Entry entry = null; + + if (pattern != null) + { + String item = pattern.trim(); + if (item.length() > 0) + { + entry = new Entry(); + entry.result = !item.startsWith("-"); + entry.partial = item.endsWith("."); + entry.classpath = entry.result ? item : item.substring(1).trim(); + } + } + return entry; + } + + /* ------------------------------------------------------------ */ + /** + * Initialize the matcher by parsing a classpath pattern string + * + * @param pattern classpath pattern string + */ + public void setPattern(String pattern) + { + ArrayList<String> patterns = new ArrayList<String>(); + StringTokenizer entries = new StringTokenizer(pattern, ":,"); + while (entries.hasMoreTokens()) + { + patterns.add(entries.nextToken()); + } + + setPatterns((String[])patterns.toArray()); + } + + /* ------------------------------------------------------------ */ + /** + * Parse a classpath pattern string and appending the result + * to the existing configuration. + * + * @param pattern classpath pattern string + */ + public void addPattern(String pattern) + { + ArrayList<String> patterns = new ArrayList<String>(); + StringTokenizer entries = new StringTokenizer(pattern, ":,"); + while (entries.hasMoreTokens()) + { + patterns.add(entries.nextToken()); + } + + addPatterns((String[])patterns.toArray()); + } + + /* ------------------------------------------------------------ */ + /** + * @return array of classpath patterns + */ + public String[] getPatterns() + { + String[] patterns = null; + + if (_patterns!=null) + { + patterns = _patterns.toArray(new String[_patterns.size()]); + } + + return patterns; + } + + /* ------------------------------------------------------------ */ + /** + * Match the class name against the pattern + * + * @param name name of the class to match + * @return true if class matches the pattern + */ + public boolean match(String name) + { + boolean result=false; + + if (_entries != null) + { + int startIdx = 0; + name = name.replace('/','.'); + name = name.replaceFirst("^[.]+",""); + + for (Entry entry : _entries) + { + if (entry != null) + { + if (entry.partial) + { + if (name.startsWith(entry.classpath)) + { + result = entry.result; + break; + } + } + else + { + if (name.equals(entry.classpath)) + { + result = entry.result; + break; + } + } + } + } + } + return result; + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DefaultsDescriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DefaultsDescriptor.java index 70c9a51ccd..e7331f6972 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DefaultsDescriptor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DefaultsDescriptor.java @@ -22,7 +22,7 @@ import org.eclipse.jetty.util.resource.Resource; */ public class DefaultsDescriptor extends Descriptor { - public DefaultsDescriptor(Resource xml, WebXmlProcessor processor) + public DefaultsDescriptor(Resource xml, MetaData processor) { super(xml, processor); } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java index 8e3458589a..e6aca3c819 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java @@ -23,8 +23,6 @@ import javax.servlet.Servlet; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.webapp.WebXmlProcessor.AbsoluteOrdering; -import org.eclipse.jetty.webapp.WebXmlProcessor.Ordering; import org.eclipse.jetty.xml.XmlParser; @@ -35,37 +33,121 @@ import org.eclipse.jetty.xml.XmlParser; * A web descriptor (web.xml/web-defaults.xml/web-overrides.xml). */ public class Descriptor -{ +{ + protected static XmlParser _parser; public enum MetaDataComplete {NotSet, True, False}; protected Resource _xml; protected XmlParser.Node _root; protected MetaDataComplete _metaDataComplete; protected int _majorVersion = 3; //default to container version protected int _minorVersion = 0; - protected ArrayList<String> _classNames; + protected ArrayList<String> _classNames = new ArrayList<String>(); protected boolean _distributable; protected boolean _validating; - protected WebXmlProcessor _processor; + protected MetaData _metaData; protected boolean _isOrdered = false; protected List<String> _ordering = new ArrayList<String>(); + + public static XmlParser newParser() + throws ClassNotFoundException + { + XmlParser xmlParser=new XmlParser(); + //set up cache of DTDs and schemas locally + URL dtd22=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_2.dtd",true); + URL dtd23=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_3.dtd",true); + URL j2ee14xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_1_4.xsd",true); + URL webapp24xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_4.xsd",true); + URL webapp25xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_5.xsd",true); + URL webapp30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_3_0.xsd",true); + URL webcommon30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-common_3_0.xsd",true); + URL webfragment30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-fragment_3_0.xsd",true); + URL schemadtd=Loader.getResource(Servlet.class,"javax/servlet/resources/XMLSchema.dtd",true); + URL xmlxsd=Loader.getResource(Servlet.class,"javax/servlet/resources/xml.xsd",true); + URL webservice11xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_web_services_client_1_1.xsd",true); + URL webservice12xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/javaee_web_services_client_1_2.xsd",true); + URL datatypesdtd=Loader.getResource(Servlet.class,"javax/servlet/resources/datatypes.dtd",true); + + URL jsp20xsd = null; + URL jsp21xsd = null; + + try + { + Class jsp_page = Loader.loadClass(WebXmlConfiguration.class, "javax.servlet.jsp.JspPage"); + jsp20xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_0.xsd"); + jsp21xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_1.xsd"); + } + catch (Exception e) + { + Log.ignore(e); + } + finally + { + if (jsp20xsd == null) jsp20xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_0.xsd", true); + if (jsp21xsd == null) jsp21xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_1.xsd", true); + } + + redirect(xmlParser,"web-app_2_2.dtd",dtd22); + redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22); + redirect(xmlParser,"web.dtd",dtd23); + redirect(xmlParser,"web-app_2_3.dtd",dtd23); + redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23); + redirect(xmlParser,"XMLSchema.dtd",schemadtd); + redirect(xmlParser,"http://www.w3.org/2001/XMLSchema.dtd",schemadtd); + redirect(xmlParser,"-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd); + redirect(xmlParser,"jsp_2_0.xsd",jsp20xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd); + redirect(xmlParser,"j2ee_1_4.xsd",j2ee14xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd); + redirect(xmlParser,"web-app_2_4.xsd",webapp24xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd); + redirect(xmlParser,"web-app_2_5.xsd",webapp25xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd); + redirect(xmlParser,"web-app_3_0.xsd",webapp30xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd",webapp30xsd); + redirect(xmlParser,"web-common_3_0.xsd",webcommon30xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd",webcommon30xsd); + redirect(xmlParser,"web-fragment_3_0.xsd",webfragment30xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd",webfragment30xsd); + redirect(xmlParser,"xml.xsd",xmlxsd); + redirect(xmlParser,"http://www.w3.org/2001/xml.xsd",xmlxsd); + redirect(xmlParser,"datatypes.dtd",datatypesdtd); + redirect(xmlParser,"http://www.w3.org/2001/datatypes.dtd",datatypesdtd); + redirect(xmlParser,"j2ee_web_services_client_1_1.xsd",webservice11xsd); + redirect(xmlParser,"http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",webservice11xsd); + redirect(xmlParser,"javaee_web_services_client_1_2.xsd",webservice12xsd); + redirect(xmlParser,"http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",webservice12xsd); + return xmlParser; + } + - public Descriptor (Resource xml, WebXmlProcessor processor) + protected static void redirect(XmlParser parser, String resource, URL source) + { + if (source != null) parser.redirectEntity(resource, source); + } + + + + public Descriptor (Resource xml, MetaData md) { _xml = xml; - _processor = processor; + _metaData = md; } public void parse () throws Exception { + if (_parser == null) + _parser = newParser(); + if (_root == null) { //boolean oldValidating = _processor.getParser().getValidating(); //_processor.getParser().setValidating(_validating); - _root = _processor.getParser().parse(_xml.getURL().toString()); + _root = _parser.parse(_xml.getURL().toString()); processVersion(); processOrdering(); //_processor.getParser().setValidating(oldValidating); @@ -98,6 +180,11 @@ public class Descriptor return _xml; } + public MetaData getMetaData() + { + return _metaData; + } + public void processVersion () { String version = _root.getAttribute("version", "DTD"); @@ -105,7 +192,7 @@ public class Descriptor { _majorVersion = 2; _minorVersion = 3; - String dtd = _processor.getParser().getDTD(); + String dtd = _parser.getDTD(); if (dtd != null && dtd.indexOf("web-app_2_2") >= 0) { _majorVersion = 2; @@ -141,7 +228,7 @@ public class Descriptor //Process the web.xml's optional <absolute-ordering> element XmlParser.Node ordering = _root.get("absolute-ordering"); if (ordering == null) - return; // could be a RelativeOrdering if we find any <ordering> clauses in web-fragments + return; _isOrdered = true; //If an absolute-ordering was already set, then ignore it in favour of this new one @@ -163,37 +250,11 @@ public class Descriptor _ordering.add(node.toString(false,true)); } } - - public void processClassNames () + + public void addClassName (String className) { - _classNames = new ArrayList<String>(); - Iterator iter = _root.iterator(); - - while (iter.hasNext()) - { - Object o = iter.next(); - if (!(o instanceof XmlParser.Node)) continue; - XmlParser.Node node = (XmlParser.Node) o; - String name = node.getTag(); - if ("servlet".equals(name)) - { - String className = node.getString("servlet-class", false, true); - if (className != null) - _classNames.add(className); - } - else if ("filter".equals(name)) - { - String className = node.getString("filter-class", false, true); - if (className != null) - _classNames.add(className); - } - else if ("listener".equals(name)) - { - String className = node.getString("listener-class", false, true); - if (className != null) - _classNames.add(className); - } - } + if (!_classNames.contains(className)) + _classNames.add(className); } public ArrayList<String> getClassNames () diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java new file mode 100644 index 0000000000..2e1a1535b1 --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java @@ -0,0 +1,68 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.log.Log; + +/** + * DiscoveredAnnotation + * + * Represents an annotation that has been discovered + * by scanning source code of WEB-INF/classes and WEB-INF/lib jars. + * + */ +public abstract class DiscoveredAnnotation +{ + protected WebAppContext _context; + protected String _className; + protected Class _clazz; + + public abstract void apply(); + + public DiscoveredAnnotation (WebAppContext context, String className) + { + _context = context; + _className = className; + } + + + public Class getTargetClass() + { + if (_clazz != null) + return _clazz; + + loadClass(); + + return _clazz; + } + + private void loadClass () + { + if (_clazz != null) + return; + + if (_className == null) + return; + + try + { + _clazz = Loader.loadClass(null, _className); + } + catch (Exception e) + { + Log.warn(e); + } + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java index 8a2781d6ef..4828738c94 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java @@ -21,7 +21,7 @@ import org.eclipse.jetty.util.resource.Resource; /** * FragmentConfiguration * - * This configuration supports some Servlet 3.0 features in jetty-7. + * * * Process web-fragments in jars */ @@ -33,16 +33,13 @@ public class FragmentConfiguration implements Configuration { if (!context.isConfigurationDiscovered()) return; - - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (processor == null) - { - processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); - } - - //parse web-fragment.xmls - parseWebFragments(context, processor); + + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException("No metadata"); + + //find all web-fragment.xmls + findWebFragments(context, metaData); } @@ -51,18 +48,12 @@ public class FragmentConfiguration implements Configuration if (!context.isConfigurationDiscovered()) return; - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (processor == null) - { - processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); - } + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException("No metadata"); - //order the fragments first - processor.orderFragments(); - - //process the fragments - processor.processFragments(); + //order the fragments + metaData.orderFragments(); } public void deconfigure(WebAppContext context) throws Exception @@ -77,18 +68,18 @@ public class FragmentConfiguration implements Configuration /* ------------------------------------------------------------------------------- */ /** - * Look for any web.xml fragments in META-INF of jars in WEB-INF/lib + * Look for any web-fragment.xml fragments in META-INF of jars in WEB-INF/lib * * @throws Exception */ - public void parseWebFragments (final WebAppContext context, final WebXmlProcessor processor) throws Exception + public void findWebFragments (final WebAppContext context, final MetaData metaData) throws Exception { List<Resource> frags = (List<Resource>)context.getAttribute(FRAGMENT_RESOURCES); if (frags!=null) { for (Resource frag : frags) { - processor.parseFragment(Resource.newResource("jar:"+frag.getURL()+"!/META-INF/web-fragment.xml")); + metaData.addFragment(frag, Resource.newResource("jar:"+frag.getURL()+"!/META-INF/web-fragment.xml")); } } } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Fragment.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java index fafb28a5e3..75c36de57a 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Fragment.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java @@ -27,13 +27,12 @@ import org.eclipse.jetty.xml.XmlParser; * * A web-fragment.xml descriptor. */ -public class Fragment extends Descriptor +public class FragmentDescriptor extends Descriptor { public static final String NAMELESS = "@@-NAMELESS-@@"; //prefix for nameless Fragments public enum OtherType {None, Before, After}; protected int _counter = 0; - protected boolean _hasOther = false; protected OtherType _otherType = OtherType.None; @@ -42,7 +41,7 @@ public class Fragment extends Descriptor protected String _name; - public Fragment (Resource xml, WebXmlProcessor processor) + public FragmentDescriptor (Resource xml, MetaData processor) throws Exception { super (xml, processor); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java index d90ff804f5..fd1507649e 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java @@ -31,8 +31,8 @@ public abstract class IterativeDescriptorProcessor implements DescriptorProcesso { public static final Class[] __signature = new Class[]{Descriptor.class, XmlParser.Node.class}; protected Map<String, Method> _visitors = new HashMap<String, Method>(); - public abstract void start(); - public abstract void end(); + public abstract void start(Descriptor descriptor); + public abstract void end(Descriptor descriptor); /** * Register a method to be called back when visiting the node with the given name. @@ -56,7 +56,7 @@ public abstract class IterativeDescriptorProcessor implements DescriptorProcesso if (descriptor == null) return; - start(); + start(descriptor); XmlParser.Node root = descriptor.getRoot(); Iterator iter = root.iterator(); @@ -69,7 +69,7 @@ public abstract class IterativeDescriptorProcessor implements DescriptorProcesso visit(descriptor, node); } - end(); + end(descriptor); } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java index c51c50a87f..02fde5d614 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java @@ -65,7 +65,7 @@ public abstract class JarScanner extends org.eclipse.jetty.util.PatternMatcher * all those starting with "aaa-" first, then "bbb-". * * @param pattern - * @param loader + * @param uris * @param isNullInclusive if true, an empty pattern means all names match, if false, none match * @throws Exception */ diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java index 1fe03ff4da..05c6c5cd24 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java @@ -13,6 +13,9 @@ package org.eclipse.jetty.webapp; +import java.util.HashMap; +import java.util.Map; + import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.xml.XmlConfiguration; @@ -29,6 +32,11 @@ import org.eclipse.jetty.xml.XmlConfiguration; */ public class JettyWebXmlConfiguration implements Configuration { + /** The value of this property points to the WEB-INF directory of + * the web-app currently installed. + * it is passed as a property to the jetty-web.xml file */ + public static final String PROPERTY_THIS_WEB_INF_URL = "this.web-inf.url"; + public void preConfigure(WebAppContext context) throws Exception { // TODO Auto-generated method stub @@ -74,6 +82,7 @@ public class JettyWebXmlConfiguration implements Configuration if(Log.isDebugEnabled()) Log.debug("Configure: "+jetty); XmlConfiguration jetty_config=new XmlConfiguration(jetty.getURL()); + setupXmlConfiguration(jetty_config, web_inf); jetty_config.configure(context); } finally @@ -85,6 +94,22 @@ public class JettyWebXmlConfiguration implements Configuration } } + /** + * Configures some well-known properties before the XmlConfiguration reads + * the configuration. + * @param jetty_config The configuration object. + */ + private void setupXmlConfiguration(XmlConfiguration jetty_config, Resource web_inf) + { + Map<Object,Object> props = jetty_config.getProperties(); + if (props == null) + { + props = new HashMap<Object, Object>(); + jetty_config.setProperties(props); + } + props.put(PROPERTY_THIS_WEB_INF_URL, web_inf.getURL()); + } + public void postConfigure(WebAppContext context) throws Exception { diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java new file mode 100644 index 0000000000..07b306e63b --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java @@ -0,0 +1,911 @@ +// ======================================================================== +// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.eclipse.jetty.util.resource.Resource; + + + + + +/** + * MetaData + * + * + */ +public class MetaData +{ + public static final String METADATA = "org.eclipse.jetty.metaData"; + public static final String METADATA_COMPLETE = "org.eclipse.jetty.metadataComplete"; + public static final String WEBXML_MAJOR_VERSION = "org.eclipse.jetty.webXmlMajorVersion"; + public static final String WEBXML_MINOR_VERSION = "org.eclipse.jetty.webXmlMinorVersion"; + public static final String WEBXML_CLASSNAMES = "org.eclipse.jetty.webXmlClassNames"; + + public enum Origin {NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation}; + + protected WebAppContext _context; + protected Map<String, OriginInfo> _origins = new HashMap<String,OriginInfo>(); + protected Descriptor _webDefaultsRoot; + protected Descriptor _webXmlRoot; + protected Descriptor _webOverrideRoot; + protected List<DiscoveredAnnotation> _annotations = new ArrayList<DiscoveredAnnotation>(); + protected List<DescriptorProcessor> _descriptorProcessors = new ArrayList<DescriptorProcessor>(); + protected List<FragmentDescriptor> _webFragmentRoots = new ArrayList<FragmentDescriptor>(); + protected Map<String,FragmentDescriptor> _webFragmentNameMap = new HashMap<String,FragmentDescriptor>(); + protected Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<Resource, FragmentDescriptor>(); + protected Map<Resource, List<DiscoveredAnnotation>> _webFragmentAnnotations = new HashMap<Resource, List<DiscoveredAnnotation>>(); + protected List<Resource> _orderedResources; + protected Ordering _ordering;//can be set to RelativeOrdering by web-default.xml, web.xml, web-override.xml + protected StandardDescriptorProcessor _standardDescriptorProcessor; + + + public static class OriginInfo + { + protected String name; + protected Origin origin; + protected Descriptor descriptor; + + public OriginInfo (String n, Descriptor d) + { + name = n; + descriptor = d; + if (d == null) + throw new IllegalArgumentException("No descriptor"); + if (d instanceof FragmentDescriptor) + origin = Origin.WebFragment; + if (d instanceof OverrideDescriptor) + origin = Origin.WebOverride; + if (d instanceof DefaultsDescriptor) + origin = Origin.WebDefaults; + origin = Origin.WebXml; + } + + public OriginInfo (String n) + { + name = n; + origin = Origin.Annotation; + } + + public OriginInfo(String n, Origin o) + { + name = n; + origin = o; + } + + public String getName() + { + return name; + } + + public Origin getOriginType() + { + return origin; + } + + public Descriptor getDescriptor() + { + return descriptor; + } + } + + /** + * Ordering + * + * + */ + public interface Ordering + { + public List<Resource> order(List<Resource> fragments); + public boolean isAbsolute (); + public boolean hasOther(); + } + + /** + * AbsoluteOrdering + * + * An <absolute-order> element in web.xml + */ + public class AbsoluteOrdering implements Ordering + { + public static final String OTHER = "@@-OTHER-@@"; + protected List<String> _order = new ArrayList<String>(); + protected boolean _hasOther = false; + + /** + * Order the list of jars in WEB-INF/lib according to the ordering declarations in the descriptors + * @see org.eclipse.jetty.webapp.MetaData.Ordering#order(java.util.List) + */ + public List<Resource> order(List<Resource> jars) + { + List<Resource> orderedList = new ArrayList<Resource>(); + List<Resource> tmp = new ArrayList<Resource>(jars); + + //1. put everything into the list of named others, and take the named ones out of there, + //assuming we will want to use the <other> clause + Map<String,FragmentDescriptor> others = new HashMap(getNamedFragments()); + + //2. for each name, take out of the list of others, add to tail of list + int index = -1; + for (String item:_order) + { + if (!item.equals(OTHER)) + { + FragmentDescriptor f = others.remove(item); + if (f != null) + { + Resource jar = getJarForFragment(item); + orderedList.add(jar); //take from others and put into final list in order, ignoring duplicate names + //remove resource from list for resource matching name of descriptor + tmp.remove(jar); + } + } + else + index = orderedList.size(); //remember the index at which we want to add in all the others + } + + //3. if <other> was specified, insert rest of the fragments + if (_hasOther) + { + orderedList.addAll((index < 0? 0: index), tmp); + } + + return orderedList; + } + + public boolean isAbsolute() + { + return true; + } + + public void add (String name) + { + _order.add(name); + } + + public void addOthers () + { + if (_hasOther) + throw new IllegalStateException ("Duplicate <other> element in absolute ordering"); + + _hasOther = true; + _order.add(OTHER); + } + + public boolean hasOther () + { + return _hasOther; + } + } + + + /** + * RelativeOrdering + * + * A set of <order> elements in web-fragment.xmls. + */ + public class RelativeOrdering implements Ordering + { + protected LinkedList<Resource> _beforeOthers = new LinkedList<Resource>(); + protected LinkedList<Resource> _afterOthers = new LinkedList<Resource>(); + protected LinkedList<Resource> _noOthers = new LinkedList<Resource>(); + + /** + * Order the list of jars according to the ordering declared + * in the various web-fragment.xml files. + * @see org.eclipse.jetty.webapp.MetaData.Ordering#order(java.util.List) + */ + public List<Resource> order(List<Resource> jars) + { + //for each jar, put it into the ordering according to the fragment ordering + for (Resource jar:jars) + { + //check if the jar has a fragment descriptor + FragmentDescriptor descriptor = _webFragmentResourceMap.get(jar); + if (descriptor != null) + { + switch (descriptor.getOtherType()) + { + case None: + { + ((RelativeOrdering)_ordering).addNoOthers(jar); + break; + } + case Before: + { + ((RelativeOrdering)_ordering).addBeforeOthers(jar); + break; + } + case After: + { + ((RelativeOrdering)_ordering).addAfterOthers(jar); + break; + } + } + } + else + { + //jar fragment has no descriptor, but there is a relative ordering in place, so it must be part of the others + ((RelativeOrdering)_ordering).addNoOthers(jar); + } + } + + //now apply the ordering + List<Resource> orderedList = new ArrayList<Resource>(); + int maxIterations = 2; + boolean done = false; + do + { + //1. order the before-others according to any explicit before/after relationships + boolean changesBefore = orderList(_beforeOthers); + + //2. order the after-others according to any explicit before/after relationships + boolean changesAfter = orderList(_afterOthers); + + //3. order the no-others according to their explicit before/after relationships + boolean changesNone = orderList(_noOthers); + + //we're finished on a clean pass through with no ordering changes + done = (!changesBefore && !changesAfter && !changesNone); + } + while (!done && (--maxIterations >0)); + + //4. merge before-others + no-others +after-others + if (!done) + throw new IllegalStateException("Circular references for fragments"); + + for (Resource r: _beforeOthers) + orderedList.add(r); + for (Resource r: _noOthers) + orderedList.add(r); + for(Resource r: _afterOthers) + orderedList.add(r); + + return orderedList; + } + + public boolean isAbsolute () + { + return false; + } + + public boolean hasOther () + { + return !_beforeOthers.isEmpty() || !_afterOthers.isEmpty(); + } + + public void addBeforeOthers (Resource r) + { + _beforeOthers.addLast(r); + } + + public void addAfterOthers (Resource r) + { + _afterOthers.addLast(r); + } + + public void addNoOthers (Resource r) + { + _noOthers.addLast(r); + } + + protected boolean orderList (LinkedList<Resource> list) + { + //Take a copy of the list so we can iterate over it and at the same time do random insertions + boolean changes = false; + List<Resource> iterable = new ArrayList(list); + Iterator<Resource> itor = iterable.iterator(); + + while (itor.hasNext()) + { + Resource r = itor.next(); + FragmentDescriptor f = getFragment(r); + if (f == null) + { + //no fragment for this resource so cannot have any ordering directives + continue; + } + + //Handle any explicit <before> relationships for the fragment we're considering + List<String> befores = f.getBefores(); + if (befores != null && !befores.isEmpty()) + { + for (String b: befores) + { + //Fragment we're considering must be before b + //Check that we are already before it, if not, move us so that we are. + //If the name does not exist in our list, then get it out of the no-other list + if (!isBefore(list, f.getName(), b)) + { + //b is not already before name, move it so that it is + int idx1 = getIndexOf(list, f.getName()); + int idx2 = getIndexOf(list, b); + + //if b is not in the same list + if (idx2 < 0) + { + changes = true; + // must be in the noOthers list or it would have been an error + Resource bResource = getJarForFragment(b); + if (bResource != null) + { + //If its in the no-others list, insert into this list so that we are before it + if (_noOthers.remove(bResource)) + { + insert(list, idx1+1, b); + + } + } + } + else + { + //b is in the same list but b is before name, so swap it around + list.remove(idx1); + insert(list, idx2, f.getName()); + changes = true; + } + } + } + } + + //Handle any explicit <after> relationships + List<String> afters = f.getAfters(); + if (afters != null && !afters.isEmpty()) + { + for (String a: afters) + { + //Check that fragment we're considering is after a, moving it if possible if its not + if (!isAfter(list, f.getName(), a)) + { + //name is not after a, move it + int idx1 = getIndexOf(list, f.getName()); + int idx2 = getIndexOf(list, a); + + //if a is not in the same list as name + if (idx2 < 0) + { + changes = true; + //take it out of the noOthers list and put it in the right place in this list + Resource aResource = getJarForFragment(a); + if (aResource != null) + { + if (_noOthers.remove(aResource)) + { + insert(list,idx1, aResource); + } + } + } + else + { + //a is in the same list as name, but in the wrong place, so move it + list.remove(idx2); + insert(list,idx1, a); + changes = true; + } + } + //Name we're considering must be after this name + //Check we're already after it, if not, move us so that we are. + //If the name does not exist in our list, then get it out of the no-other list + } + } + } + + return changes; + } + + /** + * Is fragment with name a before fragment with name b? + * @param list + * @param fragNameA + * @param fragNameB + * @return + */ + protected boolean isBefore (List<Resource> list, String fragNameA, String fragNameB) + { + //check if a and b are already in the same list, and b is already + //before a + int idxa = getIndexOf(list, fragNameA); + int idxb = getIndexOf(list, fragNameB); + + + if (idxb >=0 && idxb < idxa) + { + //a and b are in the same list but a is not before b + return false; + } + + if (idxb < 0) + { + //a and b are not in the same list, but it is still possible that a is before + //b, depending on which list we're examining + if (list == _beforeOthers) + { + //The list we're looking at is the beforeOthers.If b is in the _afterOthers or the _noOthers, then by + //definition a is before it + return true; + } + else if (list == _afterOthers) + { + //The list we're looking at is the afterOthers, then a will be the tail of + //the final list. If b is in the beforeOthers list, then b will be before a and an error. + if (_beforeOthers.contains(fragNameB)) + throw new IllegalStateException("Incorrect relationship: "+fragNameA+" before "+fragNameB); + else + return false; //b could be moved to the list + } + } + + //a and b are in the same list and a is already before b + return true; + } + + + /** + * Is fragment name "a" after fragment name "b"? + * @param list + * @param fragNameA + * @param fragNameB + * @return + */ + protected boolean isAfter(List<Resource> list, String fragNameA, String fragNameB) + { + int idxa = getIndexOf(list, fragNameA); + int idxb = getIndexOf(list, fragNameB); + + if (idxb >=0 && idxa < idxb) + { + //a and b are both in the same list, but a is before b + return false; + } + + if (idxb < 0) + { + //a and b are in different lists. a could still be after b depending on which list it is in. + + if (list == _afterOthers) + { + //The list we're looking at is the afterOthers. If b is in the beforeOthers or noOthers then + //by definition a is after b because a is in the afterOthers list. + return true; + } + else if (list == _beforeOthers) + { + //The list we're looking at is beforeOthers, and contains a and will be before + //everything else in the final ist. If b is in the afterOthers list, then a cannot be before b. + if (_afterOthers.contains(fragNameB)) + throw new IllegalStateException("Incorrect relationship: "+fragNameB+" after "+fragNameA); + else + return false; //b could be moved from noOthers list + } + } + + return true; //a and b in the same list, a is after b + } + + /** + * Insert the resource matching the fragName into the list of resources + * at the location indicated by index. + * + * @param list + * @param index + * @param fragName + */ + protected void insert(List<Resource> list, int index, String fragName) + { + Resource jar = getJarForFragment(fragName); + if (jar == null) + throw new IllegalStateException("No jar for insertion"); + + insert(list, index, jar); + } + + protected void insert(List<Resource> list, int index, Resource resource) + { + if (list == null) + throw new IllegalStateException("List is null for insertion"); + + //add it at the end + if (index > list.size()) + list.add(resource); + else + list.add(index, resource); + } + + protected void remove (List<Resource> resources, Resource r) + { + if (resources == null) + return; + resources.remove(r); + } + + protected int getIndexOf(List<Resource> resources, String fragmentName) + { + FragmentDescriptor fd = getFragment(fragmentName); + if (fd == null) + return -1; + + + Resource r = getJarForFragment(fragmentName); + if (r == null) + return -1; + + return resources.indexOf(r); + } + } + + + + public MetaData (WebAppContext context) throws ClassNotFoundException + { + _context = context; + + } + + public WebAppContext getContext() + { + return _context; + } + + + + public void setDefaults (Resource webDefaults) + throws Exception + { + _webDefaultsRoot = new DefaultsDescriptor(webDefaults, this); + _webDefaultsRoot.parse(); + if (_webDefaultsRoot.isOrdered()) + { + if (_ordering == null) + _ordering = new AbsoluteOrdering(); + + List<String> order = _webDefaultsRoot.getOrdering(); + for (String s:order) + { + if (s.equalsIgnoreCase("others")) + ((AbsoluteOrdering)_ordering).addOthers(); + else + ((AbsoluteOrdering)_ordering).add(s); + } + } + } + + public void setWebXml (Resource webXml) + throws Exception + { + _webXmlRoot = new Descriptor(webXml, this); + _webXmlRoot.parse(); + if (_webXmlRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.True) + _context.setAttribute(METADATA_COMPLETE, Boolean.TRUE); + else + _context.setAttribute(METADATA_COMPLETE, Boolean.FALSE); + _context.getServletContext().setEffectiveMajorVersion(_webXmlRoot.getMajorVersion()); + _context.getServletContext().setEffectiveMinorVersion(_webXmlRoot.getMinorVersion()); + _context.setAttribute(WEBXML_CLASSNAMES, _webXmlRoot.getClassNames()); + + if (_webXmlRoot.isOrdered()) + { + if (_ordering == null) + _ordering = new AbsoluteOrdering(); + + List<String> order = _webXmlRoot.getOrdering(); + for (String s:order) + { + if (s.equalsIgnoreCase("others")) + ((AbsoluteOrdering)_ordering).addOthers(); + else + ((AbsoluteOrdering)_ordering).add(s); + } + } + } + + public void setOverride (Resource override) + throws Exception + { + _webOverrideRoot = new OverrideDescriptor(override, this); + _webOverrideRoot.setValidating(false); + _webOverrideRoot.parse(); + if (_webOverrideRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.True) + _context.setAttribute(METADATA_COMPLETE, Boolean.TRUE); + else if (_webOverrideRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.False) + _context.setAttribute(METADATA_COMPLETE, Boolean.FALSE); + + if (_webOverrideRoot.isOrdered()) + { + if (_ordering == null) + _ordering = new AbsoluteOrdering(); + + List<String> order = _webOverrideRoot.getOrdering(); + for (String s:order) + { + if (s.equalsIgnoreCase("others")) + ((AbsoluteOrdering)_ordering).addOthers(); + else + ((AbsoluteOrdering)_ordering).add(s); + } + } + } + + + /** + * Add a web-fragment.xml + * + * @param jarResource the jar the fragment is contained in + * @param xmlResource the resource representing the xml file + * @throws Exception + */ + public void addFragment (Resource jarResource, Resource xmlResource) + throws Exception + { + Boolean metaComplete = (Boolean)_context.getAttribute(METADATA_COMPLETE); + if (metaComplete != null && metaComplete.booleanValue()) + return; //do not process anything else if web.xml/web-override.xml set metadata-complete + + //Metadata-complete is not set, or there is no web.xml + FragmentDescriptor descriptor = new FragmentDescriptor(xmlResource, this); + _webFragmentResourceMap.put(jarResource, descriptor); + _webFragmentRoots.add(descriptor); + + descriptor.parse(); + + if (descriptor.getName() != null) + _webFragmentNameMap.put(descriptor.getName(), descriptor); + + //If web.xml has specified an absolute ordering, ignore any relative ordering in the fragment + if (_ordering != null && _ordering.isAbsolute()) + return; + + if (_ordering == null && descriptor.isOrdered()) + _ordering = new RelativeOrdering(); + } + + /** + * Annotations not associated with a WEB-INF/lib fragment jar. + * These are from WEB-INF/classes or the ??container path?? + * @param annotations + */ + public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations) + { + _annotations.addAll(annotations); + } + + public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations) + { + _webFragmentAnnotations.put(resource, new ArrayList<DiscoveredAnnotation>(annotations)); + } + + public void addDescriptorProcessor(DescriptorProcessor p) + { + _descriptorProcessors.add(p); + } + + public void orderFragments () + { + //if we have already ordered them don't do it again + if (_orderedResources != null) + return; + + if (_ordering != null) + { + //Get the jars in WEB-INF/lib according to the order specified + _orderedResources = _ordering.order((List<Resource>)_context.getAttribute(WebInfConfiguration.WEB_INF_JAR_RESOURCES)); + + _context.setAttribute(WebInfConfiguration.WEB_INF_ORDERED_JAR_RESOURCES, _orderedResources); + List<String> orderedJars = new ArrayList<String>(); + + for (Resource webInfJar:_orderedResources) + { + //get just the name of the jar file + String fullname = webInfJar.getName(); + int i = fullname.indexOf(".jar"); + int j = fullname.lastIndexOf("/", i); + orderedJars.add(fullname.substring(j+1,i+4)); + } + + _context.setAttribute(ServletContext.ORDERED_LIBS, orderedJars); + } + else + _orderedResources = new ArrayList<Resource>((List<Resource>)_context.getAttribute(WebInfConfiguration.WEB_INF_JAR_RESOURCES)); + } + + + /** + * Resolve all servlet/filter/listener metadata from all sources: descriptors and annotations. + * + */ + public void resolve () + throws Exception + { + //TODO - apply all descriptors and annotations in order: + //apply descriptorProcessors to web-defaults.xml + //apply descriptorProcessors to web.xml + //apply descriptorProcessors to web-override.xml + //apply discovered annotations from container path + //apply discovered annotations from WEB-INF/classes + //for the ordering of the jars in WEB-INF/lib: + // +apply descriptorProcessors to web-fragment.xml + // +apply discovered annotations + + for (DescriptorProcessor p:_descriptorProcessors) + { + p.process(getWebDefault()); + p.process(getWebXml()); + p.process(getOverrideWeb()); + } + + for (DiscoveredAnnotation a:_annotations) + a.apply(); + + + List<Resource> resources = getOrderedResources(); + for (Resource r:resources) + { + FragmentDescriptor fd = _webFragmentResourceMap.get(r); + if (fd != null) + { + for (DescriptorProcessor p:_descriptorProcessors) + { + p.process(fd); + } + } + + List<DiscoveredAnnotation> fragAnnotations = _webFragmentAnnotations.get(r); + if (fragAnnotations != null) + { + for (DiscoveredAnnotation a:fragAnnotations) + a.apply(); + } + } + } + + public boolean isDistributable () + { + boolean distributable = ( + (_webDefaultsRoot != null && _webDefaultsRoot.isDistributable()) + || (_webXmlRoot != null && _webXmlRoot.isDistributable()) + || (_webOverrideRoot != null && _webOverrideRoot.isDistributable())); + + List<Resource> orderedResources = getOrderedResources(); + for (Resource r: orderedResources) + { + FragmentDescriptor d = _webFragmentResourceMap.get(r); + if (d!=null) + distributable = distributable && d.isDistributable(); + } + return distributable; + } + + + public Descriptor getWebXml () + { + return _webXmlRoot; + } + + public Descriptor getOverrideWeb () + { + return _webOverrideRoot; + } + + public Descriptor getWebDefault () + { + return _webDefaultsRoot; + } + + public List<FragmentDescriptor> getFragments () + { + return _webFragmentRoots; + } + + public List<Resource> getOrderedResources () + { + return _orderedResources; + } + + public List<FragmentDescriptor> getOrderedFragments () + { + List<FragmentDescriptor> list = new ArrayList<FragmentDescriptor>(); + if (_orderedResources == null) + return list; + + for (Resource r:_orderedResources) + { + FragmentDescriptor fd = _webFragmentResourceMap.get(r); + if (fd != null) + list.add(fd); + } + return list; + } + + public Ordering getOrdering() + { + return _ordering; + } + + public void setOrdering (Ordering o) + { + _ordering = o; + } + + public FragmentDescriptor getFragment (Resource jar) + { + return _webFragmentResourceMap.get(jar); + } + + public FragmentDescriptor getFragment(String name) + { + return _webFragmentNameMap.get(name); + } + + public Resource getJarForFragment (String name) + { + FragmentDescriptor f = getFragment(name); + if (f == null) + return null; + + Resource jar = null; + for (Resource r: _webFragmentResourceMap.keySet()) + { + if (_webFragmentResourceMap.get(r).equals(f)) + jar = r; + } + return jar; + } + + public Map<String,FragmentDescriptor> getNamedFragments () + { + return Collections.unmodifiableMap(_webFragmentNameMap); + } + + + public Origin getOrigin (String name) + { + OriginInfo x = _origins.get(name); + if (x == null) + return Origin.NotSet; + + return x.getOriginType(); + } + + + public Descriptor getOriginDescriptor (String name) + { + OriginInfo o = _origins.get(name); + if (o == null) + return null; + return o.getDescriptor(); + } + + public void setOrigin (String name, Descriptor d) + { + OriginInfo x = new OriginInfo (name, d); + _origins.put(name, x); + } + + public void setOrigin (String name) + { + if (name == null) + return; + + OriginInfo x = new OriginInfo (name, Origin.Annotation); + _origins.put(name, x); + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/OverrideDescriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/OverrideDescriptor.java index adcbf43342..fe7adb3599 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/OverrideDescriptor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/OverrideDescriptor.java @@ -22,7 +22,7 @@ import org.eclipse.jetty.util.resource.Resource; */ public class OverrideDescriptor extends Descriptor { - public OverrideDescriptor(Resource xml, WebXmlProcessor processor) + public OverrideDescriptor(Resource xml, MetaData processor) { super(xml, processor); } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java index 67e2d11275..d8de387c00 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java @@ -49,7 +49,7 @@ import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.webapp.WebXmlProcessor.Origin; +import org.eclipse.jetty.webapp.MetaData.Origin; import org.eclipse.jetty.xml.XmlParser; /** @@ -59,6 +59,7 @@ import org.eclipse.jetty.xml.XmlParser; */ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor { + public static final String STANDARD_PROCESSOR = "org.eclipse.jetty.standardDescriptorProcessor"; protected WebAppContext _context; //the shared configuration operated on by web-default.xml, web.xml, web-override.xml and all web-fragment.xml @@ -72,20 +73,19 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor protected Object _listenerClassNames; protected Object _welcomeFiles; protected Set<String> _roles = new HashSet<String>(); - protected Object _constraintMappings; + protected List<ConstraintMapping> _constraintMappings = new ArrayList<ConstraintMapping>(); protected Map _errorPages; protected boolean _hasJSP; protected String _jspServletName; protected String _jspServletClass; protected boolean _defaultWelcomeFileList; - protected WebXmlProcessor _processor; + protected MetaData _metaData; + - - public StandardDescriptorProcessor (WebXmlProcessor processor) + public StandardDescriptorProcessor () { - _processor = processor; - _context = _processor.getContext(); + try { registerVisitor("context-param", this.getClass().getDeclaredMethod("visitContextParam", __signature)); @@ -118,8 +118,11 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor /** * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start() */ - public void start() + public void start(Descriptor descriptor) { + _metaData = descriptor.getMetaData(); + _context = _metaData.getContext(); + //Get the current objects from the context _servletHandler = _context.getServletHandler(); _securityHandler = (SecurityHandler)_context.getSecurityHandler(); @@ -131,8 +134,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor _welcomeFiles = LazyList.array2List(_context.getWelcomeFiles()); if (_securityHandler instanceof ConstraintAware) { - _constraintMappings = LazyList.array2List(((ConstraintAware) _securityHandler).getConstraintMappings()); - + _constraintMappings.addAll(((ConstraintAware) _securityHandler).getConstraintMappings()); if (((ConstraintAware) _securityHandler).getRoles() != null) { _roles.addAll(((ConstraintAware) _securityHandler).getRoles()); @@ -146,7 +148,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor /** * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#end() */ - public void end() + public void end(Descriptor descriptor) { //Set the context with the results of the processing _servletHandler.setFilters((FilterHolder[]) LazyList.toArray(_filters, FilterHolder.class)); @@ -158,28 +160,33 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor // TODO jaspi check this if (_securityHandler instanceof ConstraintAware) { - ((ConstraintAware) _securityHandler).setConstraintMappings((ConstraintMapping[]) LazyList.toArray(_constraintMappings, - ConstraintMapping.class), - _roles); + for (ConstraintMapping m:_constraintMappings) + ((ConstraintAware) _securityHandler).addConstraintMapping(m); + for (String r:_roles) + ((ConstraintAware) _securityHandler).addRole(r); } if (_errorPages != null && _context.getErrorHandler() instanceof ErrorPageErrorHandler) ((ErrorPageErrorHandler)_context.getErrorHandler()).setErrorPages(_errorPages); - + + _roles.clear(); + _constraintMappings.clear(); + _metaData = null; + _context = null; } public void visitContextParam (Descriptor descriptor, XmlParser.Node node) { String name = node.getString("param-name", false, true); String value = node.getString("param-value", false, true); - Origin o = _processor.getOrigin("context-param."+name); + Origin o = _metaData.getOrigin("context-param."+name); switch (o) { case NotSet: { //just set it _context.getInitParams().put(name, value); - _processor.setOrigin("context-param."+name, descriptor); + _metaData.setOrigin("context-param."+name, descriptor); break; } case WebXml: @@ -187,17 +194,17 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //previously set by a web xml, allow other web xml files to override - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getInitParams().put(name, value); - _processor.setOrigin("context-param."+name, descriptor); + _metaData.setOrigin("context-param."+name, descriptor); } break; } case WebFragment: { //previously set by a web-fragment, this fragment's value must be the same - if (descriptor instanceof Fragment) + if (descriptor instanceof FragmentDescriptor) { if (!((String)_context.getInitParams().get(name)).equals(value)) throw new IllegalStateException("Conflicting context-param "+name+"="+value+" in "+descriptor.getResource()); @@ -214,10 +221,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor protected void visitDisplayName(Descriptor descriptor, XmlParser.Node node) { //Servlet Spec 3.0 p. 74 Ignore from web-fragments - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.setDisplayName(node.toString(false, true)); - _processor.setOrigin("display-name", descriptor); + _metaData.setOrigin("display-name", descriptor); } } @@ -248,14 +255,16 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String pname = paramNode.getString("param-name", false, true); String pvalue = paramNode.getString("param-value", false, true); - Origin origin = _processor.getOrigin(servlet_name+"servlet.init-param."+pname); + Origin origin = _metaData.getOrigin(servlet_name+".servlet.init-param."+pname); + switch (origin) { case NotSet: { //init-param not already set, so set it + registration.setInitParameter(pname, pvalue); - _processor.setOrigin(servlet_name+"servlet.init-param."+pname, descriptor); + _metaData.setOrigin(servlet_name+".servlet.init-param."+pname, descriptor); break; } case WebXml: @@ -264,10 +273,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor { //previously set by a web xml descriptor, if we're parsing another web xml descriptor allow override //otherwise just ignore it - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { registration.setInitParameter(pname, pvalue); - _processor.setOrigin(servlet_name+"servlet.init-param."+pname, descriptor); + _metaData.setOrigin(servlet_name+".servlet.init-param."+pname, descriptor); } break; } @@ -324,14 +333,16 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor //Set the servlet-class if (servlet_class != null) { - Origin o = _processor.getOrigin(servlet_name+".servlet-class"); + descriptor.addClassName(servlet_class); + + Origin o = _metaData.getOrigin(servlet_name+".servlet.servlet-class"); switch (o) { case NotSet: { //the class of the servlet has not previously been set, so set it holder.setClassName(servlet_class); - _processor.setOrigin(servlet_name+".servlet-class", descriptor); + _metaData.setOrigin(servlet_name+".servlet.servlet-class", descriptor); break; } case WebXml: @@ -339,10 +350,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //the class of the servlet was set by a web xml file, only allow web-override/web-default to change it - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { holder.setClassName(servlet_class); - _processor.setOrigin(servlet_name+".servlet-class", descriptor); + _metaData.setOrigin(servlet_name+".servlet.servlet-class", descriptor); } break; } @@ -388,14 +399,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor } } - Origin o = _processor.getOrigin(servlet_name+".load-on-startup"); + Origin o = _metaData.getOrigin(servlet_name+".servlet.load-on-startup"); switch (o) { case NotSet: { //not already set, so set it now registration.setLoadOnStartup(order); - _processor.setOrigin(servlet_name+".load-on-startup", descriptor); + _metaData.setOrigin(servlet_name+".servlet.load-on-startup", descriptor); break; } case WebXml: @@ -403,10 +414,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //if it was already set by a web xml descriptor and we're parsing another web xml descriptor, then override it - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { registration.setLoadOnStartup(order); - _processor.setOrigin(servlet_name+".load-on-startup", descriptor); + _metaData.setOrigin(servlet_name+".servlet.load-on-startup", descriptor); } break; } @@ -429,14 +440,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (roleName != null && roleName.length() > 0 && roleLink != null && roleLink.length() > 0) { if (Log.isDebugEnabled()) Log.debug("link role " + roleName + " to " + roleLink + " for " + this); - Origin o = _processor.getOrigin(servlet_name+".role-name."+roleName); + Origin o = _metaData.getOrigin(servlet_name+".servlet.role-name."+roleName); switch (o) { case NotSet: { //set it holder.setUserRoleLink(roleName, roleLink); - _processor.setOrigin(servlet_name+".role-name."+roleName, descriptor); + _metaData.setOrigin(servlet_name+".servlet.role-name."+roleName, descriptor); break; } case WebXml: @@ -444,10 +455,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //only another web xml descriptor (web-default,web-override web.xml) can override an already set value - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { holder.setUserRoleLink(roleName, roleLink); - _processor.setOrigin(servlet_name+".role-name."+roleName, descriptor); + _metaData.setOrigin(servlet_name+".servlet.role-name."+roleName, descriptor); } break; } @@ -473,14 +484,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (roleName != null) { - Origin o = _processor.getOrigin(servlet_name+".run-as"); + Origin o = _metaData.getOrigin(servlet_name+".servlet.run-as"); switch (o) { case NotSet: { //run-as not set, so set it registration.setRunAsRole(roleName); - _processor.setOrigin(servlet_name+".run-as", descriptor); + _metaData.setOrigin(servlet_name+".servlet.run-as", descriptor); break; } case WebXml: @@ -488,10 +499,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //run-as was set by a web xml, only allow it to be changed if we're currently parsing another web xml(override/default) - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { registration.setRunAsRole(roleName); - _processor.setOrigin(servlet_name+".run-as", descriptor); + _metaData.setOrigin(servlet_name+".servlet.run-as", descriptor); } break; } @@ -510,14 +521,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (async!=null) { boolean val = async.length()==0||Boolean.valueOf(async); - Origin o =_processor.getOrigin(servlet_name+"servlet.async-supported"); + Origin o =_metaData.getOrigin(servlet_name+".servlet.async-supported"); switch (o) { case NotSet: { //set it registration.setAsyncSupported(val); - _processor.setOrigin(servlet_name+"servlet.async-supported", descriptor); + _metaData.setOrigin(servlet_name+".servlet.async-supported", descriptor); break; } case WebXml: @@ -525,10 +536,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //async-supported set by previous web xml descriptor, only allow override if we're parsing another web descriptor(web.xml/web-override.xml/web-default.xml) - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { registration.setAsyncSupported(val); - _processor.setOrigin(servlet_name+"servlet.async-supported", descriptor); + _metaData.setOrigin(servlet_name+".servlet.async-supported", descriptor); } break; } @@ -546,14 +557,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (enabled!=null) { boolean val = enabled.length()==0||Boolean.valueOf(enabled); - Origin o = _processor.getOrigin(servlet_name+".enabled"); + Origin o = _metaData.getOrigin(servlet_name+".servlet.enabled"); switch (o) { case NotSet: { //hasn't been set yet, so set it //TODO - _processor.setOrigin(servlet_name+".enabled", descriptor); + _metaData.setOrigin(servlet_name+".servlet.enabled", descriptor); break; } case WebXml: @@ -561,10 +572,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //was set in a web xml descriptor, only allow override from another web xml descriptor - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { //TODO - _processor.setOrigin(servlet_name+".enabled", descriptor); + _metaData.setOrigin(servlet_name+".servlet.enabled", descriptor); } break; } @@ -594,14 +605,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor (maxRequest==null||"".equals(maxRequest)?-1L:Long.parseLong(maxRequest)), (threshold==null||"".equals(threshold)?0:Integer.parseInt(threshold))); - Origin o = _processor.getOrigin(servlet_name+".multipart-config"); + Origin o = _metaData.getOrigin(servlet_name+".servlet.multipart-config"); switch (o) { case NotSet: { //hasn't been set, so set it registration.setMultipartConfig(element); - _processor.setOrigin(servlet_name+".multipart-config", descriptor); + _metaData.setOrigin(servlet_name+".servlet.multipart-config", descriptor); break; } case WebXml: @@ -609,10 +620,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //was set in a web xml, only allow changes if we're parsing another web xml (web.xml/web-default.xml/web-override.xml) - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { registration.setMultipartConfig(element); - _processor.setOrigin(servlet_name+".multipart-config", descriptor); + _metaData.setOrigin(servlet_name+".servlet.multipart-config", descriptor); } break; } @@ -644,6 +655,9 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor ServletMapping mapping = new ServletMapping(); mapping.setServletName(servlet_name); + if (_metaData.getOrigin(servlet_name+".servlet.mappings") == Origin.NotSet) + _metaData.setOrigin(servlet_name+".servlet.mappings", descriptor); + ArrayList paths = new ArrayList(); Iterator iter = node.iterator("url-pattern"); while (iter.hasNext()) @@ -653,7 +667,6 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor paths.add(p); } mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()])); - _servletMappings = LazyList.add(_servletMappings, mapping); } @@ -691,14 +704,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String name = cookieConfig.getString("name", false, true); if (name != null) { - Origin o = _processor.getOrigin("cookie-config.name"); + Origin o = _metaData.getOrigin("cookie-config.name"); switch (o) { case NotSet: { //no <cookie-config><name> set yet, accept it _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setName(name); - _processor.setOrigin("cookie-config.name", descriptor); + _metaData.setOrigin("cookie-config.name", descriptor); break; } case WebXml: @@ -706,10 +719,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //<cookie-config><name> set in a web xml, only allow web-default/web-override to change - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setName(name); - _processor.setOrigin("cookie-config.name", descriptor); + _metaData.setOrigin("cookie-config.name", descriptor); } break; } @@ -727,14 +740,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String domain = cookieConfig.getString("domain", false, true); if (domain != null) { - Origin o = _processor.getOrigin("cookie-config.domain"); + Origin o = _metaData.getOrigin("cookie-config.domain"); switch (o) { case NotSet: { //no <cookie-config><domain> set yet, accept it _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setDomain(domain); - _processor.setOrigin("cookie-config.domain", descriptor); + _metaData.setOrigin("cookie-config.domain", descriptor); break; } case WebXml: @@ -742,10 +755,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //<cookie-config><domain> set in a web xml, only allow web-default/web-override to change - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setDomain(domain); - _processor.setOrigin("cookie-config.domain", descriptor); + _metaData.setOrigin("cookie-config.domain", descriptor); } break; } @@ -763,14 +776,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String path = cookieConfig.getString("path", false, true); if (path != null) { - Origin o = _processor.getOrigin("cookie-config.path"); + Origin o = _metaData.getOrigin("cookie-config.path"); switch (o) { case NotSet: { //no <cookie-config><domain> set yet, accept it _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setPath(path); - _processor.setOrigin("cookie-config.path", descriptor); + _metaData.setOrigin("cookie-config.path", descriptor); break; } case WebXml: @@ -778,10 +791,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //<cookie-config><domain> set in a web xml, only allow web-default/web-override to change - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setPath(path); - _processor.setOrigin("cookie-config.path", descriptor); + _metaData.setOrigin("cookie-config.path", descriptor); } break; } @@ -799,14 +812,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String comment = cookieConfig.getString("comment", false, true); if (comment != null) { - Origin o = _processor.getOrigin("cookie-config.comment"); + Origin o = _metaData.getOrigin("cookie-config.comment"); switch (o) { case NotSet: { //no <cookie-config><comment> set yet, accept it _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setComment(comment); - _processor.setOrigin("cookie-config.comment", descriptor); + _metaData.setOrigin("cookie-config.comment", descriptor); break; } case WebXml: @@ -814,10 +827,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //<cookie-config><comment> set in a web xml, only allow web-default/web-override to change - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setComment(comment); - _processor.setOrigin("cookie-config.comment", descriptor); + _metaData.setOrigin("cookie-config.comment", descriptor); } break; } @@ -836,14 +849,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (tNode != null) { boolean httpOnly = Boolean.parseBoolean(tNode.toString(false,true)); - Origin o = _processor.getOrigin("cookie-config.http-only"); + Origin o = _metaData.getOrigin("cookie-config.http-only"); switch (o) { case NotSet: { //no <cookie-config><http-only> set yet, accept it _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setHttpOnly(httpOnly); - _processor.setOrigin("cookie-config.http-only", descriptor); + _metaData.setOrigin("cookie-config.http-only", descriptor); break; } case WebXml: @@ -851,10 +864,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //<cookie-config><http-only> set in a web xml, only allow web-default/web-override to change - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setHttpOnly(httpOnly); - _processor.setOrigin("cookie-config.http-only", descriptor); + _metaData.setOrigin("cookie-config.http-only", descriptor); } break; } @@ -873,14 +886,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (tNode != null) { boolean secure = Boolean.parseBoolean(tNode.toString(false,true)); - Origin o = _processor.getOrigin("cookie-config.secure"); + Origin o = _metaData.getOrigin("cookie-config.secure"); switch (o) { case NotSet: { //no <cookie-config><secure> set yet, accept it _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setSecure(secure); - _processor.setOrigin("cookie-config.secure", descriptor); + _metaData.setOrigin("cookie-config.secure", descriptor); break; } case WebXml: @@ -888,10 +901,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //<cookie-config><secure> set in a web xml, only allow web-default/web-override to change - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setSecure(secure); - _processor.setOrigin("cookie-config.secure", descriptor); + _metaData.setOrigin("cookie-config.secure", descriptor); } break; } @@ -910,14 +923,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (tNode != null) { int maxAge = Integer.parseInt(tNode.toString(false,true)); - Origin o = _processor.getOrigin("cookie-config.max-age"); + Origin o = _metaData.getOrigin("cookie-config.max-age"); switch (o) { case NotSet: { //no <cookie-config><max-age> set yet, accept it _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setMaxAge(maxAge); - _processor.setOrigin("cookie-config.max-age", descriptor); + _metaData.setOrigin("cookie-config.max-age", descriptor); break; } case WebXml: @@ -925,10 +938,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //<cookie-config><max-age> set in a web xml, only allow web-default/web-override to change - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getSessionHandler().getSessionManager().getSessionCookieConfig().setMaxAge(maxAge); - _processor.setOrigin("cookie-config.max-age", descriptor); + _metaData.setOrigin("cookie-config.max-age", descriptor); } break; } @@ -952,14 +965,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String mimeType = node.getString("mime-type", false, true); if (extension != null) { - Origin o = _processor.getOrigin("extension."+extension); + Origin o = _metaData.getOrigin("extension."+extension); switch (o) { case NotSet: { //no mime-type set for the extension yet _context.getMimeTypes().addMimeMapping(extension, mimeType); - _processor.setOrigin("extension."+extension, descriptor); + _metaData.setOrigin("extension."+extension, descriptor); break; } case WebXml: @@ -967,10 +980,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //a mime-type was set for the extension in a web xml, only allow web-default/web-override to change - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.getMimeTypes().addMimeMapping(extension, mimeType); - _processor.setOrigin("extension."+extension, descriptor); + _metaData.setOrigin("extension."+extension, descriptor); } break; } @@ -987,12 +1000,12 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor protected void visitWelcomeFileList(Descriptor descriptor, XmlParser.Node node) { - Origin o = _processor.getOrigin("welcome-file-list"); + Origin o = _metaData.getOrigin("welcome-file-list"); switch (o) { case NotSet: { - _processor.setOrigin("weclome-file-list", descriptor); + _metaData.setOrigin("welcome-file-list", descriptor); addWelcomeFiles(node); break; } @@ -1004,13 +1017,12 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor } case WebDefaults: { - //web-defaults.xml set the welcome-file-list. If we're processing web.xml we - //should reset the list. - Descriptor d = _processor.getOriginDescriptor("welcome-file-list"); //if web-defaults set the welcome-file-list first and //we're processing web.xml then reset the welcome-file-list - if (!(descriptor instanceof DefaultsDescriptor) && !(descriptor instanceof OverrideDescriptor) && !(descriptor instanceof Fragment)) + if (!(descriptor instanceof DefaultsDescriptor) && !(descriptor instanceof OverrideDescriptor) && !(descriptor instanceof FragmentDescriptor)) + { _welcomeFiles = null; + } addWelcomeFiles(node); break; } @@ -1022,7 +1034,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor } case WebFragment: { - //A web-fragment first set the welcome-file-list. Other descriptors just add. + //A web-fragment first set the welcome-file-list. Other descriptors just add. addWelcomeFiles(node); break; } @@ -1040,14 +1052,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (encoding != null) { - Origin o = _processor.getOrigin("locale-encoding."+locale); + Origin o = _metaData.getOrigin("locale-encoding."+locale); switch (o) { case NotSet: { //no mapping for the locale yet, so set it _context.addLocaleEncoding(locale, encoding); - _processor.setOrigin("locale-encoding."+locale, descriptor); + _metaData.setOrigin("locale-encoding."+locale, descriptor); break; } case WebXml: @@ -1055,10 +1067,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //a value was set in a web descriptor, only allow another web descriptor to change it (web-default/web-override) - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _context.addLocaleEncoding(locale, encoding); - _processor.setOrigin("locale-encoding."+locale, descriptor); + _metaData.setOrigin("locale-encoding."+locale, descriptor); } break; } @@ -1083,14 +1095,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (_errorPages == null) _errorPages = new HashMap(); - Origin o = _processor.getOrigin("error."+error); + Origin o = _metaData.getOrigin("error."+error); switch (o) { case NotSet: { //no error page setup for this code or exception yet _errorPages.put(error, location); - _processor.setOrigin("error."+error, descriptor); + _metaData.setOrigin("error."+error, descriptor); break; } case WebXml: @@ -1098,10 +1110,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //an error page setup was set in web.xml, only allow other web xml descriptors to override it - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _errorPages.put(error, location); - _processor.setOrigin("error."+error, descriptor); + _metaData.setOrigin("error."+error, descriptor); } break; } @@ -1241,7 +1253,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor mapping.setMethod(method); mapping.setPathSpec(url); mapping.setConstraint(sc); - _constraintMappings = LazyList.add(_constraintMappings, mapping); + _constraintMappings.add(mapping); } } else @@ -1249,7 +1261,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor ConstraintMapping mapping = new ConstraintMapping(); mapping.setPathSpec(url); mapping.setConstraint(sc); - _constraintMappings = LazyList.add(_constraintMappings, mapping); + _constraintMappings.add(mapping); } } } @@ -1269,14 +1281,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (method != null) { //handle auth-method merge - Origin o = _processor.getOrigin("auth-method"); + Origin o = _metaData.getOrigin("auth-method"); switch (o) { case NotSet: { //not already set, so set it now _securityHandler.setAuthMethod(method.toString(false, true)); - _processor.setOrigin("auth-method", descriptor); + _metaData.setOrigin("auth-method", descriptor); break; } case WebXml: @@ -1284,10 +1296,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //if it was already set by a web xml descriptor and we're parsing another web xml descriptor, then override it - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _securityHandler.setAuthMethod(method.toString(false, true)); - _processor.setOrigin("auth-method", descriptor); + _metaData.setOrigin("auth-method", descriptor); } break; } @@ -1303,14 +1315,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor //handle realm-name merge XmlParser.Node name = node.get("realm-name"); String nameStr = (name == null ? "default" : name.toString(false, true)); - o = _processor.getOrigin("realm-name"); + o = _metaData.getOrigin("realm-name"); switch (o) { case NotSet: { //no descriptor has set the realm-name yet, so set it _securityHandler.setRealmName(nameStr); - _processor.setOrigin("realm-name", descriptor); + _metaData.setOrigin("realm-name", descriptor); break; } case WebXml: @@ -1318,10 +1330,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //set by a web xml file (web.xml/web-default.xm/web-override.xml), only allow it to be changed by another web xml file - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _securityHandler.setRealmName(nameStr); - _processor.setOrigin("realm-name", descriptor); + _metaData.setOrigin("realm-name", descriptor); } break; } @@ -1349,14 +1361,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor errorPageName = errorPage.toString(false, true); //handle form-login-page - o = _processor.getOrigin("form-login-page"); + o = _metaData.getOrigin("form-login-page"); switch (o) { case NotSet: { //Never been set before, so accept it _securityHandler.setInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE,loginPageName); - _processor.setOrigin("form-login-page",descriptor); + _metaData.setOrigin("form-login-page",descriptor); break; } case WebXml: @@ -1364,10 +1376,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //a web xml descriptor previously set it, only allow another one to change it (web.xml/web-default.xml/web-override.xml) - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _securityHandler.setInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE,loginPageName); - _processor.setOrigin("form-login-page",descriptor); + _metaData.setOrigin("form-login-page",descriptor); } break; } @@ -1381,14 +1393,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor } //handle form-error-page - o = _processor.getOrigin("form-error-page"); + o = _metaData.getOrigin("form-error-page"); switch (o) { case NotSet: { //Never been set before, so accept it _securityHandler.setInitParameter(FormAuthenticator.__FORM_ERROR_PAGE,errorPageName); - _processor.setOrigin("form-error-page",descriptor); + _metaData.setOrigin("form-error-page",descriptor); break; } case WebXml: @@ -1396,10 +1408,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //a web xml descriptor previously set it, only allow another one to change it (web.xml/web-default.xml/web-override.xml) - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { _securityHandler.setInitParameter(FormAuthenticator.__FORM_ERROR_PAGE,errorPageName); - _processor.setOrigin("form-error-page",descriptor); + _metaData.setOrigin("form-error-page",descriptor); } break; } @@ -1443,14 +1455,16 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String filter_class = node.getString("filter-class", false, true); if (filter_class != null) { - Origin o = _processor.getOrigin(name+".filter-class"); + descriptor.addClassName(filter_class); + + Origin o = _metaData.getOrigin(name+".filter.filter-class"); switch (o) { case NotSet: { //no class set yet holder.setClassName(filter_class); - _processor.setOrigin(name+".filter-class", descriptor); + _metaData.setOrigin(name+".filter.filter-class", descriptor); break; } case WebXml: @@ -1458,10 +1472,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //filter class was set in web.xml, only allow other web xml descriptors (override/default) to change it - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { holder.setClassName(filter_class); - _processor.setOrigin(name+".filter-class", descriptor); + _metaData.setOrigin(name+".filter.filter-class", descriptor); } break; } @@ -1483,14 +1497,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String pname = paramNode.getString("param-name", false, true); String pvalue = paramNode.getString("param-value", false, true); - Origin origin = _processor.getOrigin(name+"filter.init-param."+pname); + Origin origin = _metaData.getOrigin(name+".filter.init-param."+pname); switch (origin) { case NotSet: { //init-param not already set, so set it holder.setInitParameter(pname, pvalue); - _processor.setOrigin(name+"filter.init-param."+pname, descriptor); + _metaData.setOrigin(name+".filter.init-param."+pname, descriptor); break; } case WebXml: @@ -1499,10 +1513,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor { //previously set by a web xml descriptor, if we're parsing another web xml descriptor allow override //otherwise just ignore it - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { holder.setInitParameter(pname, pvalue); - _processor.setOrigin(name+"filter.init-param."+pname, descriptor); + _metaData.setOrigin(name+".filter.init-param."+pname, descriptor); } break; } @@ -1522,14 +1536,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor if (async!=null) { boolean val = async.length()==0||Boolean.valueOf(async); - Origin o = _processor.getOrigin(name+"filter.async-supported"); + Origin o = _metaData.getOrigin(name+".filter.async-supported"); switch (o) { case NotSet: { //set it holder.setAsyncSupported(val); - _processor.setOrigin(name+"filter.async-supported", descriptor); + _metaData.setOrigin(name+".filter.async-supported", descriptor); break; } case WebXml: @@ -1537,10 +1551,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor case WebOverride: { //async-supported set by previous web xml descriptor, only allow override if we're parsing another web descriptor(web.xml/web-override.xml/web-default.xml) - if (!(descriptor instanceof Fragment)) + if (!(descriptor instanceof FragmentDescriptor)) { holder.setAsyncSupported(val); - _processor.setOrigin(name+"filter.async-supported", descriptor); + _metaData.setOrigin(name+".filter.async-supported", descriptor); } break; } @@ -1610,6 +1624,8 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor { if (className != null && className.length()> 0) { + descriptor.addClassName(className); + //Servlet Spec 3.0 p 74 //Duplicate listener declarations don't result in duplicate listener instances if (!LazyList.contains(_listenerClassNames, className)) @@ -1622,7 +1638,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor Log.warn("Not an EventListener: " + listener); return; } - + _metaData.setOrigin(className+".listener", descriptor); _listeners = LazyList.add(_listeners, listener); } } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/TagLibConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/TagLibConfiguration.java index d5b349b35c..f5dd88f39e 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/TagLibConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/TagLibConfiguration.java @@ -45,7 +45,8 @@ import org.eclipse.jetty.xml.XmlParser; * </bile> * * - * + * TODO - this has been superceded by the new TldScanner in jasper which uses ServletContainerInitializer to + * find all the listeners in tag libs and register them. */ public class TagLibConfiguration implements Configuration { diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java index 59bebfdc0b..ca37ab4f42 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java @@ -31,6 +31,7 @@ import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.ResourceCollection; /* ------------------------------------------------------------ */ @@ -38,11 +39,11 @@ import org.eclipse.jetty.util.resource.Resource; * Specializes URLClassLoader with some utility and file mapping * methods. * - * This loader defaults to the 2.3 servlet spec behaviour where non + * This loader defaults to the 2.3 servlet spec behavior where non * system classes are loaded from the classpath in preference to the * parent loader. Java2 compliant loading, where the parent loader * always has priority, can be selected with the - * {@link org.eclipse.jetty.server.server.webapp.WebAppContext#setParentLoaderPriority(boolean)} + * {@link org.eclipse.jetty.webapp.WebAppContext#setParentLoaderPriority(boolean)} * method and influenced with {@link WebAppContext#isServerClass(String)} and * {@link WebAppContext#isSystemClass(String)}. * @@ -123,6 +124,26 @@ public class WebAppClassLoader extends URLClassLoader { return _context; } + + /* ------------------------------------------------------------ */ + /** + * @param resource Comma or semicolon separated path of filenames or URLs + * pointing to directories or jar files. Directories should end + * with '/'. + */ + public void addClassPath(Resource resource) + throws IOException + { + if (resource instanceof ResourceCollection) + { + for (Resource r : ((ResourceCollection)resource).getResources()) + addClassPath(r); + } + else + { + addClassPath(resource.toString()); + } + } /* ------------------------------------------------------------ */ /** @@ -180,9 +201,6 @@ public class WebAppClassLoader extends URLClassLoader /** Add elements to the class path for the context from the jar and zip files found * in the specified resource. * @param lib the resource that contains the jar and/or zip files. - * @param append true if the classpath entries are to be appended to any - * existing classpath, or false if they replace the existing classpath. - * @see #setClassPath(String) */ public void addJars(Resource lib) { @@ -191,10 +209,11 @@ public class WebAppClassLoader extends URLClassLoader String[] files=lib.list(); for (int f=0;files!=null && f<files.length;f++) { - try { + try + { Resource fn=lib.addPath(files[f]); String fnlc=fn.getName().toLowerCase(); - if (isFileSupported(fnlc)) + if (!fn.isDirectory() && isFileSupported(fnlc)) { String jar=fn.toString(); jar=StringUtil.replace(jar, ",", "%2C"); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index 17cf3bdd4d..0e77e9311f 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -16,10 +16,10 @@ package org.eclipse.jetty.webapp; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.net.URL; import java.security.PermissionCollection; import java.util.EventListener; import java.util.HashMap; -import java.util.List; import java.util.Map; import javax.servlet.http.HttpSessionActivationListener; @@ -30,6 +30,7 @@ import javax.servlet.http.HttpSessionListener; import org.eclipse.jetty.security.SecurityHandler; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HandlerContainer; +import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.session.SessionHandler; @@ -42,6 +43,7 @@ import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.ResourceCollection; /* ------------------------------------------------------------ */ /** Web Application Context Handler. @@ -50,8 +52,8 @@ import org.eclipse.jetty.util.resource.Resource; * {@link org.eclipse.jetty.security.ConstraintSecurityHandler}, {@link org.eclipse.jetty.server.session.SessionHandler} * and {@link org.eclipse.jetty.servlet.ServletHandler}. * The handlers are configured by pluggable configuration classes, with - * the default being {@link org.eclipse.jetty.server.server.webapp.WebXmlConfiguration} and - * {@link org.eclipse.jetty.server.server.webapp.JettyWebXmlConfiguration}. + * the default being {@link org.eclipse.jetty.webapp.WebXmlConfiguration} and + * {@link org.eclipse.jetty.webapp.JettyWebXmlConfiguration}. * * @org.apache.xbean.XBean description="Creates a servlet web application at a given context from a resource base" * @@ -61,9 +63,12 @@ import org.eclipse.jetty.util.resource.Resource; public class WebAppContext extends ServletContextHandler { public static final String TEMPDIR = "javax.servlet.context.tempdir"; + public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir"; public final static String WEB_DEFAULTS_XML="org/eclipse/jetty/webapp/webdefault.xml"; public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page"; public final static String SERVER_CONFIG = "org.eclipse.jetty.webapp.configuration"; + public final static String SERVER_SYS_CLASSES = "org.eclipse.jetty.webapp.systemClasses"; + public final static String SERVER_SRV_CLASSES = "org.eclipse.jetty.webapp.serverClasses"; private static String[] __dftConfigurationClasses = { @@ -74,7 +79,42 @@ public class WebAppContext extends ServletContextHandler "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"//, //"org.eclipse.jetty.webapp.TagLibConfiguration" } ; - private String[] _configurationClasses=null; + + // System classes are classes that cannot be replaced by + // the web application, and they are *always* loaded via + // system classloader. + private final static String[] __dftSystemClasses = + { + "java.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) + "javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) + "org.xml.", // needed by javax.xml + "org.w3c.", // needed by javax.xml + "org.apache.commons.logging.", // TODO: review if special case still needed + "org.eclipse.jetty.continuation.", // webapp cannot change continuation classes + "org.eclipse.jetty.jndi.", // webapp cannot change naming classes + "org.eclipse.jetty.plus.jaas.", // webapp cannot change jaas classes + "org.eclipse.jetty.websocket.", // WebSocket is a jetty extension + "org.eclipse.jetty.servlet.DefaultServlet" // webapp cannot change default servlets + } ; + + // Server classes are classes that are hidden from being + // loaded by the web application using system classloader, + // so if web application needs to load any of such classes, + // it has to include them in its distribution. + private final static String[] __dftServerClasses = + { + "-org.eclipse.jetty.continuation.", // don't hide continuation classes + "-org.eclipse.jetty.jndi.", // don't hide naming classes + "-org.eclipse.jetty.plus.jaas.", // don't hide jaas classes + "-org.eclipse.jetty.websocket.", // don't hide websocket extension + "-org.eclipse.jetty.servlet.DefaultServlet", // don't hide default servlet + "org.eclipse.jetty." // hide other jetty classes + } ; + + private String[] _configurationClasses = __dftConfigurationClasses; + private ClasspathPattern _systemClasses = null; + private ClasspathPattern _serverClasses = null; + private Configuration[] _configurations; private String _defaultsDescriptor=WEB_DEFAULTS_XML; private String _descriptor=null; @@ -85,26 +125,7 @@ public class WebAppContext extends ServletContextHandler private boolean _logUrlOnStart =false; private boolean _parentLoaderPriority= Boolean.getBoolean("org.eclipse.jetty.server.webapp.parentLoaderPriority"); private PermissionCollection _permissions; - private String[] _systemClasses = { - "java.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) - "javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) - "org.xml.", // needed by javax.xml - "org.w3c.", // needed by javax.xml - "org.apache.commons.logging.", // special case. - "org.eclipse.jetty.continuation.", // webapp cannot change continuation classes - "org.eclipse.jetty.jndi.", // webapp cannot change naming classes - "org.eclipse.jetty.plus.jaas.", // webapp cannot change jetty jaas classes - "org.eclipse.jetty.servlet.DefaultServlet", // webapp cannot change default servlets - "org.eclipse.jetty.websocket.", // WebSocket is a jetty extension - }; - private String[] _serverClasses = { - "-org.eclipse.jetty.continuation.", // don't hide continuation classes - "-org.eclipse.jetty.jndi.", // don't hide naming classes - "-org.eclipse.jetty.plus.jaas.", // don't hide jaas modules - "-org.eclipse.jetty.servlet.DefaultServlet", // webapp cannot change default servlets - "-org.eclipse.jetty.websocket.", // don't hide websocket extension - "org.eclipse.jetty." // hide rest of jetty classes - }; + private File _tmpDir; private String _war; private String _extraClasspath; @@ -113,15 +134,17 @@ public class WebAppContext extends ServletContextHandler private Map _resourceAliases; private boolean _ownClassLoader=false; private boolean _configurationDiscovered=true; + private boolean _configurationClassesSet=false; + private boolean _configurationsSet=false; - public static ContextHandler getCurrentWebAppContext() + public static WebAppContext getCurrentWebAppContext() { ContextHandler.Context context=ContextHandler.getCurrentContext(); if (context!=null) { ContextHandler handler = context.getContextHandler(); if (handler instanceof WebAppContext) - return handler; + return (WebAppContext)handler; } return null; } @@ -130,6 +153,7 @@ public class WebAppContext extends ServletContextHandler public WebAppContext() { super(SESSIONS|SECURITY); + _scontext=new Context(); setErrorHandler(new ErrorPageErrorHandler()); } @@ -141,6 +165,7 @@ public class WebAppContext extends ServletContextHandler public WebAppContext(String webApp,String contextPath) { super(null,contextPath,SESSIONS|SECURITY); + _scontext=new Context(); setContextPath(contextPath); setWar(webApp); setErrorHandler(new ErrorPageErrorHandler()); @@ -155,6 +180,7 @@ public class WebAppContext extends ServletContextHandler public WebAppContext(HandlerContainer parent, String webApp, String contextPath) { super(parent,contextPath,SESSIONS|SECURITY); + _scontext=new Context(); setWar(webApp); setErrorHandler(new ErrorPageErrorHandler()); } @@ -165,7 +191,7 @@ public class WebAppContext extends ServletContextHandler public WebAppContext(SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler) { super(null,sessionHandler,securityHandler,servletHandler,errorHandler); - + _scontext=new Context(); setErrorHandler(errorHandler!=null?errorHandler:new ErrorPageErrorHandler()); } @@ -299,7 +325,7 @@ public class WebAppContext extends ServletContextHandler * <li>Web Fragments</li> * <li>META-INF/resource directories</li> * </ul> - * @param servlet3autoConfig the servlet3autoConfig to set + * @param discovered true if configuration discovery is enabled for automatic configuration from the context */ public void setConfigurationDiscovered(boolean discovered) { @@ -318,7 +344,12 @@ public class WebAppContext extends ServletContextHandler // Setup configurations loadConfigurations(); + // Setup system classes + loadSystemClasses(); + // Setup server classes + loadServerClasses(); + // Configure classloader _ownClassLoader=false; if (getClassLoader()==null) @@ -342,11 +373,16 @@ public class WebAppContext extends ServletContextHandler - // Prepare for configuration + // Prepare for configuration + //Make a new MetaData to hold descriptor and annotation metadata + MetaData metadata = new MetaData(this); + setAttribute(MetaData.METADATA, metadata); + for (int i=0;i<_configurations.length;i++) _configurations[i].preConfigure(this); super.doStart(); + // Clean up after configuration for (int i=0;i<_configurations.length;i++) @@ -456,7 +492,6 @@ public class WebAppContext extends ServletContextHandler { return _permissions; } - /* ------------------------------------------------------------ */ /** @@ -465,25 +500,18 @@ public class WebAppContext extends ServletContextHandler */ public String[] getServerClasses() { - return _serverClasses; + if (_serverClasses == null) + loadServerClasses(); + + return _serverClasses.getPatterns(); } - + public void addServerClass(String classname) { - for (int i = 0, n = _serverClasses.length; i < n; i++) - { - if (_serverClasses[i].equals(classname)) - { - // Already present. - return; - } - } - - int len = _serverClasses.length + 1; - String sysclass[] = new String[len]; - System.arraycopy(_serverClasses,0,sysclass,0,len - 1); - sysclass[len - 1] = classname; - _serverClasses = sysclass; + if (_serverClasses == null) + loadServerClasses(); + + _serverClasses.addPattern(classname); } /* ------------------------------------------------------------ */ @@ -493,95 +521,75 @@ public class WebAppContext extends ServletContextHandler */ public String[] getSystemClasses() { - return _systemClasses; + if (_systemClasses == null) + loadSystemClasses(); + + return _systemClasses.getPatterns(); } public void addSystemClass(String classname) { - for (int i = 0, n = _systemClasses.length; i < n; i++) - { - if (_systemClasses[i].equals(classname)) - { - // Already present. - return; - } - } - - int len = _systemClasses.length + 1; - String sysclass[] = new String[len]; - System.arraycopy(_systemClasses,0,sysclass,0,len - 1); - sysclass[len - 1] = classname; - _systemClasses = sysclass; + if (_systemClasses == null) + loadSystemClasses(); + + _systemClasses.addPattern(classname); } /* ------------------------------------------------------------ */ public boolean isServerClass(String name) { - name=name.replace('/','.'); - while(name.startsWith(".")) - name=name.substring(1); - - String[] server_classes = getServerClasses(); - if (server_classes!=null) - { - for (int i=0;i<server_classes.length;i++) - { - boolean result=true; - String c=server_classes[i]; - if (c.startsWith("-")) - { - c=c.substring(1); // TODO cache - result=false; - } - - if (c.endsWith(".")) - { - if (name.startsWith(c)) - return result; - } - else if (name.equals(c)) - return result; - } - } - return false; + if (_serverClasses == null) + loadServerClasses(); + + return _serverClasses.match(name); } /* ------------------------------------------------------------ */ public boolean isSystemClass(String name) { - name=name.replace('/','.'); - while(name.startsWith(".")) - name=name.substring(1); - String[] system_classes = getSystemClasses(); - if (system_classes!=null) + if (_systemClasses == null) + loadSystemClasses(); + + return _systemClasses.match(name); + } + + private void loadSystemClasses() + { + if (_systemClasses != null) + return; + + //look for a Server attribute with the list of System classes + //to apply to every web application. If not present, use our defaults. + Server server = getServer(); + if (server != null) { - for (int i=0;i<system_classes.length;i++) - { - boolean result=true; - String c=system_classes[i]; - - if (c.startsWith("-")) - { - c=c.substring(1); // TODO cache - result=false; - } - - if (c.endsWith(".")) - { - if (name.startsWith(c)) - return result; - } - else if (name.equals(c)) - return result; - } + Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES); + if (systemClasses != null && systemClasses instanceof String[]) + _systemClasses = ClasspathPattern.fromArray((String[])systemClasses); } - return false; - + if (_systemClasses == null) + _systemClasses = ClasspathPattern.fromArray(__dftSystemClasses); } - - + private void loadServerClasses() + { + if (_serverClasses != null) + return; + + //look for a Server attribute with the list of Server classes + //to apply to every web application. If not present, use our defaults. + Server server = getServer(); + if (server != null) + { + Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES); + if (serverClasses != null || serverClasses instanceof String[]) + _serverClasses = ClasspathPattern.fromArray((String[])serverClasses); + } + + if (_serverClasses == null) + _serverClasses = ClasspathPattern.fromArray(__dftServerClasses); + } /* ------------------------------------------------------------ */ /** @@ -644,21 +652,26 @@ public class WebAppContext extends ServletContextHandler return _parentLoaderPriority; } + + /* ------------------------------------------------------------ */ + public String[] getDefaultConfigurationClasses () + { + return __dftConfigurationClasses; + } + + /* ------------------------------------------------------------ */ protected void loadConfigurations() throws Exception { + //if the configuration instances have been set explicitly, use them if (_configurations!=null) return; - //look for a Server attribute with the list of names of Configuration classes - //to apply to every web app. If not present, use our defaults. - String[] serverConfigs = (String[])getServer().getAttribute(SERVER_CONFIG); - if (serverConfigs != null) - _configurationClasses = serverConfigs; - if (_configurationClasses == null) + //if the configuration classnames have been set explicitly use them + if (!_configurationClassesSet) _configurationClasses=__dftConfigurationClasses; - + _configurations = new Configuration[_configurationClasses.length]; for (int i = 0; i < _configurationClasses.length; i++) { @@ -695,6 +708,7 @@ public class WebAppContext extends ServletContextHandler public void setConfigurationClasses(String[] configurations) { _configurationClasses = configurations==null?null:(String[])configurations.clone(); + _configurationClassesSet = true; } /* ------------------------------------------------------------ */ @@ -704,6 +718,7 @@ public class WebAppContext extends ServletContextHandler public void setConfigurations(Configuration[] configurations) { _configurations = configurations==null?null:(Configuration[])configurations.clone(); + _configurationsSet = true; } /* ------------------------------------------------------------ */ @@ -844,7 +859,7 @@ public class WebAppContext extends ServletContextHandler */ public void setServerClasses(String[] serverClasses) { - _serverClasses = serverClasses==null?null:(String[])serverClasses.clone(); + _serverClasses = ClasspathPattern.fromArray(serverClasses); } /* ------------------------------------------------------------ */ @@ -864,7 +879,7 @@ public class WebAppContext extends ServletContextHandler */ public void setSystemClasses(String[] systemClasses) { - _systemClasses = systemClasses==null?null:(String[])systemClasses.clone(); + _systemClasses = ClasspathPattern.fromArray(systemClasses); } @@ -950,19 +965,63 @@ public class WebAppContext extends ServletContextHandler { this._logUrlOnStart = logOnStart; } + + + /* ------------------------------------------------------------ */ + @Override + public void setServer(Server server) + { + super.setServer(server); + //if we haven't been given a set of configuration instances to + //use, and we haven't been given a set of configuration classes + //to use, use the configuration classes that came from the + //Server (if there are any) + if (!_configurationsSet && !_configurationClassesSet && server != null) + { + String[] serverConfigs = (String[])server.getAttribute(SERVER_CONFIG); + if (serverConfigs != null) + setConfigurationClasses(serverConfigs); + } + } /* ------------------------------------------------------------ */ @Override protected void startContext() throws Exception { - - // Configure webapp for (int i=0;i<_configurations.length;i++) _configurations[i].configure(this); - + + //resolve the metadata + ((MetaData)getAttribute(MetaData.METADATA)).resolve(); super.startContext(); } + + /* ------------------------------------------------------------ */ + public class Context extends ServletContextHandler.Context + { + /* ------------------------------------------------------------ */ + public URL getResource(String path) throws MalformedURLException + { + Resource resource=WebAppContext.this.getResource(path); + if (resource==null || !resource.exists()) + return null; + + // Should we go to the original war? + if (resource.isDirectory() && resource instanceof ResourceCollection && !WebAppContext.this.isExtractWAR()) + { + Resource[] resources = ((ResourceCollection)resource).getResources(); + for (int i=resources.length;i-->0;) + { + if (resources[i].getName().startsWith("jar:file")) + return resources[i].getURL(); + } + } + + return resource.getURL(); + } + } + } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 2098b22b56..a4fd810f3f 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -6,9 +6,7 @@ import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.regex.Pattern; import org.eclipse.jetty.server.Connector; @@ -25,6 +23,7 @@ public class WebInfConfiguration implements Configuration public static final String TEMPDIR_CREATED = "org.eclipse.jetty.tmpdirCreated"; public static final String CONTAINER_JAR_RESOURCES = "org.eclipse.jetty.containerJars"; public static final String WEB_INF_JAR_RESOURCES = "org.eclipse.jetty.webInfJars"; + public static final String WEB_INF_ORDERED_JAR_RESOURCES = "org.eclipse.jetty.webInfOrderedJars"; public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern"; public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern"; @@ -139,7 +138,7 @@ public class WebInfConfiguration implements Configuration // Look for classes directory Resource classes= web_inf.addPath("classes/"); if (classes.exists()) - ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes.toString()); + ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes); // Look for jars Resource lib= web_inf.addPath("lib/"); @@ -219,69 +218,53 @@ public class WebInfConfiguration implements Configuration * contents if dir already exists. * </li> * </ol> - * - * @return */ public void resolveTempDirectory (WebAppContext context) { //If a tmp directory is already set, we're done File tmpDir = context.getTempDirectory(); - if (tmpDir!=null && tmpDir.isDirectory() && tmpDir.canWrite()) - return; //Already have a suitable tmp dir configured + if (tmpDir != null && tmpDir.isDirectory() && tmpDir.canWrite()) + { + return; // Already have a suitable tmp dir configured + } - //None configured, try and come up with one - //First ... see if one is configured in a context attribute - //either as a File or name of a file - Object t = context.getAttribute(WebAppContext.TEMPDIR); - if (t != null) + // No temp directory configured, try to establish one. + // First we check the context specific, javax.servlet specified, temp directory attribute + File servletTmpDir = asFile(context.getAttribute(WebAppContext.TEMPDIR)); + if (servletTmpDir != null && servletTmpDir.isDirectory() && servletTmpDir.canWrite()) + { + // Use as tmpDir + tmpDir = servletTmpDir; + // Ensure Attribute has File object + context.setAttribute(WebAppContext.TEMPDIR,tmpDir); + // Set as TempDir in context. + context.setTempDirectory(tmpDir); + return; + } + + try { - //Is it a File? - if (t instanceof File) + // Put the tmp dir in the work directory if we had one + File work = new File(System.getProperty("jetty.home"),"work"); + if (work.exists() && work.canWrite() && work.isDirectory()) { - tmpDir=(File)t; - if (tmpDir.isDirectory() && tmpDir.canWrite()) - { - context.setTempDirectory(tmpDir); - return; - } + makeTempDirectory(work, context, false); //make a tmp dir inside work, don't delete if it exists } - // The context attribute specified a name not a File - if (t instanceof String) + else { - try + File baseTemp = asFile(context.getAttribute(WebAppContext.BASETEMPDIR)); + if (baseTemp != null && baseTemp.isDirectory() && baseTemp.canWrite()) { - tmpDir=new File((String)t); - - if (tmpDir.isDirectory() && tmpDir.canWrite()) - { - context.setAttribute(context.TEMPDIR,tmpDir); - context.setTempDirectory(tmpDir); - return; - } + // Use baseTemp directory (allow the funky Jetty_0_0_0_0.. subdirectory logic to kick in + makeTempDirectory(baseTemp,context,false); } - catch(Exception e) + else { - Log.warn(Log.EXCEPTION,e); + makeTempDirectory(new File(System.getProperty("java.io.tmpdir")),context,true); //make a tmpdir, delete if it already exists } } } - - // Second ... make a tmp directory, in a work directory if one exists - String temp = getCanonicalNameForWebAppTmpDir(context); - - try - { - //Put the tmp dir in the work directory if we had one - File work = new File(System.getProperty("jetty.home"),"work"); - if (!work.exists() || !work.canWrite() || !work.isDirectory()) - work = null; - - if (work!=null) - makeTempDirectory(work, context, false); //make a tmp dir inside work, don't delete if it exists - else - makeTempDirectory(new File(System.getProperty("java.io.tmpdir")), context, true); //make a tmpdir, delete if it already exists - } catch(Exception e) { tmpDir=null; @@ -309,7 +292,31 @@ public class WebInfConfiguration implements Configuration } } - + /** + * Given an Object, return File reference for object. + * Typically used to convert anonymous Object from getAttribute() calls to a File object. + * @param fileattr the file attribute to analyze and return from (supports type File and type String, all others return null) + * @return the File object, null if null, or null if not a File or String + */ + private File asFile(Object fileattr) + { + if (fileattr == null) + { + return null; + } + if (fileattr instanceof File) + { + return (File)fileattr; + } + if (fileattr instanceof String) + { + return new File((String)fileattr); + } + return null; + } + + + public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting) throws IOException { @@ -365,6 +372,7 @@ public class WebInfConfiguration implements Configuration public void unpack (WebAppContext context) throws IOException { Resource web_app = context.getBaseResource(); + _preUnpackBaseResource = context.getBaseResource(); if (web_app == null) { @@ -408,9 +416,12 @@ public class WebInfConfiguration implements Configuration { // look for a sibling like "foo/" to a "foo.war" File warfile=Resource.newResource(war).getFile(); - File sibling = new File(warfile.getParent(),warfile.getName().substring(0,warfile.getName().length()-4)); - if (sibling.exists() && sibling.isDirectory() && sibling.canWrite()) - extractedWebAppDir=sibling; + if (warfile!=null) + { + File sibling = new File(warfile.getParent(),warfile.getName().substring(0,warfile.getName().length()-4)); + if (sibling.exists() && sibling.isDirectory() && sibling.canWrite()) + extractedWebAppDir=sibling; + } } if (extractedWebAppDir==null) @@ -463,7 +474,7 @@ public class WebInfConfiguration implements Configuration Log.debug("webapp=" + web_app); } - _preUnpackBaseResource = context.getBaseResource(); + // Do we need to extract WEB-INF/lib? Resource web_inf= web_app.addPath("WEB-INF/"); @@ -499,7 +510,7 @@ public class WebInfConfiguration implements Configuration web_inf_classes.copyTo(webInfClassesDir); } - web_inf=Resource.newResource(extractedWebInfDir.toURL()); + web_inf=Resource.newResource(extractedWebInfDir.getCanonicalPath()); ResourceCollection rc = new ResourceCollection(new Resource[]{web_inf,web_app}); @@ -530,7 +541,7 @@ public class WebInfConfiguration implements Configuration /** * Check if the tmpDir itself is called "work", or if the tmpDir * is in a directory called "work". - * @return + * @return true if File is a temporary or work directory */ public boolean isTempWorkDirectory (File tmpDir) { @@ -546,13 +557,13 @@ public class WebInfConfiguration implements Configuration /** - * Create a canonical name for a webapp tmp directory. + * Create a canonical name for a webapp temp directory. * The form of the name is: - * "Jetty_"+host+"_"+port+"__"+resourceBase+"_"+context+"_"+virtualhost+base36 hashcode of whole string + * <code>"Jetty_"+host+"_"+port+"__"+resourceBase+"_"+context+"_"+virtualhost+base36_hashcode_of_whole_string</code> * * host and port uniquely identify the server * context and virtual host uniquely identify the webapp - * @return + * @return the canonical name for the webapp temp directory */ public String getCanonicalNameForWebAppTmpDir (WebAppContext context) { @@ -643,7 +654,7 @@ public class WebInfConfiguration implements Configuration /** * Look for jars in WEB-INF/lib * @param context - * @return + * @return the list of jar resources found within context * @throws Exception */ protected List<Resource> findJars (WebAppContext context) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java index 51a07da984..abb952d479 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 2003-2010 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,20 +34,18 @@ public class WebXmlConfiguration implements Configuration /* ------------------------------------------------------------------------------- */ /** - * Process webdefaults.xml + * * * */ public void preConfigure (WebAppContext context) throws Exception { - - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (processor == null) - { - processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); - } - + + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException("No metadata"); + + //parse webdefault.xml String defaultsDescriptor = context.getDefaultsDescriptor(); if (defaultsDescriptor != null && defaultsDescriptor.length() > 0) @@ -55,7 +53,7 @@ public class WebXmlConfiguration implements Configuration Resource dftResource = Resource.newSystemResource(defaultsDescriptor); if (dftResource == null) dftResource = context.newResource(defaultsDescriptor); - processor.parseDefaults (dftResource); + metaData.setDefaults (dftResource); } @@ -63,7 +61,7 @@ public class WebXmlConfiguration implements Configuration Resource webxml = findWebXml(context); if (webxml != null) { - processor.parseWebXml(webxml); + metaData.setWebXml(webxml); } //parse but don't process override-web.xml @@ -73,7 +71,7 @@ public class WebXmlConfiguration implements Configuration Resource orideResource = Resource.newSystemResource(overrideDescriptor); if (orideResource == null) orideResource = context.newResource(overrideDescriptor); - processor.parseOverride(orideResource); + metaData.setOverride(orideResource); } } @@ -90,31 +88,35 @@ public class WebXmlConfiguration implements Configuration if (Log.isDebugEnabled()) Log.debug("Cannot configure webapp after it is started"); return; } + + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException("No metadata"); + + metaData.addDescriptorProcessor(new StandardDescriptorProcessor()); - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (processor == null) + /* + StandardDescriptorProcessor descriptorProcessor = (StandardDescriptorProcessor)context.getAttribute(StandardDescriptorProcessor.STANDARD_PROCESSOR); + if (descriptorProcessor == null) { - processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); + descriptorProcessor = new StandardDescriptorProcessor(metaData); + context.setAttribute(StandardDescriptorProcessor.STANDARD_PROCESSOR, descriptorProcessor); } - //process web-default.xml - processor.process(processor.getWebDefault()); + descriptorProcessor.process(metaData.getWebDefault()); //process web.xml - processor.process(processor.getWebXml()); + descriptorProcessor.process(metaData.getWebXml()); //process override-web.xml - processor.process(processor.getOverrideWeb()); - + descriptorProcessor.process(metaData.getOverrideWeb()); + */ } public void postConfigure(WebAppContext context) throws Exception { - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, null); - context.setAttribute(WebXmlProcessor.METADATA_COMPLETE, null); - context.setAttribute(WebXmlProcessor.WEBXML_CLASSNAMES, null); + context.setAttribute(MetaData.WEBXML_CLASSNAMES, null); } /* ------------------------------------------------------------------------------- */ @@ -154,8 +156,6 @@ public class WebXmlConfiguration implements Configuration context.setEventListeners(null); context.setWelcomeFiles(null); - if (_securityHandler instanceof ConstraintAware) - ((ConstraintAware) _securityHandler).setConstraintMappings(new ConstraintMapping[]{}, Collections.EMPTY_SET); if (context.getErrorHandler() instanceof ErrorPageErrorHandler) ((ErrorPageErrorHandler) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlProcessor.java deleted file mode 100644 index f069e16abd..0000000000 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlProcessor.java +++ /dev/null @@ -1,758 +0,0 @@ -// ======================================================================== -// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== - -package org.eclipse.jetty.webapp; - -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import javax.servlet.Servlet; -import javax.servlet.ServletContext; - -import org.eclipse.jetty.util.Loader; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.xml.XmlParser; - - - - - -/** - * WebXmlProcessor - * - * - */ -public class WebXmlProcessor -{ - public static final String WEB_PROCESSOR = "org.eclipse.jetty.webProcessor"; - public static final String METADATA_COMPLETE = "org.eclipse.jetty.metadataComplete"; - public static final String WEBXML_MAJOR_VERSION = "org.eclipse.jetty.webXmlMajorVersion"; - public static final String WEBXML_MINOR_VERSION = "org.eclipse.jetty.webXmlMinorVersion"; - public static final String WEBXML_CLASSNAMES = "org.eclipse.jetty.webXmlClassNames"; - - public enum Origin {NotSet, WebXml, WebDefaults, WebOverride, WebFragment}; - - protected WebAppContext _context; - protected Map<String, Descriptor> _origins = new HashMap<String,Descriptor>(); - protected Descriptor _webDefaultsRoot; - protected Descriptor _webXmlRoot; - protected Descriptor _webOverrideRoot; - protected List<Fragment> _webFragmentRoots = new ArrayList<Fragment>(); - protected Map<String,Fragment> _webFragmentNameMap = new HashMap<String,Fragment>(); - protected List<Fragment> _orderedFragments = new LinkedList<Fragment>(); - protected XmlParser _parser; - protected Ordering _ordering;//can be set to RelativeOrdering by web-default.xml, web.xml, web-override.xml - protected StandardDescriptorProcessor _standardDescriptorProcessor; - - - - - public static XmlParser newParser() - throws ClassNotFoundException - { - XmlParser xmlParser=new XmlParser(); - //set up cache of DTDs and schemas locally - URL dtd22=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_2.dtd",true); - URL dtd23=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_3.dtd",true); - URL j2ee14xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_1_4.xsd",true); - URL webapp24xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_4.xsd",true); - URL webapp25xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_5.xsd",true); - URL webapp30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_3_0.xsd",true); - URL webcommon30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-common_3_0.xsd",true); - URL webfragment30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-fragment_3_0.xsd",true); - URL schemadtd=Loader.getResource(Servlet.class,"javax/servlet/resources/XMLSchema.dtd",true); - URL xmlxsd=Loader.getResource(Servlet.class,"javax/servlet/resources/xml.xsd",true); - URL webservice11xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_web_services_client_1_1.xsd",true); - URL webservice12xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/javaee_web_services_client_1_2.xsd",true); - URL datatypesdtd=Loader.getResource(Servlet.class,"javax/servlet/resources/datatypes.dtd",true); - - URL jsp20xsd = null; - URL jsp21xsd = null; - - try - { - Class jsp_page = Loader.loadClass(WebXmlConfiguration.class, "javax.servlet.jsp.JspPage"); - jsp20xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_0.xsd"); - jsp21xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_1.xsd"); - } - catch (Exception e) - { - Log.ignore(e); - } - finally - { - if (jsp20xsd == null) jsp20xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_0.xsd", true); - if (jsp21xsd == null) jsp21xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_1.xsd", true); - } - - redirect(xmlParser,"web-app_2_2.dtd",dtd22); - redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22); - redirect(xmlParser,"web.dtd",dtd23); - redirect(xmlParser,"web-app_2_3.dtd",dtd23); - redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23); - redirect(xmlParser,"XMLSchema.dtd",schemadtd); - redirect(xmlParser,"http://www.w3.org/2001/XMLSchema.dtd",schemadtd); - redirect(xmlParser,"-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd); - redirect(xmlParser,"jsp_2_0.xsd",jsp20xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd); - redirect(xmlParser,"j2ee_1_4.xsd",j2ee14xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd); - redirect(xmlParser,"web-app_2_4.xsd",webapp24xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd); - redirect(xmlParser,"web-app_2_5.xsd",webapp25xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd); - redirect(xmlParser,"web-app_3_0.xsd",webapp30xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd",webapp30xsd); - redirect(xmlParser,"web-common_3_0.xsd",webcommon30xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd",webcommon30xsd); - redirect(xmlParser,"web-fragment_3_0.xsd",webfragment30xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd",webfragment30xsd); - redirect(xmlParser,"xml.xsd",xmlxsd); - redirect(xmlParser,"http://www.w3.org/2001/xml.xsd",xmlxsd); - redirect(xmlParser,"datatypes.dtd",datatypesdtd); - redirect(xmlParser,"http://www.w3.org/2001/datatypes.dtd",datatypesdtd); - redirect(xmlParser,"j2ee_web_services_client_1_1.xsd",webservice11xsd); - redirect(xmlParser,"http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",webservice11xsd); - redirect(xmlParser,"javaee_web_services_client_1_2.xsd",webservice12xsd); - redirect(xmlParser,"http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",webservice12xsd); - return xmlParser; - } - - - protected static void redirect(XmlParser parser, String resource, URL source) - { - if (source != null) parser.redirectEntity(resource, source); - } - - /** - * Ordering - * - * - */ - public interface Ordering - { - public List<Fragment> order(); - public boolean isAbsolute (); - } - - /** - * AbsoluteOrdering - * - * An <absolute-order> element in web.xml - */ - public class AbsoluteOrdering implements Ordering - { - public static final String OTHER = "@@-OTHER-@@"; - protected List<String> _order = new ArrayList<String>(); - protected boolean _hasOther = false; - - public List<Fragment> order() - { - List<Fragment> orderedList = new ArrayList<Fragment>(); - - //1. put everything into the list of named others, and take the named ones out of there, - //assuming we will want to use the <other> clause - Map<String,Fragment> others = new HashMap(getNamedFragments()); - - //2. for each name, take out of the list of others, add to tail of list - int index = -1; - for (String item:_order) - { - if (!item.equals(OTHER)) - { - Fragment f = others.remove(item); - if (f != null) - orderedList.add(f); //take from others and put into final list in order, ignoring duplicate names - } - else - index = orderedList.size(); //remember the index at which we want to add in all the others - } - - //3. if <other> was specified, insert the leftovers - if (_hasOther) - orderedList.addAll((index < 0? 0: index), others.values()); - - return orderedList; - } - - public boolean isAbsolute() - { - return true; - } - - public void add (String name) - { - _order.add(name); - } - - public void addOthers () - { - if (_hasOther) - throw new IllegalStateException ("Duplicate <other> element in absolute ordering"); - - _hasOther = true; - _order.add(OTHER); - } - } - - - /** - * RelativeOrdering - * - * A set of <order> elements in web-fragment.xmls. - */ - public class RelativeOrdering implements Ordering - { - protected LinkedList<String> _beforeOthers = new LinkedList<String>(); - protected LinkedList<String> _afterOthers = new LinkedList<String>(); - protected LinkedList<String> _noOthers = new LinkedList<String>(); - - public List<Fragment> order() - { - List<Fragment> orderedList = new ArrayList<Fragment>(); - - int maxIterations = 2; - boolean done = false; - do - { - //1. order the before-others according to any explicit before/after relationships - done = orderList(_beforeOthers); - - //2. order the after-others according to any explicit before/after relationships - done = orderList(_afterOthers); - - //3. order the no-others according to their explicit before/after relationships - done = orderList(_noOthers); - } - while (!done && (--maxIterations >0)); - - //5. merge before-others + no-others +after-others - if (!done) - throw new IllegalStateException("Circular references for fragments"); - - for (String s: _beforeOthers) - orderedList.add(getFragment(s)); - for (String s: _noOthers) - orderedList.add(getFragment(s)); - for(String s: _afterOthers) - orderedList.add(getFragment(s)); - - return orderedList; - } - - public boolean isAbsolute () - { - return false; - } - - public void addBeforeOthers (Fragment d) - { - _beforeOthers.addLast(d.getName()); - } - - public void addAfterOthers (Fragment d) - { - _afterOthers.addLast(d.getName()); - } - - public void addNoOthers (Fragment d) - { - _noOthers.addLast(d.getName()); - } - - protected boolean orderList (LinkedList<String> list) - { - //Take a copy of the list so we can iterate over it and at the same time do random insertions - boolean noChanges = true; - List<String> iterable = new ArrayList(list); - Iterator<String> itor = iterable.iterator(); - - while (itor.hasNext()) - { - String name = itor.next(); - Fragment f = _webFragmentNameMap.get(name); - if (f == null) - throw new IllegalStateException ("No fragment matching name "+name); - - //Handle any explicit <before> relationships for the fragment we're considering - List<String> befores = f.getBefores(); - if (befores != null && !befores.isEmpty()) - { - for (String b: befores) - { - //Fragment we're considering must be before this name - //Check that we are already before it, if not, move us so that we are. - //If the name does not exist in our list, then get it out of the no-other list - - if (!isBefore(list, name, b)) - { - //b is not already before name, move it so that it is - int idx1 = list.indexOf(name); - int idx2 = list.indexOf(b); - - //if b is not in the same list - if (idx2 < 0) - { - // must be in the noOthers list or it would have been an error - _noOthers.remove(b); - - //If its in the no-others list, insert into this list so that we are before it - insert(list, idx1+1, b); - noChanges = false; - } - else - { - //b is in the same list but b is before name, so swap it around - list.remove(name); - insert(list, idx2, name); - noChanges = false; - } - } - } - } - - //Handle any explicit <after> relationships - List<String> afters = f.getAfters(); - if (afters != null && !afters.isEmpty()) - { - for (String a: afters) - { - //Check that name is after a, moving it if possible if its not - if (!isAfter(list, name, a)) - { - //name is not after a, move it - int idx1 = list.indexOf(name); - int idx2 = list.indexOf(a); - - //if a is not in the same list as name - if (idx2 < 0) - { - //take it out of the noOthers list and put it in the right place in this list - _noOthers.remove(a); - insert(list,idx1, a); - noChanges = false; - } - else - { - //a is in the same list as name, but in the wrong place, so move it - list.remove(a); - insert(list,idx1, a); - noChanges = false; - } - } - //Name we're considering must be after this name - //Check we're already after it, if not, move us so that we are. - //If the name does not exist in our list, then get it out of the no-other list - } - } - } - - return noChanges; - } - - /** - * Is a before b? - * @param list - * @param a - * @param b - * @return - */ - protected boolean isBefore (List<String> list, String a, String b) - { - //check if a and b are already in the same list, and b is already - //before a - int idxa = list.indexOf(a); - int idxb = list.indexOf(b); - - - if (idxb >=0 && idxb < idxa) - { - //a and b are in the same list but a is not before b - return false; - } - - if (idxb < 0) - { - //a and b are not in the same list, but it is still possible that a is before - //b, depending on which list we're examining - if (list == _beforeOthers) - { - //The list we're looking at is the beforeOthers.If b is in the _afterOthers or the _noOthers, then by - //definition a is before it - return true; - } - else if (list == _afterOthers) - { - //The list we're looking at is the afterOthers, then a will be the tail of - //the final list. If b is in the beforeOthers list, then b will be before a and an error. - if (_beforeOthers.contains(b)) - throw new IllegalStateException("Incorrect relationship: "+a+" before "+b); - else - return false; //b could be moved to the list - } - } - - //a and b are in the same list and a is already before b - return true; - } - - - /** - * Is a after b? - * @param list - * @param a - * @param b - * @return - */ - protected boolean isAfter(List<String> list, String a, String b) - { - int idxa = list.indexOf(a); - int idxb = list.indexOf(b); - - if (idxb >=0 && idxa < idxb) - { - //a and b are both in the same list, but a is before b - return false; - } - - if (idxb < 0) - { - //a and b are in different lists. a could still be after b depending on which list it is in. - - if (list == _afterOthers) - { - //The list we're looking at is the afterOthers. If b is in the beforeOthers or noOthers then - //by definition a is after b because a is in the afterOthers list. - return true; - } - else if (list == _beforeOthers) - { - //The list we're looking at is beforeOthers, and contains a and will be before - //everything else in the final ist. If b is in the afterOthers list, then a cannot be before b. - if (_afterOthers.contains(b)) - throw new IllegalStateException("Incorrect relationship: "+b+" after "+a); - else - return false; //b could be moved from noOthers list - } - } - - return true; //a and b in the same list, a is after b - } - - protected void insert(List<String> list, int index, String element) - { - if (index > list.size()) - list.add(element); - else - list.add(index, element); - } - } - - - - public WebXmlProcessor (WebAppContext context) throws ClassNotFoundException - { - _context = context; - _parser = newParser(); - } - - public WebAppContext getContext() - { - return _context; - } - - public XmlParser getParser() - { - return _parser; - } - - public void parseDefaults (Resource webDefaults) - throws Exception - { - _webDefaultsRoot = new DefaultsDescriptor(webDefaults, this); - _webDefaultsRoot.parse(); - if (_webDefaultsRoot.isOrdered()) - { - if (_ordering == null) - _ordering = new AbsoluteOrdering(); - - List<String> order = _webDefaultsRoot.getOrdering(); - for (String s:order) - { - if (s.equalsIgnoreCase("others")) - ((AbsoluteOrdering)_ordering).addOthers(); - else - ((AbsoluteOrdering)_ordering).add(s); - } - } - } - - public void parseWebXml (Resource webXml) - throws Exception - { - _webXmlRoot = new Descriptor(webXml, this); - _webXmlRoot.parse(); - _webXmlRoot.processClassNames(); - if (_webXmlRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.True) - _context.setAttribute(METADATA_COMPLETE, Boolean.TRUE); - else - _context.setAttribute(METADATA_COMPLETE, Boolean.FALSE); - _context.getServletContext().setEffectiveMajorVersion(_webXmlRoot.getMajorVersion()); - _context.getServletContext().setEffectiveMinorVersion(_webXmlRoot.getMinorVersion()); - _context.setAttribute(WEBXML_CLASSNAMES, _webXmlRoot.getClassNames()); - - if (_webXmlRoot.isOrdered()) - { - if (_ordering == null) - _ordering = new AbsoluteOrdering(); - - List<String> order = _webXmlRoot.getOrdering(); - for (String s:order) - { - if (s.equalsIgnoreCase("others")) - ((AbsoluteOrdering)_ordering).addOthers(); - else - ((AbsoluteOrdering)_ordering).add(s); - } - } - } - - public void parseOverride (Resource override) - throws Exception - { - _webOverrideRoot = new OverrideDescriptor(override, this); - _webOverrideRoot.setValidating(false); - _webOverrideRoot.parse(); - if (_webOverrideRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.True) - _context.setAttribute(METADATA_COMPLETE, Boolean.TRUE); - else if (_webOverrideRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.False) - _context.setAttribute(METADATA_COMPLETE, Boolean.FALSE); - - if (_webOverrideRoot.isOrdered()) - { - if (_ordering == null) - _ordering = new AbsoluteOrdering(); - - List<String> order = _webOverrideRoot.getOrdering(); - for (String s:order) - { - if (s.equalsIgnoreCase("others")) - ((AbsoluteOrdering)_ordering).addOthers(); - else - ((AbsoluteOrdering)_ordering).add(s); - } - } - } - - - public void parseFragment (Resource fragment) - throws Exception - { - Boolean metaComplete = (Boolean)_context.getAttribute(METADATA_COMPLETE); - if (metaComplete != null && metaComplete.booleanValue()) - return; //do not process anything else if web.xml/web-override.xml set metadata-complete - - //Metadata-complete is not set, or there is no web.xml - Fragment frag = new Fragment(fragment, this); - frag.parse(); - _webFragmentRoots.add(frag); - if (frag.getName() != null) - _webFragmentNameMap.put(frag.getName(), frag); - - //If web.xml has specified an absolute ordering, ignore any relative ordering in the fragment - if (_ordering != null && _ordering.isAbsolute()) - return; - - if (frag.isOrdered()) - { - if (_ordering == null) - _ordering = new RelativeOrdering(); - - switch (frag.getOtherType()) - { - case None: - { - ((RelativeOrdering)_ordering).addNoOthers(frag); - break; - } - case Before: - { - ((RelativeOrdering)_ordering).addBeforeOthers(frag); - break; - } - case After: - { - ((RelativeOrdering)_ordering).addAfterOthers(frag); - break; - } - } - } - } - - - - public void orderFragments () - { - if (_ordering != null) - { - _orderedFragments = _ordering.order(); - - List<String> orderedJars = new ArrayList<String>(); - for (Descriptor frag: _orderedFragments) - { - //get just the name of the jar file - String fullname = frag.getResource().getName(); - int i = fullname.indexOf(".jar"); - int j = fullname.lastIndexOf("/", i); - orderedJars.add(fullname.substring(j+1,i+4)); - } - _context.setAttribute(ServletContext.ORDERED_LIBS, orderedJars); - } - else - _orderedFragments = _webFragmentRoots; - } - - - public void processFragments () - throws Exception - { - //Servlet Spec 3.0 p.74 says all descriptors must say distributable - boolean distributable = ((_webDefaultsRoot != null && _webDefaultsRoot.isDistributable()) - || (_webXmlRoot != null && _webXmlRoot.isDistributable()) - || (_webOverrideRoot != null && _webOverrideRoot.isDistributable())); - for (Fragment frag : _orderedFragments) - { - process(frag); - distributable = distributable && frag.isDistributable(); - } - - _context.setDistributable(distributable); - } - - - - public Descriptor getWebXml () - { - return _webXmlRoot; - } - - public Descriptor getOverrideWeb () - { - return _webOverrideRoot; - } - - public Descriptor getWebDefault () - { - return _webDefaultsRoot; - } - - public List<Fragment> getFragments () - { - return _webFragmentRoots; - } - - public List<Fragment> getOrderedFragments () - { - return _orderedFragments; - } - - public Ordering getOrdering() - { - return _ordering; - } - - public void setOrdering (Ordering o) - { - _ordering = o; - } - - public Fragment getFragment(String name) - { - return _webFragmentNameMap.get(name); - } - - public Map<String,Fragment> getNamedFragments () - { - return Collections.unmodifiableMap(_webFragmentNameMap); - } - - - /** - * Convenience method. Process the standard elements of the web descriptor. - * @param descriptor - * @throws Exception - */ - public void process (Descriptor descriptor) - throws Exception - { - if (descriptor != null) - { - initStandardDescriptorProcessor(); - process(descriptor, _standardDescriptorProcessor); - } - } - - - - /** - * Process the elements of the Descriptor according to the - * given DescriptorProcessor. - * @param descriptor - * @param processor - * @throws Exception - */ - public void process (Descriptor descriptor, DescriptorProcessor processor) - throws Exception - { - if (descriptor != null && processor != null) - processor.process(descriptor); - } - - public Origin getOrigin (String name) - { - Descriptor d = _origins.get(name); - if (d == null) - return Origin.NotSet; - if (d instanceof Fragment) - return Origin.WebFragment; - if (d instanceof OverrideDescriptor) - return Origin.WebOverride; - if (d instanceof DefaultsDescriptor) - return Origin.WebDefaults; - return Origin.WebXml; - } - - public Descriptor getOriginDescriptor (String name) - { - return _origins.get(name); - } - - public void setOrigin (String name, Descriptor d) - { - _origins.put(name, d); - } - - public void initStandardDescriptorProcessor () - { - if (_standardDescriptorProcessor == null) - _standardDescriptorProcessor = new StandardDescriptorProcessor(this); - } -} diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java index cb31c10366..7e20c21da2 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java @@ -13,13 +13,20 @@ package org.eclipse.jetty.webapp; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.webapp.WebXmlProcessor.AbsoluteOrdering; -import org.eclipse.jetty.webapp.WebXmlProcessor.RelativeOrdering; +import org.eclipse.jetty.webapp.MetaData.AbsoluteOrdering; +import org.eclipse.jetty.webapp.MetaData.RelativeOrdering; /** * OrderingTest @@ -28,193 +35,415 @@ import org.eclipse.jetty.webapp.WebXmlProcessor.RelativeOrdering; */ public class OrderingTest extends TestCase { + public class TestResource extends Resource + { + public String _name; + + public TestResource (String name) + { + _name =name; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#addPath(java.lang.String) + */ + public Resource addPath(String path) throws IOException, MalformedURLException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#delete() + */ + public boolean delete() throws SecurityException + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#exists() + */ + public boolean exists() + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getFile() + */ + public File getFile() throws IOException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getInputStream() + */ + public InputStream getInputStream() throws IOException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getName() + */ + public String getName() + { + return _name; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getOutputStream() + */ + public OutputStream getOutputStream() throws IOException, SecurityException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getURL() + */ + public URL getURL() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#isContainedIn(org.eclipse.jetty.util.resource.Resource) + */ + public boolean isContainedIn(Resource r) throws MalformedURLException + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#isDirectory() + */ + public boolean isDirectory() + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#lastModified() + */ + public long lastModified() + { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#length() + */ + public long length() + { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#list() + */ + public String[] list() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#release() + */ + public void release() + { + // TODO Auto-generated method stub + + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#renameTo(org.eclipse.jetty.util.resource.Resource) + */ + public boolean renameTo(Resource dest) throws SecurityException + { + // TODO Auto-generated method stub + return false; + } + + } + + public void testRelativeOrdering0 () throws Exception { //Example from ServletSpec p.70 WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new RelativeOrdering(); + MetaData metaData = new MetaData(wac); + List<Resource> resources = new ArrayList<Resource>(); + metaData._ordering = metaData.new RelativeOrdering(); //A: after others, after C - Fragment f1 = new Fragment((Resource)null, processor); + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); f1._name = "A"; - processor._webFragmentNameMap.put(f1._name, f1); - f1._hasOther=true; - ((RelativeOrdering)processor._ordering).addAfterOthers(f1); + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + f1._otherType = FragmentDescriptor.OtherType.After; + //((RelativeOrdering)metaData._ordering).addAfterOthers(r1); f1._afters.add("C"); //B: before others - Fragment f2 = new Fragment((Resource)null, processor); + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); f2._name="B"; - processor._webFragmentNameMap.put(f2._name, f2); - f2._hasOther = true; - ((RelativeOrdering)processor._ordering).addBeforeOthers(f2); + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + f2._otherType = FragmentDescriptor.OtherType.Before; + //((RelativeOrdering)metaData._ordering).addBeforeOthers(r2); //C: after others - Fragment f3 = new Fragment((Resource)null, processor); + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); f3._name="C"; - processor._webFragmentNameMap.put(f3._name, f3); - ((RelativeOrdering)processor._ordering).addAfterOthers(f3); + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3, f3); + f3._otherType = FragmentDescriptor.OtherType.After; + //((RelativeOrdering)metaData._ordering).addAfterOthers(r3); //D: no ordering - Fragment f4 = new Fragment((Resource)null, processor); + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData); f4._name="D"; - processor._webFragmentNameMap.put(f4._name, f4); - ((RelativeOrdering)processor._ordering).addNoOthers(f4); - - //E: no ordering - Fragment f5 = new Fragment((Resource)null, processor); + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4, f4); + f4._otherType = FragmentDescriptor.OtherType.None; + //((RelativeOrdering)metaData._ordering).addNoOthers(r4); + + //E: no ordering + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData); f5._name="E"; - processor._webFragmentNameMap.put(f5._name, f5); - ((RelativeOrdering)processor._ordering).addNoOthers(f5); + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5, f5); + f5._otherType = FragmentDescriptor.OtherType.None; + //((RelativeOrdering)metaData._ordering).addNoOthers(r5); //F: before others, before B - Fragment f6 = new Fragment((Resource)null, processor); + TestResource jar6 = new TestResource("F"); + resources.add(jar6); + TestResource r6 = new TestResource("F/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData); f6._name="F"; - processor._webFragmentNameMap.put(f6._name, f6); - f6._hasOther=true; - ((RelativeOrdering)processor._ordering).addBeforeOthers(f6); + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6,f6); + f6._otherType = FragmentDescriptor.OtherType.Before; + //((RelativeOrdering)metaData._ordering).addBeforeOthers(r6); f6._befores.add("B"); - /* - * p.70 outcome: F, B, D, E, C, A - */ + // + // p.70 outcome: F, B, D, E, C, A + // String[] outcomes = {"FBDECA"}; - List<Fragment> orderedList = processor._ordering.order(); + List<Resource> orderedList = metaData._ordering.order(resources); String result = ""; - for (Fragment f:orderedList) - result+=(f._name); - + for (Resource r:orderedList) + result+=(((TestResource)r)._name); + if (!checkResult(result, outcomes)) fail("No outcome matched "+result); } - + + public void testRelativeOrdering1 () throws Exception { + List<Resource> resources = new ArrayList<Resource>(); WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new RelativeOrdering(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); //Example from ServletSpec p.70-71 //No name: after others, before C - Fragment f1 = new Fragment((Resource)null, processor); - f1._name = Fragment.NAMELESS+"1"; - processor._webFragmentNameMap.put(f1._name, f1); - f1._hasOther=true; - ((RelativeOrdering)processor._ordering).addAfterOthers(f1); + TestResource jar1 = new TestResource("plain"); + resources.add(jar1); + TestResource r1 = new TestResource("plain/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = FragmentDescriptor.NAMELESS+"1"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); + f1._otherType = FragmentDescriptor.OtherType.After; + //((RelativeOrdering)metaData._ordering).addAfterOthers(f1); f1._befores.add("C"); //B: before others - Fragment f2 = new Fragment((Resource)null, processor); + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); f2._name="B"; - processor._webFragmentNameMap.put(f2._name, f2); - f2._hasOther = true; - ((RelativeOrdering)processor._ordering).addBeforeOthers(f2); + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + f2._otherType = FragmentDescriptor.OtherType.Before; + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f2); //C: no ordering - Fragment f3 = new Fragment((Resource)null, processor); + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); f3._name="C"; - processor._webFragmentNameMap.put(f3._name, f3); - ((RelativeOrdering)processor._ordering).addNoOthers(f3); + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addNoOthers(f3); + f3._otherType = FragmentDescriptor.OtherType.None; //D: after others - Fragment f4 = new Fragment((Resource)null, processor); + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData); f4._name="D"; - processor._webFragmentNameMap.put(f4._name, f4); - f4._hasOther = true; - ((RelativeOrdering)processor._ordering).addAfterOthers(f4); + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4,f4); + //((RelativeOrdering)metaData._ordering).addAfterOthers(f4); + f4._otherType = FragmentDescriptor.OtherType.After; //E: before others - Fragment f5 = new Fragment((Resource)null, processor); + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData); f5._name="E"; - processor._webFragmentNameMap.put(f5._name, f5); - f5._hasOther=true; - ((RelativeOrdering)processor._ordering).addBeforeOthers(f5); + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5,f5); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f5); + f5._otherType = FragmentDescriptor.OtherType.Before; //F: no ordering - Fragment f6 = new Fragment((Resource)null, processor); + TestResource jar6 = new TestResource("F"); + resources.add(jar6); + TestResource r6 = new TestResource("F/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData); f6._name="F"; - processor._webFragmentNameMap.put(f6._name, f6); - ((RelativeOrdering)processor._ordering).addNoOthers(f6); + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6,f6); + //((RelativeOrdering)metaData._ordering).addNoOthers(f6); + f6._otherType = FragmentDescriptor.OtherType.None; - List<Fragment> orderedList = processor._ordering.order(); + List<Resource> orderedList = metaData._ordering.order(resources); - /* p.70-71 Possible outcomes are: - * B, E, F, noname, C, D - * B, E, F, noname, D, C - * E, B, F, noname, C, D - * E, B, F, noname, D, C - * E, B, F, D, noname, C - */ - String[] outcomes = {"BEF"+f1._name+"CD", - "BEF"+ f1._name+ "DC", - "EBF"+ f1._name+ "CD", - "EBF"+ f1._name+ "DC", - "EBFD"+ f1._name}; + // p.70-71 Possible outcomes are: + // B, E, F, noname, C, D + // B, E, F, noname, D, C + // E, B, F, noname, C, D + // E, B, F, noname, D, C + // E, B, F, D, noname, C + // + String[] outcomes = {"BEFplainCD", + "BEFplainDC", + "EBFplainCD", + "EBFplainDC", + "EBFDplain"}; String orderedNames = ""; - for (Fragment f:orderedList) - orderedNames+=(f._name); + for (Resource r:orderedList) + orderedNames+=(((TestResource)r)._name); - if (!checkResult(orderedNames, outcomes)) fail("No outcome matched "+orderedNames); } + public void testRelativeOrdering2 () throws Exception { + List<Resource> resources = new ArrayList<Resource>(); WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new RelativeOrdering(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); //Example from Spec p. 71-72 //A: after B - Fragment f1 = new Fragment((Resource)null, processor); + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); f1._name = "A"; - processor._webFragmentNameMap.put(f1._name, f1); - ((RelativeOrdering)processor._ordering).addNoOthers(f1); + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + //((RelativeOrdering)metaData._ordering).addNoOthers(f1); + f1._otherType = FragmentDescriptor.OtherType.None; f1._afters.add("B"); //B: no order - Fragment f2 = new Fragment((Resource)null, processor); + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); f2._name="B"; - processor._webFragmentNameMap.put(f2._name, f2); - ((RelativeOrdering)processor._ordering).addNoOthers(f2); + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + //((RelativeOrdering)metaData._ordering).addNoOthers(f2); + f2._otherType = FragmentDescriptor.OtherType.None; //C: before others - Fragment f3 = new Fragment((Resource)null, processor); + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); f3._name="C"; - processor._webFragmentNameMap.put(f3._name, f3); - ((RelativeOrdering)processor._ordering).addBeforeOthers(f3); + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f3); + f3._otherType = FragmentDescriptor.OtherType.Before; //D: no order - Fragment f4 = new Fragment((Resource)null, processor); + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData); f4._name="D"; - processor._webFragmentNameMap.put(f4._name, f4); - ((RelativeOrdering)processor._ordering).addNoOthers(f4); - - /* - * p.71-72 possible outcomes are: - * C,B,D,A - * C,D,B,A - * C,B,A,D - */ + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4, f4); + //((RelativeOrdering)metaData._ordering).addNoOthers(f4); + f4._otherType = FragmentDescriptor.OtherType.None; + // + // p.71-72 possible outcomes are: + // C,B,D,A + // C,D,B,A + // C,B,A,D + // String[] outcomes = {"CBDA", "CDBA", "CBAD"}; - List<Fragment> orderedList = processor._ordering.order(); + List<Resource> orderedList = metaData._ordering.order(resources); String result = ""; - for (Fragment f:orderedList) - result+=(f._name); + for (Resource r:orderedList) + result+=(((TestResource)r)._name); if (!checkResult(result, outcomes)) fail ("No outcome matched "+result); @@ -224,73 +453,96 @@ public class OrderingTest extends TestCase public void testRelativeOrdering3 () throws Exception { + List<Resource> resources = new ArrayList<Resource>(); WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new RelativeOrdering(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); //A: after others, before C - Fragment f1 = new Fragment((Resource)null, processor); + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); f1._name = "A"; - processor._webFragmentNameMap.put(f1._name, f1); - f1._hasOther=true; - ((RelativeOrdering)processor._ordering).addAfterOthers(f1); + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + //((RelativeOrdering)metaData._ordering).addAfterOthers(f1); + f1._otherType = FragmentDescriptor.OtherType.After; f1._befores.add("C"); //B: before others, before C - Fragment f2 = new Fragment((Resource)null, processor); + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); f2._name="B"; - processor._webFragmentNameMap.put(f2._name, f2); - f2._hasOther = true; - ((RelativeOrdering)processor._ordering).addBeforeOthers(f2); + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f2); + f2._otherType = FragmentDescriptor.OtherType.Before; f2._befores.add("C"); //C: no ordering - Fragment f3 = new Fragment((Resource)null, processor); + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); f3._name="C"; - processor._webFragmentNameMap.put(f3._name, f3); - ((RelativeOrdering)processor._ordering).addNoOthers(f3); + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addNoOthers(f3); + f3._otherType = FragmentDescriptor.OtherType.None; //result: BAC String[] outcomes = {"BAC"}; - List<Fragment> orderedList = processor._ordering.order(); + List<Resource> orderedList = metaData._ordering.order(resources); String result = ""; - for (Fragment f:orderedList) - result+=(f._name); + for (Resource r:orderedList) + result+=(((TestResource)r)._name); if (!checkResult(result, outcomes)) fail ("No outcome matched "+result); } - - + public void testCircular1 () throws Exception { //A: after B //B: after A - + List<Resource> resources = new ArrayList<Resource>(); WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new RelativeOrdering(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); //A: after B - Fragment f1 = new Fragment((Resource)null, processor); + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); f1._name = "A"; - processor._webFragmentNameMap.put(f1._name, f1); - ((RelativeOrdering)processor._ordering).addNoOthers(f1); + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + //((RelativeOrdering)metaData._ordering).addNoOthers(f1); + f1._otherType = FragmentDescriptor.OtherType.None; f1._afters.add("B"); //B: after A - Fragment f2 = new Fragment((Resource)null, processor); + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); f2._name="B"; - processor._webFragmentNameMap.put(f2._name, f2); - ((RelativeOrdering)processor._ordering).addNoOthers(f2); + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + //((RelativeOrdering)metaData._ordering).addNoOthers(f2); + f2._otherType = FragmentDescriptor.OtherType.None; f2._afters.add("A"); try { - List<Fragment> orderedList = processor._ordering.order(); + List<Resource> orderedList = metaData._ordering.order(resources); fail("No circularity detected"); } catch (Exception e) @@ -300,38 +552,58 @@ public class OrderingTest extends TestCase } + + public void testInvalid1 () throws Exception { + List<Resource> resources = new ArrayList<Resource>(); WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new RelativeOrdering(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); //A: after others, before C - Fragment f1 = new Fragment((Resource)null, processor); + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); f1._name = "A"; - processor._webFragmentNameMap.put(f1._name, f1); - f1._hasOther=true; - ((RelativeOrdering)processor._ordering).addAfterOthers(f1); + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); + //((RelativeOrdering)metaData._ordering).addAfterOthers(r1); + f1._otherType = FragmentDescriptor.OtherType.After; f1._befores.add("C"); //B: before others, after C - Fragment f2 = new Fragment((Resource)null, processor); + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); f2._name="B"; - processor._webFragmentNameMap.put(f2._name, f2); - f2._hasOther = true; - ((RelativeOrdering)processor._ordering).addBeforeOthers(f2); + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(r2); + f2._otherType = FragmentDescriptor.OtherType.Before; f2._afters.add("C"); //C: no ordering - Fragment f3 = new Fragment((Resource)null, processor); + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); f3._name="C"; - processor._webFragmentNameMap.put(f3._name, f3); - ((RelativeOrdering)processor._ordering).addNoOthers(f3); + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addNoOthers(r3); + f3._otherType = FragmentDescriptor.OtherType.None; try { - List<Fragment> orderedList = processor._ordering.order(); + List<Resource> orderedList = metaData._ordering.order(resources); + String result = ""; + for (Resource r:orderedList) + result +=((TestResource)r)._name; + System.err.println("Invalid Result = "+result); fail("A and B have an impossible relationship to C"); } catch (Exception e) @@ -344,111 +616,316 @@ public class OrderingTest extends TestCase public void testAbsoluteOrdering1 () throws Exception { - /* - * A,B,C,others - */ + // + // A,B,C,others + // + List<Resource> resources = new ArrayList<Resource>(); WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new AbsoluteOrdering(); - ((AbsoluteOrdering)processor._ordering).add("A"); - ((AbsoluteOrdering)processor._ordering).add("B"); - ((AbsoluteOrdering)processor._ordering).add("C"); - ((AbsoluteOrdering)processor._ordering).addOthers(); - - Fragment f1 = new Fragment((Resource)null, processor); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new AbsoluteOrdering(); + ((AbsoluteOrdering)metaData._ordering).add("A"); + ((AbsoluteOrdering)metaData._ordering).add("B"); + ((AbsoluteOrdering)metaData._ordering).add("C"); + ((AbsoluteOrdering)metaData._ordering).addOthers(); + + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); f1._name = "A"; - processor._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); - Fragment f2 = new Fragment((Resource)null, processor); + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); f2._name="B"; - processor._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); - Fragment f3 = new Fragment((Resource)null, processor); + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); f3._name="C"; - processor._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3, f3); - Fragment f4 = new Fragment((Resource)null, processor); + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor((Resource)null, metaData); f4._name="D"; - processor._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4, f4); - Fragment f5 = new Fragment((Resource)null, processor); + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor((Resource)null, metaData); f5._name="E"; - processor._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5, f5); - Fragment f6 = new Fragment((Resource)null, processor); - f6._name=Fragment.NAMELESS+"1"; - processor._webFragmentNameMap.put(f6._name, f6); + TestResource jar6 = new TestResource("plain"); + resources.add(jar6); + TestResource r6 = new TestResource ("plain/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor((Resource)null, metaData); + f6._name=FragmentDescriptor.NAMELESS+"1"; + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6, f6); - List<Fragment> list = processor._ordering.order(); + List<Resource> list = metaData._ordering.order(resources); - String[] outcomes = {"ABCDE"+f6._name}; + String[] outcomes = {"ABCDEplain"}; String result = ""; - for (Fragment f:list) - result += f._name; + for (Resource r:list) + result += ((TestResource)r)._name; if (!checkResult(result, outcomes)) fail("No outcome matched "+result); } - + public void testAbsoluteOrdering2 () throws Exception { - // A,B,C - WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new AbsoluteOrdering(); - ((AbsoluteOrdering)processor._ordering).add("A"); - ((AbsoluteOrdering)processor._ordering).add("B"); - ((AbsoluteOrdering)processor._ordering).add("C"); + // C,B,A + List<Resource> resources = new ArrayList<Resource>(); - Fragment f1 = new Fragment((Resource)null, processor); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new AbsoluteOrdering(); + ((AbsoluteOrdering)metaData._ordering).add("C"); + ((AbsoluteOrdering)metaData._ordering).add("B"); + ((AbsoluteOrdering)metaData._ordering).add("A"); + + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); f1._name = "A"; - processor._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); - Fragment f2 = new Fragment((Resource)null, processor); + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); f2._name="B"; - processor._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); - Fragment f3 = new Fragment((Resource)null, processor); + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); f3._name="C"; - processor._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); - Fragment f4 = new Fragment((Resource)null, processor); + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData); f4._name="D"; - processor._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4,f4); - Fragment f5 = new Fragment((Resource)null, processor); + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData); f5._name="E"; - processor._webFragmentNameMap.put(f5._name, f5); - - Fragment f6 = new Fragment((Resource)null, processor); - f6._name=Fragment.NAMELESS+"1"; - processor._webFragmentNameMap.put(f6._name, f6); - - List<Fragment> list = processor._ordering.order(); - String[] outcomes = {"ABC"}; + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5,f5); + + TestResource jar6 = new TestResource("plain"); + resources.add(jar6); + TestResource r6 = new TestResource("plain/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData); + f6._name=FragmentDescriptor.NAMELESS+"1"; + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6,f6); + + List<Resource> list = metaData._ordering.order(resources); + String[] outcomes = {"CBA"}; String result = ""; - for (Fragment f:list) - result += f._name; + for (Resource r:list) + result += ((TestResource)r)._name; + if (!checkResult(result, outcomes)) fail("No outcome matched "+result); } - + public void testAbsoluteOrdering3 () throws Exception { //empty <absolute-ordering> WebAppContext wac = new WebAppContext(); - WebXmlProcessor processor = new WebXmlProcessor(wac); - processor._ordering = processor.new AbsoluteOrdering(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new AbsoluteOrdering(); + List<Resource> resources = new ArrayList<Resource>(); + + resources.add(new TestResource("A")); + resources.add(new TestResource("B")); - List<Fragment> list = processor._ordering.order(); + List<Resource> list = metaData._ordering.order(resources); assertTrue(list.isEmpty()); } + + public void testRelativeOrderingWithPlainJars () + throws Exception + { + //B,A,C other jars with no fragments + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); + + //A: after others, before C + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + //((RelativeOrdering)metaData._ordering).addAfterOthers(f1); + f1._otherType = FragmentDescriptor.OtherType.After; + f1._befores.add("C"); + + //B: before others, before C + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f2); + f2._otherType = FragmentDescriptor.OtherType.Before; + f2._befores.add("C"); + + //C: after A + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addNoOthers(f3); + f3._otherType = FragmentDescriptor.OtherType.None; + f3._afters.add("A"); + + //No fragment jar 1 + TestResource r4 = new TestResource("plain1"); + resources.add(r4); + + //No fragment jar 2 + TestResource r5 = new TestResource("plain2"); + resources.add(r5); + + //result: BAC + String[] outcomes = {"Bplain1plain2AC"}; + + List<Resource> orderedList = metaData._ordering.order(resources); + String result = ""; + for (Resource r:orderedList) + result+=(((TestResource)r)._name); + + if (!checkResult(result, outcomes)) + fail ("No outcome matched "+result); + } + + public void testAbsoluteOrderingWithPlainJars() + throws Exception + { + // + // A,B,C,others + // + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new AbsoluteOrdering(); + ((AbsoluteOrdering)metaData._ordering).add("A"); + ((AbsoluteOrdering)metaData._ordering).add("B"); + ((AbsoluteOrdering)metaData._ordering).add("C"); + ((AbsoluteOrdering)metaData._ordering).addOthers(); + + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); + + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3, f3); + + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor((Resource)null, metaData); + f4._name="D"; + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4, f4); + + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor((Resource)null, metaData); + f5._name="E"; + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5, f5); + + TestResource jar6 = new TestResource("plain"); + resources.add(jar6); + TestResource r6 = new TestResource("plain/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor((Resource)null, metaData); + f6._name=FragmentDescriptor.NAMELESS+"1"; + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6, f6); + + //plain jar + TestResource r7 = new TestResource("plain1"); + resources.add(r7); + + TestResource r8 = new TestResource("plain2"); + resources.add(r8); + + List<Resource> list = metaData._ordering.order(resources); + + String[] outcomes = {"ABCDEplainplain1plain2"}; + String result = ""; + for (Resource r:list) + result += ((TestResource)r)._name; + + if (!checkResult(result, outcomes)) + fail("No outcome matched "+result); + } + + + public boolean checkResult (String result, String[] outcomes) { boolean matched = false; diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java index 9a8db2c868..469a28b091 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java @@ -2,62 +2,61 @@ package org.eclipse.jetty.webapp; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.Enumeration; import java.util.List; import org.eclipse.jetty.util.resource.Resource; +import org.junit.Before; +import org.junit.Test; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -public class WebAppClassLoaderTest extends TestCase +public class WebAppClassLoaderTest { - WebAppContext _context; - WebAppClassLoader _loader; - - /* ------------------------------------------------------------ */ - /** - * @see junit.framework.TestCase#setUp() - */ - @Override - protected void setUp() throws Exception + private WebAppContext _context; + private WebAppClassLoader _loader; + + @Before + public void init() throws Exception { Resource webapp = Resource.newResource("./src/test/webapp"); - + _context = new WebAppContext(); _context.setBaseResource(webapp); _context.setContextPath("/test"); - + _loader = new WebAppClassLoader(_context); _loader.addJars(webapp.addPath("WEB-INF/lib")); - _loader.addClassPath(webapp.addPath("WEB-INF/classes").toString()); + _loader.addClassPath(webapp.addPath("WEB-INF/classes")); _loader.setName("test"); - } - - + + @Test public void testParentLoad() throws Exception { _context.setParentLoaderPriority(true); assertTrue(canLoadClass("org.acme.webapp.ClassInJarA")); assertTrue(canLoadClass("org.acme.webapp.ClassInJarB")); assertTrue(canLoadClass("org.acme.other.ClassInClassesC")); - - assertFalse(canLoadClass("org.eclipse.jetty.webapp.Configuration")); - + + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration")); + Class clazzA = _loader.loadClass("org.acme.webapp.ClassInJarA"); assertTrue(clazzA.getField("FROM_PARENT")!=null); } - + + @Test public void testWebAppLoad() throws Exception { _context.setParentLoaderPriority(false); assertTrue(canLoadClass("org.acme.webapp.ClassInJarA")); assertTrue(canLoadClass("org.acme.webapp.ClassInJarB")); assertTrue(canLoadClass("org.acme.other.ClassInClassesC")); - - assertFalse(canLoadClass("org.eclipse.jetty.webapp.Configuration")); - + + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration")); + Class<?> clazzA = _loader.loadClass("org.acme.webapp.ClassInJarA"); try { @@ -69,7 +68,8 @@ public class WebAppClassLoaderTest extends TestCase assertTrue(true); } } - + + @Test public void testExposedClass() throws Exception { String[] oldSC=_context.getServerClasses(); @@ -77,15 +77,16 @@ public class WebAppClassLoaderTest extends TestCase newSC[0]="-org.eclipse.jetty.webapp.Configuration"; System.arraycopy(oldSC,0,newSC,1,oldSC.length); _context.setServerClasses(newSC); - + assertTrue(canLoadClass("org.acme.webapp.ClassInJarA")); assertTrue(canLoadClass("org.acme.webapp.ClassInJarB")); assertTrue(canLoadClass("org.acme.other.ClassInClassesC")); - + assertTrue(canLoadClass("org.eclipse.jetty.webapp.Configuration")); - assertFalse(canLoadClass("org.eclipse.jetty.webapp.JarScanner")); + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.JarScanner")); } - + + @Test public void testSystemServerClass() throws Exception { String[] oldServC=_context.getServerClasses(); @@ -93,32 +94,33 @@ public class WebAppClassLoaderTest extends TestCase newServC[0]="org.eclipse.jetty.webapp.Configuration"; System.arraycopy(oldServC,0,newServC,1,oldServC.length); _context.setServerClasses(newServC); - + String[] oldSysC=_context.getSystemClasses(); String[] newSysC=new String[oldSysC.length+1]; newSysC[0]="org.eclipse.jetty.webapp."; System.arraycopy(oldSysC,0,newSysC,1,oldSysC.length); _context.setSystemClasses(newSysC); - + assertTrue(canLoadClass("org.acme.webapp.ClassInJarA")); assertTrue(canLoadClass("org.acme.webapp.ClassInJarB")); assertTrue(canLoadClass("org.acme.other.ClassInClassesC")); - - assertFalse(canLoadClass("org.eclipse.jetty.webapp.Configuration")); - assertFalse(canLoadClass("org.eclipse.jetty.webapp.JarScanner")); + + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration")); + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.JarScanner")); } - + + @Test public void testResources() throws Exception { List<URL> resources; - + _context.setParentLoaderPriority(false); resources =toList( _loader.getResources("org/acme/resource.txt")); assertEquals(3,resources.size()); assertEquals(0,resources.get(0).toString().indexOf("jar:file:")); assertEquals(-1,resources.get(1).toString().indexOf("test-classes")); assertEquals(0,resources.get(2).toString().indexOf("file:")); - + _context.setParentLoaderPriority(true); resources =toList( _loader.getResources("org/acme/resource.txt")); assertEquals(3,resources.size()); @@ -150,7 +152,7 @@ public class WebAppClassLoaderTest extends TestCase assertEquals(1,resources.size()); assertEquals(0,resources.get(0).toString().indexOf("file:")); } - + private List<URL> toList(Enumeration<URL> e) { List<URL> list = new ArrayList<URL>(); @@ -159,15 +161,20 @@ public class WebAppClassLoaderTest extends TestCase return list; } - private boolean canLoadClass(String clazz) + private boolean canLoadClass(String clazz) throws ClassNotFoundException + { + return _loader.loadClass(clazz)!=null; + } + + private boolean cantLoadClass(String clazz) { try { - return _loader.loadClass(clazz)!=null; + return _loader.loadClass(clazz)==null; } catch(ClassNotFoundException e) { - return false; + return true; } } } diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java new file mode 100644 index 0000000000..4fe342a346 --- /dev/null +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java @@ -0,0 +1,79 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.webapp; + +import java.util.Arrays; + +import org.eclipse.jetty.server.Server; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class WebAppContextTest +{ + @Test + public void testConfigurationClassesFromDefault () + { + Server server = new Server(); + //test if no classnames set, its the defaults + WebAppContext wac = new WebAppContext(); + assertNull(wac.getConfigurations()); + String[] classNames = wac.getConfigurationClasses(); + assertNotNull(classNames); + + //test if no classname set, and none from server its the defaults + wac.setServer(server); + assertTrue(Arrays.equals(classNames, wac.getConfigurationClasses())); + } + + @Test + public void testConfigurationClassesExplicit () + { + String[] classNames = {"x.y.z"}; + + Server server = new Server(); + server.setAttribute(WebAppContext.SERVER_CONFIG, classNames); + + //test an explicitly set classnames list overrides that from the server + WebAppContext wac = new WebAppContext(); + String[] myClassNames = {"a.b.c", "d.e.f"}; + wac.setConfigurationClasses(myClassNames); + wac.setServer(server); + String[] names = wac.getConfigurationClasses(); + assertTrue(Arrays.equals(myClassNames, names)); + + + //test if no explicit classnames, they come from the server + WebAppContext wac2 = new WebAppContext(); + wac2.setServer(server); + assertTrue(Arrays.equals(classNames, wac2.getConfigurationClasses())); + } + + @Test + public void testConfigurationInstances () + { + Configuration[] configs = {new WebInfConfiguration()}; + WebAppContext wac = new WebAppContext(); + wac.setConfigurations(configs); + assertTrue(Arrays.equals(configs, wac.getConfigurations())); + + //test that explicit config instances override any from server + String[] classNames = {"x.y.z"}; + Server server = new Server(); + server.setAttribute(WebAppContext.SERVER_CONFIG, classNames); + wac.setServer(server); + assertTrue(Arrays.equals(configs,wac.getConfigurations())); + } +} diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index cc3b9388db..195db55bf6 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -20,6 +20,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> @@ -61,16 +62,17 @@ </execution> </executions> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature - with a snapshot. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.websocket.*</onlyAnalyze> + </configuration> </plugin> </plugins> </build> diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnection.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnection.java index 5903481976..4da7611506 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnection.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnection.java @@ -1,13 +1,22 @@ package org.eclipse.jetty.websocket; import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.zip.Checksum; +import org.eclipse.jetty.http.HttpParser; +import org.eclipse.jetty.http.security.Credential.MD5; import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.nio.IndirectNIOBuffer; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.thread.Timeout; public class WebSocketConnection implements Connection, WebSocket.Outbound { @@ -17,11 +26,26 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound final WebSocketGenerator _generator; final long _timestamp; final WebSocket _websocket; - final int _maxIdleTimeMs=300000; + String _key1; + String _key2; + ByteArrayBuffer _hixie; - public WebSocketConnection(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, long maxIdleTime) + public WebSocketConnection(WebSocket websocket, EndPoint endpoint) + throws IOException { + this(websocket,endpoint,new WebSocketBuffers(8192),System.currentTimeMillis(),300000); + } + + public WebSocketConnection(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime) + throws IOException + { + // TODO - can we use the endpoint idle mechanism? + if (endpoint instanceof AsyncEndPoint) + ((AsyncEndPoint)endpoint).cancelIdle(); + _endp = endpoint; + _endp.setMaxIdleTime(maxIdleTime); + _timestamp = timestamp; _websocket = websocket; _generator = new WebSocketGenerator(buffers, _endp); @@ -71,10 +95,10 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound { public void access(EndPoint endp) { - scep.getSelectSet().scheduleTimeout(scep.getTimeoutTask(),_maxIdleTimeMs); + scep.scheduleIdle(); } }; - scep.getSelectSet().scheduleTimeout(scep.getTimeoutTask(),_maxIdleTimeMs); + scep.scheduleIdle(); } else { @@ -85,6 +109,13 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound }; } } + + public void setHixieKeys(String key1,String key2) + { + _key1=key1; + _key2=key2; + _hixie=new IndirectNIOBuffer(16); + } public Connection handle() throws IOException { @@ -92,6 +123,53 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound try { + // handle stupid hixie random bytes + if (_hixie!=null) + { + while(progress) + { + // take bytes from the parser buffer. + if (_parser.getBuffer().length()>0) + { + int l=_parser.getBuffer().length(); + if (l>8) + l=8; + _hixie.put(_parser.getBuffer().peek(_parser.getBuffer().getIndex(),l)); + _parser.getBuffer().skip(l); + progress=true; + } + + // do we have enough? + if (_hixie.length()<8) + { + // no, then let's fill + int filled=_endp.fill(_hixie); + progress |= filled>0; + + if (filled<0) + { + _endp.close(); + break; + } + } + + // do we now have enough + if (_hixie.length()==8) + { + // we have the silly random bytes + // so let's work out the stupid 16 byte reply. + doTheHixieHixieShake(); + _endp.flush(_hixie); + _hixie=null; + _endp.flush(); + break; + } + } + + return this; + } + + // handle the framing protocol while (progress) { int flushed=_generator.flush(); @@ -108,7 +186,6 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound } catch(IOException e) { - e.printStackTrace(); throw e; } finally @@ -125,6 +202,16 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound return this; } + private void doTheHixieHixieShake() + { + byte[] result=WebSocketGenerator.doTheHixieHixieShake( + WebSocketParser.hixieCrypt(_key1), + WebSocketParser.hixieCrypt(_key2), + _hixie.asArray()); + _hixie.clear(); + _hixie.put(result); + } + public boolean isOpen() { return _endp!=null&&_endp.isOpen(); @@ -152,7 +239,7 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound public void sendMessage(byte frame, String content) throws IOException { - _generator.addFrame(frame,content,_maxIdleTimeMs); + _generator.addFrame(frame,content,_endp.getMaxIdleTime()); _generator.flush(); checkWriteable(); _idle.access(_endp); @@ -165,7 +252,7 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound public void sendMessage(byte frame, byte[] content, int offset, int length) throws IOException { - _generator.addFrame(frame,content,offset,length,_maxIdleTimeMs); + _generator.addFrame(frame,content,offset,length,_endp.getMaxIdleTime()); _generator.flush(); checkWriteable(); _idle.access(_endp); @@ -175,7 +262,7 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound { try { - _generator.flush(_maxIdleTimeMs); + _generator.flush(_endp.getMaxIdleTime()); _endp.close(); } catch(IOException e) diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java index cd8eb94748..37f5de71d0 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java @@ -16,7 +16,7 @@ import org.eclipse.jetty.server.HttpConnection; public class WebSocketFactory { private WebSocketBuffers _buffers; - private long _maxIdleTime=300000; + private int _maxIdleTime=300000; /* ------------------------------------------------------------ */ public WebSocketFactory() @@ -43,7 +43,7 @@ public class WebSocketFactory /** Set the maxIdleTime. * @param maxIdleTime the maxIdleTime to set */ - public void setMaxIdleTime(long maxIdleTime) + public void setMaxIdleTime(int maxIdleTime) { _maxIdleTime = maxIdleTime; } @@ -91,17 +91,38 @@ public class WebSocketFactory HttpConnection http = HttpConnection.getCurrentConnection(); ConnectedEndPoint endp = (ConnectedEndPoint)http.getEndPoint(); WebSocketConnection connection = new WebSocketConnection(websocket,endp,_buffers,http.getTimeStamp(), _maxIdleTime); - + String uri=request.getRequestURI(); + String query=request.getQueryString(); + if (query!=null && query.length()>0) + uri+="?"+query; String host=request.getHeader("Host"); - - response.setHeader("Upgrade","WebSocket"); - response.addHeader("Connection","Upgrade"); - response.addHeader("WebSocket-Origin",origin); - response.addHeader("WebSocket-Location","ws://"+host+uri); - if (protocol!=null) - response.addHeader("WebSocket-Protocol",protocol); - response.sendError(101,"Web Socket Protocol Handshake"); + + String key1 = request.getHeader("Sec-WebSocket-Key1"); + if (key1!=null) + { + String key2 = request.getHeader("Sec-WebSocket-Key2"); + connection.setHixieKeys(key1,key2); + + response.setHeader("Upgrade","WebSocket"); + response.addHeader("Connection","Upgrade"); + response.addHeader("Sec-WebSocket-Origin",origin); + response.addHeader("Sec-WebSocket-Location",(request.isSecure()?"wss://":"ws://")+host+uri); + if (protocol!=null) + response.addHeader("Sec-WebSocket-Protocol",protocol); + response.sendError(101,"WebSocket Protocol Handshake"); + } + else + { + response.setHeader("Upgrade","WebSocket"); + response.addHeader("Connection","Upgrade"); + response.addHeader("WebSocket-Origin",origin); + response.addHeader("WebSocket-Location",(request.isSecure()?"wss://":"ws://")+host+uri); + if (protocol!=null) + response.addHeader("WebSocket-Protocol",protocol); + response.sendError(101,"Web Socket Protocol Handshake"); + } + response.flushBuffer(); connection.fill(((HttpParser)http.getParser()).getHeaderBuffer()); @@ -109,6 +130,5 @@ public class WebSocketFactory websocket.onConnect(connection); request.setAttribute("org.eclipse.jetty.io.Connection",connection); - response.flushBuffer(); } } diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGenerator.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGenerator.java index 75b607d757..3666b3b07d 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGenerator.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGenerator.java @@ -2,9 +2,14 @@ package org.eclipse.jetty.websocket; import java.io.IOException; import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ @@ -94,6 +99,8 @@ public class WebSocketGenerator private synchronized void bufferPut(byte datum, long blockFor) throws IOException { + if (_buffer==null) + _buffer=_buffers.getDirectBuffer(); _buffer.put(datum); if (_buffer.space() == 0) expelBuffer(blockFor); @@ -124,7 +131,7 @@ public class WebSocketGenerator private synchronized int flushBuffer() throws IOException { if (!_endp.isOpen()) - throw new IOException("Closed"); + throw new EofException(); if (_buffer!=null) return _endp.flush(_buffer); @@ -134,6 +141,8 @@ public class WebSocketGenerator private synchronized int expelBuffer(long blockFor) throws IOException { + if (_buffer==null) + return 0; int result = flushBuffer(); _buffer.compact(); if (!_endp.isBlocking()) @@ -157,4 +166,32 @@ public class WebSocketGenerator { return _buffer==null || _buffer.length()==0; } + + public static byte[] doTheHixieHixieShake(long key1,long key2,byte[] key3) + { + try + { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte [] fodder = new byte[16]; + + fodder[0]=(byte)(0xff&(key1>>24)); + fodder[1]=(byte)(0xff&(key1>>16)); + fodder[2]=(byte)(0xff&(key1>>8)); + fodder[3]=(byte)(0xff&key1); + fodder[4]=(byte)(0xff&(key2>>24)); + fodder[5]=(byte)(0xff&(key2>>16)); + fodder[6]=(byte)(0xff&(key2>>8)); + fodder[7]=(byte)(0xff&key2); + for (int i=0;i<8;i++) + fodder[8+i]=key3[i]; + md.update(fodder); + byte[] result=md.digest(); + return result; + } + catch (NoSuchAlgorithmException e) + { + throw new IllegalStateException(e); + } + } + } diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParser.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParser.java index e0a0160837..49449fbe52 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParser.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParser.java @@ -190,10 +190,26 @@ public class WebSocketParser _buffer.put(buffer); buffer.clear(); } - - } - + + /* ------------------------------------------------------------ */ + static long hixieCrypt(String key) + { + // Don't ask me what all this is about. + // I think it's pretend secret stuff, kind of + // like talking in pig latin! + long number=0; + int spaces=0; + for (char c : key.toCharArray()) + { + if (Character.isDigit(c)) + number=number*10+(c-'0'); + else if (c==' ') + spaces++; + } + return number/spaces; + } + /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketServlet.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketServlet.java index e89d5f31d0..43abe6e7be 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketServlet.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketServlet.java @@ -49,7 +49,11 @@ public abstract class WebSocketServlet extends HttpServlet { if ("WebSocket".equals(request.getHeader("Upgrade"))) { - String protocol=request.getHeader("WebSocket-Protocol"); + boolean hixie = request.getHeader("Sec-WebSocket-Key1")!=null; + + String protocol=request.getHeader(hixie?"Sec-WebSocket-Protocol":"WebSocket-Protocol"); + if (protocol==null) + protocol=request.getHeader("Sec-WebSocket-Protocol"); WebSocket websocket=doWebSocketConnect(request,protocol); String host=request.getHeader("Host"); @@ -59,7 +63,11 @@ public abstract class WebSocketServlet extends HttpServlet if (websocket!=null) _websocket.upgrade(request,response,websocket,origin,protocol); else + { + if (hixie) + response.setHeader("Connection","close"); response.sendError(503); + } } else super.service(request,response); diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorTest.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorTest.java index 1b2a67648d..755d905af1 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorTest.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorTest.java @@ -1,34 +1,35 @@ package org.eclipse.jetty.websocket; -import junit.framework.TestCase; +import java.security.MessageDigest; + import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.TypeUtil; +import org.junit.Before; +import org.junit.Test; +import static junit.framework.Assert.assertEquals; -/* ------------------------------------------------------------ */ /** + * @version $Revision: 1441 $ $Date: 2010-04-02 12:28:17 +0200 (Fri, 02 Apr 2010) $ */ -public class WebSocketGeneratorTest extends TestCase +public class WebSocketGeneratorTest { + private ByteArrayBuffer _out; + private WebSocketGenerator _generator; - WebSocketBuffers _buffers; - ByteArrayBuffer _out; - ByteArrayEndPoint _endp; - WebSocketGenerator _generator; - - /* ------------------------------------------------------------ */ - @Override - protected void setUp() throws Exception + @Before + public void setUp() throws Exception { - _buffers=new WebSocketBuffers(1024); - _endp = new ByteArrayEndPoint(); - _generator = new WebSocketGenerator(_buffers,_endp); + WebSocketBuffers buffers = new WebSocketBuffers(1024); + ByteArrayEndPoint endPoint = new ByteArrayEndPoint(); + _generator = new WebSocketGenerator(buffers, endPoint); _out = new ByteArrayBuffer(2048); - _endp.setOut(_out); + endPoint.setOut(_out); } - /* ------------------------------------------------------------ */ + @Test public void testOneString() throws Exception { _generator.addFrame((byte)0x04,"Hell\uFF4F W\uFF4Frld",0); @@ -52,6 +53,7 @@ public class WebSocketGeneratorTest extends TestCase assertEquals(0xff,0xff&_out.get()); } + @Test public void testOneBuffer() throws Exception { _generator.addFrame((byte)0x84,"Hell\uFF4F W\uFF4Frld".getBytes(StringUtil.__UTF8),0); @@ -75,6 +77,7 @@ public class WebSocketGeneratorTest extends TestCase assertEquals('d',_out.get()); } + @Test public void testOneLongBuffer() throws Exception { byte[] b=new byte[150]; @@ -90,4 +93,35 @@ public class WebSocketGeneratorTest extends TestCase for (int i=0;i<b.length;i++) assertEquals('0'+(i%10),0xff&_out.get()); } + + @Test + public void testHixie() throws Exception + { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] result; + byte[] expected; + + expected=md.digest(TypeUtil.fromHexString("00000000000000000000000000000000")); + result=WebSocketGenerator.doTheHixieHixieShake( + 0 ,0, new byte[8]); + assertEquals(TypeUtil.toHexString(expected),TypeUtil.toHexString(result)); + + expected=md.digest(TypeUtil.fromHexString("01020304050607080000000000000000")); + result=WebSocketGenerator.doTheHixieHixieShake( + 0x01020304, + 0x05060708, + new byte[8]); + assertEquals(TypeUtil.toHexString(expected),TypeUtil.toHexString(result)); + + byte[] random = new byte[8]; + for (int i=0;i<8;i++) + random[i]=(byte)(0xff&"Tm[K T2u".charAt(i)); + result=WebSocketGenerator.doTheHixieHixieShake( + 155712099,173347027,random); + StringBuilder b = new StringBuilder(); + + for (int i=0;i<16;i++) + b.append((char)result[i]); + assertEquals("fQJ,fN/4F4!~K~MH",b.toString()); + } } diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketLoadTest.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketLoadTest.java new file mode 100644 index 0000000000..0cb355b657 --- /dev/null +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketLoadTest.java @@ -0,0 +1,223 @@ +package org.eclipse.jetty.websocket; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.lang.management.ManagementFactory; +import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @version $Revision$ $Date$ + */ +public class WebSocketLoadTest +{ + private static Server _server; + private static Connector _connector; + + @BeforeClass + public static void startServer() throws Exception + { + _server = new Server(); + + _connector = new SelectChannelConnector(); + _server.addConnector(_connector); + + QueuedThreadPool threadPool = new QueuedThreadPool(200); + threadPool.setMaxStopTimeMs(1000); + _server.setThreadPool(threadPool); + + WebSocketHandler wsHandler = new WebSocketHandler() + { + @Override + protected WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) + { + return new EchoWebSocket(); + } + }; + wsHandler.setHandler(new DefaultHandler()); + _server.setHandler(wsHandler); + + _server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + _server.stop(); + _server.join(); + } + + @Test + public void testLoad() throws Exception + { + int count = 50; + int iterations = 10; + + ExecutorService threadPool = Executors.newCachedThreadPool(); + try + { + CountDownLatch latch = new CountDownLatch(count * iterations); + WebSocketClient[] clients = new WebSocketClient[count]; + for (int i = 0; i < clients.length; ++i) + { + clients[i] = new WebSocketClient("localhost", _connector.getLocalPort(), 1000, latch, iterations); + clients[i].open(); + } + + long start = System.nanoTime(); + for (WebSocketClient client : clients) + threadPool.execute(client); + + int parallelism = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); + long maxTimePerIteration = 5; + assertTrue(latch.await(iterations * (count / parallelism + 1) * maxTimePerIteration, TimeUnit.MILLISECONDS)); + long end = System.nanoTime(); + System.err.println("Elapsed: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms"); + + for (WebSocketClient client : clients) + client.close(); + } + finally + { + threadPool.shutdown(); + assertTrue(threadPool.awaitTermination(2, TimeUnit.SECONDS)); + } + } + + private static class EchoWebSocket implements WebSocket + { + private volatile Outbound outbound; + + public void onConnect(Outbound outbound) + { + this.outbound = outbound; + } + + public void onMessage(byte frame, String data) + { + try + { + outbound.sendMessage(data); + } + catch (IOException x) + { + outbound.disconnect(); + } + } + + public void onMessage(byte frame, byte[] data, int offset, int length) + { + } + + public void onDisconnect() + { + } + } + + private class WebSocketClient implements Runnable + { + private final Socket socket; + private final BufferedWriter output; + private final BufferedReader input; + private final int iterations; + private final CountDownLatch latch; + + public WebSocketClient(String host, int port, int readTimeout, CountDownLatch latch, int iterations) throws IOException + { + this.latch = latch; + socket = new Socket(host, port); + socket.setSoTimeout(readTimeout); + output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1")); + input = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1")); + this.iterations = iterations; + } + + private void open() throws IOException + { + output.write("GET /test HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Upgrade: WebSocket\r\n" + + "Connection: Upgrade\r\n" + + "\r\n"); + output.flush(); + + String responseLine = input.readLine(); + assertTrue(responseLine.startsWith("HTTP/1.1 101 Web Socket Protocol Handshake")); + // Read until we find an empty line, which signals the end of the http response + String line; + while ((line = input.readLine()) != null) + if (line.length() == 0) + break; + } + + public void run() + { + try + { + String message = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"; + for (int i = 0; i < iterations; ++i) + { + writeString(message); + String result = readString(); + assertEquals(message, result); + latch.countDown(); + } + } + catch (IOException x) + { + throw new RuntimeException(x); + } + } + + private void writeString(String message) throws IOException + { + output.write(0x00); + output.write(message); + output.write(0xFF); + output.flush(); + } + + private String readString() throws IOException + { + StringBuilder result = new StringBuilder(); + int frameStart = input.read(); + assertEquals(0x00, frameStart); + while (true) + { + int read = input.read(); + if (read == -1) + throw new EOFException(); + char c = (char)read; + if (c == 0xFF) + break; + result.append(c); + } + return result.toString(); + } + + public void close() throws IOException + { + socket.close(); + } + } +} diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketMessageTest.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketMessageTest.java index c95f5fc459..96321f7fdd 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketMessageTest.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketMessageTest.java @@ -10,24 +10,30 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; -import junit.framework.TestCase; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.util.StringUtil; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** * @version $Revision$ $Date$ */ -public class WebSocketMessageTest extends TestCase +public class WebSocketMessageTest { - private Server _server; - private Connector _connector; - private TestWebSocket _serverWebSocket; + private static Server _server; + private static Connector _connector; + private static TestWebSocket _serverWebSocket; - @Override - protected void setUp() throws Exception + @BeforeClass + public static void startServer() throws Exception { _server = new Server(); _connector = new SelectChannelConnector(); @@ -45,13 +51,14 @@ public class WebSocketMessageTest extends TestCase _server.start(); } - @Override - protected void tearDown() throws Exception + @AfterClass + public static void stopServer() throws Exception { _server.stop(); _server.join(); } + @Test public void testServerSendBigStringMessage() throws Exception { Socket socket = new Socket("localhost", _connector.getLocalPort()); @@ -104,6 +111,7 @@ public class WebSocketMessageTest extends TestCase assertEquals(message.length() + "0x00".length() + "0xFF".length(), result.length()); } + @Test public void testServerSendBigBinaryMessage() throws Exception { Socket socket = new Socket("localhost", _connector.getLocalPort()); @@ -158,7 +166,7 @@ public class WebSocketMessageTest extends TestCase } } - private class TestWebSocket implements WebSocket + private static class TestWebSocket implements WebSocket { private final CountDownLatch latch = new CountDownLatch(1); private volatile Outbound outbound; diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserTest.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserTest.java index 419797b391..8fa1bd27d9 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserTest.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserTest.java @@ -3,58 +3,61 @@ package org.eclipse.jetty.websocket; import java.util.ArrayList; import java.util.List; -import junit.framework.TestCase; - import org.eclipse.jetty.http.HttpHeaderValues; import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; -import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.util.StringUtil; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -/* ------------------------------------------------------------ */ /** + * @version $Revision: 1441 $ $Date: 2010-04-02 12:28:17 +0200 (Fri, 02 Apr 2010) $ */ -public class WebSocketParserTest extends TestCase -{ - WebSocketBuffers _buffers; - ByteArrayBuffer _in; - ByteArrayEndPoint _endp; - Handler _handler; - WebSocketParser _parser; - - /* ------------------------------------------------------------ */ - @Override - protected void setUp() throws Exception +public class WebSocketParserTest +{ + private ByteArrayBuffer _in; + private Handler _handler; + private WebSocketParser _parser; + + @Before + public void setUp() throws Exception { - _buffers=new WebSocketBuffers(1024); - _endp = new ByteArrayEndPoint(); + WebSocketBuffers buffers = new WebSocketBuffers(1024); + ByteArrayEndPoint endPoint = new ByteArrayEndPoint(); _handler = new Handler(); - _parser=new WebSocketParser(_buffers,_endp,_handler); + _parser=new WebSocketParser(buffers, endPoint,_handler); _in = new ByteArrayBuffer(2048); - _endp.setIn(_in); + endPoint.setIn(_in); } + @Test public void testCache() throws Exception { assertEquals(HttpHeaderValues.UPGRADE_ORDINAL ,((CachedBuffer)HttpHeaderValues.CACHE.lookup("Upgrade")).getOrdinal()); } - + + @Test public void testOneUtf8() throws Exception { _in.put((byte)0x00); _in.put("Hello World".getBytes(StringUtil.__UTF8)); _in.put((byte)0xff); - + int filled =_parser.parseNext(); - + assertEquals(13,filled); assertEquals("Hello World",_handler._data.get(0)); assertTrue(_parser.isBufferEmpty()); assertTrue(_parser.getBuffer()==null); } + @Test public void testTwoUtf8() throws Exception { _in.put((byte)0x00); @@ -63,42 +66,44 @@ public class WebSocketParserTest extends TestCase _in.put((byte)0x00); _in.put("Hell\uFF4F W\uFF4Frld".getBytes(StringUtil.__UTF8)); _in.put((byte)0xff); - + int filled =_parser.parseNext(); - + assertEquals(30,filled); assertEquals("Hello World",_handler._data.get(0)); assertFalse(_parser.isBufferEmpty()); assertFalse(_parser.getBuffer()==null); - + filled =_parser.parseNext(); - + assertEquals(0,filled); assertEquals("Hell\uFF4f W\uFF4Frld",_handler._data.get(1)); assertTrue(_parser.isBufferEmpty()); assertTrue(_parser.getBuffer()==null); } + @Test public void testOneBinary() throws Exception { _in.put((byte)0x80); _in.put((byte)11); _in.put("Hello World".getBytes(StringUtil.__UTF8)); - + int filled =_parser.parseNext(); - + assertEquals(13,filled); assertEquals("Hello World",_handler._data.get(0)); assertTrue(_parser.isBufferEmpty()); assertTrue(_parser.getBuffer()==null); } + @Test public void testTwoBinary() throws Exception { _in.put((byte)0x80); _in.put((byte)11); _in.put("Hello World".getBytes(StringUtil.__UTF8)); - + byte[] data = new byte[150]; for (int i=0;i<data.length;i++) data[i]=(byte)('0'+(i%10)); @@ -107,14 +112,14 @@ public class WebSocketParserTest extends TestCase _in.put((byte)(0x80|(data.length>>7))); _in.put((byte)(data.length&0x7f)); _in.put(data); - - + + int filled =_parser.parseNext(); assertEquals(13+3+data.length,filled); assertEquals("Hello World",_handler._data.get(0)); assertFalse(_parser.isBufferEmpty()); assertFalse(_parser.getBuffer()==null); - + filled =_parser.parseNext(); assertEquals(0,filled); String got=_handler._data.get(1); @@ -123,22 +128,23 @@ public class WebSocketParserTest extends TestCase assertTrue(_parser.isBufferEmpty()); assertTrue(_parser.getBuffer()==null); } - + + + @Test + public void testHixieCrypt() throws Exception + { + assertEquals(155712099,WebSocketParser.hixieCrypt("18x 6]8vM;54 *(5: { U1]8 z [ 8")); + assertEquals(173347027,WebSocketParser.hixieCrypt("1_ tx7X d < nw 334J702) 7]o}` 0")); + } // TODO test: - // blocking, + // blocking, // async // full // EOF // errors - - - - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - class Handler implements WebSocketParser.EventHandler + + private class Handler implements WebSocketParser.EventHandler { public List<String> _data = new ArrayList<String>(); @@ -151,6 +157,5 @@ public class WebSocketParserTest extends TestCase { _data.add(data); } - } } diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketTest.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketTest.java index 292eb67e4b..eb62f5a1eb 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketTest.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketTest.java @@ -1,11 +1,8 @@ package org.eclipse.jetty.websocket; import java.io.IOException; - import javax.servlet.http.HttpServletRequest; -import junit.framework.TestCase; - import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.server.LocalConnector; @@ -13,24 +10,26 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -public class WebSocketTest extends TestCase +public class WebSocketTest { - TestWebSocket _websocket; - LocalConnector _connector; - Server _server; - WebSocketHandler _handler; - - - - /* ------------------------------------------------------------ */ - @Override - protected void setUp() throws Exception + private static TestWebSocket _websocket; + private static LocalConnector _connector; + private static Server _server; + + @BeforeClass + public static void startServer() throws Exception { _server = new Server(); _connector = new LocalConnector(); _server.addConnector(_connector); - _handler= new WebSocketHandler() + WebSocketHandler handler = new WebSocketHandler() { @Override protected WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) @@ -39,24 +38,31 @@ public class WebSocketTest extends TestCase return _websocket; } }; - _handler.setHandler(new DefaultHandler()); - _server.setHandler(_handler); - - _server.start(); + handler.setHandler(new DefaultHandler()); + _server.setHandler(handler); + + _server.start(); } - - + + @AfterClass + public static void stopServer() throws Exception + { + _server.stop(); + _server.join(); + } + + @Test public void testNoWebSocket() throws Exception { String response = _connector.getResponses( "GET /foo HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n",false); - + assertTrue(response.startsWith("HTTP/1.1 404 ")); } - /* ------------------------------------------------------------ */ + @Test public void testOpenWebSocket() throws Exception { String response = _connector.getResponses( @@ -65,45 +71,42 @@ public class WebSocketTest extends TestCase "Upgrade: WebSocket\r\n" + "Connection: Upgrade\r\n" + "\r\n",false); - + assertTrue(response.startsWith("HTTP/1.1 101 Web Socket Protocol Handshake")); assertTrue(response.contains("Upgrade: WebSocket")); assertTrue(response.contains("Connection: Upgrade")); } - /* ------------------------------------------------------------ */ + @Test public void testSendReceiveUtf8WebSocket() throws Exception { ByteArrayBuffer buffer = new ByteArrayBuffer(1024); - + buffer.put( ("GET /demo HTTP/1.1\r\n" + "Host: localhost\r\n" + "Upgrade: WebSocket\r\n" + "Connection: Upgrade\r\n" + "\r\n").getBytes(StringUtil.__ISO_8859_1)); - + buffer.put((byte)0); buffer.put("Hello World".getBytes(StringUtil.__UTF8)); buffer.put((byte)0xFF); - + ByteArrayBuffer out = _connector.getResponses(buffer,true); - + String response = StringUtil.printable(out.asArray()); System.err.println(response); - + assertTrue(response.startsWith("HTTP/1.1 101 Web Socket Protocol Handshake")); assertTrue(response.contains("Upgrade: WebSocket")); assertTrue(response.contains("Connection: Upgrade")); assertTrue(response.contains("0x00Roger That0xFF")); - + assertEquals("Hello World",_websocket._utf8); } - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - class TestWebSocket implements WebSocket + private static class TestWebSocket implements WebSocket { Outbound _outbound; Buffer _binary; @@ -122,7 +125,7 @@ public class WebSocketTest extends TestCase Log.warn(e); } } - + public void onMessage(byte frame, byte[] data,int offset, int length) { _binary=new ByteArrayBuffer(data,offset,length).duplicate(Buffer.READONLY); @@ -138,5 +141,4 @@ public class WebSocketTest extends TestCase _disconnected=true; } } - } diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketTestServer.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketTestServer.java index 878c6c8601..e500b337c2 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketTestServer.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketTestServer.java @@ -1,34 +1,27 @@ package org.eclipse.jetty.websocket; import java.io.IOException; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; - import javax.servlet.http.HttpServletRequest; -import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.DefaultHandler; -import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.websocket.WebSocketTest.TestWebSocket; public class WebSocketTestServer extends Server { TestWebSocket _websocket; SelectChannelConnector _connector; WebSocketHandler _handler; - ConcurrentLinkedQueue<TestWebSocket> _webSockets= new ConcurrentLinkedQueue<TestWebSocket>(); - + ConcurrentLinkedQueue<TestWebSocket> _webSockets = new ConcurrentLinkedQueue<TestWebSocket>(); + public WebSocketTestServer() { _connector = new SelectChannelConnector(); _connector.setPort(8080); - + addConnector(_connector); - _handler= new WebSocketHandler() + _handler = new WebSocketHandler() { @Override protected WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) @@ -37,7 +30,7 @@ public class WebSocketTestServer extends Server return _websocket; } }; - + setHandler(_handler); } @@ -50,26 +43,26 @@ public class WebSocketTestServer extends Server public void onConnect(Outbound outbound) { System.err.println("onConnect"); - _outbound=outbound; + _outbound = outbound; _webSockets.add(this); - + } - - public void onMessage(byte frame, byte[] data,int offset, int length) + + public void onMessage(byte frame, byte[] data, int offset, int length) { } public void onMessage(final byte frame, final String data) { - System.err.println("onMessage "+data); + System.err.println("onMessage " + data); for (TestWebSocket ws : _webSockets) { - if (ws!=this) + if (ws != this) { try { if (ws._outbound.isOpen()) - ws._outbound.sendMessage(frame,data); + ws._outbound.sendMessage(frame, data); } catch (IOException e) { @@ -84,9 +77,8 @@ public class WebSocketTestServer extends Server _webSockets.remove(this); } } - - - public static void main(String[] args) + + public static void main(String[] args) { try { @@ -94,12 +86,10 @@ public class WebSocketTestServer extends Server server.start(); server.join(); } - catch(Exception e) + catch (Exception e) { Log.warn(e); } } - - - + } diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index c55bb79b4f..87a1b7c83a 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -33,16 +33,11 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> - <!-- always include sources since jetty-xbean makes use of them --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - </plugin> <!-- <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -62,6 +57,13 @@ </executions> </plugin> --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <onlyAnalyze>org.eclipse.jetty.xml.*</onlyAnalyze> + </configuration> + </plugin> </plugins> </build> <dependencies> @@ -73,6 +75,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java index 8f51b03e95..ad2e51a261 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java @@ -787,15 +787,12 @@ public class XmlConfiguration { String id = node.getAttribute("id"); String name = node.getAttribute("name"); - Object defval = node.getAttribute("default"); + String defval = node.getAttribute("default"); Object prop=null; if (_propertyMap!=null && _propertyMap.containsKey(name)) - { prop=_propertyMap.get(name); - } - else if (defval != null) - prop=defval; - + else + prop=defval; if (id != null) _idMap.put(id, prop); if (prop!=null) diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/TestConfiguration.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/TestConfiguration.java index 3a5df4319f..7682376b04 100644 --- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/TestConfiguration.java +++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/TestConfiguration.java @@ -4,17 +4,21 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== -package org.eclipse.jetty.xml;import java.net.URL; +package org.eclipse.jetty.xml; + +import java.net.URL; import java.util.HashMap; +import org.junit.Ignore; +@Ignore public class TestConfiguration extends HashMap { public static int VALUE=77; @@ -28,6 +32,7 @@ public class TestConfiguration extends HashMap public int[] ia; public int testField1; public int testField2; + public int propValue; public void setTest(Object value) { @@ -38,6 +43,12 @@ public class TestConfiguration extends HashMap { testInt=value; } + + public void setPropertyTest(int value) + { + propValue=value; + } + public void call() { diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java index 4d4a40b642..254c51fc1f 100644 --- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java +++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java @@ -4,11 +4,11 @@ // 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 +// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.xml; @@ -17,14 +17,15 @@ import java.net.URL; import java.util.HashMap; import java.util.Map; -import junit.framework.TestCase; +import org.junit.Test; -public class XmlConfigurationTest extends TestCase +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class XmlConfigurationTest { - public final static String __CRLF = "\015\012"; - - /* ------------------------------------------------------------ */ - public static void testXmlParser() throws Exception + @Test + public void testXmlParser() throws Exception { XmlParser parser = new XmlParser(); @@ -44,40 +45,41 @@ public class XmlConfigurationTest extends TestCase parser.redirectEntity("configure_1_0.dtd", configURL); parser.redirectEntity("http://jetty.eclipse.org/configure_1_0.dtd", configURL); parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.0//EN", configURL); - + URL url = XmlConfigurationTest.class.getClassLoader().getResource("org/eclipse/jetty/xml/configure.xml"); XmlParser.Node testDoc = parser.parse(url.toString()); String testDocStr = testDoc.toString().trim(); - + assertTrue(testDocStr.startsWith("<Configure")); assertTrue(testDocStr.endsWith("</Configure>")); - } - /* ------------------------------------------------------------ */ - public static void testXmlConfiguration() throws Exception + @Test + public void testXmlConfiguration() throws Exception { Map properties = new HashMap(); properties.put("whatever", "xxx"); - + URL url = XmlConfigurationTest.class.getClassLoader().getResource("org/eclipse/jetty/xml/configure.xml"); XmlConfiguration configuration = new XmlConfiguration(url); TestConfiguration tc = new TestConfiguration(); configuration.setProperties(properties); configuration.configure(tc); - + assertEquals("Set String","SetValue",tc.testObject); assertEquals("Set Type",2,tc.testInt); + assertEquals(18080, tc.propValue); + assertEquals("Put","PutValue",tc.get("Test")); assertEquals("Put dft","2",tc.get("TestDft")); assertEquals("Put type",new Integer(2),tc.get("TestInt")); - + assertEquals("Trim","PutValue",tc.get("Trim")); assertEquals("Null",null,tc.get("Null")); assertEquals("NullTrim",null,tc.get("NullTrim")); - + assertEquals("ObjectTrim",new Double(1.2345),tc.get("ObjectTrim")); assertEquals("Objects","-1String",tc.get("Objects")); assertEquals( "ObjectsTrim", "-1String",tc.get("ObjectsTrim")); @@ -87,49 +89,45 @@ public class XmlConfigurationTest extends TestCase assertEquals( "ObjectString", "\n 1.2345\n ",tc.get("ObjectString")); assertEquals( "ObjectsString", "-1String",tc.get("ObjectsString")); assertEquals( "ObjectsWhiteString", "-1\n String",tc.get("ObjectsWhiteString")); - + assertEquals( "SystemProperty", System.getProperty("user.dir")+"/stuff",tc.get("SystemProperty")); assertEquals( "Property", "xxx", tc.get("Property")); - - + + assertEquals( "Called", "Yes",tc.get("Called")); - + assertTrue(TestConfiguration.called); - + assertEquals("oa[0]","Blah",tc.oa[0]); assertEquals("oa[1]","1.2.3.4:5678",tc.oa[1]); assertEquals("oa[2]",new Double(1.2345),tc.oa[2]); assertEquals("oa[3]",null,tc.oa[3]); - + assertEquals("ia[0]",1,tc.ia[0]); assertEquals("ia[1]",2,tc.ia[1]); assertEquals("ia[2]",3,tc.ia[2]); assertEquals("ia[3]",0,tc.ia[3]); - + TestConfiguration tc2=tc.nested; assertTrue(tc2!=null); assertEquals( "Called(bool)", new Boolean(true),tc2.get("Arg")); - + assertEquals("nested config",null,tc.get("Arg")); assertEquals("nested config",new Boolean(true),tc2.get("Arg")); - + assertEquals("nested config","Call1",tc2.testObject); assertEquals("nested config",4,tc2.testInt); assertEquals( "nested call", "http://www.eclipse.com/",tc2.url.toString()); - + configuration = new XmlConfiguration("<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\"><Set name=\"Test\">SetValue</Set><Set name=\"Test\" type=\"int\">2</Set></Configure>"); TestConfiguration tc3 = new TestConfiguration(); configuration.configure(tc3); assertEquals("Set String 3","SetValue",tc3.testObject); assertEquals("Set Type 3",2,tc3.testInt); - + assertEquals("static to field",tc.testField1,77); assertEquals("field to field",tc.testField2,2); assertEquals("literal to static",TestConfiguration.VALUE,42); - } - - - } diff --git a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml index e8ef9d28ee..784cca9193 100644 --- a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml +++ b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml @@ -5,6 +5,8 @@ <Set name="Test">SetValue</Set> <Set name="Test" type="int">2</Set> + + <Set name="PropertyTest"><Property name="anIntegerNoActualPropDefined" default="18080"/></Set> <Put name="Test">PutValue</Put> <Put name="TestDft">2</Put> diff --git a/linux-packaging.xml b/linux-packaging.xml new file mode 100644 index 0000000000..4da7c80062 --- /dev/null +++ b/linux-packaging.xml @@ -0,0 +1,242 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<linux-packaging> + <mapping> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jsp-api-2.1-glassfish</artifactId> + <debian available="false"/> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <required-classes> + <class>ch.qos.logback.classic.LoggerContext</class> + </required-classes> + <debian criteria=">= 0.9.18">liblogback-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>2.5</version> + <required-classes> + <class>javax.servlet.http.HttpServlet</class> + </required-classes> + <debian available="false"/> + <redhat avaialble="false">tomcat6-servlet-2.5-api</redhat> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <!-- In order to assure proper packaging setup, a few classes + should be specified to check for on the classpath. + If these classes are not present on the classpath, then + the jar is downloaded from the maven repo and used in + an embedded fashion. --> + <required-classes> + <class>junit.framework.Assert</class> + <class>junit.framework.TestCase</class> + </required-classes> + <!-- The debian packaging refers to the version-less package name. + An optional criteria can be specified that would indicate + a minimum version to be present on the system. + This information will (eventually) be verified against + the debian/control file to ensure that the packaging + is still valid. + If the information is determined to not be present + in the debian/control file than a build error is + (hopefully) produced to let the maintainers know + that this information is now out of date. --> + <debian criteria=">= 3.8">junit</debian> + <redhat>junit</redhat> + </dependency> + <dependency> + <groupId>org.eclipse.jdt.core.compiler</groupId> + <artifactId>ecj</artifactId> + <debian available="false"/> + <redhat>ecj</redhat> + </dependency> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jsp-2.1-glassfish</artifactId> + <debian available="false"/> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + <required-classes> + <class>ch.qos.logback.core.joran.JoranConfiguratorBase</class> + </required-classes> + <debian criteria=">= 0.9.18">liblogback-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jaspic_1.0_spec</artifactId> + <debian available="false"/> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.eclipse.equinox.http</groupId> + <artifactId>servlet</artifactId> + <debian criteria=">= 3.5">eclipse-platform</debian> + </dependency> + <dependency> + <groupId>org.eclipse.osgi</groupId> + <artifactId>services</artifactId> + <debian available="false"/> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jta_1.1_spec</artifactId> + <debian available="false">libgeronimo-jta-1.1-spec-1.1.1-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.eclipse</groupId> + <artifactId>osgi</artifactId> + <required-classes> + <class>org.osgi.framework.BundleContext</class> + </required-classes> + <debian available="false"/> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <debian criteria=">= 1.5.10">libslf4j-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>asm</groupId> + <artifactId>asm-commons</artifactId> + <debian criteria=">= 3.1">libasm3-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>ant</groupId> + <artifactId>ant</artifactId> + <debian criteria=">= 1.6">ant</debian> + <redhat>ant</redhat> + </dependency> + <dependency> + <groupId>asm</groupId> + <artifactId>asm</artifactId> + <debian criteria=">= 3.1">libasm3-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>asm</groupId> + <artifactId>asm-tree</artifactId> + <debian criteria=">= 3.1">libasm3-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>javax.mail</groupId> + <artifactId>mail</artifactId> + <required-classes> + <class>javax.mail.Authenticator</class> + <class>javax.mail.PasswordAuthentication</class> + <class>javax.mail.Session</class> + </required-classes> + <debian>libgnumail-java</debian> + <redhat>sun-mail</redhat> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-annotation_1.0_spec</artifactId> + <debian available="false"/> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>log4j-over-slf4j</artifactId> + <debian criteria=">= 1.5.10">libslf4j-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.testng</groupId> + <artifactId>testng</artifactId> + <debian criteria=">= 5.8">testng</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>servlet-api</artifactId> + <version>3.0.20100224</version> + <required-classes> + <class>javax.servlet.AsyncContext</class> + <class>javax.servlet.AsyncEvent</class> + <class>javax.servlet.AsyncListener</class> + </required-classes> + <debian available="false"/> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <required-classes> + <class>org.slf4j.Logger</class> + </required-classes> + <debian criteria=">= 1.5.10">libslf4j-java</debian> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-util</artifactId> + <debian available="false"/> + <redhat available="false"/> + </dependency> + <dependency> + <groupId>javax.activation</groupId> + <artifactId>activation</artifactId> + <debian>libgnujav-java</debian> + <redhat>sun-jaf</redhat> + </dependency> + </mapping> + <!-- Excluding due to Geronimo Dependency Requirements --> + <project groupId="org.eclipse.jetty"> + <exclude>jetty-annotations</exclude> + <exclude>jetty-jaspi</exclude> + <exclude>jetty-plus</exclude> + <exclude>example-jetty-embedded</exclude> + <exclude>test-continuation</exclude> + <exclude>test-continuation-jetty6</exclude> + <exclude>test-jetty-servlet</exclude> + </project> + <!-- Dependencies for OSGI are too complicated to deal with right now --> + <project groupId="org.eclipse.jetty.osgi"> + <exclude>jetty-osgi</exclude> + <exclude>jetty-osgi-boot</exclude> + <exclude>jetty-osgi-boot-jsp</exclude> + <exclude>jetty-osgi-boot-logback</exclude> + <exclude>jetty-osgi-boot-warurl</exclude> + <exclude>jetty-httpservice</exclude> + </project> + <!-- Aggregate Projects need not be built by linux-packaging --> + <project groupId="org.eclipse.jetty.aggregate"> + <exclude>jetty-server</exclude> + <exclude>jetty-client</exclude> + <exclude>jetty-servlet</exclude> + <exclude>jetty-webapp</exclude> + <exclude>jetty-plus</exclude> + <exclude>jetty-all-server</exclude> + <exclude>jetty-all</exclude> + </project> + <project groupId="org.eclipse.jetty.tests"> + <exclude>test-sessions-common</exclude> + <exclude>test-jdbc-sessions</exclude> + <exclude>test-hash-sessions</exclude> + <exclude>test-integration</exclude> + <exclude>test-webapp-rfc2616</exclude> + </project> + <daemon> + <script>jetty-distribution/src/main/resources/bin/jetty.sh</script> + <debian>debian/jetty.init</debian> + <redhat>rpm/jetty.init</redhat> + </daemon> +</linux-packaging> + @@ -1,10 +1,9 @@ -<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-parent</artifactId> - <version>12</version> + <version>15</version> </parent> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-project</artifactId> @@ -13,20 +12,19 @@ <url>${jetty.url}</url> <packaging>pom</packaging> <properties> - <jetty.url>http://www.eclipse.org/jetty</jetty.url> <felix.bundle.version>2.0.0</felix.bundle.version> - <activation-version>1.1</activation-version> - <ant-version>1.6.5</ant-version> - <jta-spec-version>1.1.1</jta-spec-version> + <javax-activation-version>1.1</javax-activation-version> + <javax-mail-version>1.4.1</javax-mail-version> + <javax-transaction-version>1.1.1</javax-transaction-version> + <jetty.url>http://www.eclipse.org/jetty</jetty.url> <junit-version>3.8.2</junit-version> - <mail-version>1.4</mail-version> - <slf4j-version>1.5.10</slf4j-version> - <eclipse-compiler-version>3.1.1</eclipse-compiler-version> - <cometd-version>1.0.1</cometd-version> + <junit4-version>4.8.1</junit4-version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <slf4j-version>1.5.10</slf4j-version> <servlet.spec.groupId>org.mortbay.jetty</servlet.spec.groupId> <servlet.spec.artifactId>servlet-api</servlet.spec.artifactId> <servlet.spec.version>3.0.20100224</servlet.spec.version> + <build-support-version>1.0</build-support-version> </properties> <scm> <connection>scm:svn:http://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/tags/jetty-8.0.0.M1</connection> @@ -48,26 +46,54 @@ <artifactId>maven-release-plugin</artifactId> <configuration> <tagBase>svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/tags</tagBase> + <autoVersionSubmodules>true</autoVersionSubmodules> </configuration> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-remote-resources-plugin</artifactId> - <executions> - <execution> - <phase>generate-resources</phase> - <goals> - <goal>process</goal> - </goals> - <configuration> - <resourceBundles> - <resourceBundle>org.eclipse.jetty.toolchain:jetty-artifact-remote-resources:1.0</resourceBundle> - </resourceBundles> - </configuration> - </execution> - </executions> - </plugin> - + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-remote-resources-plugin</artifactId> + <executions> + <execution> + <phase>generate-resources</phase> + <goals> + <goal>process</goal> + </goals> + <configuration> + <resourceBundles> + <resourceBundle>org.eclipse.jetty.toolchain:jetty-artifact-remote-resources:1.0</resourceBundle> + </resourceBundles> + </configuration> + </execution> + </executions> + </plugin> + <!-- source maven plugin creates the source bundle and adds manifest --> + <plugin> + <inherited>true</inherited> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>2.1.1</version> + <executions> + <execution> + <id>attach-sources</id> + <phase>process-classes</phase> + <goals> + <goal>jar</goal> + </goals> + <configuration> + <archive> + <manifestEntries> + <Bundle-ManifestVersion>2</Bundle-ManifestVersion> + <Bundle-Name>${project.name}</Bundle-Name> + <Bundle-SymbolicName>${bundle-symbolic-name}.source;singleton:=true</Bundle-SymbolicName> + <Bundle-Vendor>Eclipse.org - Jetty</Bundle-Vendor> + <Bundle-Version>${parsedVersion.osgiVersion}</Bundle-Version> + <Eclipse-SourceBundle>${bundle-symbolic-name};version="${parsedVersion.osgiVersion}";roots:="."</Eclipse-SourceBundle> + </manifestEntries> + </archive> + </configuration> + </execution> + </executions> + </plugin> <!-- Build helper maven plugin sets the parsedVersion.osgiVersion property --> <plugin> <groupId>org.codehaus.mojo</groupId> @@ -76,58 +102,111 @@ <executions> <execution> <id>set-osgi-version</id> - <phase>compile</phase> + <phase>validate</phase> <goals> <goal>parse-version</goal> </goals> </execution> </executions> - </plugin> - </plugins> - <pluginManagement> - <plugins> - <plugin> + </plugin> + <!-- Enforcer Plugin --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-enforcer-plugin</artifactId> + <version>1.0-alpha-4</version> + <executions> + <execution> + <id>enforce-java</id> + <goals> + <goal>enforce</goal> + </goals> + <configuration> + <rules> + <requireMavenVersion> + <version>[2.0.6,)</version> + </requireMavenVersion> + <requireJavaVersion> + <version>[1.5,)</version> + </requireJavaVersion> + <versionTxtRule implementation="org.eclipse.jetty.toolchain.enforcer.rules.VersionTxtRule" /> + <versionOsgiRule implementation="org.eclipse.jetty.toolchain.enforcer.rules.RequireOsgiCompatibleVersionRule" /> + <versionRedhatRule implementation="org.eclipse.jetty.toolchain.enforcer.rules.RequireRedhatCompatibleVersionRule" /> + <versionDebianRule implementation="org.eclipse.jetty.toolchain.enforcer.rules.RequireDebianCompatibleVersionRule" /> + </rules> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.toolchain</groupId> + <artifactId>jetty-build-support</artifactId> + <version>${build-support-version}</version> + </dependency> + </dependencies> + </plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> + <artifactId>maven-pmd-plugin</artifactId> + <version>2.5</version> <configuration> - <archive> - <manifestEntries> - <Implementation-Version>${project.version}</Implementation-Version> - <Implementation-Vendor>Eclipse.org - Jetty</Implementation-Vendor> - <url>${jetty.url}</url> - </manifestEntries> - </archive> + <targetJdk>1.5</targetJdk> + <rulesets> + <ruleset>jetty/pmd_ruleset.xml</ruleset> + </rulesets> </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <version>2.4.2</version> - <configuration> - <failIfNoTests>false</failIfNoTests> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <version>2.0.0</version> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment> - <Bundle-DocURL>${jetty.url}</Bundle-DocURL> - <Bundle-Vendor>Eclipse Jetty Project</Bundle-Vendor> - <Bundle-Localization>plugin</Bundle-Localization> - <Bundle-Classpath>.</Bundle-Classpath> - <Bundle-Copyright>Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.</Bundle-Copyright> - <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy> - </instructions> - </configuration> - </plugin> - <plugin> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.toolchain</groupId> + <artifactId>jetty-build-support</artifactId> + <version>${build-support-version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifestEntries> + <Implementation-Version>${project.version}</Implementation-Version> + <Implementation-Vendor>Eclipse.org - Jetty</Implementation-Vendor> + <url>${jetty.url}</url> + </manifestEntries> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.4.2</version> + <configuration> + <failIfNoTests>false</failIfNoTests> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>2.0.0</version> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment> + <Bundle-DocURL>${jetty.url}</Bundle-DocURL> + <Bundle-Vendor>Eclipse Jetty Project</Bundle-Vendor> + <Bundle-Localization>plugin</Bundle-Localization> + <Bundle-Classpath>.</Bundle-Classpath> + <Bundle-Copyright>Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.</Bundle-Copyright> + <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy> + </instructions> + </configuration> + </plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> - <version>2.2-beta-3</version> + <version>2.2-beta-5</version> <dependencies> <dependency> <groupId>org.eclipse.jetty.toolchain</groupId> @@ -135,39 +214,63 @@ <version>1.0</version> </dependency> </dependencies> - </plugin> - - <!-- source maven plugin creates the source bundle and adds manifest --> - <plugin> - <inherited>true</inherited> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-source-plugin</artifactId> - <version>2.1.1</version> - <executions> - <execution> - <id>attach-sources</id> - <phase>process-classes</phase> - <goals> - <goal>jar</goal> - </goals> - </execution> - </executions> - <configuration> - <archive> - <manifestEntries> - <Bundle-ManifestVersion>2</Bundle-ManifestVersion> - <Bundle-Name>${name}</Bundle-Name> - <Bundle-SymbolicName>${bundle-symbolic-name}.source;singleton:=true</Bundle-SymbolicName> - <Bundle-Vendor>Eclipse.org - Jetty</Bundle-Vendor> - <Bundle-Version>${parsedVersion.osgiVersion}</Bundle-Version> - <Eclipse-SourceBundle>${bundle-symbolic-name};version="${parsedVersion.osgiVersion}";roots:="."</Eclipse-SourceBundle> - </manifestEntries> - </archive> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <version>2.3.1</version> + <configuration> + <findbugsXmlOutput>true</findbugsXmlOutput> + <xmlOutput>true</xmlOutput> + <effort>Max</effort> + <onlyAnalyze>org.eclipse.jetty.*</onlyAnalyze> </configuration> </plugin> </plugins> </pluginManagement> </build> + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jxr-plugin</artifactId> + <version>2.2</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <additionalJOption>-J-Xmx128m</additionalJOption> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <configuration> + <targetJdk>1.5</targetJdk> + <rulesets> + <ruleset>jetty/pmd_ruleset.xml</ruleset> + </rulesets> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + </plugin> + </plugins> + </reporting> + <!-- + <repositories> + <repository> + <snapshots> + <enabled>true</enabled> + </snapshots> + <id>sonatype-snapshots</id> + <name>Sonatype Jetty Snapshots</name> + <url>http://oss.sonatype.org/content/groups/jetty</url> + </repository> + </repositories> + --> <modules> <module>jetty-util</module> <module>jetty-io</module> @@ -235,28 +338,23 @@ <version>${slf4j-version}</version> </dependency> <dependency> - <groupId>ant</groupId> - <artifactId>ant</artifactId> - <version>${ant-version}</version> - </dependency> - <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-jta_1.1_spec</artifactId> - <version>${jta-spec-version}</version> + <version>${javax-transaction-version}</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> - <version>${mail-version}</version> + <version>${javax-mail-version}</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> - <version>${activation-version}</version> + <version>${javax-activation-version}</version> </dependency> </dependencies> </dependencyManagement> - <!-- + <!-- Usage: configure settings.xml for jetty.eclipse.website server entry > mvn -Paggregate-site javadoc:aggregate jxr:jxr @@ -277,27 +375,26 @@ </configuration> </plugin> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-javadoc-plugin</artifactId> - <configuration> - <excludePackageNames>com.acme</excludePackageNames> - <links> - <link>http://java.sun.com/j2se/1.5.0/docs/api</link> - <link>http://java.sun.com/javaee/5/docs/api</link> - <link>http://junit.sourceforge.net/javadoc/</link> - </links> - </configuration> - </plugin> - </plugins> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <excludePackageNames>com.acme</excludePackageNames> + <links> + <link>http://java.sun.com/javase/6/docs/api/</link> + <link>http://java.sun.com/javaee/6/docs/api</link> + <link>http://junit.sourceforge.net/javadoc/</link> + </links> + <tags> + <tag> + <name>org.apache.xbean.XBean</name> + <placement>X</placement> + <head /> + </tag> + </tags> + </configuration> + </plugin> + </plugins> </build> </profile> - <profile> - <id>jetty-spec</id> - <properties> - <servlet.spec.groupId>org.mortbay.jetty</servlet.spec.groupId> - <servlet.spec.artifactId>servlet-api</servlet.spec.artifactId> - <servlet.spec.version>3.0.20100224</servlet.spec.version> - </properties> - </profile> </profiles> </project> diff --git a/test-continuation-jetty6/pom.xml b/test-continuation-jetty6/pom.xml index 25d4c40bb8..62d987e8f5 100644 --- a/test-continuation-jetty6/pom.xml +++ b/test-continuation-jetty6/pom.xml @@ -10,6 +10,16 @@ <name>Test :: Continuation - (Jetty 6)</name> <description>Asynchronous API</description> <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <!-- DO NOT DEPLOY (or Release) --> + <skip>true</skip> + </configuration> + </plugin> + </plugins> </build> <dependencies> <dependency> @@ -50,7 +60,7 @@ <dependency> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty</artifactId> - <version>6.1.18</version> + <version>6.1.24</version> <type>jar</type> <scope>test</scope> </dependency> diff --git a/test-continuation/pom.xml b/test-continuation/pom.xml index 004da4642b..ab44d1f3e5 100644 --- a/test-continuation/pom.xml +++ b/test-continuation/pom.xml @@ -10,6 +10,16 @@ <name>Test :: Continuation</name> <description>Asynchronous API</description> <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <!-- DO NOT DEPLOY (or Release) --> + <skip>true</skip> + </configuration> + </plugin> + </plugins> </build> <dependencies> <dependency> diff --git a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java index 83bd0578a2..edbcd5a4bd 100644 --- a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java +++ b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java @@ -314,7 +314,7 @@ public class HttpTester /* ------------------------------------------------------------ */ /** * @param cookie - * @see org.eclipse.jetty.http.HttpFields#addSetCookie(javax.servlet.http.Cookie) + * @see org.eclipse.jetty.http.HttpFields#addSetCookie(org.eclipse.jetty.http.HttpCookie) */ public void addSetCookie(Cookie cookie) { @@ -333,7 +333,7 @@ public class HttpTester /* ------------------------------------------------------------ */ /** * @param name - * @return + * @return the header value as a date * @see org.eclipse.jetty.http.HttpFields#getDateField(java.lang.String) */ public long getDateHeader(String name) @@ -343,7 +343,7 @@ public class HttpTester /* ------------------------------------------------------------ */ /** - * @return + * @return the header value names * @see org.eclipse.jetty.http.HttpFields#getFieldNames() */ public Enumeration getHeaderNames() @@ -354,7 +354,7 @@ public class HttpTester /* ------------------------------------------------------------ */ /** * @param name - * @return + * @return the header value as a long * @throws NumberFormatException * @see org.eclipse.jetty.http.HttpFields#getLongField(java.lang.String) */ @@ -366,7 +366,7 @@ public class HttpTester /* ------------------------------------------------------------ */ /** * @param name - * @return + * @return the header value * @see org.eclipse.jetty.http.HttpFields#getStringField(java.lang.String) */ public String getHeader(String name) @@ -377,7 +377,7 @@ public class HttpTester /* ------------------------------------------------------------ */ /** * @param name - * @return + * @return the header values * @see org.eclipse.jetty.http.HttpFields#getValues(java.lang.String) */ public Enumeration getHeaderValues(String name) diff --git a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java index 640f8b5778..a1aec59a57 100644 --- a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java +++ b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java @@ -24,6 +24,7 @@ import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.bio.SocketConnector; +import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -63,6 +64,7 @@ public class ServletTester { try { + _server.addBean(new ErrorHandler()); _server.setSendServerVersion(false); _server.addConnector(_connector); _server.setHandler(_context); @@ -142,7 +144,7 @@ public class ServletTester /* ------------------------------------------------------------ */ /** Create a Socket connector. * This methods adds a socket connector to the server - * @param locahost if true, only listen on local host, else listen on all interfaces. + * @param localhost if true, only listen on local host, else listen on all interfaces. * @return A URL to access the server via the socket connector. * @throws Exception */ @@ -214,7 +216,7 @@ public class ServletTester /* ------------------------------------------------------------ */ /** * @param listener - * @see org.eclipse.jetty.handler.ContextHandler#addEventListener(java.util.EventListener) + * @see org.eclipse.jetty.server.handler.ContextHandler#addEventListener(java.util.EventListener) */ public void addEventListener(EventListener listener) { @@ -226,8 +228,8 @@ public class ServletTester * @param filterClass * @param pathSpec * @param dispatches - * @return - * @see org.eclipse.jetty.servlet.Scope#addFilter(java.lang.Class, java.lang.String, int) + * @return the FilterHolder + * @see org.eclipse.jetty.servlet.ServletContextHandler#addFilter(java.lang.Class, java.lang.String, int) */ public FilterHolder addFilter(Class filterClass, String pathSpec, EnumSet<DispatcherType> dispatches) { @@ -239,8 +241,8 @@ public class ServletTester * @param filterClass * @param pathSpec * @param dispatches - * @return - * @see org.eclipse.jetty.servlet.Scope#addFilter(java.lang.String, java.lang.String, int) + * @return the FilterHolder + * @see org.eclipse.jetty.servlet.ServletContextHandler#addFilter(java.lang.String, java.lang.String, int) */ public FilterHolder addFilter(String filterClass, String pathSpec, EnumSet<DispatcherType> dispatches) { @@ -251,8 +253,8 @@ public class ServletTester /** * @param servlet * @param pathSpec - * @return - * @see org.eclipse.jetty.servlet.Scope#addServlet(java.lang.Class, java.lang.String) + * @return the ServletHolder + * @see org.eclipse.jetty.servlet.ServletContextHandler#addServlet(java.lang.Class, java.lang.String) */ public ServletHolder addServlet(Class servlet, String pathSpec) { @@ -263,8 +265,8 @@ public class ServletTester /** * @param className * @param pathSpec - * @return - * @see org.eclipse.jetty.servlet.Scope#addServlet(java.lang.String, java.lang.String) + * @return the ServletHolder + * @see org.eclipse.jetty.servlet.ServletContextHandler#addServlet(java.lang.String, java.lang.String) */ public ServletHolder addServlet(String className, String pathSpec) { @@ -274,8 +276,8 @@ public class ServletTester /* ------------------------------------------------------------ */ /** * @param name - * @return - * @see org.eclipse.jetty.handler.ContextHandler#getAttribute(java.lang.String) + * @return the Attribute object + * @see org.eclipse.jetty.servlet.ServletContextHandler#getAttribute(java.lang.String) */ public Object getAttribute(String name) { @@ -284,8 +286,8 @@ public class ServletTester /* ------------------------------------------------------------ */ /** - * @return - * @see org.eclipse.jetty.handler.ContextHandler#getAttributeNames() + * @return the Attribute Names + * @see org.eclipse.jetty.servlet.ServletContextHandler#getAttributeNames() */ public Enumeration getAttributeNames() { @@ -294,8 +296,8 @@ public class ServletTester /* ------------------------------------------------------------ */ /** - * @return - * @see org.eclipse.jetty.handler.ContextHandler#getAttributes() + * @return the attributes + * @see org.eclipse.jetty.servlet.ServletContextHandler#getAttributes() */ public Attributes getAttributes() { @@ -304,8 +306,8 @@ public class ServletTester /* ------------------------------------------------------------ */ /** - * @return - * @see org.eclipse.jetty.handler.ContextHandler#getResourceBase() + * @return the resource base + * @see org.eclipse.jetty.servlet.ServletContextHandler#getResourceBase() */ public String getResourceBase() { @@ -316,7 +318,7 @@ public class ServletTester /** * @param name * @param value - * @see org.eclipse.jetty.handler.ContextHandler#setAttribute(java.lang.String, java.lang.Object) + * @see org.eclipse.jetty.servlet.ServletContextHandler#setAttribute(java.lang.String, java.lang.Object) */ public void setAttribute(String name, Object value) { @@ -326,7 +328,7 @@ public class ServletTester /* ------------------------------------------------------------ */ /** * @param classLoader - * @see org.eclipse.jetty.handler.ContextHandler#setClassLoader(java.lang.ClassLoader) + * @see org.eclipse.jetty.servlet.ServletContextHandler#setClassLoader(java.lang.ClassLoader) */ public void setClassLoader(ClassLoader classLoader) { @@ -336,7 +338,7 @@ public class ServletTester /* ------------------------------------------------------------ */ /** * @param contextPath - * @see org.eclipse.jetty.handler.ContextHandler#setContextPath(java.lang.String) + * @see org.eclipse.jetty.servlet.ServletContextHandler#setContextPath(java.lang.String) */ public void setContextPath(String contextPath) { @@ -346,7 +348,7 @@ public class ServletTester /* ------------------------------------------------------------ */ /** * @param eventListeners - * @see org.eclipse.jetty.handler.ContextHandler#setEventListeners(java.util.EventListener[]) + * @see org.eclipse.jetty.servlet.ServletContextHandler#setEventListeners(java.util.EventListener[]) */ public void setEventListeners(EventListener[] eventListeners) { @@ -356,7 +358,7 @@ public class ServletTester /* ------------------------------------------------------------ */ /** * @param resourceBase - * @see org.eclipse.jetty.handler.ContextHandler#setResourceBase(java.lang.String) + * @see org.eclipse.jetty.servlet.ServletContextHandler#setResourceBase(java.lang.String) */ public void setResourceBase(String resourceBase) { diff --git a/test-jetty-servlet/src/test/java/org/eclipse/jetty/testing/ServletTest.java b/test-jetty-servlet/src/test/java/org/eclipse/jetty/testing/ServletTest.java index 22e2bba9b0..48a34c137d 100644 --- a/test-jetty-servlet/src/test/java/org/eclipse/jetty/testing/ServletTest.java +++ b/test-jetty-servlet/src/test/java/org/eclipse/jetty/testing/ServletTest.java @@ -252,7 +252,7 @@ public class ServletTest extends TestCase ByteArrayBuffer out = new ByteArrayBuffer(4096); out.put(request0.getBytes("iso8859-1")); String responses = tester.getResponses(out).toString(); - + int offset = responses.indexOf("HTTP/1.1 500"); assertTrue(offset>=0); offset = responses.indexOf("Content-Length: ",offset); diff --git a/test-jetty-webapp/pom.xml b/test-jetty-webapp/pom.xml index 4b34394048..ca891bdd20 100644 --- a/test-jetty-webapp/pom.xml +++ b/test-jetty-webapp/pom.xml @@ -38,16 +38,67 @@ <configuration> <descriptors> <descriptor>config.xml</descriptor> + <descriptor>src/main/assembly/web-bundle.xml</descriptor> </descriptors> + <archive> + <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> + </archive> </configuration> </execution> </executions> </plugin> + <!-- also make this webapp an osgi bundle --> + <plugin> + <artifactId>maven-war-plugin</artifactId> + <configuration> + <archive> + <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>${felix.bundle.version}</version> + <extensions>true</extensions> + <configuration> + <supportedProjectTypes> + <supportedProjectType>war</supportedProjectType> + </supportedProjectTypes> + </configuration> + <executions> + <execution> + <id>bundle-manifest</id> + <phase>process-classes</phase> + <goals> + <goal>manifest</goal> + </goals> + <configuration> + <instructions> + <Bundle-SymbolicName>org.eclipse.jetty.test-jetty-webapp</Bundle-SymbolicName> + <Import-Package>javax.servlet,*</Import-Package> + <Export-Package>!com.acme*</Export-Package> + <!-- the test webapp is configured via a jetty xml file + in order to add the security handler. --> + <Web-ContextPath>/</Web-ContextPath> + <!-- in fact the '.' must not be there + but Felix-BND has a bug: + http://www.mail-archive.com/users@felix.apache.org/msg04730.html + https://issues.apache.org/jira/browse/FELIX-1571 + --> + <Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath> + <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment> + </instructions> + </configuration> + </execution> + </executions> + </plugin> + <!-- <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> - <version>7.0.0.RC2-SNAPSHOT</version> + <version>7.1.1-SNAPSHOT</version> <configuration> <stopPort>8087</stopPort> <stopKey>foo</stopKey> @@ -70,13 +121,12 @@ <loginServices> <loginService implementation="org.eclipse.jetty.security.HashLoginService"> <name>Test Realm</name> - <config>../jetty-server/src/main/config/etc/realm.properties</config> + <config>src/main/config/etc/realm.properties</config> </loginService> </loginServices> </configuration> </plugin> --> - <!-- uncomment to precompile jsps --> <!-- <plugin> @@ -152,5 +202,11 @@ <version>${project.version}</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>javax.servlet.jsp</groupId> + <artifactId>jsp-api</artifactId> + <version>2.1</version> + <scope>provided</scope> + </dependency> </dependencies> </project> diff --git a/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml b/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml new file mode 100644 index 0000000000..c181c35eac --- /dev/null +++ b/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> + +<!-- ================================================================== +Configure and deploy the test web application in $(jetty.home)/webapps/test + +Note. If this file did not exist or used a context path other that /test +then the default configuration of jetty.xml would discover the test +webapplication with a WebAppDeployer. By specifying a context in this +directory, additional configuration may be specified and hot deployments +detected. +===================================================================== --> + +<Configure class="org.eclipse.jetty.webapp.WebAppContext"> + + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- Required minimal context configuration : --> + <!-- + contextPath --> + <!-- + war OR resourceBase --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <Set name="contextPath">/</Set> + <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test.war</Set> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <!-- Optional context configuration --> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <Set name="extractWAR">true</Set> + <Set name="copyWebDir">false</Set> + <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set> + <Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/contexts/test.d/override-web.xml</Set> + + <!-- virtual hosts + <Set name="virtualHosts"> + <Array type="String"> + <Item>www.myVirtualDomain.com</Item> + <Item>localhost</Item> + <Item>127.0.0.1</Item> + </Array> + </Set> + --> + + <!-- disable cookies + <Get name="sessionHandler"> + <Get name="sessionManager"> + <Set name="usingCookies" type="boolean">false</Set> + </Get> + </Get> + --> + + <Get name="securityHandler"> + <Set name="loginService"> + <New class="org.eclipse.jetty.security.HashLoginService"> + <Set name="name">Test Realm</Set> + <Set name="config"><Property name="this.web-inf.url"/>realm.properties</Set> + <!-- To enable reload of realm when properties change, uncomment the following lines --> + <!-- changing refreshInterval (in seconds) as desired --> + <!-- + <Set name="refreshInterval">5</Set> + <Call name="start"></Call> + --> + </New> + </Set> + <Set name="checkWelcomeFiles">true</Set> + </Get> + + <!-- Non standard error page mapping --> + <!-- + <Get name="errorHandler"> + <Call name="addErrorPage"> + <Arg type="int">500</Arg> + <Arg type="int">599</Arg> + <Arg type="String">/dump/errorCodeRangeMapping</Arg> + </Call> + </Get> + --> + + <!-- Add context specific logger + <Set name="handler"> + <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"> + <Set name="requestLog"> + <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> + <Set name="filename"><Property name="jetty.logs" default="./logs"/>/test-yyyy_mm_dd.request.log</Set> + <Set name="filenameDateFormat">yyyy_MM_dd</Set> + <Set name="append">true</Set> + <Set name="LogTimeZone">GMT</Set> + </New> + </Set> + </New> + </Set> + --> + +</Configure> diff --git a/test-jetty-webapp/src/main/assembly/web-bundle.xml b/test-jetty-webapp/src/main/assembly/web-bundle.xml new file mode 100644 index 0000000000..b80faf973d --- /dev/null +++ b/test-jetty-webapp/src/main/assembly/web-bundle.xml @@ -0,0 +1,35 @@ +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>webbundle</id> + <formats> + <format>jar</format> + </formats> + <includeBaseDirectory>false</includeBaseDirectory> + <!-- baseDirectory>${basedir}/${project.build.directory}/${project.build.finalName}</baseDirectory --> + <fileSets> + <fileSet> + <directory>${basedir}/${project.build.directory}/${project.build.finalName}/</directory> + <outputDirectory></outputDirectory> + <includes> + <include>**/*.*</include> + </includes> + <excludes> + <exclude>WEB-INF/lib/**</exclude> + <exclude>WEB-INF/jetty-web.xml</exclude> + </excludes> + </fileSet> + </fileSets> + <files> + <file> + <source>src/main/assembly/embedded-jetty-web-for-webbundle.xml</source> + <outputDirectory>WEB-INF</outputDirectory> + <destName>jetty-web.xml</destName> + </file> + <file> + <source>src/main/config/etc/realm.properties</source> + <outputDirectory>WEB-INF</outputDirectory> + <destName>realm.properties</destName> + </file> + </files> +</assembly> diff --git a/test-jetty-webapp/src/main/config/contexts/demo.xml b/test-jetty-webapp/src/main/config/contexts-available/move-context.xml index 5e1ed11be9..7821b3d903 100644 --- a/test-jetty-webapp/src/main/config/contexts/demo.xml +++ b/test-jetty-webapp/src/main/config/contexts-available/move-context.xml @@ -2,8 +2,8 @@ <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> <Configure class="org.eclipse.jetty.server.handler.MovedContextHandler"> - <Set name="contextPath">/demo</Set> - <Set name="newContextURL">/test</Set> + <Set name="contextPath">/oldContextPath</Set> + <Set name="newContextURL">/test/dump/newContextPath</Set> <Set name="permanent">false</Set> <Set name="discardPathInfo">false</Set> <Set name="discardQuery">false</Set> diff --git a/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml b/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml index 432ba81344..9e42d6d5ef 100644 --- a/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml +++ b/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml @@ -15,6 +15,16 @@ <param-value>a context value</param-value> </context-param> + <!-- Add or override filter init parameter --> + <filter> + <filter-name>TestFilter</filter-name> + <filter-class>com.acme.TestFilter</filter-class> + <init-param> + <param-name>remote</param-name> + <param-value>false</param-value> + </init-param> + </filter> + <!-- Add or override servlet init parameter --> <servlet> <servlet-name>Dump</servlet-name> diff --git a/test-jetty-webapp/src/main/config/contexts/test.xml b/test-jetty-webapp/src/main/config/contexts/test.xml index fb5f7d31c5..3c36173b13 100644 --- a/test-jetty-webapp/src/main/config/contexts/test.xml +++ b/test-jetty-webapp/src/main/config/contexts/test.xml @@ -75,4 +75,19 @@ detected. </Get> --> + <!-- Add context specific logger + <Set name="handler"> + <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"> + <Set name="requestLog"> + <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> + <Set name="filename"><Property name="jetty.logs" default="./logs"/>/test-yyyy_mm_dd.request.log</Set> + <Set name="filenameDateFormat">yyyy_MM_dd</Set> + <Set name="append">true</Set> + <Set name="LogTimeZone">GMT</Set> + </New> + </Set> + </New> + </Set> + --> + </Configure> diff --git a/test-jetty-webapp/src/main/config/etc/jetty-testrealm.xml b/test-jetty-webapp/src/main/config/etc/jetty-testrealm.xml new file mode 100644 index 0000000000..5926b19c89 --- /dev/null +++ b/test-jetty-webapp/src/main/config/etc/jetty-testrealm.xml @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> + +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <!-- =========================================================== --> + <!-- Configure Authentication Login Service --> + <!-- Realms may be configured for the entire server here, or --> + <!-- they can be configured for a specific web app in a context --> + <!-- configuration (see $(jetty.home)/contexts/test.xml for an --> + <!-- example). --> + <!-- =========================================================== --> + <Call name="addBean"> + <Arg> + <New class="org.eclipse.jetty.security.HashLoginService"> + <Set name="name">Test Realm</Set> + <Set name="config"><Property name="jetty.home" default="."/>/etc/realm.properties</Set> + <Set name="refreshInterval">0</Set> + </New> + </Arg> + </Call> + +</Configure> diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/realm.properties b/test-jetty-webapp/src/main/config/etc/realm.properties index cbf905de9f..cbf905de9f 100644 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/realm.properties +++ b/test-jetty-webapp/src/main/config/etc/realm.properties diff --git a/test-jetty-webapp/src/main/java/com/acme/Counter.java b/test-jetty-webapp/src/main/java/com/acme/Counter.java index 62b89abe42..d5546e5be9 100644 --- a/test-jetty-webapp/src/main/java/com/acme/Counter.java +++ b/test-jetty-webapp/src/main/java/com/acme/Counter.java @@ -1,20 +1,20 @@ -// ======================================================================== -// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== +//======================================================================== +//Copyright 2004-2008 Mort Bay Consulting Pty. Ltd. +//------------------------------------------------------------------------ +//Licensed 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 com.acme; - -public class Counter +public class Counter implements java.io.Serializable { int counter=0; String last; diff --git a/test-jetty-webapp/src/main/java/com/acme/Date2Tag.java b/test-jetty-webapp/src/main/java/com/acme/Date2Tag.java new file mode 100644 index 0000000000..de9c9f49b6 --- /dev/null +++ b/test-jetty-webapp/src/main/java/com/acme/Date2Tag.java @@ -0,0 +1,49 @@ +//======================================================================== +//Copyright 2004-2008 Mort Bay Consulting Pty. Ltd. +//------------------------------------------------------------------------ +//Licensed 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 com.acme; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.StringTokenizer; + +import javax.servlet.jsp.JspContext; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.tagext.JspFragment; +import javax.servlet.jsp.tagext.SimpleTagSupport; + +public class Date2Tag extends SimpleTagSupport +{ + String format; + + public void setFormat(String value) { + this.format = value; + } + + public void doTag() throws JspException, IOException { + String formatted = + new SimpleDateFormat("long".equals(format)?"EEE 'the' d:MMM:yyyy":"d:MM:yy") + .format(new Date()); + StringTokenizer tok = new StringTokenizer(formatted,":"); + JspContext context = getJspContext(); + context.setAttribute("day", tok.nextToken() ); + context.setAttribute("month", tok.nextToken() ); + context.setAttribute("year", tok.nextToken() ); + + JspFragment fragment = getJspBody(); + fragment.invoke(null); + } +} + diff --git a/test-jetty-webapp/src/main/java/com/acme/DateTag.java b/test-jetty-webapp/src/main/java/com/acme/DateTag.java new file mode 100644 index 0000000000..a54c72dda7 --- /dev/null +++ b/test-jetty-webapp/src/main/java/com/acme/DateTag.java @@ -0,0 +1,66 @@ +//======================================================================== +//Copyright 2004-2008 Mort Bay Consulting Pty. Ltd. +//------------------------------------------------------------------------ +//Licensed 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 com.acme; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspTagException; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.tagext.BodyContent; +import javax.servlet.jsp.tagext.BodyTagSupport; +import javax.servlet.jsp.tagext.Tag; + +public class DateTag extends BodyTagSupport +{ + Tag parent; + BodyContent body; + String tz="GMT"; + + public void setParent(Tag parent) {this.parent=parent;} + public Tag getParent() {return parent;} + public void setBodyContent(BodyContent content) {body=content;} + public void setPageContext(PageContext pageContext) {} + + public void setTz(String value) {tz=value;} + + public int doStartTag() throws JspException {return EVAL_BODY_TAG;} + + public int doEndTag() throws JspException {return EVAL_PAGE;} + + public void doInitBody() throws JspException {} + + public int doAfterBody() throws JspException { + try + { + SimpleDateFormat format = new SimpleDateFormat(body.getString()); + format.setTimeZone(TimeZone.getTimeZone(tz)); + body.getEnclosingWriter().write(format.format(new Date())); + return SKIP_BODY; + } + catch (Exception ex) { + ex.printStackTrace(); + throw new JspTagException(ex.toString()); + } + } + + public void release() + { + body=null; + } +} + diff --git a/test-jetty-webapp/src/main/java/com/acme/Dump.java b/test-jetty-webapp/src/main/java/com/acme/Dump.java index 399d8cd6a6..86a04ffbd0 100644 --- a/test-jetty-webapp/src/main/java/com/acme/Dump.java +++ b/test-jetty-webapp/src/main/java/com/acme/Dump.java @@ -13,6 +13,7 @@ package com.acme; import java.io.BufferedWriter; +import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -20,10 +21,12 @@ import java.io.PrintWriter; import java.io.Reader; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.util.Date; import java.util.Enumeration; import java.util.Locale; import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; @@ -551,7 +554,6 @@ public class Dump extends HttpServlet pout.write("</pre></td>"); } - pout.write("</tr><tr>\n"); pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Request Attributes:</big></th>"); Enumeration a= request.getAttributeNames(); @@ -560,8 +562,16 @@ public class Dump extends HttpServlet name= (String)a.nextElement(); pout.write("</tr><tr>\n"); pout.write("<th align=\"right\" valign=\"top\">"+name.replace("."," .")+": </th>"); - pout.write("<td>"+"<pre>" + toString(request.getAttribute(name)) + "</pre>"+"</td>"); - } + Object value=request.getAttribute(name); + if (value instanceof File) + { + File file = (File)value; + pout.write("<td>"+"<pre>" + file.getName()+" ("+file.length()+" "+new Date(file.lastModified())+ ")</pre>"+"</td>"); + } + else + pout.write("<td>"+"<pre>" + toString(request.getAttribute(name)) + "</pre>"+"</td>"); + } + request.setAttribute("org.eclipse.jetty.servlet.MultiPartFilter.files",null); pout.write("</tr><tr>\n"); @@ -597,13 +607,28 @@ public class Dump extends HttpServlet pout.write("<td>"+"<pre>" + toString(getServletContext().getAttribute(name)) + "</pre>"+"</td>"); } - String res= request.getParameter("resource"); if (res != null && res.length() > 0) { pout.write("</tr><tr>\n"); pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Get Resource: \""+res+"\"</big></th>"); + + pout.write("</tr><tr>\n"); + pout.write("<th align=\"right\">getServletContext().getContext(...): </th>"); + + ServletContext context = getServletContext().getContext(res); + pout.write("<td>"+context+"</td>"); + if (context!=null) + { + String cp=context.getContextPath(); + if (cp==null || "/".equals(cp)) + cp=""; + pout.write("</tr><tr>\n"); + pout.write("<th align=\"right\">getServletContext().getContext(...),getRequestDispatcher(...): </th>"); + pout.write("<td>"+getServletContext().getContext(res).getRequestDispatcher(res.substring(cp.length()))+"</td>"); + } + pout.write("</tr><tr>\n"); pout.write("<th align=\"right\">this.getClass().getResource(...): </th>"); pout.write("<td>"+this.getClass().getResource(res)+"</td>"); diff --git a/test-jetty-webapp/src/main/java/com/acme/TestFilter.java b/test-jetty-webapp/src/main/java/com/acme/TestFilter.java index 5c2c367360..0d43e8158e 100644 --- a/test-jetty-webapp/src/main/java/com/acme/TestFilter.java +++ b/test-jetty-webapp/src/main/java/com/acme/TestFilter.java @@ -14,6 +14,8 @@ package com.acme; import java.io.IOException; +import java.util.HashSet; +import java.util.Set; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -25,15 +27,23 @@ import javax.servlet.ServletRequestWrapper; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ /** TestFilter. * - * + * This filter checks for a none local request, and if the init parameter + * "remote" is not set to true, then all non local requests are forwarded + * to /remote.html + * */ public class TestFilter implements Filter { + private boolean _remote; private ServletContext _context; + private final Set<String> _allowed = new HashSet<String>(); /* ------------------------------------------------------------ */ /* @@ -42,6 +52,11 @@ public class TestFilter implements Filter public void init(FilterConfig filterConfig) throws ServletException { _context= filterConfig.getServletContext(); + _remote=Boolean.parseBoolean(filterConfig.getInitParameter("remote")); + _allowed.add("/favicon.ico"); + _allowed.add("/jetty_banner.gif"); + + Log.debug("TestFilter#remote="+_remote); } /* ------------------------------------------------------------ */ @@ -51,6 +66,21 @@ public class TestFilter implements Filter public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + String from = request.getRemoteHost(); + String to = request.getServerName(); + String path=((HttpServletRequest)request).getServletPath(); + + if (!_remote && !_allowed.contains(path) && ( + !from.equals("localhost") && !from.startsWith("127.") || + !to.equals("localhost")&&!to.startsWith("127.0.0."))) + { + if ("/".equals(path)) + _context.getRequestDispatcher("/remote.html").forward(request,response); + else + ((HttpServletResponse)response).sendRedirect("/remote.html"); + return; + } + Integer old_value=null; ServletRequest r = request; while (r instanceof ServletRequestWrapper) diff --git a/test-jetty-webapp/src/main/java/com/acme/WebSocketChatServlet.java b/test-jetty-webapp/src/main/java/com/acme/WebSocketChatServlet.java index 4ba4b54204..3b1e3090f4 100644 --- a/test-jetty-webapp/src/main/java/com/acme/WebSocketChatServlet.java +++ b/test-jetty-webapp/src/main/java/com/acme/WebSocketChatServlet.java @@ -50,16 +50,21 @@ public class WebSocketChatServlet extends WebSocketServlet public void onMessage(byte frame, String data) { - // Log.info(this+" onMessage: "+data); - for (ChatWebSocket member : _members) + if (data.indexOf("disconnect")>=0) + _outbound.disconnect(); + else { - try + // Log.info(this+" onMessage: "+data); + for (ChatWebSocket member : _members) { - member._outbound.sendMessage(frame,data); - } - catch(IOException e) - { - Log.warn(e); + try + { + member._outbound.sendMessage(frame,data); + } + catch(IOException e) + { + Log.warn(e); + } } } } diff --git a/test-jetty-webapp/src/main/webapp/META-INF/MANIFEST.MF b/test-jetty-webapp/src/main/webapp/META-INF/MANIFEST.MF index 5e9495128c..cc61b1a652 100644 --- a/test-jetty-webapp/src/main/webapp/META-INF/MANIFEST.MF +++ b/test-jetty-webapp/src/main/webapp/META-INF/MANIFEST.MF @@ -1,3 +1,23 @@ Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: TestIt
+Bundle-SymbolicName: TestIt
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: testit.Activator
+Import-Package: javax.servlet,
+ javax.servlet.http,
+ javax.servlet.jsp,
+ javax.servlet.jsp.tagext
+Require-Bundle: org.eclipse.jetty.client,
+ org.eclipse.jetty.continuation,
+ org.eclipse.jetty.http,
+ org.eclipse.jetty.io,
+ org.eclipse.jetty.servlets,
+ org.eclipse.jetty.util,
+ org.eclipse.jetty.websocket
+Bundle-ClassPath: WEB-INF/classes
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-ActivationPolicy: lazy
+Web-ContextPath: /
Class-Path:
diff --git a/test-jetty-webapp/src/main/webapp/WEB-INF/acme-taglib.tld b/test-jetty-webapp/src/main/webapp/WEB-INF/acme-taglib.tld new file mode 100644 index 0000000000..03adecef5e --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/WEB-INF/acme-taglib.tld @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE taglib + PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" + "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> + +<taglib> + + <tlib-version>1.0</tlib-version> + <jsp-version>1.2</jsp-version> + <short-name>acme</short-name> + <uri>http://www.acme.com/taglib</uri> + <description>taglib example</description> + <listener> + <listener-class>com.acme.TagListener</listener-class> + </listener> + + <tag> + <name>date</name> + <tag-class>com.acme.DateTag</tag-class> + <body-content>TAGDEPENDENT</body-content> + <description>Display Date</description> + <attribute> + <name>tz</name> + <required>false</required> + </attribute> + </tag> + +</taglib> diff --git a/test-jetty-webapp/src/main/webapp/WEB-INF/acme-taglib2.tld b/test-jetty-webapp/src/main/webapp/WEB-INF/acme-taglib2.tld new file mode 100644 index 0000000000..3edb7bb14f --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/WEB-INF/acme-taglib2.tld @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<taglib xmlns="http://java.sun.com/xml/ns/j2ee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd" + version="2.0"> + <description>Acme JSP2 tags</description> + <tlib-version>1.0</tlib-version> + <short-name>acme2</short-name> + <uri>http://www.acme.com/taglib2</uri> + <tag> + <description>Simple Date formatting</description> + <name>date2</name> + <tag-class>com.acme.Date2Tag</tag-class> + <body-content>scriptless</body-content> + <variable> + <description>Day of the Month</description> + <name-given>day</name-given> + </variable> + <variable> + <description>Month of the Year</description> + <name-given>month</name-given> + </variable> + <variable> + <description>Year</description> + <name-given>year</name-given> + </variable> + <attribute> + <name>format</name> + <required>true</required> + <rtexprvalue>true</rtexprvalue> + </attribute> + </tag> +</taglib> + diff --git a/test-jetty-webapp/src/main/webapp/WEB-INF/tags/panel.tag b/test-jetty-webapp/src/main/webapp/WEB-INF/tags/panel.tag new file mode 100644 index 0000000000..fa0540a61d --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/WEB-INF/tags/panel.tag @@ -0,0 +1,17 @@ +<%--
+ - Copyright (c) 2002 The Apache Software Foundation. All rights
+ - reserved.
+--%>
+<%@ attribute name="color" %>
+<%@ attribute name="bgcolor" %>
+<%@ attribute name="title" %>
+<table border="1" bgcolor="${color}">
+ <tr>
+ <td><b>${title}</b></td>
+ </tr>
+ <tr>
+ <td bgcolor="${bgcolor}">
+ <jsp:doBody/>
+ </td>
+ </tr>
+</table>
diff --git a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml index c962d53c99..9cb725596a 100644 --- a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml +++ b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml @@ -9,7 +9,7 @@ <context-param> <param-name>org.eclipse.jetty.server.context.ManagedAttributes</param-name> - <param-value>org.eclipse.jetty.servlets.ProxyServlet.Logger,org.eclipse.jetty.servlets.ProxyServlet.ThreadPool,org.eclipse.jetty.servlets.ProxyServlet.HttpClient</param-value> + <param-value>QoSFilter,TransparentProxy.Logger,TransparentProxy.ThreadPool,TransparentProxy.HttpClient</param-value> </context-param> <!-- Declare TestListener, which declares TestFilter --> @@ -18,19 +18,37 @@ </listener> <filter> + <filter-name>TestFilter</filter-name> + <filter-class>com.acme.TestFilter</filter-class> + <init-param> + <param-name>remote</param-name> + <param-value>false</param-value> + </init-param> + </filter> + <filter-mapping> + <filter-name>TestFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + + <filter> <filter-name>QoSFilter</filter-name> <filter-class>org.eclipse.jetty.servlets.QoSFilter</filter-class> <init-param> <param-name>maxRequests</param-name> <param-value>20</param-value> </init-param> - </filter> - + <init-param> + <param-name>managedAttr</param-name> + <param-value>true</param-value> + </init-param> + </filter> <filter-mapping> <filter-name>QoSFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> + <filter> <filter-name>MultiPart</filter-name> <filter-class>org.eclipse.jetty.servlets.MultiPartFilter</filter-class> @@ -44,6 +62,7 @@ <url-pattern>/dump/*</url-pattern> </filter-mapping> + <filter> <filter-name>GzipFilter</filter-name> <filter-class>org.eclipse.jetty.servlets.IncludableGzipFilter</filter-class> @@ -216,17 +235,19 @@ <servlet-name>TransparentProxy</servlet-name> <servlet-class>org.eclipse.jetty.servlets.ProxyServlet$Transparent</servlet-class> <init-param> - <param-name>Prefix</param-name><param-value>/google</param-value> + <param-name>Prefix</param-name><param-value>/javadoc</param-value> + </init-param> + <init-param> + <param-name>ProxyTo</param-name><param-value>http://download.eclipse.org/jetty/stable-7/apidocs</param-value> </init-param> <init-param> - <param-name>ProxyTo</param-name><param-value>http://www.google.com</param-value> + <param-name>HostHeader</param-name><param-value>download.eclipse.org</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> - <servlet-mapping> <servlet-name>TransparentProxy</servlet-name> - <url-pattern>/google/*</url-pattern> + <url-pattern>/javadoc/*</url-pattern> </servlet-mapping> <error-page> @@ -284,12 +305,10 @@ </user-data-constraint> </security-constraint> -<!-- <login-config> <auth-method>BASIC</auth-method> <realm-name>Test Realm</realm-name> </login-config> ---> <!-- <login-config> @@ -298,6 +317,7 @@ </login-config> --> +<!-- <login-config> <auth-method>FORM</auth-method> <realm-name>Test Realm</realm-name> @@ -306,6 +326,7 @@ <form-error-page>/logonError.html?param=test</form-error-page> </form-login-config> </login-config> +--> <session-config> <session-timeout>5</session-timeout> diff --git a/test-jetty-webapp/src/main/webapp/index.html b/test-jetty-webapp/src/main/webapp/index.html index bf44fdd476..f96f625d95 100644 --- a/test-jetty-webapp/src/main/webapp/index.html +++ b/test-jetty-webapp/src/main/webapp/index.html @@ -10,8 +10,8 @@ <p> This is the Test webapp for the Jetty 8 HTTP Server and Servlet Container. For more information about Jetty, please visit our -<a href="http://jetty.eclipse.org">website</a> -or <a href="http://docs.codehaus.org/display/JETTY/Jetty+Wiki">wiki</a>. +<a href="http://www.eclipse.org/jetty">website</a> +or <a href="http://wiki.eclipse.org/Jetty">wiki</a>. Commercial support for Jetty is available via <a href="http://www.webtide.com">webtide</a>. </p> <p> @@ -28,7 +28,8 @@ This is a test context that serves: <li>Dump: <a href="dump/info">Request</a>, <a href="session/">Session</a>, <a href="cookie/">Cookie</a></li> <li><a href="dispatch">Dispatcher Servlet</a></li> <li><a href="rewrite/">Request Rewrite Servlet</a></li> -<li><a href="google/">Transparent Proxy</a> (to www.google.com)</li> +<li><a href="jsp/">JSP examples</a></li> +<li><a href="javadoc/">Transparent Proxy</a> (to javadoc @ eclipse.org)</li> <li>Comet Chat: <a href="chat/">Long Polling</a>, <a href="ws">WebSocket</a></li> <li><a href="auth.html">Authentication</a></li> </ul> diff --git a/test-jetty-webapp/src/main/webapp/jsp/bean1.jsp b/test-jetty-webapp/src/main/webapp/jsp/bean1.jsp new file mode 100644 index 0000000000..0c15da2ca4 --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/jsp/bean1.jsp @@ -0,0 +1,15 @@ +<html> +<%@ page session="true"%> +<body> +<jsp:useBean id='counter' scope='session' class='com.acme.Counter' type="com.acme.Counter" /> + +<h1>JSP1.2 Beans: 1</h1> + +Counter accessed <jsp:getProperty name="counter" property="count"/> times.<br/> +Counter last accessed by <jsp:getProperty name="counter" property="last"/><br/> +<jsp:setProperty name="counter" property="last" value="<%= request.getRequestURI()%>"/> + +<a href="bean2.jsp">Goto bean2.jsp</a> + +</body> +</html> diff --git a/test-jetty-webapp/src/main/webapp/jsp/bean2.jsp b/test-jetty-webapp/src/main/webapp/jsp/bean2.jsp new file mode 100644 index 0000000000..624dc2e59d --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/jsp/bean2.jsp @@ -0,0 +1,15 @@ +<html> +<%@ page session="true"%> +<body> +<jsp:useBean id='counter' scope='session' class='com.acme.Counter' type="com.acme.Counter" /> + +<h1>JSP1.2 Beans: 2</h1> + +Counter accessed <jsp:getProperty name="counter" property="count"/> times.<br/> +Counter last accessed by <jsp:getProperty name="counter" property="last"/><br/> +<jsp:setProperty name="counter" property="last" value="<%= request.getRequestURI()%>"/> + +<a href="bean1.jsp">Goto bean1.jsp</a> + +</body> +</html> diff --git a/test-jetty-webapp/src/main/webapp/jsp/dump.jsp b/test-jetty-webapp/src/main/webapp/jsp/dump.jsp new file mode 100644 index 0000000000..fb73b0b000 --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/jsp/dump.jsp @@ -0,0 +1,23 @@ +<html><head> +<%@ page import="java.util.Enumeration" %> +</head><body> +<h1>JSP Dump</h1> + +<table border="1"> +<tr><th>Request URI:</th><td><%= request.getRequestURI() %></td></tr> +<tr><th>ServletPath:</th><td><%= request.getServletPath() %></td></tr> +<tr><th>PathInfo:</th><td><%= request.getPathInfo() %></td></tr> + +<% + Enumeration e =request.getParameterNames(); + while(e.hasMoreElements()) + { + String name = (String)e.nextElement(); +%> +<tr> + <th>getParameter("<%= name %>")</th> + <td><%= request.getParameter(name) %></td></tr> +<% } %> + +</table> +</body></html> diff --git a/test-jetty-webapp/src/main/webapp/jsp/expr.jsp b/test-jetty-webapp/src/main/webapp/jsp/expr.jsp new file mode 100644 index 0000000000..e0b25e2020 --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/jsp/expr.jsp @@ -0,0 +1,23 @@ +<html> +<h1>JSP2.0 Expressions</h1> + +<table border="1"> + <tr><th>Expression</th><th>Result</th></tr> + <tr> + <td>\${param["A"]}</td> + <td>${param["A"]} </td> + </tr><tr> + <td>\${header["host"]}</td> + <td>${header["host"]}</td> + </tr><tr> + <td>\${header["user-agent"]}</td> + <td>${header["user-agent"]}</td> + </tr><tr> + <td>\${1+1}</td> + <td>${1+1}</td> + </tr><tr> + <td>\${param["A"] * 2}</td> + <td>${param["A"] * 2} </td> + </tr> +</table> +</html> diff --git a/test-jetty-webapp/src/main/webapp/jsp/index.html b/test-jetty-webapp/src/main/webapp/jsp/index.html new file mode 100644 index 0000000000..935f85bc7a --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/jsp/index.html @@ -0,0 +1,18 @@ +<html> +<body> + +<h1>JSP Examples</h1> + +<ul> +<li><a href="dump.jsp">JSP 1.2 embedded java</a><br/> +<li><a href="bean1.jsp">JSP 1.2 Bean demo</a><br/> +<li><a href="tag.jsp">JSP 1.2 BodyTag demo</a><br/> +<li><a href="tag2.jsp">JSP 2.0 SimpleTag demo</a><br/> +<li><a href="tagfile.jsp">JSP 2.0 Tag File demo</a><br/> +<li><a href="expr.jsp?A=1">JSP 2.0 Tag Expression</a><br/> +</ul> +<a href="/">Main Menu</a> + + +</body> +</html> diff --git a/test-jetty-webapp/src/main/webapp/jsp/tag.jsp b/test-jetty-webapp/src/main/webapp/jsp/tag.jsp new file mode 100644 index 0000000000..069d8c67b1 --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/jsp/tag.jsp @@ -0,0 +1,16 @@ +<html> +<body> + +<%@ taglib uri="http://www.acme.com/taglib" prefix="acme" %> + +<small><acme:date tz="GMT">EEE, dd/MMM/yyyy HH:mm:ss ZZZ</acme:date> +==></small> +<acme:date tz="GMT">EEE, dd/MMM/yyyy HH:mm:ss ZZZ</acme:date> +<br/> +<small><acme:date tz="EST">EEE, dd-MMM-yyyy HH:mm:ss ZZZ</acme:date> +==></small> +<acme:date tz="EST">EEE, dd-MMM-yyyy HH:mm:ss ZZZ</acme:date> +<br/> + +</body> +</html> diff --git a/test-jetty-webapp/src/main/webapp/jsp/tag2.jsp b/test-jetty-webapp/src/main/webapp/jsp/tag2.jsp new file mode 100644 index 0000000000..8071927562 --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/jsp/tag2.jsp @@ -0,0 +1,19 @@ +<html> +<body> + +<%@ taglib uri="http://www.acme.com/taglib2" prefix="acme" %> + +<acme:date2 format="long"> + On ${day} of ${month} in the year ${year} +</acme:date2> + +<br/> + +<acme:date2 format="short"> + ${day} - ${month} - ${year} +</acme:date2> + +<br/> + +</body> +</html> diff --git a/test-jetty-webapp/src/main/webapp/jsp/tagfile.jsp b/test-jetty-webapp/src/main/webapp/jsp/tagfile.jsp new file mode 100644 index 0000000000..67299f0229 --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/jsp/tagfile.jsp @@ -0,0 +1,37 @@ +<%@ taglib prefix="acme" tagdir="/WEB-INF/tags" %> +<html> + <head> + </head> + <body> + <h1>JSP 2.0 Tag File Example</h1> + <hr> + <p>Panel tag created from JSP fragment file in WEB-INF/tags + <hr> + <table border="0"> + <tr valign="top"> + <td> + <acme:panel color="#ff8080" bgcolor="#ffc0c0" title="Panel 1"> + First panel.<br/> + </acme:panel> + </td> + <td> + <acme:panel color="#80ff80" bgcolor="#c0ffc0" title="Panel 2"> + Second panel.<br/> + Second panel.<br/> + Second panel.<br/> + Second panel.<br/> + </acme:panel> + </td> + <td> + <acme:panel color="#8080ff" bgcolor="#c0c0ff" title="Panel 3"> + Third panel.<br/> + <acme:panel color="#ff80ff" bgcolor="#ffc0ff" title="Inner"> + A panel in a panel. + </acme:panel> + Third panel.<br/> + </acme:panel> + </td> + </tr> + </table> + </body> +</html> diff --git a/test-jetty-webapp/src/main/webapp/remote.html b/test-jetty-webapp/src/main/webapp/remote.html new file mode 100644 index 0000000000..f979afc369 --- /dev/null +++ b/test-jetty-webapp/src/main/webapp/remote.html @@ -0,0 +1,33 @@ +<HTML> + <HEAD> + <TITLE>Powered By Jetty</TITLE> + <META http-equiv="Pragma" content="no-cache"> + <META http-equiv="Cache-Control" content="no-cache,no-store"> + </HEAD> +<BODY> +<A HREF="http://jetty.eclipse.org"><IMG SRC="jetty_banner.gif"></A> +<h1>Welcome to Jetty 7 - REMOTE ACCESS!!</h1> +<p> +This is the Test webapp for the Jetty 7 HTTP Server and Servlet Container. +For more information about Jetty, please visit our +<a href="http://jetty.eclipse.org">website</a> +or <a href="http://docs.codehaus.org/display/JETTY/Jetty+Wiki">wiki</a>. +Commercial support for Jetty is available via <a href="http://www.webtide.com">webtide</a>. +</p> +<p> +This is a test context that serves several demo filters and servlets. However, these +test servlets are not safe for deployment on the internet as (by design) they contain +cross domain scripting vulnerabilities and reveal private information. This page +is displayed because you have access the context from a non local IP address. +</p> +<p> +You can disable the remote address checking by editing contexts/test.d/override-web.xml and changing the +"remote" init parameter to true for the TestFilter. +</p> +<p> +This webapp is deployed in $JETTY_HOME/webapp/test and configured by $JETTY_HOME/contexts/test.xml +and $JETTY_HOME/contexts/test.d/override-web.xml +</p> + +</BODY> +</HTML> diff --git a/test-jetty-webapp/src/main/webapp/ws/index.html b/test-jetty-webapp/src/main/webapp/ws/index.html index 9e801eebe0..a88db337ab 100644 --- a/test-jetty-webapp/src/main/webapp/ws/index.html +++ b/test-jetty-webapp/src/main/webapp/ws/index.html @@ -14,7 +14,7 @@ var room = { join: function(name) { this._username=name; - var location = document.location.toString().replace('http:','ws:'); + var location = document.location.toString().replace('http://','ws://').replace('https://','wss://'); this._ws=new WebSocket(location); this._ws.onopen=this._onopen; this._ws.onmessage=this._onmessage; diff --git a/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java b/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java index eeb1a0b379..952752173b 100644 --- a/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java +++ b/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java @@ -13,6 +13,7 @@ package org.eclipse.jetty; +import java.io.File; import java.lang.management.ManagementFactory; import org.eclipse.jetty.jmx.MBeanContainer; @@ -28,6 +29,7 @@ import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.StdErrLog; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.webapp.WebAppContext; @@ -35,8 +37,10 @@ public class TestServer { public static void main(String[] args) throws Exception { - String jetty_home = System.getProperty("jetty.home","../jetty-distribution/target/distribution"); - System.setProperty("jetty.home",jetty_home); + Log.getLog().setDebugEnabled(true); + ((StdErrLog)Log.getLog()).setSource(false); + + String jetty_root = ".."; Server server = new Server(); server.setSendDateHeader(true); @@ -63,10 +67,10 @@ public class TestServer SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector(); ssl_connector.setPort(8443); - ssl_connector.setKeystore(jetty_home + "/etc/keystore"); + ssl_connector.setKeystore(jetty_root + "/jetty-server/src/main/config/etc/keystore"); ssl_connector.setPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); ssl_connector.setKeyPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); - ssl_connector.setTruststore(jetty_home + "/etc/keystore"); + ssl_connector.setTruststore(jetty_root + "/jetty-server/src/main/config/etc/keystore"); ssl_connector.setTrustPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); server.addConnector(ssl_connector); @@ -82,24 +86,24 @@ public class TestServer HashLoginService login = new HashLoginService(); login.setName("Test Realm"); - login.setConfig(jetty_home + "/etc/realm.properties"); + login.setConfig(jetty_root + "/test-jetty-webapp/src/main/config/etc/realm.properties"); server.addBean(login); - NCSARequestLog requestLog = new NCSARequestLog(jetty_home + "/logs/jetty-yyyy_mm_dd.log"); + File log=File.createTempFile("jetty-yyyy_mm_dd", "log"); + NCSARequestLog requestLog = new NCSARequestLog(log.toString()); requestLog.setExtended(false); requestLogHandler.setRequestLog(requestLog); server.setStopAtShutdown(true); server.setSendServerVersion(true); - WebAppContext webapp = new WebAppContext(); webapp.setParentLoaderPriority(true); webapp.setResourceBase("./src/main/webapp"); + webapp.setAttribute("testAttribute","testValue"); contexts.addHandler(webapp); - server.start(); server.join(); } diff --git a/tests/pom.xml b/tests/pom.xml index b476b4f47f..1fb4d64c6b 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -28,10 +28,29 @@ <name>Jetty Tests :: Parent</name> <packaging>pom</packaging> <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <!-- No Point running Findbugs on testing projects --> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <!-- DO NOT DEPLOY (or Release) --> + <skip>true</skip> + </configuration> + </plugin> + </plugins> </build> <modules> <module>test-integration</module> <module>test-webapps</module> <module>test-sessions</module> + <module>test-loginservice</module> </modules> </project> diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml index 97b18517cb..06b584d6ee 100644 --- a/tests/test-integration/pom.xml +++ b/tests/test-integration/pom.xml @@ -75,7 +75,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> - <version>4.6</version> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/AbstractJettyTestCase.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/AbstractJettyTestCase.java deleted file mode 100644 index 900aa7cf54..0000000000 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/AbstractJettyTestCase.java +++ /dev/null @@ -1,98 +0,0 @@ -// ======================================================================== -// 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.test; - -import java.io.File; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; - -public abstract class AbstractJettyTestCase extends TestCase -{ - public static final boolean IS_ON_WINDOWS = System.getProperty("os.name").startsWith("Windows"); - private File baseDir; - - public File getBaseDir() - { - if (baseDir == null) - { - String baseDirPath = System.getProperty("basedir"); - if (baseDirPath == null) - { - baseDirPath = System.getProperty("user.dir","."); - } - baseDir = new File(baseDirPath); - } - - return baseDir; - } - - public File getTargetDir() - { - File path = new File(getBaseDir(),"target"); - assertDirExists("target dir",path); - return path; - } - - public File getTestResourcesDir() - { - File path = new File(getBaseDir(),"src/test/resources"); - assertDirExists("test resources dir",path); - return path; - } - - public File getDocRootBase() - { - File path = new File(getTestResourcesDir(),"docroots"); - assertDirExists("docroot base dir",path); - return path; - } - - public void assertDirExists(String msg, File path) - { - assertNotNull(msg + " should not be null",path); - assertTrue(msg + " should exist",path.exists()); - assertTrue(msg + " should be a directory",path.isDirectory()); - } - - /** - * Return the port that the server is listening on. - * - * Assumes 1 connector, and that server is started already. - * - * @param server - * the server port. - * @return the port that the server is listening on. - */ - public int findServerPort(Server server) - { - Connector connectors[] = server.getConnectors(); - for (int i = 0; i < connectors.length; i++) - { - Connector connector = connectors[i]; - if (connector.getLocalPort() > 0) - { - return connector.getLocalPort(); - } - } - - throw new AssertionFailedError("No valid connector port found."); - } -} diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/DefaultHandlerTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/DefaultHandlerTest.java index 0906e7835f..402f7521ba 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/DefaultHandlerTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/DefaultHandlerTest.java @@ -31,41 +31,42 @@ import org.eclipse.jetty.test.support.rawhttp.HttpResponseTester; import org.eclipse.jetty.test.support.rawhttp.HttpSocketImpl; import org.eclipse.jetty.test.support.rawhttp.HttpTesting; import org.eclipse.jetty.util.IO; -import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; /** * Tests against the facilities within the TestSuite to ensure that the various * org.eclipse.jetty.test.support.* classes do what they are supposed to. */ -public class DefaultHandlerTest extends AbstractJettyTestCase +public class DefaultHandlerTest { - private boolean debug = true; - private TestableJettyServer server; + private boolean debug = false; + private static TestableJettyServer server; private int serverPort; - @Override - @Before - public void setUp() throws Exception + @BeforeClass + public static void setUpServer() throws Exception { - super.setUp(); - server = new TestableJettyServer(); server.setScheme(HttpSchemes.HTTP); server.addConfiguration("DefaultHandler.xml"); server.load(); server.start(); + } + + @Before + public void testInit() { serverPort = server.getServerPort(); } - @Override - @After - public void tearDown() throws Exception + @AfterClass + public static void tearDownServer() throws Exception { server.stop(); - super.tearDown(); } @Test @@ -80,7 +81,7 @@ public class DefaultHandlerTest extends AbstractJettyTestCase String response = IO.toString(in); String expected = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"; - assertEquals("Response",expected,response); + Assert.assertEquals("Response",expected,response); } @Test diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/DigestPostTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/DigestPostTest.java index 12c6c490b6..60a1569333 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/DigestPostTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/DigestPostTest.java @@ -5,13 +5,12 @@ import java.io.FileInputStream; import java.io.IOException; import java.net.Socket; import java.security.MessageDigest; +import java.util.Collections; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.security.Realm; @@ -34,9 +33,12 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; - -public class DigestPostTest extends TestCase +public class DigestPostTest { private static final String NC = "00000001"; @@ -52,10 +54,10 @@ public class DigestPostTest extends TestCase "The quick brown fox jumped over the lazy dog.\n"; public volatile static String _received = null; - private Server _server; + private static Server _server; - @Override - public void setUp() + @BeforeClass + public static void setUpServer() { try { @@ -81,7 +83,7 @@ public class DigestPostTest extends TestCase mapping.setConstraint(constraint); mapping.setPathSpec("/*"); - security.setConstraintMappings(new ConstraintMapping[]{mapping}); + security.setConstraintMappings(Collections.singletonList(mapping)); HandlerCollection handlers = new HandlerCollection(); handlers.setHandlers(new Handler[] @@ -96,16 +98,13 @@ public class DigestPostTest extends TestCase } } - - /* (non-Javadoc) - * @see junit.framework.TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception + @AfterClass + public static void tearDownServer() throws Exception { _server.stop(); } + @Test public void testServerDirectlyHTTP10() throws Exception { Socket socket = new Socket("127.0.0.1",_server.getConnectors()[0].getLocalPort()); @@ -122,8 +121,8 @@ public class DigestPostTest extends TestCase String result = IO.toString(socket.getInputStream()); - assertTrue(result.startsWith("HTTP/1.1 401 Unauthorized")); - assertEquals(null,_received); + Assert.assertTrue(result.startsWith("HTTP/1.1 401 Unauthorized")); + Assert.assertEquals(null,_received); int n=result.indexOf("nonce="); String nonce=result.substring(n+7,result.indexOf('"',n+7)); @@ -149,10 +148,11 @@ public class DigestPostTest extends TestCase result = IO.toString(socket.getInputStream()); - assertTrue(result.startsWith("HTTP/1.1 200 OK")); - assertEquals(__message,_received); + Assert.assertTrue(result.startsWith("HTTP/1.1 200 OK")); + Assert.assertEquals(__message,_received); } + @Test public void testServerDirectlyHTTP11() throws Exception { Socket socket = new Socket("127.0.0.1",_server.getConnectors()[0].getLocalPort()); @@ -173,8 +173,8 @@ public class DigestPostTest extends TestCase int len=socket.getInputStream().read(buf); String result=new String(buf,0,len,"UTF-8"); - assertTrue(result.startsWith("HTTP/1.1 401 Unauthorized")); - assertEquals(null,_received); + Assert.assertTrue(result.startsWith("HTTP/1.1 401 Unauthorized")); + Assert.assertEquals(null,_received); int n=result.indexOf("nonce="); String nonce=result.substring(n+7,result.indexOf('"',n+7)); @@ -197,10 +197,11 @@ public class DigestPostTest extends TestCase result = IO.toString(socket.getInputStream()); - assertTrue(result.startsWith("HTTP/1.1 200 OK")); - assertEquals(__message,_received); + Assert.assertTrue(result.startsWith("HTTP/1.1 200 OK")); + Assert.assertEquals(__message,_received); } + @Test public void testServerWithHttpClientStringContent() throws Exception { HttpClient client = new HttpClient(); @@ -219,11 +220,11 @@ public class DigestPostTest extends TestCase client.send(ex); ex.waitForDone(); - assertEquals(__message,_received); - assertEquals(200,ex.getResponseStatus()); + Assert.assertEquals(__message,_received); + Assert.assertEquals(200,ex.getResponseStatus()); } - + @Test public void testServerWithHttpClientStreamContent() throws Exception { HttpClient client = new HttpClient(); @@ -243,9 +244,8 @@ public class DigestPostTest extends TestCase ex.waitForDone(); String sent = IO.toString(new FileInputStream("src/test/resources/message.txt")); - assertEquals(sent,_received); - - assertEquals(200,ex.getResponseStatus()); + Assert.assertEquals(sent,_received); + Assert.assertEquals(200,ex.getResponseStatus()); } public static class TestRealm implements Realm @@ -268,6 +268,7 @@ public class DigestPostTest extends TestCase public static class PostServlet extends HttpServlet { + private static final long serialVersionUID = 1L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/MavenTestingUtils.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/MavenTestingUtils.java new file mode 100644 index 0000000000..3c36256025 --- /dev/null +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/MavenTestingUtils.java @@ -0,0 +1,220 @@ +// ======================================================================== +// 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.test; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.eclipse.jetty.util.IO; + +/** + * Common utility methods for working with JUnit tests cases in a maven friendly way. + */ +public class MavenTestingUtils +{ + private static File basedir; + private static File testResourcesDir; + private static File targetDir; + + // private static Boolean surefireRunning; + + public static File getBasedir() + { + if (basedir == null) + { + String cwd = System.getProperty("basedir"); + + if (cwd == null) + { + cwd = System.getProperty("user.dir"); + } + + basedir = new File(cwd); + } + + return basedir; + } + + /** + * Get the directory to the /target directory for this project. + * + * @return the directory path to the target directory. + */ + public static File getTargetDir() + { + if (targetDir == null) + { + targetDir = new File(getBasedir(),"target"); + PathAssert.assertDirExists("Target Dir",targetDir); + } + return targetDir; + } + + /** + * Create a {@link File} object for a path in the /target directory. + * + * @param path + * the path desired, no validation of existence is performed. + * @return the File to the path. + */ + public static File getTargetFile(String path) + { + return new File(getTargetDir(),path.replace("/",File.separator)); + } + + public static File getTargetTestingDir() + { + File dir = new File(getTargetDir(),"testing"); + if (!dir.exists()) + { + dir.mkdirs(); + } + return dir; + } + + /** + * Get a dir in /target/ that uses the JUnit 3.x {@link TestCase#getName()} to make itself unique. + * + * @param test + * the junit 3.x testcase to base this new directory on. + * @return the dir in /target/ that uses the JUnit 3.x {@link TestCase#getName()} to make itself unique. + */ + public static File getTargetTestingDir(TestCase test) + { + return getTargetTestingDir(test.getName()); + } + + /** + * Get a dir in /target/ that uses the an arbitrary name. + * + * @param testname + * the testname to create directory against. + * @return the dir in /target/ that uses the an arbitrary name. + */ + public static File getTargetTestingDir(String testname) + { + File dir = new File(getTargetDir(),"test-" + testname); + return dir; + } + + /** + * Get a dir from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist as a dir) + * @return the dir in src/test/resource + */ + public static File getTestResourceDir(String name) + { + File dir = new File(getTestResourcesDir(),name); + PathAssert.assertDirExists("Test Resource Dir",dir); + return dir; + } + + /** + * Get a file from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist as a file) + * @return the file in src/test/resource + */ + public static File getTestResourceFile(String name) + { + File file = new File(getTestResourcesDir(),name); + PathAssert.assertFileExists("Test Resource File",file); + return file; + } + + /** + * Get a path resource (File or Dir) from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist) + * @return the path in src/test/resource + */ + public static File getTestResourcePath(String name) + { + File path = new File(getTestResourcesDir(),name); + PathAssert.assertExists("Test Resource Path",path); + return path; + } + + /** + * Get the directory to the src/test/resource directory + * + * @return the directory {@link File} to the src/test/resources directory + */ + public static File getTestResourcesDir() + { + if (testResourcesDir == null) + { + testResourcesDir = new File(basedir,"src/test/resources".replace("/",File.separator)); + PathAssert.assertDirExists("Test Resources Dir",testResourcesDir); + } + return testResourcesDir; + } + + /** + * Read the contents of a file into a String and return it. + * + * @param file + * the file to read. + * @return the contents of the file. + * @throws IOException + * if unable to read the file. + */ + public static String readToString(File file) throws IOException + { + FileReader reader = null; + try + { + reader = new FileReader(file); + return IO.toString(reader); + } + finally + { + IO.close(reader); + } + } + + public static String getTestID() + { + StackTraceElement stacked[] = new Throwable().getStackTrace(); + + String name = null; + + for (StackTraceElement stack : stacked) + { + if (stack.getClassName().endsWith("Test")) + { + name = stack.getClassName(); + if (stack.getMethodName().startsWith("test")) + { + return stack.getClassName() + "#" + stack.getMethodName(); + } + } + } + + if (name == null) + { + return "Unidentified_Test"; + } + return name; + } +} diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/PathAssert.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/PathAssert.java new file mode 100644 index 0000000000..4eb6c6539e --- /dev/null +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/PathAssert.java @@ -0,0 +1,40 @@ +// ======================================================================== +// 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.test; + +import java.io.File; + +import org.junit.Assert; + +public class PathAssert +{ + public static void assertDirExists(String msg, File path) + { + assertExists(msg,path); + Assert.assertTrue(msg + " path should be a Dir : " + path.getAbsolutePath(),path.isDirectory()); + } + + public static void assertFileExists(String msg, File path) + { + assertExists(msg,path); + Assert.assertTrue(msg + " path should be a File : " + path.getAbsolutePath(),path.isFile()); + } + + public static void assertExists(String msg, File path) + { + Assert.assertTrue(msg + " path should exist: " + path.getAbsolutePath(),path.exists()); + } +} diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BIOHttpTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BIOHttpTest.java index ad59455b50..9ca740b056 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BIOHttpTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BIOHttpTest.java @@ -16,20 +16,19 @@ package org.eclipse.jetty.test.rfcs; -import java.io.IOException; - import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.test.support.TestableJettyServer; import org.eclipse.jetty.test.support.rawhttp.HttpSocket; import org.eclipse.jetty.test.support.rawhttp.HttpSocketImpl; +import org.junit.BeforeClass; /** * Perform the RFC2616 tests against a server running with the Jetty BIO Connector and listening on standard HTTP. */ public class RFC2616BIOHttpTest extends RFC2616BaseTest { - @Override - public TestableJettyServer getJettyServer() throws IOException + @BeforeClass + public static void setupServer() throws Exception { TestableJettyServer server = new TestableJettyServer(); server.setScheme(HttpSchemes.HTTP); @@ -37,7 +36,7 @@ public class RFC2616BIOHttpTest extends RFC2616BaseTest server.addConfiguration("RFC2616_Redirects.xml"); server.addConfiguration("RFC2616_Filters.xml"); server.addConfiguration("BIOHttp.xml"); - return server; + setUpServer(server); } @Override diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BIOHttpsTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BIOHttpsTest.java index 7faa84b358..dc2f814806 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BIOHttpsTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BIOHttpsTest.java @@ -16,20 +16,20 @@ package org.eclipse.jetty.test.rfcs; -import java.io.IOException; - import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.test.support.TestableJettyServer; import org.eclipse.jetty.test.support.rawhttp.HttpSocket; import org.eclipse.jetty.test.support.rawhttp.HttpsSocketImpl; +import org.junit.BeforeClass; /** - * Perform the RFC2616 tests against a server running with the Jetty BIO Connector and listening on HTTPS (HTTP over SSL). + * Perform the RFC2616 tests against a server running with the Jetty BIO Connector and listening on HTTPS (HTTP over + * SSL). */ public class RFC2616BIOHttpsTest extends RFC2616BaseTest { - @Override - public TestableJettyServer getJettyServer() throws IOException + @BeforeClass + public static void setupServer() throws Exception { TestableJettyServer server = new TestableJettyServer(); server.setScheme(HttpSchemes.HTTPS); @@ -37,7 +37,7 @@ public class RFC2616BIOHttpsTest extends RFC2616BaseTest server.addConfiguration("RFC2616_Redirects.xml"); server.addConfiguration("RFC2616_Filters.xml"); server.addConfiguration("BIOHttps.xml"); - return server; + setUpServer(server); } @Override diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java index 984191c175..026b1a4bfd 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java @@ -31,29 +31,30 @@ import java.util.TimeZone; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.test.AbstractJettyTestCase; +import org.eclipse.jetty.test.MavenTestingUtils; import org.eclipse.jetty.test.StringAssert; import org.eclipse.jetty.test.support.StringUtil; import org.eclipse.jetty.test.support.TestableJettyServer; import org.eclipse.jetty.test.support.rawhttp.HttpResponseTester; import org.eclipse.jetty.test.support.rawhttp.HttpSocket; import org.eclipse.jetty.test.support.rawhttp.HttpTesting; -import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * <a href="http://tools.ietf.org/html/rfc2616">RFC 2616</a> (HTTP/1.1) Test Case */ -public abstract class RFC2616BaseTest extends AbstractJettyTestCase +public abstract class RFC2616BaseTest { private static final String ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"; /** STRICT RFC TESTS */ private static final boolean STRICT = false; + private static TestableJettyServer server; private List<HttpResponseTester> responses; private HttpResponseTester response; private HttpTesting http; - private TestableJettyServer server; class TestFile { @@ -78,13 +79,12 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase } } - @Override - @Before - public void setUp() throws Exception + public static void setUpServer(TestableJettyServer testableserver) throws Exception { - super.setUp(); - - File testWorkDir = new File(getTargetDir(),"work" + File.separator + getClass().getSimpleName() + File.separator + getName()); + File targetDir = MavenTestingUtils.getTargetDir(); + String testId = MavenTestingUtils.getTestID(); + + File testWorkDir = new File(targetDir,"work" + File.separator + testId); if (!testWorkDir.exists()) { testWorkDir.mkdirs(); @@ -92,22 +92,23 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase System.setProperty("java.io.tmpdir",testWorkDir.getAbsolutePath()); - server = getJettyServer(); + server = testableserver; server.load(); server.start(); + } + + @Before + public void setUp() throws Exception + { http = new HttpTesting(getHttpClientSocket(),server.getServerPort()); } - @Override - @After - public void tearDown() throws Exception + @AfterClass + public static void tearDownServer() throws Exception { server.stop(); - super.tearDown(); } - public abstract TestableJettyServer getJettyServer() throws IOException; - public abstract HttpSocket getHttpClientSocket() throws Exception; /** @@ -145,7 +146,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase // Test formatting fields.putDateField("Date",expected.getTime().getTime()); - assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.getStringField("Date")); + Assert.assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.getStringField("Date")); } /** @@ -170,7 +171,16 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase response = http.request(req1); response.assertStatus("3.6 Transfer Coding / Bad 400",HttpStatus.BAD_REQUEST_400); - + } + + /** + * Test Transfer Codings + * + * @see <a href="http://tools.ietf.org/html/rfc2616#section-3.6">RFC 2616 (section 3.6)</a> + */ + @Test + public void test3_6_2() throws Throwable + { // Chunked StringBuffer req2 = new StringBuffer(); req2.append("GET /echo/R1 HTTP/1.1\n"); @@ -201,7 +211,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req2.append("\n"); responses = http.requests(req2); - assertEquals("Response Count",3,responses.size()); + Assert.assertEquals("Response Count",3,responses.size()); response = responses.get(0); // Response 1 response.assertStatusOK("3.6.1 Transfer Codings / Response 1 Code"); @@ -214,9 +224,17 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase response = responses.get(2); // Response 3 response.assertStatusOK("3.6.1 Transfer Codings / Response 3 Code"); response.assertNoBody("3.6.1 Transfer Codings / No Body"); + } + /** + * Test Transfer Codings + * + * @see <a href="http://tools.ietf.org/html/rfc2616#section-3.6">RFC 2616 (section 3.6)</a> + */ + @Test + public void test3_6_3() throws Throwable + { // Chunked - StringBuffer req3 = new StringBuffer(); req3.append("POST /echo/R1 HTTP/1.1\n"); req3.append("Host: localhost\n"); @@ -246,7 +264,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req3.append("\n"); responses = http.requests(req3); - assertEquals("Response Count",3,responses.size()); + Assert.assertEquals("Response Count",3,responses.size()); response = responses.get(0); // Response 1 response.assertStatusOK("3.6.1 Transfer Codings / Response 1 Code"); @@ -260,8 +278,17 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase response.assertStatusOK("3.6.1 Transfer Codings / Response 3 Code"); response.assertNoBody("3.6.1 Transfer Codings / No Body"); - // Chunked and keep alive + } + /** + * Test Transfer Codings + * + * @see <a href="http://tools.ietf.org/html/rfc2616#section-3.6">RFC 2616 (section 3.6)</a> + */ + @Test + public void test3_6_4() throws Throwable + { + // Chunked and keep alive StringBuffer req4 = new StringBuffer(); req4.append("GET /echo/R1 HTTP/1.1\n"); req4.append("Host: localhost\n"); @@ -281,7 +308,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req4.append("\n"); responses = http.requests(req4); - assertEquals("Response Count",2,responses.size()); + Assert.assertEquals("Response Count",2,responses.size()); response = responses.get(0); // Response 1 response.assertStatusOK("3.6.1 Transfer Codings / Response 1 Code"); @@ -305,12 +332,12 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase fields.put("Q","bbb;q=0.5,aaa,ccc;q=0.002,d;q=0,e;q=0.0001,ddd;q=0.001,aa2,abb;q=0.7"); Enumeration<String> qualities = fields.getValues("Q",", \t"); List<?> list = HttpFields.qualityList(qualities); - assertEquals("Quality parameters","aaa",HttpFields.valueParameters(list.get(0).toString(),null)); - assertEquals("Quality parameters","aa2",HttpFields.valueParameters(list.get(1).toString(),null)); - assertEquals("Quality parameters","abb",HttpFields.valueParameters(list.get(2).toString(),null)); - assertEquals("Quality parameters","bbb",HttpFields.valueParameters(list.get(3).toString(),null)); - assertEquals("Quality parameters","ccc",HttpFields.valueParameters(list.get(4).toString(),null)); - assertEquals("Quality parameters","ddd",HttpFields.valueParameters(list.get(5).toString(),null)); + Assert.assertEquals("Quality parameters","aaa",HttpFields.valueParameters(list.get(0).toString(),null)); + Assert.assertEquals("Quality parameters","aa2",HttpFields.valueParameters(list.get(1).toString(),null)); + Assert.assertEquals("Quality parameters","abb",HttpFields.valueParameters(list.get(2).toString(),null)); + Assert.assertEquals("Quality parameters","bbb",HttpFields.valueParameters(list.get(3).toString(),null)); + Assert.assertEquals("Quality parameters","ccc",HttpFields.valueParameters(list.get(4).toString(),null)); + Assert.assertEquals("Quality parameters","ddd",HttpFields.valueParameters(list.get(5).toString(),null)); } /** @@ -340,7 +367,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req1.append("\n"); responses = http.requests(req1); - assertEquals("Response Count",2,responses.size()); + Assert.assertEquals("Response Count",2,responses.size()); response = responses.get(0); response.assertStatusOK("4.4.2 Message Length / Response Code"); @@ -377,7 +404,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req2.append("7890AB"); responses = http.requests(req2); - assertEquals("Response Count",2,responses.size()); + Assert.assertEquals("Response Count",2,responses.size()); response = responses.get(0); // response 1 response.assertStatusOK("4.4.3 Ignore Content-Length / Response Code"); @@ -630,7 +657,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req2.append("\n"); responses = http.requests(req2); - assertEquals("Response Count",2,responses.size()); // Should not have a R3 response. + Assert.assertEquals("Response Count",2,responses.size()); // Should not have a R3 response. response = responses.get(0); // response 1 response.assertStatusOK("8.1 Persistent Connections"); @@ -660,7 +687,8 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req2.append("Expect: unknown\n"); // Invalid Expect header. req2.append("Content-Type: text/plain\n"); req2.append("Content-Length: 8\n"); - req2.append("\n"); // No body + req2.append("\n"); + req2.append("12345678\n"); response = http.request(req2); @@ -838,7 +866,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase responses = http.requests(req2); - assertEquals("Response Count",2,responses.size()); // Should have 2 responses + Assert.assertEquals("Response Count",2,responses.size()); // Should have 2 responses response = responses.get(0); // Only interested in first response response.assertHeaderExists("9.2 OPTIONS","Allow"); @@ -975,7 +1003,6 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req2.append("Range: bytes=1-3\n"); // request first 3 bytes req2.append("\n"); - http.enableDebug(); response = http.request(req2); response.assertStatus("10.2.7 Partial Content",HttpStatus.PARTIAL_CONTENT_206); @@ -1070,7 +1097,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req2.append("\n"); responses = http.requests(req2); - assertEquals("Response Count",2,responses.size()); + Assert.assertEquals("Response Count",2,responses.size()); response = responses.get(0); String specId = "10.3 Redirection HTTP/1.1 - basic (response 1)"; @@ -1259,7 +1286,6 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req1.append("\n"); http.setTimeoutMillis(60000); - http.enableDebug(); response = http.request(req1); String msg = "Partial Range (Mixed): 'bytes=a-b,5-8'"; @@ -1448,7 +1474,6 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req1.append("Connection: close\n"); req1.append("\n"); - http.enableDebug(); response = http.request(req1); String msg = "Partial (Byte) Range: '" + rangedef + "'"; @@ -1522,16 +1547,16 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase if (parts[i].trim().startsWith("boundary=")) { String boundparts[] = StringUtil.split(parts[i],'='); - assertEquals(msg + " Boundary parts.length",2,boundparts.length); + Assert.assertEquals(msg + " Boundary parts.length",2,boundparts.length); boundary = boundparts[1]; } } - assertNotNull(msg + " Should have found boundary in Content-Type header",boundary); + Assert.assertNotNull(msg + " Should have found boundary in Content-Type header",boundary); // Find boundary offsets within body List<HttpResponseTester> multiparts = response.findBodyMultiparts(boundary); - assertEquals(msg + " multiparts in body (count)",2,multiparts.size()); + Assert.assertEquals(msg + " multiparts in body (count)",2,multiparts.size()); // Validate multipart #1 HttpResponseTester multipart1 = multiparts.get(0); @@ -1566,7 +1591,6 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req1.append("Connection: close\n"); req1.append("\n"); - http.enableDebug(); response = http.request(req1); String msg = "Partial (Byte) Range: '" + rangedef + "'"; @@ -1584,16 +1608,16 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase if (parts[i].trim().startsWith("boundary=")) { String boundparts[] = StringUtil.split(parts[i],'='); - assertEquals(msg + " Boundary parts.length",2,boundparts.length); + Assert.assertEquals(msg + " Boundary parts.length",2,boundparts.length); boundary = boundparts[1]; } } - assertNotNull(msg + " Should have found boundary in Content-Type header",boundary); + Assert.assertNotNull(msg + " Should have found boundary in Content-Type header",boundary); // Find boundary offsets within body List<HttpResponseTester> multiparts = response.findBodyMultiparts(boundary); - assertEquals(msg + " multiparts in body (count)",3,multiparts.size()); + Assert.assertEquals(msg + " multiparts in body (count)",3,multiparts.size()); // Validate multipart #1 HttpResponseTester multipart1 = multiparts.get(0); @@ -1688,7 +1712,6 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req1.append("Connection: close\n"); req1.append("\n"); - http.enableDebug(); response = http.request(req1); specId = "14.39 TE Header"; response.assertStatusOK(specId); @@ -1767,7 +1790,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase responses = http.requests(req2); // Since R2 closes the connection, should only get 2 responses (R1 & // R2), not (R3) - assertEquals("Response Count",2,responses.size()); + Assert.assertEquals("Response Count",2,responses.size()); response = responses.get(0); // response 1 specId = "19.6.2 Compatibility with previous HTTP - Keep-alive"; @@ -1808,7 +1831,7 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase req3.append("Connection: close\n"); req3.append("\n"); responses = http.requests(req3); - assertEquals("Response Count",3,responses.size()); + Assert.assertEquals("Response Count",3,responses.size()); specId = "19.6.2 Compatibility with HTTP/1.0- Keep-alive"; response = responses.get(0); @@ -1834,6 +1857,6 @@ public abstract class RFC2616BaseTest extends AbstractJettyTestCase String actual = sdf.format(new Date(actualTime)); String expected = sdf.format(expectedTime.getTime()); - assertEquals(msg,expected,actual); + Assert.assertEquals(msg,expected,actual); } } diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616NIOHttpTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616NIOHttpTest.java index 4fbfcaf95c..9e254a4420 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616NIOHttpTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616NIOHttpTest.java @@ -16,20 +16,19 @@ package org.eclipse.jetty.test.rfcs; -import java.io.IOException; - import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.test.support.TestableJettyServer; import org.eclipse.jetty.test.support.rawhttp.HttpSocket; import org.eclipse.jetty.test.support.rawhttp.HttpSocketImpl; +import org.junit.BeforeClass; /** * Perform the RFC2616 tests against a server running with the Jetty NIO Connector and listening on standard HTTP. */ public class RFC2616NIOHttpTest extends RFC2616BaseTest { - @Override - public TestableJettyServer getJettyServer() throws IOException + @BeforeClass + public static void setupServer() throws Exception { TestableJettyServer server = new TestableJettyServer(); server.setScheme(HttpSchemes.HTTP); @@ -37,7 +36,7 @@ public class RFC2616NIOHttpTest extends RFC2616BaseTest server.addConfiguration("RFC2616_Redirects.xml"); server.addConfiguration("RFC2616_Filters.xml"); server.addConfiguration("NIOHttp.xml"); - return server; + setUpServer(server); } @Override diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616NIOHttpsTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616NIOHttpsTest.java index 0d9accfd61..88e3262d9f 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616NIOHttpsTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616NIOHttpsTest.java @@ -16,20 +16,19 @@ package org.eclipse.jetty.test.rfcs; -import java.io.IOException; - import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.test.support.TestableJettyServer; import org.eclipse.jetty.test.support.rawhttp.HttpSocket; import org.eclipse.jetty.test.support.rawhttp.HttpsSocketImpl; +import org.junit.BeforeClass; /** * Perform the RFC2616 tests against a server running with the Jetty NIO Connector and listening on HTTPS (HTTP over SSL). */ public class RFC2616NIOHttpsTest extends RFC2616BaseTest { - @Override - public TestableJettyServer getJettyServer() throws IOException + @BeforeClass + public static void setupServer() throws Exception { TestableJettyServer server = new TestableJettyServer(); server.setScheme(HttpSchemes.HTTPS); @@ -37,7 +36,7 @@ public class RFC2616NIOHttpsTest extends RFC2616BaseTest server.addConfiguration("RFC2616_Redirects.xml"); server.addConfiguration("RFC2616_Filters.xml"); server.addConfiguration("NIOHttps.xml"); - return server; + setUpServer(server); } @Override diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/StringUtil.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/StringUtil.java index bc520d15d7..3d845bec6d 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/StringUtil.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/StringUtil.java @@ -118,7 +118,7 @@ public class StringUtil * * @param str * input string. - * @return + * @return the same string, with any LF or CR returned as system default. */ public static String toSystemLN(String str) { diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java index deb66de87b..b4b377e61d 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java @@ -90,7 +90,7 @@ public class TestableJettyServer public void addConfiguration(File xmlConfigFile) throws MalformedURLException { - xmlConfigurations.add(xmlConfigFile.toURL()); + xmlConfigurations.add(xmlConfigFile.toURI().toURL()); } public void addConfiguration(String testConfigName) throws MalformedURLException @@ -103,6 +103,7 @@ public class TestableJettyServer properties.setProperty(key,value); } + @SuppressWarnings("unchecked") public void load() throws Exception { XmlConfiguration last = null; diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpRequestTester.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpRequestTester.java index 4361533bb1..34293bf70f 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpRequestTester.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpRequestTester.java @@ -173,7 +173,7 @@ public class HttpRequestTester /** * @param cookie - * @see org.eclipse.jetty.http.HttpFields#addSetCookie(javax.servlet.http.Cookie) + * @see org.eclipse.jetty.http.HttpFields#addSetCookie(org.eclipse.jetty.http.HttpCookie) */ public void addSetCookie(Cookie cookie) { diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpRequestTesterTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpRequestTesterTest.java index 308bf429be..602d247da4 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpRequestTesterTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpRequestTesterTest.java @@ -18,10 +18,12 @@ package org.eclipse.jetty.test.support.rawhttp; import java.io.IOException; -import org.eclipse.jetty.test.AbstractJettyTestCase; +import org.junit.Assert; +import org.junit.Test; -public class HttpRequestTesterTest extends AbstractJettyTestCase +public class HttpRequestTesterTest { + @Test public void testBasicHttp10Request() throws IOException { HttpRequestTester request = new HttpRequestTester(); @@ -37,9 +39,10 @@ public class HttpRequestTesterTest extends AbstractJettyTestCase expectedRequest.append("Host: fakehost\r\n"); expectedRequest.append("\r\n"); - assertEquals("Basic Request",expectedRequest.toString(),rawRequest); + Assert.assertEquals("Basic Request",expectedRequest.toString(),rawRequest); } + @Test public void testBasicHttp11Request() throws IOException { HttpRequestTester request = new HttpRequestTester(); @@ -59,6 +62,6 @@ public class HttpRequestTesterTest extends AbstractJettyTestCase expectedRequest.append("0\r\n"); expectedRequest.append("\r\n"); - assertEquals("Basic Request",expectedRequest.toString(),rawRequest); + Assert.assertEquals("Basic Request",expectedRequest.toString(),rawRequest); } } diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTester.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTester.java index 07deaf0028..3eaa47039f 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTester.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTester.java @@ -226,7 +226,7 @@ public class HttpResponseTester /** * @param name - * @return + * @return the header value as a date * @see org.eclipse.jetty.http.HttpFields#getDateField(java.lang.String) */ public long getDateHeader(String name) @@ -236,7 +236,7 @@ public class HttpResponseTester /** * @param name - * @return + * @return the header value as a long * @throws NumberFormatException * @see org.eclipse.jetty.http.HttpFields#getLongField(java.lang.String) */ @@ -247,7 +247,7 @@ public class HttpResponseTester /** * @param name - * @return + * @return the header value * @see org.eclipse.jetty.http.HttpFields#getStringField(java.lang.String) */ public String getHeader(String name) diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java index be22a94b73..5330a3dfff 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java @@ -23,10 +23,10 @@ import static org.junit.Assert.assertThat; import java.io.IOException; import java.util.List; -import org.eclipse.jetty.test.AbstractJettyTestCase; +import org.junit.Assert; import org.junit.Test; -public class HttpResponseTesterTest extends AbstractJettyTestCase +public class HttpResponseTesterTest { @Test public void testHttp11Response() throws IOException @@ -46,17 +46,17 @@ public class HttpResponseTesterTest extends AbstractJettyTestCase HttpResponseTester response = new HttpResponseTester(); response.parse(rawResponse); - assertEquals("Response.version","HTTP/1.1",response.getVersion()); - assertEquals("Response.status",200,response.getStatus()); - assertEquals("Response.reason","OK",response.getReason()); + Assert.assertEquals("Response.version","HTTP/1.1",response.getVersion()); + Assert.assertEquals("Response.status",200,response.getStatus()); + Assert.assertEquals("Response.reason","OK",response.getReason()); - assertEquals("Response[Content-Type]","text/plain",response.getContentType()); - assertEquals("Response[Content-Length]",28,response.getLongHeader("Content-Length")); - assertEquals("Response[Connection]","close",response.getHeader("Connection")); + Assert.assertEquals("Response[Content-Type]","text/plain",response.getContentType()); + Assert.assertEquals("Response[Content-Length]",28,response.getLongHeader("Content-Length")); + Assert.assertEquals("Response[Connection]","close",response.getHeader("Connection")); String expected = "ABCDEFGHIJKLMNOPQRSTTUVWXYZ\n"; - assertEquals("Response.content",expected,response.getContent().toString()); + Assert.assertEquals("Response.content",expected,response.getContent().toString()); } @Test @@ -93,8 +93,8 @@ public class HttpResponseTesterTest extends AbstractJettyTestCase rawResponse.append("\n"); List<HttpResponseTester> responses = HttpResponseTester.parseMulti(rawResponse); - assertNotNull("Responses should not be null",responses); - assertEquals("Responses.size",3,responses.size()); + Assert.assertNotNull("Responses should not be null",responses); + Assert.assertEquals("Responses.size",3,responses.size()); HttpResponseTester resp1 = responses.get(0); resp1.assertStatusOK(); diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpTesting.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpTesting.java index 27d58e426b..312d9369cc 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpTesting.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpTesting.java @@ -144,7 +144,7 @@ public class HttpTesting * Read the raw response from the socket. * * @param sock - * @return + * @return all of the the data from the socket as a String * @throws IOException */ public String readRaw(Socket sock) throws IOException @@ -157,10 +157,12 @@ public class HttpTesting } /** - * Read the raw response from the socket, reading whatever is available. Any SocketTimeoutException is consumed and just stops the reading. + * Read the raw response from the socket, reading whatever is available. + * Any {@link SocketTimeoutException} is consumed and just stops the reading. * * @param sock - * @return + * @return the raw data from the socket in string form, reading whatever is available. + * a {@link SocketTimeoutException} will result in the read stopping. * @throws IOException */ public String readRawAvailable(Socket sock) throws IOException @@ -190,7 +192,7 @@ public class HttpTesting * * Note: not for HTTPS requests. * - * @param request + * @param rawRequest * the request * @return the response * @throws IOException diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpsSocketImpl.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpsSocketImpl.java index 7ddba4ec20..a2552a402e 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpsSocketImpl.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpsSocketImpl.java @@ -61,6 +61,7 @@ public class HttpsSocketImpl implements HttpSocket } } }; + @SuppressWarnings("unused") HostnameVerifier hostnameVerifier = new HostnameVerifier() { public boolean verify(String urlHostName, SSLSession session) diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml new file mode 100644 index 0000000000..e995f9db4d --- /dev/null +++ b/tests/test-loginservice/pom.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +// ======================================================================== +// 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. +// ======================================================================== + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>tests-parent</artifactId> + <version>8.0.0.M1</version> + </parent> + <artifactId>test-loginservice</artifactId> + <name>Jetty Tests :: Login Service</name> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derby</artifactId> + <version>10.4.1.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derbytools</artifactId> + <version>10.4.1.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4-version}</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java new file mode 100644 index 0000000000..6eb658dd57 --- /dev/null +++ b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java @@ -0,0 +1,453 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.HashSet; +import java.util.Collections; +import java.util.Set; + +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.derby.tools.ij; +import org.eclipse.jetty.client.ContentExchange; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.security.Realm; +import org.eclipse.jetty.client.security.SimpleRealmResolver; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.security.Constraint; +import org.eclipse.jetty.io.ByteArrayBuffer; +import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.JDBCLoginService; +import org.eclipse.jetty.security.LoginService; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.Loader; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class JdbcLoginServiceTest +{ + private static String _content = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+ + "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+ + "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+ + "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+ + "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+ + "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+ + "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+ + "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+ + "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+ + "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+ + "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+ + "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque."; + + private static File _docRoot; + private static Server _server; + private static HttpClient _client; + private static Realm _realm; + private static String _protocol; + private static String _baseUrl; + private static String _requestContent; + + protected static boolean createDB(String homeDir, String fileName, String dbUrl) + { + FileInputStream fileStream = null; + try + { + File scriptFile = new File(fileName); + fileStream = new FileInputStream(scriptFile); + + Loader.loadClass(fileStream.getClass(), "org.apache.derby.jdbc.EmbeddedDriver").newInstance(); + Connection connection = DriverManager.getConnection(dbUrl, "", ""); + + OutputStream out = new ByteArrayOutputStream(); + int result = ij.runScript(connection, fileStream, "UTF-8", out, "UTF-8"); + + return (result==0); + } + catch (Exception e) + { + return false; + } + finally { + if (fileStream!=null) + { + try + { + fileStream.close(); + } + catch (IOException e) {} + } + } + } + + protected static void configureServer(Server server) + throws Exception + { + setProtocol("http"); + setRealm(new Realm() + { + public String getId() + { + return "JdbcRealm"; + } + + public String getPrincipal() + { + return "jetty"; + } + + public String getCredentials() + { + return "jetty"; + } + }); + + SelectChannelConnector connector = new SelectChannelConnector(); + server.addConnector(connector); + + LoginService loginService = new JDBCLoginService("JdbcRealm", "./src/test/resources/jdbcrealm.properties"); + server.addBean(loginService); + + ConstraintSecurityHandler security = new ConstraintSecurityHandler(); + server.setHandler(security); + + Constraint constraint = new Constraint(); + constraint.setName("auth"); + constraint.setAuthenticate( true ); + constraint.setRoles(new String[]{"user", "admin"}); + + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setPathSpec( "/*" ); + mapping.setConstraint( constraint ); + + Set<String> knownRoles = new HashSet<String>(); + knownRoles.add("user"); + knownRoles.add("admin"); + + security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); + security.setAuthenticator(new BasicAuthenticator()); + security.setLoginService(loginService); + security.setStrict(false); + + ServletContextHandler root = new ServletContextHandler(); + root.setContextPath("/"); + root.setResourceBase(getBasePath()); + ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); + servletHolder.setInitParameter( "gzip", "true" ); + root.addServlet( servletHolder, "/*" ); + + Handler handler = new TestHandler(getBasePath()); + + HandlerCollection handlers = new HandlerCollection(); + handlers.setHandlers(new Handler[]{handler, root}); + security.setHandler(handlers); + } + + @BeforeClass + public static void setUp() + throws Exception + { + _docRoot = new File("target/test-output/docroot/"); + _docRoot.mkdirs(); + _docRoot.deleteOnExit(); + + File content = new File(_docRoot,"input.txt"); + FileOutputStream out = new FileOutputStream(content); + out.write(_content.getBytes("utf-8")); + out.close(); + + File dbRoot = new File("target/test-output/derby"); + String dbPath = dbRoot.getAbsolutePath(); + System.setProperty("derby.system.home", dbPath); + if (!dbRoot.exists()) + { + dbRoot.mkdirs(); + createDB(dbPath, "src/test/resources/createdb.sql", "jdbc:derby:jdbcrealm;create=true"); + } + + _server = new Server(); + configureServer(_server); + _server.start(); + + int port = _server.getConnectors()[0].getLocalPort(); + _baseUrl = _protocol+"://localhost:"+port+ "/"; + } + + @AfterClass + public static void tearDown() + throws Exception + { + if (_server != null) + { + _server.stop(); + _server = null; + } + } + + @Test + public void testPut() throws Exception + { + startClient(_realm); + + ContentExchange putExchange = new ContentExchange(); + putExchange.setURL(getBaseUrl() + "output.txt"); + putExchange.setMethod(HttpMethods.PUT); + putExchange.setRequestContent(new ByteArrayBuffer(_content.getBytes())); + + _client.send(putExchange); + int state = putExchange.waitForDone(); + + int responseStatus = putExchange.getResponseStatus(); + + stopClient(); + + boolean statusOk = (responseStatus == 200 || responseStatus == 201); + assertTrue(statusOk); + + String content = IO.toString(new FileInputStream(new File(_docRoot,"output.txt"))); + assertEquals(_content,content); + } + + @Test + public void testGet() throws Exception + { + startClient(_realm); + + ContentExchange getExchange = new ContentExchange(); + getExchange.setURL(getBaseUrl() + "input.txt"); + getExchange.setMethod(HttpMethods.GET); + + _client.send(getExchange); + int state = getExchange.waitForDone(); + + String content = ""; + int responseStatus = getExchange.getResponseStatus(); + if (responseStatus == HttpStatus.OK_200) + { + content = getExchange.getResponseContent(); + } + + stopClient(); + + assertEquals(HttpStatus.OK_200,responseStatus); + assertEquals(_content,content); + } + + @Test + public void testHead() throws Exception + { + startClient(_realm); + + ContentExchange getExchange = new ContentExchange(); + getExchange.setURL(getBaseUrl() + "input.txt"); + getExchange.setMethod(HttpMethods.HEAD); + + _client.send(getExchange); + int state = getExchange.waitForDone(); + + int responseStatus = getExchange.getResponseStatus(); + + stopClient(); + + assertEquals(HttpStatus.OK_200,responseStatus); + } + + @Test + public void testPost() throws Exception + { + startClient(_realm); + + ContentExchange postExchange = new ContentExchange(); + postExchange.setURL(getBaseUrl() + "test"); + postExchange.setMethod(HttpMethods.POST); + postExchange.setRequestContent(new ByteArrayBuffer(_content.getBytes())); + + _client.send(postExchange); + int state = postExchange.waitForDone(); + + int responseStatus = postExchange.getResponseStatus(); + + stopClient(); + + assertEquals(HttpStatus.OK_200,responseStatus); + assertEquals(_content,_requestContent); + } + + protected void startClient(Realm realm) + throws Exception + { + _client = new HttpClient(); + _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + if (realm != null) + _client.setRealmResolver(new SimpleRealmResolver(realm)); + _client.start(); + } + + protected void stopClient() + throws Exception + { + if (_client != null) + { + _client.stop(); + _client = null; + } + } + + protected static String getBasePath() + { + return _docRoot.getAbsolutePath(); + } + + protected String getBaseUrl() + { + return _baseUrl; + } + + protected HttpClient getClient() + { + return _client; + } + + protected Realm getRealm() + { + return _realm; + } + + protected String getContent() + { + return _content; + } + + protected static void setProtocol(String protocol) + { + _protocol = protocol; + } + + protected static void setRealm(Realm realm) + { + _realm = realm; + } + + public static void copyStream(InputStream in, OutputStream out) + { + try + { + byte[] buffer=new byte[1024]; + int len; + while ((len=in.read(buffer))>=0) + { + out.write(buffer,0,len); + } + } + catch (EofException e) + { + System.err.println(e); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + protected static class TestHandler extends AbstractHandler { + private final String resourcePath; + + public TestHandler(String repositoryPath) { + this.resourcePath = repositoryPath; + } + + public void handle(String target, Request baseRequest, + HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + if (baseRequest.isHandled()) + { + return; + } + + OutputStream out = null; + + if (baseRequest.getMethod().equals("PUT")) + { + baseRequest.setHandled(true); + + File file = new File(resourcePath, URLDecoder.decode(request.getPathInfo())); + file.getParentFile().mkdirs(); + file.deleteOnExit(); + + out = new FileOutputStream(file); + + response.setStatus(HttpServletResponse.SC_CREATED); + } + + if (baseRequest.getMethod().equals("POST")) + { + baseRequest.setHandled(true); + out = new ByteArrayOutputStream(); + + response.setStatus(HttpServletResponse.SC_OK); + } + + if (out != null) + { + ServletInputStream in = request.getInputStream(); + try + { + copyStream( in, out ); + } + finally + { + in.close(); + out.close(); + } + + if (!(out instanceof FileOutputStream)) + _requestContent = out.toString(); + } + + } + } +} diff --git a/tests/test-loginservice/src/test/resources/createdb.sql b/tests/test-loginservice/src/test/resources/createdb.sql new file mode 100644 index 0000000000..3953b668a4 --- /dev/null +++ b/tests/test-loginservice/src/test/resources/createdb.sql @@ -0,0 +1,40 @@ +CREATE TABLE roles +( + id INT NOT NULL PRIMARY KEY, + role VARCHAR(100) NOT NULL UNIQUE +); + +CREATE TABLE users +( + id INT NOT NULL PRIMARY KEY, + username VARCHAR(100) NOT NULL UNIQUE, + pwd VARCHAR(50) NOT NULL +); + +CREATE TABLE user_roles +( + user_id INT NOT NULL, + role_id INT NOT NULL, + UNIQUE(user_id, role_id) +); + +INSERT INTO roles VALUES +(0,'user'), +(1,'admin'); + +INSERT INTO users VALUES +(1,'jetty','MD5:164c88b302622e17050af52c89945d44'), +(2,'admin','CRYPT:adpexzg3FUZAk'), +(3,'other','OBF:1xmk1w261u9r1w1c1xmq'), +(4,'plain','plain'), +(5,'user','password'), +(6,'digest','MD5:6e120743ad67abfbc385bc2bb754e297'); + +INSERT INTO user_roles VALUES +(1,1), +(2,1), +(2,2), +(3,1), +(4,1), +(5,1), +(6,1);
\ No newline at end of file diff --git a/tests/test-loginservice/src/test/resources/jdbcrealm.properties b/tests/test-loginservice/src/test/resources/jdbcrealm.properties new file mode 100644 index 0000000000..bb79638ed6 --- /dev/null +++ b/tests/test-loginservice/src/test/resources/jdbcrealm.properties @@ -0,0 +1,15 @@ +jdbcdriver = org.apache.derby.jdbc.EmbeddedDriver +url = jdbc:derby:jdbcrealm +username = +password = +usertable = users +usertablekey = id +usertableuserfield = username +usertablepasswordfield = pwd +roletable = roles +roletablekey = id +roletablerolefield = role +userroletable = user_roles +userroletableuserkey = user_id +userroletablerolekey = role_id +cachetime = 300
\ No newline at end of file diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index 7613428682..72178b47fb 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -34,13 +34,6 @@ <target>1.5</target> </configuration> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <groups>hash-all</groups> - </configuration> - </plugin> </plugins> </build> <dependencies> @@ -65,10 +58,9 @@ <version>${project.version}</version> </dependency> <dependency> - <groupId>org.testng</groupId> - <artifactId>testng</artifactId> - <version>5.8</version> - <classifier>jdk15</classifier> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index f5da28ceed..5069ae462d 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -13,10 +13,7 @@ package org.eclipse.jetty.server.session; - -import org.testng.annotations.Test; - - +import org.junit.Test; public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest { @@ -25,7 +22,7 @@ public class ClientCrossContextSessionTest extends AbstractClientCrossContextSes return new HashTestServer(port); } - @Test(groups={"hash-all"}) + @Test public void testCrossContextDispatch() throws Exception { super.testCrossContextDispatch(); diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java index 5de13caaf2..839e266f42 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java @@ -12,13 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; + /** * LightLoadTest - * - * */ - public class LightLoadTest extends AbstractLightLoadTest { @@ -27,7 +25,7 @@ public class LightLoadTest extends AbstractLightLoadTest return new HashTestServer(port); } - @Test(groups={"hash-all"}) + @Test public void testLightLoad() throws Exception { super.testLightLoad(); diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java index d06df8ee8c..3d58bc72f2 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java @@ -12,14 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * NewSessionTest - * - * */ - public class NewSessionTest extends AbstractNewSessionTest { @@ -28,10 +25,9 @@ public class NewSessionTest extends AbstractNewSessionTest return new HashTestServer(port,max,scavenge); } - @Test(groups={"hash-all"}) + @Test public void testNewSession() throws Exception { super.testNewSession(); } - } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java index dd6312b8c8..5be9208c1e 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java @@ -12,25 +12,21 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * OrphanedSessionTest - * - * */ public class OrphanedSessionTest extends AbstractOrphanedSessionTest { - public AbstractTestServer createServer(int port, int max, int scavenge) { return new HashTestServer(port,max,scavenge); } - @Test(groups={"hash-all"}) + @Test public void testOrphanedSession() throws Exception { super.testOrphanedSession(); } - } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index ef29ba1764..35a9c2bb27 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -12,12 +12,10 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * ReentrantRequestSessionTest - * - * */ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest { @@ -26,7 +24,7 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession return new HashTestServer(port); } - @Test(groups={"hash-all"}) + @Test public void testReentrantRequestSession() throws Exception { super.testReentrantRequestSession(); diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java index 15a6a93bc2..c95f8dd81c 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java @@ -13,22 +13,18 @@ package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; - - +import org.junit.Test; public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest { - public AbstractTestServer createServer(int port) { return new HashTestServer(port); } - @Test(groups={"hash-all"}) + @Test public void testCrossContextDispatch() throws Exception { super.testCrossContextDispatch(); } - } diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 4df99280f1..7645612f87 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -34,13 +34,6 @@ <target>1.5</target> </configuration> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <groups>jdbc-all</groups> - </configuration> - </plugin> </plugins> </build> <dependencies> @@ -77,10 +70,9 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.testng</groupId> - <artifactId>testng</artifactId> - <version>5.8</version> - <classifier>jdk15</classifier> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index 8bfaf60916..4195058cad 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -12,7 +12,7 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * ClientCrossContextSessionTest @@ -22,19 +22,14 @@ import org.testng.annotations.Test; public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest { - - public AbstractTestServer createServer(int port) { return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testCrossContextDispatch() throws Exception { super.testCrossContextDispatch(); } - - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java index 538419db9f..2d7ac694ac 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java @@ -12,7 +12,7 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * ImmortalSessionTest @@ -22,18 +22,14 @@ import org.testng.annotations.Test; public class ImmortalSessionTest extends AbstractImmortalSessionTest { - - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs) { return new JdbcTestServer(port, maxInactiveMs, scavengeMs); } - - @Test(groups={"jdbc-all"}) + @Test public void testImmortalSession() throws Exception { super.testImmortalSession(); } - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java index 6babe36161..124486363a 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java @@ -12,14 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * InvalidationSessionTest - * - * */ - public class InvalidationSessionTest extends AbstractInvalidationSessionTest { public AbstractTestServer createServer(int port) @@ -43,10 +40,9 @@ public class InvalidationSessionTest extends AbstractInvalidationSessionTest } } - @Test(groups={"jdbc-all"}) + @Test public void testInvalidation() throws Exception { super.testInvalidation(); } - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java index d3c805a0ad..1e900108b2 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java @@ -14,11 +14,10 @@ package org.eclipse.jetty.server.session; import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.server.SessionManager; +import org.eclipse.jetty.server.session.test.MavenTestingUtils; /** * JdbcTestServer - * - * */ public class JdbcTestServer extends AbstractTestServer { @@ -29,7 +28,7 @@ public class JdbcTestServer extends AbstractTestServer static { - System.setProperty("derby.system.home", System.getProperty("java.io.tmpdir")); + System.setProperty("derby.system.home", MavenTestingUtils.getTargetTestingDir().getAbsolutePath()); } public JdbcTestServer(int port) diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java index 82e89ef0dd..77c96a7afb 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java @@ -12,27 +12,21 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * LastAccessTimeTest - * - * */ - public class LastAccessTimeTest extends AbstractLastAccessTimeTest { - public AbstractTestServer createServer(int port, int max, int scavenge) { return new JdbcTestServer(port,max,scavenge); } - @Test(groups={"jdbc-all"}) + @Test public void testLastAccessTime() throws Exception { super.testLastAccessTime(); } - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java index 773e5df07b..535ceec460 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java @@ -12,14 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * LocalSessionScavengingTest - * - * */ - public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTest { public void pause (int scavenge) @@ -44,7 +41,7 @@ public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTe return new JdbcTestServer(port,max,scavenge); } - @Test(groups={"jdbc-all"}) + @Test public void testLocalSessionsScavenging() throws Exception { super.testLocalSessionsScavenging(); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java index 5fd1d18873..7264696269 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java @@ -12,16 +12,13 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * NewSessionTest - * - * */ public class NewSessionTest extends AbstractNewSessionTest { - /** * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int) */ @@ -30,7 +27,7 @@ public class NewSessionTest extends AbstractNewSessionTest return new JdbcTestServer(port,max,scavenge); } - @Test(groups={"jdbc-all"}) + @Test public void testNewSession() throws Exception { super.testNewSession(); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java index 5b565bf941..b5e415dce6 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java @@ -12,27 +12,21 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * OrphanedSessionTest - * - * */ public class OrphanedSessionTest extends AbstractOrphanedSessionTest { - public AbstractTestServer createServer(int port, int max, int scavenge) { return new JdbcTestServer(port,max,scavenge); } - @Test(groups={"jdbc-all"}) + @Test public void testOrphanedSession() throws Exception { super.testOrphanedSession(); } - - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index 407ccc4352..5bab446e04 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -12,12 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; + /** * ReentrantRequestSessionTest - * - * */ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest { @@ -27,11 +26,9 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testReentrantRequestSession() throws Exception { super.testReentrantRequestSession(); } - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java index d7d4a6038d..c6732c34a5 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java @@ -12,12 +12,10 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * ServerCrossContextSessionTest - * - * */ public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest { @@ -27,12 +25,9 @@ public class ServerCrossContextSessionTest extends AbstractServerCrossContextSes return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testCrossContextDispatch() throws Exception { super.testCrossContextDispatch(); } - - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java index d0a3995de3..3400628007 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java @@ -1,6 +1,5 @@ //======================================================================== -//$Id$ -//Copyright 2010 Mort Bay Consulting Pty. Ltd. +// Copyright 2010 Mort Bay Consulting Pty. Ltd. //------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -13,11 +12,10 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; + /** * SessionMigrationTest - * - * */ public class SessionMigrationTest extends AbstractSessionMigrationTest { @@ -27,12 +25,9 @@ public class SessionMigrationTest extends AbstractSessionMigrationTest return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testSessionMigration() throws Exception { super.testSessionMigration(); } - - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java index 43b1ddabf9..4389143b8b 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java @@ -12,7 +12,8 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; + /** * WebAppObjectInSessionTest * @@ -26,11 +27,9 @@ public class WebAppObjectInSessionTest extends AbstractWebAppObjectInSessionTest return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testWebappObjectInSession() throws Exception { super.testWebappObjectInSession(); } - - } diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index 5f704c2cf4..36898d6e0e 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -44,10 +44,9 @@ <version>${project.version}</version> </dependency> <dependency> - <groupId>org.testng</groupId> - <artifactId>testng</artifactId> - <version>5.8</version> - <classifier>jdk15</classifier> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>compile</scope> </dependency> </dependencies> diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java index e79ed1bcc9..0674120620 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java @@ -22,19 +22,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.Test; /** * AbstractClientCrossContextSessionTest - * - * */ - public abstract class AbstractClientCrossContextSessionTest { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java index 54506a5de8..89f16737b3 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java @@ -23,18 +23,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractImmortalSessionTest - * - * */ - public abstract class AbstractImmortalSessionTest { public abstract AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java index aee0b40297..ecf1008985 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java @@ -22,19 +22,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; - +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractInvalidationSessionTest * Goal of the test is to be sure that invalidating a session on one node * result in the session being unavailable in the other node also. - * */ - public abstract class AbstractInvalidationSessionTest { public abstract AbstractTestServer createServer(int port); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java index cac47f0e61..379f6b3b45 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java @@ -21,17 +21,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractLastAccessTimeTest - * - * */ - public abstract class AbstractLastAccessTimeTest { public abstract AbstractTestServer createServer(int port, int max, int scavenge); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java index 0df0f27e9a..588ed2b6c8 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java @@ -27,18 +27,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractLightLoadTest - * - * */ - public abstract class AbstractLightLoadTest { protected boolean _stress = Boolean.getBoolean( "STRESS" ); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java index 386c14d8aa..03f8db0c97 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java @@ -21,20 +21,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.eclipse.jetty.client.ContentExchange; +import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.SessionManager; -import org.eclipse.jetty.client.ContentExchange; -import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; - +import org.junit.Test; /** * AbstractLocalSessionScavengingTest - * - * */ - public abstract class AbstractLocalSessionScavengingTest { public abstract AbstractTestServer createServer(int port, int max, int scavenge); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java index fa5f53f3c9..4c3867344c 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java @@ -21,18 +21,15 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.Test; /** * AbstractNewSessionTest - * - * */ - public abstract class AbstractNewSessionTest { public abstract AbstractTestServer createServer(int port, int max, int scavenge); @@ -48,6 +45,7 @@ public abstract class AbstractNewSessionTest e.printStackTrace(); } } + @Test public void testNewSession() throws Exception { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java index e223bdaa81..29be97b5f2 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java @@ -23,17 +23,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractOrphanedSessionTest - * - * */ - public abstract class AbstractOrphanedSessionTest { @@ -51,18 +48,18 @@ public abstract class AbstractOrphanedSessionTest // Disable scavenging for the first server, so that we simulate its "crash". String contextPath = ""; String servletMapping = "/server"; - int port1 = random.nextInt(50000) + 10000; int inactivePeriod = 5; - AbstractTestServer server1 = createServer(port1, inactivePeriod, -1); + AbstractTestServer server1 = createServer(0, inactivePeriod, -1); server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping); server1.start(); + int port1 = server1.getPort(); try { - int port2 = random.nextInt(50000) + 10000; int scavengePeriod = 2; - AbstractTestServer server2 = createServer(port2, inactivePeriod, scavengePeriod); + AbstractTestServer server2 = createServer(0, inactivePeriod, scavengePeriod); server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping); server2.start(); + int port2 = server2.getPort(); try { HttpClient client = new HttpClient(); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractReentrantRequestSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractReentrantRequestSessionTest.java index ad776a332d..d8d5064172 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractReentrantRequestSessionTest.java @@ -22,18 +22,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractReentrantRequestSessionTest - * - * */ - public abstract class AbstractReentrantRequestSessionTest { public abstract AbstractTestServer createServer(int port); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractServerCrossContextSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractServerCrossContextSessionTest.java index fe07c05da0..e91fffd402 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractServerCrossContextSessionTest.java @@ -25,18 +25,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.Test; /** * AbstractServerCrossContextSessionTest - * - * */ - public abstract class AbstractServerCrossContextSessionTest { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java index 511efbe161..b4584fd5ae 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java @@ -23,17 +23,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractSessionMigrationTest - * - * */ - public abstract class AbstractSessionMigrationTest { public abstract AbstractTestServer createServer (int port); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java index 8edde246bc..71f592ebc9 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java @@ -60,6 +60,11 @@ public abstract class AbstractTestServer _server.setHandler(_contexts); _server.start(); } + + public int getPort() + { + return _server.getConnectors()[0].getLocalPort(); + } public ServletContextHandler addContext(String contextPath) { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java index aaaa3c19c3..3679dc9d42 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java @@ -21,13 +21,12 @@ import java.util.Random; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.client.ContentExchange; +import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.client.ContentExchange; -import org.eclipse.jetty.client.HttpClient; - -import org.testng.annotations.Test; +import org.junit.Test; /** * AbstractWebAppObjectInSessionTest @@ -37,9 +36,7 @@ import org.testng.annotations.Test; * the same webapp on nodeB is able to load that object from the session. * * This test is only appropriate for clustered session managers. - * */ - public abstract class AbstractWebAppObjectInSessionTest { public abstract AbstractTestServer createServer(int port); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/MavenTestingUtils.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/MavenTestingUtils.java new file mode 100644 index 0000000000..028afd3ce1 --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/MavenTestingUtils.java @@ -0,0 +1,221 @@ +// ======================================================================== +// 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.server.session.test; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.eclipse.jetty.util.IO; + +/** + * Common utility methods for working with JUnit tests cases in a maven friendly way. + */ +public class MavenTestingUtils +{ + private static File basedir; + private static File testResourcesDir; + private static File targetDir; + + // private static Boolean surefireRunning; + + public static File getBasedir() + { + if (basedir == null) + { + String cwd = System.getProperty("basedir"); + + if (cwd == null) + { + cwd = System.getProperty("user.dir"); + } + + basedir = new File(cwd); + } + + return basedir; + } + + /** + * Get the directory to the /target directory for this project. + * + * @return the directory path to the target directory. + */ + public static File getTargetDir() + { + if (targetDir == null) + { + targetDir = new File(getBasedir(),"target"); + PathAssert.assertDirExists("Target Dir",targetDir); + } + return targetDir; + } + + /** + * Create a {@link File} object for a path in the /target directory. + * + * @param path + * the path desired, no validation of existence is performed. + * @return the File to the path. + */ + public static File getTargetFile(String path) + { + return new File(getTargetDir(),path.replace("/",File.separator)); + } + + public static File getTargetTestingDir() + { + File dir = new File(getTargetDir(),"testing"); + if (!dir.exists()) + { + dir.mkdirs(); + } + return dir; + } + + /** + * Get a dir in /target/ that uses the JUnit 3.x {@link TestCase#getName()} to make itself unique. + * + * @param test + * the junit 3.x testcase to base this new directory on. + * @return the File path to the testcase specific testing directory underneath the + * <code>${basedir}/target</code> sub directory + */ + public static File getTargetTestingDir(TestCase test) + { + return getTargetTestingDir(test.getName()); + } + + /** + * Get a dir in /target/ that uses the an arbitrary name. + * + * @param testname + * the testname to create directory against. + * @return the File path to the testname sepecific testing directory underneath the + * <code>${basedir}/target</code> sub directory + */ + public static File getTargetTestingDir(String testname) + { + File dir = new File(getTargetDir(),"test-" + testname); + return dir; + } + + /** + * Get a dir from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist as a dir) + * @return the dir in src/test/resource + */ + public static File getTestResourceDir(String name) + { + File dir = new File(getTestResourcesDir(),name); + PathAssert.assertDirExists("Test Resource Dir",dir); + return dir; + } + + /** + * Get a file from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist as a file) + * @return the file in src/test/resource + */ + public static File getTestResourceFile(String name) + { + File file = new File(getTestResourcesDir(),name); + PathAssert.assertFileExists("Test Resource File",file); + return file; + } + + /** + * Get a path resource (File or Dir) from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist) + * @return the path in src/test/resource + */ + public static File getTestResourcePath(String name) + { + File path = new File(getTestResourcesDir(),name); + PathAssert.assertExists("Test Resource Path",path); + return path; + } + + /** + * Get the directory to the src/test/resource directory + * + * @return the directory {@link File} to the src/test/resources directory + */ + public static File getTestResourcesDir() + { + if (testResourcesDir == null) + { + testResourcesDir = new File(basedir,"src/test/resources".replace("/",File.separator)); + PathAssert.assertDirExists("Test Resources Dir",testResourcesDir); + } + return testResourcesDir; + } + + /** + * Read the contents of a file into a String and return it. + * + * @param file + * the file to read. + * @return the contents of the file. + * @throws IOException + * if unable to read the file. + */ + public static String readToString(File file) throws IOException + { + FileReader reader = null; + try + { + reader = new FileReader(file); + return IO.toString(reader); + } + finally + { + IO.close(reader); + } + } + + public static String getTestID() + { + StackTraceElement stacked[] = new Throwable().getStackTrace(); + + String name = null; + + for(StackTraceElement stack: stacked) { + if(stack.getClassName().endsWith("Test")) + { + name = stack.getClassName(); + if (stack.getMethodName().startsWith("test")) + { + return stack.getClassName() + "#" + stack.getMethodName(); + } + } + } + + if(name == null) + { + return "Unidentified_Test"; + } + return name; + } +} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/PathAssert.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/PathAssert.java new file mode 100644 index 0000000000..f85a0976df --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/PathAssert.java @@ -0,0 +1,40 @@ +// ======================================================================== +// 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.server.session.test; + +import java.io.File; + +import org.junit.Assert; + +public class PathAssert +{ + public static void assertDirExists(String msg, File path) + { + assertExists(msg,path); + Assert.assertTrue(msg + " path should be a Dir : " + path.getAbsolutePath(),path.isDirectory()); + } + + public static void assertFileExists(String msg, File path) + { + assertExists(msg,path); + Assert.assertTrue(msg + " path should be a File : " + path.getAbsolutePath(),path.isFile()); + } + + public static void assertExists(String msg, File path) + { + Assert.assertTrue(msg + " path should exist: " + path.getAbsolutePath(),path.exists()); + } +} |