diff options
author | Jan Bartel | 2010-07-12 07:04:55 +0000 |
---|---|---|
committer | Jan Bartel | 2010-07-12 07:04:55 +0000 |
commit | d7dc957e5b46d2f0e850492ae216f992d3ee92e1 (patch) | |
tree | 3a094b746fc9d33dbedf78a18099a51bb35484b5 | |
parent | af08a447085e05bcc02940f13e839d6e85946160 (diff) | |
parent | f4bfe83ef0831fca024112fe415209bdffdc6de8 (diff) | |
download | org.eclipse.jetty.project-jetty-8.0.0.M1.tar.gz org.eclipse.jetty.project-jetty-8.0.0.M1.tar.xz org.eclipse.jetty.project-jetty-8.0.0.M1.zip |
[maven-release-plugin] copy for tag jetty-8.0.0.M1jetty-8.0.0.M1
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/tags/jetty-8.0.0.M1@2102 7e9141cc-0065-0410-87d8-b60c137991c4
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> |