From bf2740148a46278580985c4312b0c812b81093d5 Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Thu, 28 Apr 2016 17:07:52 -0500 Subject: [PATCH 1/2] Issue #436 Migrate Jetty Documentation --- jetty-documentation/pom.xml | 256 ++ .../asciidoc/administration/alpn/alpn.adoc | 277 +++ .../asciidoc/administration/alpn/chapter.adoc | 20 + .../administration/annotations/chapter.adoc | 25 + .../annotations/quick-annotations-setup.adoc | 43 + .../using-annotations-embedded.adoc | 190 ++ .../annotations/using-annotations.adoc | 154 ++ .../extras/balancer-servlet.adoc | 38 + .../administration/extras/cgi-servlet.adoc | 44 + .../administration/extras/chapter.adoc | 44 + .../extras/cross-origin-filter.adoc | 97 + .../administration/extras/debug-handler.adoc | 70 + .../extras/default-handler.adoc | 54 + .../extras/default-servlet.adoc | 66 + .../administration/extras/dos-filter.adoc | 117 + .../administration/extras/error-handler.adoc | 33 + .../administration/extras/gzip-filter.adoc | 85 + .../extras/ipaccess-handler.adoc | 73 + .../extras/moved-context-handler.adoc | 74 + .../administration/extras/proxy-servlet.adoc | 81 + .../administration/extras/qos-filter.adoc | 171 ++ .../extras/resource-handler.adoc | 56 + .../extras/rewrite-handler.adoc | 146 ++ .../extras/shutdown-handler.adoc | 71 + .../extras/statistics-handler.adoc | 125 + .../administration/fastcgi/chapter.adoc | 21 + .../fastcgi/configuring-fastcgi.adoc | 176 ++ .../administration/fastcgi/fastcgi-intro.adoc | 34 + .../administration/http2/chapter.adoc | 24 + .../http2/configuring-haproxy.adoc | 201 ++ .../http2/configuring-http2.adoc | 64 + .../http2/configuring-push.adoc | 65 + .../administration/http2/enabling-http2.adoc | 70 + .../administration/http2/introduction.adoc | 42 + .../asciidoc/administration/jmx/chapter.adoc | 22 + .../administration/jmx/images/jconsole1.jpg | Bin 0 -> 16550 bytes .../administration/jmx/images/jconsole2.jpg | Bin 0 -> 143745 bytes .../administration/jmx/jetty-jconsole.adoc | 98 + .../jmx/jetty-jmx-annotations.adoc | 138 ++ .../administration/jmx/using-jmx.adoc | 198 ++ .../asciidoc/administration/jndi/chapter.adoc | 27 + .../jndi/jndi-configuration.adoc | 382 +++ .../administration/jndi/jndi-datasources.adoc | 447 ++++ .../administration/jndi/jndi-embedded.adoc | 146 ++ .../administration/jndi/quick-jndi-setup.adoc | 56 + .../administration/jndi/using-jndi.adoc | 195 ++ .../administration/logging/chapter.adoc | 21 + .../logging/configuring-jetty-logging.adoc | 99 + .../configuring-jetty-request-logs.adoc | 123 + .../default-logging-with-stderrlog.adoc | 150 ++ .../logging/example-apache-log4j.adoc | 89 + .../example-java-util-logging-native.adoc | 109 + .../logging/example-java-util-logging.adoc | 112 + .../example-logback-centralized-logging.adoc | 166 ++ .../logging/example-logback-sifting.adoc | 48 + .../logging/example-logback.adoc | 86 + .../example-slf4j-multiple-loggers.adoc | 200 ++ .../asciidoc/administration/npn/chapter.adoc | 18 + .../main/asciidoc/administration/npn/npn.adoc | 303 +++ .../main/asciidoc/administration/part.adoc | 30 + .../administration/runner/chapter.adoc | 22 + .../administration/runner/jetty-runner.adoc | 322 +++ .../administration/sessions/chapter.adoc | 25 + .../session-clustering-gcloud-datastore.adoc | 219 ++ .../session-clustering-infinispan.adoc | 238 ++ .../sessions/session-clustering-jdbc.adoc | 271 +++ .../sessions/session-clustering-mongodb.adoc | 300 +++ .../setting-session-characteristics.adoc | 295 +++ .../sessions/using-persistent-sessions.adoc | 125 + .../administration/startup/chapter.adoc | 27 + .../startup/images/modules-9.3-simplified.dot | 254 ++ .../startup/images/modules-9.3-simplified.png | Bin 0 -> 306780 bytes .../startup/images/windows-service-jetty.png | Bin 0 -> 138765 bytes .../startup/screen-empty-base-listconfig.adoc | 66 + .../startup/screen-empty-base.adoc | 22 + .../screen-http-webapp-deploy-listconfig.adoc | 81 + .../startup/screen-http-webapp-deploy.adoc | 28 + .../startup/screen-list-modules.adoc | 349 +++ .../administration/startup/start-jar.adoc | 213 ++ .../administration/startup/start-matrix.adoc | 20 + .../startup/startup-base-vs-home.adoc | 331 +++ .../startup/startup-classpath.adoc | 124 + .../startup/startup-modules.adoc | 168 ++ .../startup/startup-overview.adoc | 265 +++ .../startup/startup-troubleshooting.adoc | 20 + .../startup/startup-unix-service.adoc | 291 +++ .../startup/startup-windows-service.adoc | 329 +++ .../startup/startup-xml-config.adoc | 32 + .../administration/tuning/chapter.adoc | 28 + .../tuning/garbage-collection.adoc | 70 + .../administration/tuning/high-load.adoc | 157 ++ .../administration/tuning/limit-load.adoc | 45 + .../configuring/connectors/chapter.adoc | 24 + .../connectors/configuring-connectors.adoc | 366 +++ .../connectors/configuring-ssl.adoc | 684 ++++++ ...tting-port80-access-for-non-root-user.adoc | 165 ++ .../configuring/contexts/chapter.adoc | 27 + .../contexts/configuring-virtual-hosts.adoc | 268 +++ .../contexts/custom-error-pages.adoc | 202 ++ .../serving-webapp-from-particular-port.adoc | 80 + .../contexts/setting-context-path.adoc | 79 + .../contexts/setting-form-size.adoc | 74 + .../contexts/temporary-directories.adoc | 182 ++ .../deploying/anatomy-of-a-webapp.adoc | 53 + .../automatic-webapp-deployment.adoc | 46 + .../configuring/deploying/chapter.adoc | 33 + ...onfiguring-specific-webapp-deployment.adoc | 195 ++ .../deploying/deployment-architecture.adoc | 206 ++ .../deployment-processing-webapps.adoc | 372 +++ .../configuring/deploying/hot-deployment.adoc | 78 + .../Jetty_DeployManager_AppLifeCycle-1.png | Bin 0 -> 20022 bytes ...loyManager_DefaultAppLifeCycleBindings.png | Bin 0 -> 65653 bytes ..._DeployManager_DeploymentManager_Roles.png | Bin 0 -> 21894 bytes .../deploying/overlay-deployer.adoc | 396 ++++ .../deploying/quickstart-webapp.adoc | 130 + .../setting-deployment-bindings.adoc | 51 + .../deploying/static-content-deployment.adoc | 46 + .../asciidoc/configuring/jsp/chapter.adoc | 20 + .../configuring/jsp/configuring-jsp.adoc | 605 +++++ .../src/main/asciidoc/configuring/part.adoc | 23 + .../configuring/security/authentication.adoc | 487 ++++ .../configuring/security/authorization.adoc | 39 + .../configuring/security/chapter.adoc | 26 + .../security/configuring-form-size.adoc | 83 + .../configuring/security/jaas-support.adoc | 519 ++++ .../security/jetty-home-and-jetty-base.adoc | 534 +++++ .../security/secure-passwords.adoc | 120 + .../security/serving-aliased-files.adoc | 126 + .../configuring/security/spnego-support.adoc | 203 ++ .../asciidoc/development/ant/chapter.adoc | 22 + .../asciidoc/development/ant/jetty-ant.adoc | 618 +++++ .../development/clients/http/chapter.adoc | 22 + .../clients/http/http-client-api.adoc | 432 ++++ .../clients/http/http-client-intro.adoc | 83 + .../clients/http/http-client-other.adoc | 167 ++ .../development/continuations/chapter.adoc | 22 + .../continuations/continuations-intro.adoc | 127 + .../continuations/continuations-patterns.adoc | 124 + .../continuations/continuations-using.adoc | 114 + .../development/debugging/chapter.adoc | 28 + .../debugging/debugging-with-eclipse.adoc | 57 + .../debugging/debugging-with-intellij.adoc | 67 + .../debugging/enable-remote-debugging.adoc | 97 + .../debugging/images/debug-eclipse-1.png | Bin 0 -> 122854 bytes .../debugging/images/debug-eclipse-2.png | Bin 0 -> 340485 bytes .../debugging/images/debug-eclipse-3.png | Bin 0 -> 275553 bytes .../debugging/images/intellij_debug_view.png | Bin 0 -> 443702 bytes .../images/intellij_new_remote_config.png | Bin 0 -> 281731 bytes .../images/intellij_select_debug.png | Bin 0 -> 555356 bytes .../images/intellij_set_breakpoint.png | Bin 0 -> 405149 bytes .../development/embedding/chapter.adoc | 22 + .../embedding/embedded-examples.adoc | 84 + .../embedding/embedding-jetty.adoc | 245 ++ .../examples/embedded-file-server.adoc | 47 + .../examples/embedded-many-connectors.adoc | 54 + .../examples/embedded-minimal-servlet.adoc | 54 + .../examples/embedded-one-webapp.adoc | 48 + .../embedded-secured-hello-handler.adoc | 57 + .../examples/embedded-split-file-server.adoc | 54 + .../embedding/jetty-helloworld.adoc | 83 + .../development/frameworks/chapter.adoc | 23 + .../development/frameworks/metro.adoc | 59 + .../asciidoc/development/frameworks/osgi.adoc | 1428 +++++++++++ .../development/frameworks/spring-usage.adoc | 101 + .../asciidoc/development/frameworks/weld.adoc | 80 + .../development/handlers/chapter.adoc | 20 + .../handlers/writing-custom-handlers.adoc | 172 ++ .../asciidoc/development/maven/chapter.adoc | 25 + .../maven/jetty-jspc-maven-plugin.adoc | 256 ++ .../maven/jetty-maven-helloworld.adoc | 309 +++ .../development/maven/jetty-maven-plugin.adoc | 1149 +++++++++ .../maven/jetty-maven-scanning.adoc | 37 + .../src/main/asciidoc/development/part.adoc | 29 + .../development/websockets/intro/chapter.adoc | 128 + .../development/websockets/java/chapter.adoc | 21 + .../java/java-websocket-client-api.adoc | 22 + .../java/java-websocket-server-api.adoc | 22 + .../development/websockets/jetty/chapter.adoc | 30 + .../jetty/jetty-websocket-api-adapter.adoc | 27 + .../jetty-websocket-api-annotations.adoc | 107 + .../jetty/jetty-websocket-api-events.adoc | 47 + .../jetty/jetty-websocket-api-listener.adoc | 28 + .../jetty-websocket-api-send-message.adoc | 298 +++ .../jetty/jetty-websocket-api-session.adoc | 70 + .../websockets/jetty/jetty-websocket-api.adoc | 22 + .../jetty/jetty-websocket-client-api.adoc | 51 + .../jetty/jetty-websocket-server-api.adoc | 79 + .../src/main/asciidoc/index-docinfo.xml | 96 + .../src/main/asciidoc/index.adoc | 28 + .../quick-start/configuring/chapter.adoc | 21 + .../configuring/how-to-configure.adoc | 120 + .../configuring/what-to-configure.adoc | 291 +++ .../quick-start/getting-started/chapter.adoc | 26 + .../getting-started/jetty-coordinates.adoc | 53 + .../getting-started/jetty-deploying.adoc | 73 + .../getting-started/jetty-installing.adoc | 58 + .../getting-started/jetty-running.adoc | 211 ++ .../quick-start/introduction/chapter.adoc | 22 + .../introduction/jetty-javaee.adoc | 107 + .../introduction/what-is-jetty.adoc | 28 + .../introduction/what-version.adoc | 38 + .../src/main/asciidoc/quick-start/part.adoc | 21 + .../reference/architecture/1xx-responses.adoc | 39 + .../architecture/basic-architecture.adoc | 151 ++ .../reference/architecture/chapter.adoc | 25 + .../images/basic-architecture-connectors.png | Bin 0 -> 56437 bytes .../images/basic-architecture-handlers.png | Bin 0 -> 55665 bytes .../basic-architecture-nested-handlers.png | Bin 0 -> 12452 bytes .../images/basic-architecture-patterns.png | Bin 0 -> 44966 bytes .../basic-architecture-servlet-handler.png | Bin 0 -> 41033 bytes .../basic-architecture-web-application.png | Bin 0 -> 21701 bytes .../images/jetty-high-level-architecture.png | Bin 0 -> 4502 bytes .../architecture/jetty-classloading.adoc | 166 ++ .../server-side-architecture.adoc | 97 + .../asciidoc/reference/contributing/bugs.adoc | 24 + .../reference/contributing/chapter.adoc | 30 + .../contributing/coding-standards.adoc | 87 + .../reference/contributing/community.adoc | 53 + .../reference/contributing/documentation.adoc | 234 ++ .../reference/contributing/patches.adoc | 51 + .../contributing/release-testing.adoc | 218 ++ .../contributing/releasing-jetty.adoc | 265 +++ .../reference/contributing/source-build.adoc | 95 + .../main/asciidoc/reference/faq/chapter.adoc | 19 + .../asciidoc/reference/jetty-xml/chapter.adoc | 26 + .../reference/jetty-xml/jetty-env-xml.adoc | 97 + .../jetty-xml/jetty-web-xml-config.adoc | 65 + .../reference/jetty-xml/jetty-xml-config.adoc | 62 + .../reference/jetty-xml/jetty-xml-syntax.adoc | 1044 +++++++++ .../reference/jetty-xml/jetty-xml-usage.adoc | 71 + .../reference/jetty-xml/override-web-xml.adoc | 100 + .../reference/jetty-xml/webdefault-xml.adoc | 116 + .../src/main/asciidoc/reference/part.adoc | 23 + .../asciidoc/reference/platforms/chapter.adoc | 34 + .../reference/platforms/cloudfoundry.adoc | 140 ++ .../platforms/elastic-beanstalk.adoc | 86 + .../asciidoc/reference/platforms/fedora.adoc | 24 + .../reference/platforms/jelastic.adoc | 24 + .../asciidoc/reference/platforms/ubuntu.adoc | 23 + .../reference/troubleshooting/chapter.adoc | 26 + .../preventing-memory-leaks.adoc | 161 ++ .../troubleshooting/security-reports.adoc | 115 + .../troubleshooting/slow-deployment.adoc | 49 + .../troubleshooting-locked-files.adoc | 124 + .../troubleshooting-zip-exceptions.adoc | 42 + .../asciidoc/reference/upgrading/chapter.adoc | 20 + .../asciidoc/reference/upgrading/sample.adoc | 23 + .../src/main/assembly/html.xml | 16 + .../src/main/docbkx-resources/css/docbook.css | 310 +++ .../css/font-awesome/font-awesome-ie7.min.css | 22 + .../css/font-awesome/font-awesome.css | 2086 +++++++++++++++++ .../css/font-awesome/font-awesome.css.map | 7 + .../css/font-awesome/font-awesome.min.css | 4 + .../css/highlighter/default.css | 155 ++ .../css/highlighter/github.css | 123 + .../css/highlighter/googlecode.css | 144 ++ .../docbkx-resources/fonts/FontAwesome.otf | Bin 0 -> 109688 bytes .../fonts/fontawesome-webfont.eot | Bin 0 -> 70807 bytes .../fonts/fontawesome-webfont.svg | 655 ++++++ .../fonts/fontawesome-webfont.ttf | Bin 0 -> 142072 bytes .../fonts/fontawesome-webfont.woff | Bin 0 -> 83588 bytes .../fonts/fontawesome-webfont.woff2 | Bin 0 -> 66624 bytes .../main/docbkx-resources/images/caution.png | Bin 0 -> 1250 bytes .../main/docbkx-resources/images/caution.svg | 25 + .../docbkx-resources/images/draft-ribbon.png | Bin 0 -> 9413 bytes .../main/docbkx-resources/images/favicon.ico | Bin 0 -> 1150 bytes .../docbkx-resources/images/important.png | Bin 0 -> 722 bytes .../docbkx-resources/images/important.svg | 25 + .../docbkx-resources/images/jetty-avatar.svg | 179 ++ .../images/jetty-header-logo.png | Bin 0 -> 5822 bytes .../images/jetty-logo-shadow.png | Bin 0 -> 37553 bytes .../images/jetty-logo-shadow.svg | 113 + .../docbkx-resources/images/jetty-logo.svg | 88 + .../main/docbkx-resources/images/jetty.gif | Bin 0 -> 9918 bytes .../src/main/docbkx-resources/images/note.png | Bin 0 -> 490 bytes .../src/main/docbkx-resources/images/note.svg | 33 + .../src/main/docbkx-resources/images/tip.png | Bin 0 -> 449 bytes .../src/main/docbkx-resources/images/tip.svg | 31 + .../main/docbkx-resources/images/warning.png | Bin 0 -> 1241 bytes .../main/docbkx-resources/images/warning.svg | 23 + .../docbkx-resources/js/highlight.pack.js | 1 + .../src/main/docbkx-stylesheet/fo/docbook.xsl | 288 +++ .../main/docbkx-stylesheet/html/docbook.xsl | 468 ++++ 283 files changed, 35055 insertions(+) create mode 100644 jetty-documentation/pom.xml create mode 100644 jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/alpn/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/annotations/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/annotations/quick-annotations-setup.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/balancer-servlet.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/cgi-servlet.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/debug-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/default-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/default-servlet.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/dos-filter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/error-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/gzip-filter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/ipaccess-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/moved-context-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/proxy-servlet.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/qos-filter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/resource-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/rewrite-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/shutdown-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/fastcgi/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/fastcgi/fastcgi-intro.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/http2/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/http2/configuring-haproxy.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/http2/configuring-push.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/http2/introduction.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jmx/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jmx/images/jconsole1.jpg create mode 100644 jetty-documentation/src/main/asciidoc/administration/jmx/images/jconsole2.jpg create mode 100644 jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jconsole.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jmx-annotations.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jmx/using-jmx.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jndi/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jndi/jndi-configuration.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/jndi/using-jndi.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/example-logback-sifting.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/npn/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/npn/npn.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/part.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/runner/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-gcloud-datastore.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-infinispan.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-jdbc.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-mongodb.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/sessions/setting-session-characteristics.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/sessions/using-persistent-sessions.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/images/modules-9.3-simplified.dot create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/images/modules-9.3-simplified.png create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/images/windows-service-jetty.png create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/screen-list-modules.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/start-matrix.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/startup-overview.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/startup-troubleshooting.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/startup-unix-service.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/startup-windows-service.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/startup/startup-xml-config.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/tuning/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/tuning/garbage-collection.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc create mode 100644 jetty-documentation/src/main/asciidoc/administration/tuning/limit-load.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/connectors/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-connectors.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/connectors/setting-port80-access-for-non-root-user.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/contexts/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/contexts/configuring-virtual-hosts.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/contexts/custom-error-pages.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/contexts/serving-webapp-from-particular-port.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/contexts/setting-context-path.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/contexts/setting-form-size.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/contexts/temporary-directories.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/anatomy-of-a-webapp.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/automatic-webapp-deployment.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/configuring-specific-webapp-deployment.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-architecture.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-processing-webapps.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/hot-deployment.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/images/Jetty_DeployManager_AppLifeCycle-1.png create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/images/Jetty_DeployManager_DefaultAppLifeCycleBindings.png create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/images/Jetty_DeployManager_DeploymentManager_Roles.png create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/overlay-deployer.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/setting-deployment-bindings.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/deploying/static-content-deployment.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/jsp/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/jsp/configuring-jsp.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/part.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/authentication.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/authorization.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/configuring-form-size.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/jetty-home-and-jetty-base.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/secure-passwords.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/serving-aliased-files.adoc create mode 100644 jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/ant/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/clients/http/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/clients/http/http-client-api.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/clients/http/http-client-intro.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/clients/http/http-client-other.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/continuations/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/continuations/continuations-intro.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/continuations/continuations-patterns.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/continuations/continuations-using.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/debugging-with-eclipse.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/debugging-with-intellij.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/enable-remote-debugging.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/images/debug-eclipse-1.png create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/images/debug-eclipse-2.png create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/images/debug-eclipse-3.png create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/images/intellij_debug_view.png create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/images/intellij_new_remote_config.png create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/images/intellij_select_debug.png create mode 100644 jetty-documentation/src/main/asciidoc/development/debugging/images/intellij_set_breakpoint.png create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/embedded-examples.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/embedding-jetty.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-file-server.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-many-connectors.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-minimal-servlet.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-one-webapp.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-secured-hello-handler.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-split-file-server.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/frameworks/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/frameworks/metro.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/frameworks/weld.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/handlers/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/handlers/writing-custom-handlers.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/maven/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-scanning.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/part.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/intro/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/java/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-client-api.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-server-api.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-events.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-send-message.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-session.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc create mode 100644 jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc create mode 100644 jetty-documentation/src/main/asciidoc/index-docinfo.xml create mode 100644 jetty-documentation/src/main/asciidoc/index.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/configuring/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/configuring/how-to-configure.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/configuring/what-to-configure.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/getting-started/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-coordinates.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-deploying.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/introduction/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-javaee.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/introduction/what-is-jetty.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc create mode 100644 jetty-documentation/src/main/asciidoc/quick-start/part.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/1xx-responses.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/basic-architecture.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/images/basic-architecture-connectors.png create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/images/basic-architecture-handlers.png create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/images/basic-architecture-nested-handlers.png create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/images/basic-architecture-patterns.png create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/images/basic-architecture-servlet-handler.png create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/images/basic-architecture-web-application.png create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/images/jetty-high-level-architecture.png create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/jetty-classloading.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/architecture/server-side-architecture.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/bugs.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/coding-standards.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/community.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/documentation.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/patches.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/release-testing.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/releasing-jetty.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/contributing/source-build.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/faq/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/jetty-xml/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-env-xml.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-config.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/part.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/platforms/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/platforms/cloudfoundry.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/platforms/elastic-beanstalk.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/platforms/fedora.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/platforms/jelastic.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/platforms/ubuntu.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/troubleshooting/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/troubleshooting/preventing-memory-leaks.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/troubleshooting/security-reports.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/troubleshooting/slow-deployment.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-locked-files.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-zip-exceptions.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/upgrading/chapter.adoc create mode 100644 jetty-documentation/src/main/asciidoc/reference/upgrading/sample.adoc create mode 100644 jetty-documentation/src/main/assembly/html.xml create mode 100644 jetty-documentation/src/main/docbkx-resources/css/docbook.css create mode 100644 jetty-documentation/src/main/docbkx-resources/css/font-awesome/font-awesome-ie7.min.css create mode 100755 jetty-documentation/src/main/docbkx-resources/css/font-awesome/font-awesome.css create mode 100755 jetty-documentation/src/main/docbkx-resources/css/font-awesome/font-awesome.css.map create mode 100755 jetty-documentation/src/main/docbkx-resources/css/font-awesome/font-awesome.min.css create mode 100644 jetty-documentation/src/main/docbkx-resources/css/highlighter/default.css create mode 100644 jetty-documentation/src/main/docbkx-resources/css/highlighter/github.css create mode 100644 jetty-documentation/src/main/docbkx-resources/css/highlighter/googlecode.css create mode 100755 jetty-documentation/src/main/docbkx-resources/fonts/FontAwesome.otf create mode 100755 jetty-documentation/src/main/docbkx-resources/fonts/fontawesome-webfont.eot create mode 100755 jetty-documentation/src/main/docbkx-resources/fonts/fontawesome-webfont.svg create mode 100755 jetty-documentation/src/main/docbkx-resources/fonts/fontawesome-webfont.ttf create mode 100755 jetty-documentation/src/main/docbkx-resources/fonts/fontawesome-webfont.woff create mode 100755 jetty-documentation/src/main/docbkx-resources/fonts/fontawesome-webfont.woff2 create mode 100644 jetty-documentation/src/main/docbkx-resources/images/caution.png create mode 100644 jetty-documentation/src/main/docbkx-resources/images/caution.svg create mode 100644 jetty-documentation/src/main/docbkx-resources/images/draft-ribbon.png create mode 100644 jetty-documentation/src/main/docbkx-resources/images/favicon.ico create mode 100644 jetty-documentation/src/main/docbkx-resources/images/important.png create mode 100644 jetty-documentation/src/main/docbkx-resources/images/important.svg create mode 100644 jetty-documentation/src/main/docbkx-resources/images/jetty-avatar.svg create mode 100644 jetty-documentation/src/main/docbkx-resources/images/jetty-header-logo.png create mode 100644 jetty-documentation/src/main/docbkx-resources/images/jetty-logo-shadow.png create mode 100644 jetty-documentation/src/main/docbkx-resources/images/jetty-logo-shadow.svg create mode 100644 jetty-documentation/src/main/docbkx-resources/images/jetty-logo.svg create mode 100644 jetty-documentation/src/main/docbkx-resources/images/jetty.gif create mode 100644 jetty-documentation/src/main/docbkx-resources/images/note.png create mode 100644 jetty-documentation/src/main/docbkx-resources/images/note.svg create mode 100644 jetty-documentation/src/main/docbkx-resources/images/tip.png create mode 100644 jetty-documentation/src/main/docbkx-resources/images/tip.svg create mode 100644 jetty-documentation/src/main/docbkx-resources/images/warning.png create mode 100644 jetty-documentation/src/main/docbkx-resources/images/warning.svg create mode 100644 jetty-documentation/src/main/docbkx-resources/js/highlight.pack.js create mode 100644 jetty-documentation/src/main/docbkx-stylesheet/fo/docbook.xsl create mode 100644 jetty-documentation/src/main/docbkx-stylesheet/html/docbook.xsl diff --git a/jetty-documentation/pom.xml b/jetty-documentation/pom.xml new file mode 100644 index 00000000000..39a6a67ffd1 --- /dev/null +++ b/jetty-documentation/pom.xml @@ -0,0 +1,256 @@ + + + 4.0.0 + + org.eclipse.jetty + jetty-project + 9.3.9-SNAPSHOT + + jetty-documentation + Jetty :: Documentation + pom + + UTF-8 + 1.5.3 + ${project.build.directory}/current + + + + + + org.apache.felix + maven-bundle-plugin + 3.0.1 + + + + + + maven-resources-plugin + 2.6 + + + copy-assets + process-resources + + copy-resources + + + + + src/main/resources + + ** + + + + ${html.directory} + + + + + + org.asciidoctor + asciidoctor-maven-plugin + ${asciidoctor.version} + + + output-html + compile + + process-asciidoc + + + docbook + book + index.adoc + + + ${project.version} + true + true + true + ${project.version} + http://download.eclipse.org/jetty/stable-9/apidocs + http://download.eclipse.org/jetty/stable-9/xref + ${basedir}/.. + https://github.com/eclipse/jetty.project/master + + + + + + + com.agilejava.docbkx + docbkx-maven-plugin + 2.0.14 + + + html + compile + + generate-html + + + css/docbook.css + ${basedir}/src/main/docbkx-stylesheet/html/docbook.xsl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${project.build.directory}/generated-docs + index.xml + ${project.build.directory}/docbkx/generated + true + true + + + + net.sf.docbook + docbook-xml + 5.0-all + resources + zip + runtime + + + net.sf.xslthl + xslthl + 2.0.1 + runtime + + + org.eclipse.jetty.toolchain + jetty-xslt-tools + 1.3 + runtime + + + + + maven-assembly-plugin + 2.6 + + + src/main/assembly/html.xml + + + + + make-assembly + package + + single + + + + + + + + + + generate-pdf + + + + com.agilejava.docbkx + docbkx-maven-plugin + + + generate-pdf + compile + + generate-pdf + + + index.xml + 1 + A4 + src/main/docbkx-stylesheet/fo/docbook.xsl + + + + + + net.sf.offo + fop-hyph + 1.2 + runtime + + + + + org.asciidoctor + asciidoctor-maven-plugin + ${asciidoctor.version} + + + org.asciidoctor + asciidoctorj-pdf + 1.5.0-alpha.11 + + + + + output-pdf + generate-sources + + process-asciidoc + + + pdf + rouge + index.adoc + + + ${project.version} + true + true + true + ${project.version} + http://download.eclipse.org/jetty/stable-9/apidocs + http://download.eclipse.org/jetty/stable-9/xref + ${basedir}/../jetty.project/ + https://github.com/eclipse/jetty.project/master + font + + + + - + + + + + + + + + + diff --git a/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc b/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc new file mode 100644 index 00000000000..1af6c9de850 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc @@ -0,0 +1,277 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[alpn]] +=== Introducing ALPN + +The development of new web protocols such as HTTP/2 raised the need of protocol negotiation within a Transport Layer Security (TLS) handshake. +A protocol negotiation called https://tools.ietf.org/html/rfc7301[ALPN] (Application Layer Protocol Negotiation) RFC7301 has been defined to accomplish this. + +ALPN has now replaced the older (and now fully deprecated) NPN in the general Web of 2016. + +For those browsers that support HTTP/2, they all now support the ALPN negotiation layers for TLS. + +Starting with Jetty 9.3.0, only ALPN is supported by Jetty. + +The Jetty project provides an implementation of the TLS extension for ALPN for OpenJDK 7 and OpenJDK 8. +ALPN allows the application layer to negotiate which protocol to use over the secure connection. + +Any protocol can be negotiated by ALPN within a TLS connection. +The protocols that are most commonly negotiated are HTTP/2 (for browsers that support it) and, historically, SPDY. +The ALPN implementation is therefore not HTTP/2 or SPDY specific in any way. +Jetty's ALPN implementation, although hosted under the umbrella of the Jetty project, is independent of Jetty (the Servlet Container); you can use the ALPN implementation in any other Java network server. + +The Jetty distribution will automatically enable ALPN when it is needed to by a HTTP/2 connector, so for the most part ALPN is transparent to the average deployer. +This section provides the detail required for unusual deployments or developing to the ALPN API. + +[[alpn-starting]] +==== Starting the JVM + +To enable ALPN support, start the JVM as follows: + +[source,plain] +---- +java -Xbootclasspath/p: ... +---- + +where `path_to_alpn_boot_jar` is the path on the file system for the ALPN Boot Jar file, for example, one at the Maven coordinates `org.mortbay.jetty.alpn:alpn-boot`. + +Be certain link:#alpn-versions[to get the ALPN Boot Jar version which matches the version of your JRE]. + +[[alpn-osgi]] +===== Starting in OSGi + +To use ALPN in an OSGi environment, in addition to putting the ALPN jar on the boot classpath for the container, you will also need to deploy the jetty-osgi-alpn jar. +This jar contains a Fragment-Host directive that ensures the ALPN classes will be available from the system bundle. + +You can download the http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-alpn/[jetty-osgi-alpn jar] from Maven Central. + +[[alpn-understanding]] +==== Understanding the ALPN API + +Applications need to interact with ALPN TLS extension protocol negotiations. +For example, server applications need to know whether the client supports ALPN, and client applications needs to know whether the server supports ALPN. + +To implement this interaction, Jetty's ALPN implementation provides an API to applications, hosted at Maven coordinates +`org.eclipse.jetty.alpn:alpn-api`. +You need to declare this dependency as provided, because the `alpn-boot` Jar already includes it (see the previous section), and it is therefore available from the boot classpath. + +The API consists of a single class, `org.eclipse.jetty.alpn.ALPN`, and applications need to register instances of `SSLSocket` or `SSLEngine` with a `ClientProvider` or `ServerProvider` (depending on whether the application is a client application or server application). +Refer to `ALPN` Javadocs and to the examples below for further details about client and server provider methods. + +[[alpn-client-example]] +==== Client Example + +[source,java] +---- +SSLContext sslContext = ...; +final SSLSocket sslSocket = (SSLSocket)context.getSocketFactory().createSocket("localhost", server.getLocalPort()); + +ALPN.put(sslSocket, new ALPN.ClientProvider() +{ + @Override + public boolean supports() + { + return true; + } + + @Override + public List protocols() + { + return Arrays.asList("h2", "http/1.1"); + } + + @Override + public void unsupported() + { + ALPN.remove(sslSocket); + } + + @Override + public void selected(String protocol) + { + ALPN.remove(sslSocket); + System.out.println("Protocol Selected is: " + protocol); + } +}); +---- + +The ALPN implementation calls `ALPN.ClientProvider` methods `supports()`, `protocols()`, `unsupported()` and `selected(String)`, so that the client application can: + +* decide whether to support ALPN. +* provide the protocols supported. +* know whether the server supports ALPN. +* know the protocol chosen by the server. + +[[alpn-server-example]] +==== Server Example + +The example for SSLEngine is identical, and you just need to replace the SSLSocket instance with an SSLEngine instance. + +[source,java] +---- +final SSLSocket sslSocket = ...; +ALPN.put(sslSocket, new ALPN.ServerProvider() +{ + @Override + public void unsupported() + { + ALPN.remove(sslSocket); + } + + @Override + public String select(List protocols); + { + ALPN.remove(sslSocket); + return protocols.get(0); + } +}); +---- + +The ALPN implementation calls `ALPN.ServerProvider` methods `unsupported()`, and `select(List),` so that the server application can: + +* know whether the client supports ALPN. +* select one of the protocols the client supports. + +[[alpn-implementation]] +==== Implementation Details + +It is important that implementations of `ALPN.ServerProvider` and `ALPN.ClientProvider` remove the `sslSocket` or `sslEngine` when the negotiation is complete, like shown in the examples above. + +Failing to do so will cause a memory leak. + +[[alpn-tests]] +==== Unit Tests + +You can write and run unit tests that use the ALPN implementation. +The solution that we use with Maven is to specify an additional command line argument to the Surefire plugin: + +[source,xml] +---- + + + + 8.1.4.v20150727 + + + + + + maven-surefire-plugin + + + -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn-boot-version}/alpn-boot-${alpn-boot-version}.jar + + + + + ... + + + + +... + + +---- + +[[alpn-debugging]] +==== Debugging + +You can enable debug logging for the ALPN implementation in this way: + +.... +ALPN.debug = true; +.... + +Since the ALPN class is in the boot classpath, we chose not to use logging libraries because we do not want to override application logging library choices; therefore the logging is performed directly on `System.err.` + +[[alpn-license-details]] +==== License Details + +The ALPN implementation relies on modification of a few OpenJDK classes and on a few new classes that need to live in the `sun.security.ssl` package. +These classes are released under the same GPLv2+exception license of OpenJDK. + +The ALPN class and its nested classes are released under same license as the classes of the Jetty project. + +[[alpn-versions]] +==== Versions + +The ALPN implementation, relying on modifications of OpenJDK classes, updates every time there are updates to the modified OpenJDK classes. + +.ALPN vs. OpenJDK versions +[cols=",",options="header",] +|============================= +|OpenJDK version |ALPN version +|1.7.0u40 |7.1.0.v20141016 +|1.7.0u45 |7.1.0.v20141016 +|1.7.0u51 |7.1.0.v20141016 +|1.7.0u55 |7.1.0.v20141016 +|1.7.0u60 |7.1.0.v20141016 +|1.7.0u65 |7.1.0.v20141016 +|1.7.0u67 |7.1.0.v20141016 +|1.7.0u71 |7.1.2.v20141202 +|1.7.0u72 |7.1.2.v20141202 +|1.7.0u75 |7.1.3.v20150130 +|1.7.0u76 |7.1.3.v20150130 +|1.7.0u79 |7.1.3.v20150130 +|1.7.0u80 |7.1.3.v20150130 +|1.8.0 |8.1.0.v20141016 +|1.8.0u05 |8.1.0.v20141016 +|1.8.0u11 |8.1.0.v20141016 +|1.8.0u20 |8.1.0.v20141016 +|1.8.0u25 |8.1.2.v20141202 +|1.8.0u31 |8.1.3.v20150130 +|1.8.0u40 |8.1.3.v20150130 +|1.8.0u45 |8.1.3.v20150130 +|1.8.0u51 |8.1.4.v20150727 +|1.8.0u60 |8.1.5.v20150921 +|1.8.0u65 |8.1.6.v20151105 +|1.8.0u66 |8.1.6.v20151105 +|1.8.0u71 |8.1.7.v20160121 +|1.8.0u72 |8.1.7.v20160121 +|1.8.0u73 |8.1.7.v20160121 +|1.8.0u74 |8.1.7.v20160121 +|1.8.0u77 |8.1.7.v20160121 +|============================= + +[[alpn-build]] +==== How to build ALPN + +This section is for Jetty developers that need to update the ALPN implementation with the OpenJDK versions. + +Clone the OpenJDK repository with the following command: + +.... +$ hg clone http://hg.openjdk.java.net/jdk7u/jdk7u jdk7u # OpenJDK 7 +$ hg clone http://hg.openjdk.java.net/jdk8u/jdk8u jdk8u # OpenJDK 8 +$ cd !$ +$ ./get_source.sh + +.... + +To update the source to a specific tag, use the following command: + +.... +$ ./make/scripts/hgforest.sh update + +.... + +The list of OpenJDK tags can be obtained from these pages: +http://hg.openjdk.java.net/jdk7u/jdk7u/tags[OpenJDK 7] / +http://hg.openjdk.java.net/jdk8u/jdk8u/tags[OpenJDK 8]. + +Then you need to compare and incorporate the OpenJDK source changes into the modified OpenJDK classes at the https://github.com/jetty-project/jetty-alpn[ALPN GitHub Repository], branch `openjdk7` for OpenJDK 7 and branch `master` for OpenJDK 8. diff --git a/jetty-documentation/src/main/asciidoc/administration/alpn/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/alpn/chapter.adoc new file mode 100644 index 00000000000..000f3cb75f8 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/alpn/chapter.adoc @@ -0,0 +1,20 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[alpn-chapter]] +== ALPN + +include::alpn.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/chapter.adoc new file mode 100644 index 00000000000..a9691829763 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/chapter.adoc @@ -0,0 +1,25 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[annotations]] +== Annotations + +Jetty supports the servlet specification annotations. +It is not enable by default, so the following sections show you how to enable it, and how to use them. + +include::quick-annotations-setup.adoc[] +include::using-annotations.adoc[] +include::using-annotations-embedded.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/quick-annotations-setup.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/quick-annotations-setup.adoc new file mode 100644 index 00000000000..c9a3c388c09 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/quick-annotations-setup.adoc @@ -0,0 +1,43 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[annotations-quick-setup]] +=== Quick Setup + +==== Jetty Distribution + +If you are using the jetty distribution, then annotations are enabled by default. +The *annotations* link:#startup-modules[module] and its transitive dependencies are responsible for making annotation processing available. + +Note that annotations that relate to link:#jndi[JNDI], such as @Resource and @Resources are enabled via the *jndi* module, which is a transitive dependency on the annotations module, and thus is also enabled by default for the distribution. + +==== Jetty Maven Plugin + +Annotations and JNDI are pre-enabled for the maven plugin. + +==== Embedding + +To use annotations in an embedded scenario, you will need to include the jetty-annotations jar and all its dependencies onto your classpath. +You will also need to include the org.eclipse.jetty.annotations.AnnotationConfiguration into the list of link:#webapp-configurations[Configuration classes] applied to the org.eclipse.jetty.webapp.WebAppContext representing your webapp. + +Here is an example application that sets up the standard test-spec.war webapp from the distribution in embedded fashion. +It can be found in the jetty git repository in the examples/embedded project. +Note that the test-spec.war uses not only annotations, but also link:#jndi[JNDI], so this example also enables their processing (via the link:#jndi-configuration-classes[org.eclipse.jetty.plus.webapp.EnvConfiguration], link:#jndi-configuration-classes[org.eclipse.jetty.plus.webapp.PlusConfiguration] and their related jars). + +[source,java] +---- +include::{SRCDIR}/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithAnnotations.java[] +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc new file mode 100644 index 00000000000..67d72eac66d --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc @@ -0,0 +1,190 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[using-annotations-embedded]] +=== Using Annotations with Jetty Embedded + +==== Setting up the Classpath + +You will need to place the following jetty jars onto the classpath of your application. You can obtain them from the http://download.eclipse.org/jetty/stable-9/dist/[jetty distribution], or the http://central.maven.org/maven2/org/eclipse/jetty/jetty-annotations[maven repository]: + +.... +jetty-plus.jar +jetty-annotations.jar +.... + +You will also need the http://asm.ow2.org/[asm] jar, which you can obtain from the http://download.eclipse.org/jetty/orbit/[Jetty dependencies site]. + +==== Example + +Here's an example application that sets up a Jetty server, does some setup to ensure that annotations are scanned and deploys a webapp that uses annotations. +This example also uses the @Resource annotation which involves JNDI, so we would also link:#jndi-embedded[add the necessary jndi jars to the classpath]., and we also add in the configuration classes that are responsible for JNDI (see line 19). + +Here is the embedding code: + +[source,java] +---- +import org.eclipse.jetty.security.HashLoginService; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.webapp.WebAppContext; + +/** + * ServerWithAnnotations + * + * + */ +public class ServerWithAnnotations +{ + public static final void main(String args[]) throws Exception + { + //Create the server + Server server = new Server(8080); + + //Enable parsing of jndi-related parts of web.xml and jetty-env.xml + org.eclipse.jetty.webapp.Configuration.ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server); + classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration"); + classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration"); + + //Create a WebApp + WebAppContext webapp = new WebAppContext(); + webapp.setContextPath("/"); + webapp.setWar("../../tests/test-webapps/test-servlet-spec/test-spec-webapp/target/test-spec-webapp-9.0.4-SNAPSHOT.war"); + server.setHandler(webapp); + + //Register new transaction manager in JNDI + //At runtime, the webapp accesses this as java:comp/UserTransaction + org.eclipse.jetty.plus.jndi.Transaction transactionMgr = new org.eclipse.jetty.plus.jndi.Transaction(new com.acme.MockUserTransaction()); + + //Define an env entry with webapp scope. + org.eclipse.jetty.plus.jndi.EnvEntry maxAmount = new org.eclipse.jetty.plus.jndi.EnvEntry (webapp, "maxAmount", new Double(100), true); + + + // Register a mock DataSource scoped to the webapp + org.eclipse.jetty.plus.jndi.Resource mydatasource = new org.eclipse.jetty.plus.jndi.Resource(webapp, "jdbc/mydatasource", new com.acme.MockDataSource()); + + // Configure a LoginService + HashLoginService loginService = new HashLoginService(); + loginService.setName("Test Realm"); + loginService.setConfig("src/test/resources/realm.properties"); + server.addBean(loginService); + + + server.start(); + server.join(); + } + +} +---- + +On line 19 we add in the configuration classes responsible for setting up JNDI and java:comp/env. + +On line 20 we add in the configuration class that ensures annotations are inspected. + +On lines 30, 33 and 37 we set up some JNDI resources that we will be able to reference with @Resource annotations. + +With the setup above, we can create a servlet that uses annotations and Jetty will honour the annotations when the webapp is deployed: + +[source,java] +---- +import javax.annotation.security.DeclareRoles; +import javax.annotation.security.RunAs; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.annotation.WebInitParam; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.sql.DataSource; +import javax.transaction.UserTransaction; + +/** + * AnnotationTest + * + * Use servlet 3.0 annotations from within Jetty. + * + * Also uses servlet 2.5 resource injection and lifecycle callbacks + */ + +@RunAs("special") +@WebServlet(urlPatterns = {"/","/test/*"}, name="AnnotationTest", initParams={@WebInitParam(name="fromAnnotation", value="xyz")}) +@DeclareRoles({"user","client"}) +public class AnnotationTest extends HttpServlet +{ + private DataSource myDS; + + @Resource(mappedName="UserTransaction") + private UserTransaction myUserTransaction; + + @Resource(mappedName="maxAmount") + private Double maxAmount; + + + @Resource(mappedName="jdbc/mydatasource") + public void setMyDatasource(DataSource ds) + { + myDS=ds; + } + + + @PostConstruct + private void myPostConstructMethod () + { + System.err.println("PostConstruct called"); + } + + + @PreDestroy + private void myPreDestroyMethod() + { + System.err.println("PreDestroy called"); + } + + public void init(ServletConfig config) throws ServletException + { + super.init(config); + } + + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + doGet(request, response); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + try + { + response.setContentType("text/html"); + ServletOutputStream out = response.getOutputStream(); + out.println(""); + out.println(""); + out.println("

Results

"); + out.println(myDS.toString()); + out.println("
"); + out.println(maxAmount.toString()); + out.println(""); + out.println(""); + out.flush(); + } + catch (Exception e) + { + throw new ServletException(e); + } + } +} +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations.adoc new file mode 100644 index 00000000000..d9708ac05a6 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations.adoc @@ -0,0 +1,154 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[using-annotations]] +=== Working with Annotations + +==== Which Annotations Are Supported + +Jetty supports interpretation and application of the following annotations: + +* @Resource +* @Resources +* @PostConstruct +* @PreDestroy +* @DeclaredRoles +* @RunAs +* @MultipartConfig +* @WebServlet +* @WebFilter +* @WebListener +* @WebInitParam +* @ServletSecurity, @HttpConstraint, @HttpMethodConstraint +* @HandlesTypes (on ServletContainerInitializers) + +[[discoverable_introspectable_annotations]] +==== Discovered vs Introspected Annotations + +Some types of annotation can be placed on any classes, not necessarily just those with which the container interacts directly. +We call these type of annotations "discovered" to indicate that the container must take proactive action to go out and find them. +The other type of annotation we call "introspected", meaning that they occur on classes with which the container interacts during their lifecycle (eg javax.servlet.Servlet, javax.servlet.Filter etc), and hence can be found by simple inspection of the class at that point. + +Some examples of discovered annotations are: + +* @WebServlet +* @WebFilter +* @WebListener + +Some examples of introspected annotations are: + +* @PostConstruct +* @PreDestroy +* @Resource + +[[jars-scanned-for-annotations]] +==== Which Jars Are Scanned For Discovered Annotations + +The web.xml file can contain the attribute `metadata-complete`. +If this is set to `true`, then _no_ scanning of discoverable annotations takes place. +However, scanning of classes may _still_ occur because of http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html[javax.servlet.ServletContainerInitializer]s. +Classes implementing this interface are found by Jetty using the http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html[javax.util.ServiceLoader] mechanism, and if one is present _and_ it includes the @HandlesTypes annotation, then Jetty must scan the class hierarchy of the web application. +This may be very time-consuming if you have many jars in the container's path or in the webapp's WEB-INF/lib. + +If scanning is to take place - because either `metadata-complete` is `false` or missing, or because there are one or more http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html[javax.servlet.ServletContainerIntializer]s with @HandlesTypes - then Jetty must consider both the container's classpath and the webapp's classpath. + +By default, Jetty will _not_ scan any classes that are on the container's classpath. +If you need to cause jars and classes that are on the container's classpath to be scanned, then you can use the link:#container-include-jar-pattern[org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern] link:#context_attributes[context attribute] to specify a pattern for jars and directories from the container's classpath to scan. + +By default, Jetty will scan __all__classes from `WEB-INF/classes`, and all jars from `WEB-INF/lib` according to the order, if any, established by absolute or relative ordering clauses in web.xml. +If your webapp contains many jars, you can significantly speed up deployment by omitting them from scanning. +To do this, use the link:#web-inf-include-jar-pattern[org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern] link:#context_attributes[context attribute] to define the patterns of jars that you specifically want to be scanned. + +Note that if you have configured an link:#using-extra-classpath-method[extraClasspath] for the webapp, then it participates in the scanning process too. +Any classes dirs are treated the same for scanning purposes as if they were in WEB-INF/classes and jars are treated as if they were in WEB-INF/lib. + +See also the next section on link:#servlet-container-initializers[ServletContainerInitializers] if you need to link:#servlet-container-initializers[control the order in which they are applied]. + +==== Multi-threaded Annotation Scanning + +Since jetty-9.1,link:#jars-scanned-for-annotations[if annotation scanning is to be performed], by default Jetty will do it in a multi-threaded manner in order to complete it in the minimum amount of time. + +If for some reason you don't want to do it multi-threaded, you can configure Jetty to revert to single-threaded scanning. +You have several ways to configure this: + +1. set the link:#context_attributes[context attribute] `org.eclipse.jetty.annotations.multiThreaded` to `false` +2. set the link:#server_attributes[Server attribute] `org.eclipse.jetty.annotations.multiThreaded` to `false` +3. set the System property `org.eclipse.jetty.annotations.multiThreaded` to `false` + +Method 1 will only affect the current webapp. +Method 2 will affect all webapps deployed to the same Server instance. +Method 3 will affect all webapps deployed in the same jvm. + +By default, Jetty will wait a maximum of 60 seconds for all of the scanning threads to complete. +You can set this to a higher or lower number of seconds by doing one of the following: + +1. set the link:#context_attributes[context attribute] `org.eclipse.jetty.annotations.maxWait` +2. set the link:#server_attributes[Server attribute] `org.eclipse.jetty.annotations.maxWait` +3. set the System property `org.eclipse.jetty.annotations.maxWait` + +Method 1 will only affect the current webapp. +Method 2 will affect all webapps deployed to the same Server instance. +Method 3 will affect all webapps deployed in the same jvm. + +[[servlet-container-initializers]] +==== ServletContainerInitializers + +http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html[javax.servlet.ServletContainerInitializers] can exist in: the container's classpath, the webapp's WEB-INF/classes directory, the webapp's WEB-INF/lib jars, or any external link:#using-extra-classpath-method[extraClasspath] that you have configured on the webapp. + +The http://jcp.org/aboutJava/communityprocess/final/jsr340/[Servlet Specification] does not define any order in which these ServletContainerInitializers must be called when the webapp starts. +Since jetty-9.1, by default Jetty will call them in the following order: + +1. ServletContainerInitializers from the container's classpath +2. ServletContainerInitializers from WEB-INF/classes +3. ServletContainerInitializers from WEB-INF/lib jars __in the order established in web.xml__, or in the order that the SCI is returned by the http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html[javax.util.ServiceLoader] if there is _no_ ordering + +As is the case with annotation scanning, the link:#using-extra-classpath-method[extraClasspath] is fully considered for ServletContainerInitializer callbacks. ServletContainerInitializers derived from a classes dir on the extraClasspath and jars from an extraClasspath for the webapp are called in step 2 and 3 respectively. + +===== Controlling the order of ServletContainerInitializer invocation + +If you need ServletContainerInitializers called in a specific order that is different from that outlined above, then you can use the link:#context_attributes[context attribute] `org.eclipse.jetty.containerInitializerOrder`. Set it to a list of comma separated class names of ServletContainerInitializers in the order that you want them applied. +You may optionally use the wildcard character "*" *once* in the list. +It will match all ServletContainerInitializers not explicitly named in the list. Here's an example, setting the context attribute in code (although you can also do the link:#intro-jetty-configuration-webapps[same in xml]): + +[source,java] +---- +WebAppContext context = new WebAppContext(); +context.setAttribute("org.eclipse.jetty.containerInitializerOrder", + "org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer, com.acme.Foo.MySCI, *"); +---- + +In this example, we ensure that the WebSocketServerContainerInitializer is the very first ServletContainerInitializer that is called, followed by MySCI and then any other ServletContainerInitializers that were discovered but not yet called. + +[[excluding-scis]] +===== Excluding ServletContainerInitializers + +By default, as according to the Servlet Specification, all ServletContainerInitializers that are discovered are invoked (see above for how to control the invocation order). +Sometimes, you may need to prevent some being called at all. + +In this case, you can define the `org.eclipse.jetty.containerInitializerExclusionPattern` link:#context_attributes[context attribute]. +This is a regular expression that defines http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html[patterns] of classnames that you want to exclude. +Here's an example, setting the context attribute in code, although you may do exactly the link:#intro-jetty-configuration-webapps[same in xml]: + +[source,java] +---- +WebAppContext context = new WebAppContext(); +context.setAttribute("org.eclipse.jetty.containerInitializerExclusionPattern", + "com.acme.*|com.corp.SlowContainerInitializer"); +---- + +In this example we exclude *all* ServletContainerInitializers in the com.acme package, and the SlowContainerInitializer. + +It is possible to use exclusion and ordering together to control ServletContainerInitializer invocation - the exclusions will be applied before the ordering. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/balancer-servlet.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/balancer-servlet.adoc new file mode 100644 index 00000000000..f4d47ebe6e8 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/balancer-servlet.adoc @@ -0,0 +1,38 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[balancer-servlet]] +=== Balancer Servlet + +[[balancer-servlet-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.proxy.BalancerServlet` +* Maven Artifact: org.eclipse.jetty:jetty-proxy +* Javadoc: {JDURL}/org/eclipse/jetty/proxy/BalancerServlet.html +* Xref: {JXURL}/org/eclipse/jetty/proxy/BalancerServlet.html + +[[balancer-servlet-usage]] +==== Usage + +The Balancer servlet allows for simple, sticky round robin load balancing leveraging the ProxyServlet that is distributed with Jetty. + +In addition to the parameters for ProxyServlet, the following are available for the balancer servlet: + +stickySessions:: + true if sessions should be sticky for subsequent requests +balancerMember..proxyTo:: + One of more of these are required and will be the locations that are used to proxy traffic to. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/cgi-servlet.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/cgi-servlet.adoc new file mode 100644 index 00000000000..0b6913d00ec --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/cgi-servlet.adoc @@ -0,0 +1,44 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[cgi-servlet]] +=== CGI Servlet + +[[cgi-servlet-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.servlets.CGI` +* Maven Artifact: org.eclipse.jetty:jetty-servlets +* Javadoc: {JDURL}/org/eclipse/jetty/servlets/CGI.html +* Xref: {JXURL}/org/eclipse/jetty/servlets/CGI.html + +[[cgi-servlet-usage]] +==== Usage + +The CGI servlet class extends the abstract HttpServlet class. +When the init parameter is called, the cgi bin directory is set with the cgibinResourceBase. +Otherwise, it defaults to the resource base of the context. +See CGI javadoc. + +The cgi bin uses three parameters: + +commandPrefix:: + The init parameter obtained when there is a prefix set to all commands directed to the method exec. +Path:: + An init parameter passed to the exec environment as a PATH. + This must be run unpacked somewhere in the filesystem. +ENV_:: + An init parameter that points to an environment variable with the name stripped of the leading ENV_ and using the init parameter value. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/chapter.adoc new file mode 100644 index 00000000000..5beffd3d0c7 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/chapter.adoc @@ -0,0 +1,44 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[advanced-extras]] +== Provided Servlets, Filters, and Handlers + +Jetty ships with a bundle of servlets that interact with the key classes. +Most are in the org.eclipse.jetty.servlets package. +These servlets and filters are among the principle elements of Jetty as a component-based infrastructure that holds and runs J2EE applications. +As described, they play a major role in running and maintaining the Jetty server. + +Also included are a number of Jetty specific handlers that allow access to internals of jetty that would not normally be exposed and are very useful testing environments and many production scenarios. + +include::default-servlet.adoc[] +include::proxy-servlet.adoc[] +include::balancer-servlet.adoc[] +include::cgi-servlet.adoc[] +include::qos-filter.adoc[] +include::dos-filter.adoc[] +include::gzip-filter.adoc[] +include::cross-origin-filter.adoc[] +include::resource-handler.adoc[] +include::debug-handler.adoc[] +include::statistics-handler.adoc[] +include::ipaccess-handler.adoc[] +include::moved-context-handler.adoc[] +include::shutdown-handler.adoc[] +include::default-handler.adoc[] +include::error-handler.adoc[] +include::rewrite-handler.adoc[] + diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc new file mode 100644 index 00000000000..72a6fdf61ba --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc @@ -0,0 +1,97 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[cross-origin-filter]] +=== Cross Origin Filter + +[[cross-origin-filter-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.servlets.CrossOriginFilter` +* Maven Artifact: org.eclipse.jetty:jetty-servlets +* Javadoc: {JDURL}/org/eclipse/jetty/servlets/CrossOriginFilter.html +* Xref: {JXURL}/org/eclipse/jetty/servlets/CrossOriginFilter.html + +[[cross-origin-filter-usage]] +==== Usage + +HTTP requests made from a script are subject to well known restrictions, the most prominent being the same domain policy. + +Firefox 3.5 introduced support for W3C's Access Control for Cross-Site Requests specification, which requires a compliant client (for example, Firefox 3.5) and a compliant server (via this servlet filter). + +This filter implements the required bits to support the server-side contract of the specification, and will allow a compliant client to perform cross-domain requests via the standard XMLHttpRequest object. +If the client does not issue a compliant cross-domain request, this filter does nothing, and its overhead is the check of the presence of the cross-domain HTTP header. + +This is extremely useful in CometD web applications where it is now possible to perform cross-domain long polling without using script injection (also known as the JSONP transport), and therefore removing all the downsides that the JSONP transport has (it's chattier, does not react quickly to failures, has a message size limit, uses GET instead of POST, etc.). + +[[cross-origin-setup]] +==== Setup + +You will need to put the jetty-servlets.jar file onto your classpath. +If you are creating a webapp, ensure that this jar is included in your webapp's WEB-INF/lib. +Or, if you are running jetty embedded you will need to ensure that jetty-servlets.jar is on the execution classpath. +You can download the jetty-servlets.jar from the Maven Central Repository at http://central.maven.org/maven2/org/eclipse/jetty/jetty-servlets/. + +[[cross-origin-config]] +==== Configuration + +This is a regular servlet filter that must be configured in web.xml. + +It supports the following configuration parameters: + +allowedOrigins:: + a comma separated list of origins that are allowed to access the resources. + Default value is: * (all origins) +allowedMethods:: + a comma separated list of HTTP methods that are allowed to be used when accessing the resources. + Default value is: GET,POST,HEAD +allowedHeaders:: + a comma separated list of HTTP headers that are allowed to be specified when accessing the resources. + Default value is: X-Requested-With,Content-Type,Accept,Origin +allowCredentials:: + a boolean indicating if the resource allows requests with credentials. + Default value is: true +preflightMaxAge:: + the number of seconds that preflight requests can be cached by the client. + Default value is 1800 seconds (30 minutes) +chainPreflight:: + if true preflight requests are chained to their target resource for normal handling (as an OPTION request). + Otherwise the filter will response to the preflight. + Default is true. +exposedHeaders:: + a comma separated list of HTTP headers that are allowed to be exposed on the client. + Default value is the empty list. + +A typical configuration could be: + +[source,xml] +---- + + + + + cross-origin + org.eclipse.jetty.servlets.CrossOriginFilter + + + cross-origin + /cometd/* + + + + + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/debug-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/debug-handler.adoc new file mode 100644 index 00000000000..86469ab0e63 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/debug-handler.adoc @@ -0,0 +1,70 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[debug-handler]] +=== Debug Handler + +[[debug-handler-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.DebugHandler` +* Maven Artifact: org.eclipse.jetty:jetty-server +* Javadoc: {JDURL}/org/eclipse/jetty/server/handler/DebugHandler.html +* Xref: {JXURL}/org/eclipse/jetty/server/handler/DebugHandler.html + +[[debug-handler-usage]] +==== Usage + +A simple handler that is useful to debug incoming traffic. +It will log entry and exit points of http requests as well as the response code. + +==== Usage in standard distribution + +Simply include jetty-debug.xml in your *.ini configs. +For example in start.ini. + +==== Embedded usage + +[source,java] +---- +Server server = new Server(8080); +RolloverFileOutputStream outputStream = new RolloverFileOutputStream("MeinLogPfad/yyyy_mm_dd.request.log", true,10); + +DebugHandler debugHandler = new DebugHandler(); +debugHandler.setOutputStream(outputStream); +debugHandler.setHandler(server.getHandler()); + +server.setHandler(debugHandler); +server.start(); + +---- + +==== Some example output + +[source,bash] +---- +15:14:05.838:qtp551889550-13-selector-0 OPENED HttpConnection@e910ee4{IDLE},g=HttpGenerator{s=START},p=HttpParser{s=START,0 of 0} +15:14:05.846:qtp551889550-57:http://0:0:0:0:0:0:0:1:8080/ REQUEST 0:0:0:0:0:0:0:1 GET __utma=111872281.10102721.1321534299.1369833564.1370447492.35; __utmz=111872281.1321534299.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _opt_vi_RPY720HZ=75E12E63-0CD0-4D6F-8383-C90D5C8397C7; Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0 +15:14:05.894:qtp551889550-57:http://0:0:0:0:0:0:0:1:8080/ RESPONSE 200 null +15:14:05.959:qtp551889550-59:http://0:0:0:0:0:0:0:1:8080/jetty.css REQUEST 0:0:0:0:0:0:0:1 GET __utma=111872281.10102721.1321534299.1369833564.1370447492.35; __utmz=111872281.1321534299.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _opt_vi_RPY720HZ=75E12E63-0CD0-4D6F-8383-C90D5C8397C7; visited=yes; Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0 +15:14:05.962:qtp551889550-59:http://0:0:0:0:0:0:0:1:8080/jetty.css RESPONSE 200 null +15:14:06.052:qtp551889550-57:http://0:0:0:0:0:0:0:1:8080/images/jetty-header.jpg REQUEST 0:0:0:0:0:0:0:1 GET __utma=111872281.10102721.1321534299.1369833564.1370447492.35; __utmz=111872281.1321534299.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _opt_vi_RPY720HZ=75E12E63-0CD0-4D6F-8383-C90D5C8397C7; visited=yes; Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0 +15:14:06.055:qtp551889550-57:http://0:0:0:0:0:0:0:1:8080/images/jetty-header.jpg RESPONSE 200 null +15:14:07.248:qtp551889550-59:http://0:0:0:0:0:0:0:1:8080/favicon.ico REQUEST 0:0:0:0:0:0:0:1 GET __utma=111872281.10102721.1321534299.1369833564.1370447492.35; __utmz=111872281.1321534299.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _opt_vi_RPY720HZ=75E12E63-0CD0-4D6F-8383-C90D5C8397C7; visited=yes; Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0 +15:14:07.251:qtp551889550-59:http://0:0:0:0:0:0:0:1:8080/favicon.ico RESPONSE 404 text/html;charset=ISO-8859-1 +15:14:09.330:qtp551889550-57 CLOSED HttpConnection@e910ee4{INTERESTED},g=HttpGenerator{s=START},p=HttpParser{s=START,0 of -1} + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/default-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/default-handler.adoc new file mode 100644 index 00000000000..d1087892800 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/default-handler.adoc @@ -0,0 +1,54 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[default-handler]] +=== Default Handler + +[[default-handler-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.DefaultHandler` +* Maven Artifact: org.eclipse.jetty:jetty-server +* Javadoc: {JDURL}/org/eclipse/jetty/server/handler/DefaultHandler.html +* Xref: {JXURL}/org/eclipse/jetty/server/handler/DefaultHandler.html + +[[default-handler-usage]] +==== Usage + +A simple handler that is useful to terminate handler chains with a clean fashion. +As in the example below, if a resource to be served is not matched within the resource handler, the DefaultHandler will take care of producing a 404 page. +This class is a useful template to either extend and embrace or simply provide a similar implementation for customizing to your needs. +There is also an link:#error-handler[Error Handler] that services errors related to the servlet api specification so it is best to not get the two confused. + +_____ +[NOTE] +The DefaultHandler will also handle serving out the flav.ico file should a request make it through all of the other handlers without being resolved. +_____ + +[source,java] +---- + + Server server = new Server(8080); + HandlerList handlers = new HandlerList(); + ResourceHandler resourceHandler = new ResourceHandler(); + resourceHandler.setBaseResource(Resource.newResource(".")); + handlers.setHandlers(new Handler[] + { resourceHandler, new DefaultHandler() }); + server.setHandler(handlers); + server.start(); + + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/default-servlet.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/default-servlet.adoc new file mode 100644 index 00000000000..bcb8b3cf543 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/default-servlet.adoc @@ -0,0 +1,66 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[default-servlet]] +=== Default Servlet + +[[default-servlet-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.servlet.DefaultServlet` +* Maven Artifact: org.eclipse.jetty:jetty-servlet +* Javadoc: {JDURL}/org/eclipse/jetty/servlet/DefaultServlet.html +* Xref: {JXURL}/org/eclipse/jetty/servlet/DefaultServlet.html + +[[default-servlet-usage]] +==== Usage + +The DefaultServlet implements the ResourceFactory interface and extends the HttpServlet abstract class. +It is usually mapped to / and provides handling for static content, OPTION and TRACE methods for the context. +The MOVE method is allowed if PUT and DELETE are allowed. +See DefaultServlet link:{JDURL}/org/eclipse/jetty/servlet/DefaultServlet.html[javadoc]. + +[[default-servlet-init]] +==== Init Parameters + +Jetty supports the following initParameters: + +acceptRanges:: + If true, range requests and responses are supported. +dirAllowed:: + If true, directory listings are returned if no welcome file is found. + Otherwise 403 Forbidden displays. +redirectWelcome:: + If true, welcome files are redirected rather that forwarded. +gzip:: + If set to true, then static content is served as gzip content encoded if a matching resource is found ending with ".gz". +resourceBase:: + Set to replace the context resource base. +aliases:: + If true, aliases of resources are allowed (that is, symbolic links and caps variations) and may bypass security constraints. +maxCacheSize:: + Maximum total size of the cache or 0 for no cache. +maxCachedFileSize:: + Maximum size of a file to cache. +maxCachedFiles:: + Maximum number of files to cache. +useFileMappedBuffer:: + If set to true, mapped file buffer serves static content. + Setting this value to false means that a direct buffer is used instead of a mapped file buffer. + By default, this is set to true. +otherGzipFileExtensions:: + A comma separated list of other file extensions that signify that a file is gzip compressed. + If you don't explicitly set this, it defaults to ".svgz". diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/dos-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/dos-filter.adoc new file mode 100644 index 00000000000..1f2ca7029be --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/dos-filter.adoc @@ -0,0 +1,117 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[dos-filter]] +=== Denial of Service Filter + +[[dos-filter-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.servlets.DoSFilter` +* Maven Artifact: org.eclipse.jetty:jetty-servlets +* Javadoc: {JDURL}/org/eclipse/jetty/servlets/DoSFilter.html +* Xref: {JXURL}/org/eclipse/jetty/servlets/DoSFilter.html + +[[dos-filter-usage]] +==== Usage + +The Denial of Service (DoS) filter limits exposure to request flooding, whether malicious, or as a result of a misconfigured client. +The DoS filter keeps track of the number of requests from a connection per second. +If the requests exceed the limit, Jetty rejects, delays, or throttles the request, and sends a warning message. +The filter works on the assumption that the attacker might be written in simple blocking style, so by suspending requests you are hopefully consuming the attacker's resources. +The DoS filter is related to the QoS filter, using Continuations to prioritize requests and avoid thread starvation. + +[[dos-filter-using]] +==== Using the DoS Filter + +Jetty places throttled requests in a priority queue, giving priority first to authenticated users and users with an HttpSession, then to connections identified by their IP addresses. +Connections with no way to identify them have lowest priority. +To uniquely identify authenticated users, you should implement the The extractUserId(ServletRequest request) function. + +===== Required JARs + +To use the DoS Filter, these JAR files must be available in WEB-INF/lib: + +* $JETTY_HOME/lib/ext/jetty-util.jar +* $JETTY_HOME/lib/ext/jetty-servlets.jar + +===== Sample Configuration + +Place the configuration in a webapp's web.xml or jetty-web.xml. +The default configuration allows 25 requests per connection at a time, servicing more important requests first, and queuing up the rest. +This example allow 30 requests at a time: + +[source,xml] +---- + + + DoSFilter + org.eclipse.jetty.servlets.DoSFilter + + maxRequestsPerSec + 30 + + + + +---- + +[[dos-filter-init]] +===== Configuring DoS Filter Parameters + +The following init parameters control the behavior of the filter: + +maxRequestsPerSec:: + Maximum number of requests from a connection per second. + Requests in excess of this are first delayed, then throttled. + Default is 25. + +delayMs:: + Delay imposed on all requests over the rate limit, before they are considered at all: ++ +* 100 (ms) = Default +* -1 = Reject request +* 0 = No delay +* any other value = Delay in ms + +maxWaitMs:: + Length of time, in ms, to blocking wait for the throttle semaphore. + Default is 50 ms. +throttledRequests:: + Number of requests over the rate limit able to be considered at once. + Default is 5. +throttleMs:: + Length of time, in ms, to async wait for semaphore. Default is 30000L. +maxRequestMs:: + Length of time, in ms, to allow the request to run. Default is 30000L. +maxIdleTrackerMs:: + Length of time, in ms, to keep track of request rates for a connection, before deciding that the user has gone away, and + discarding it. + Default is 30000L. +insertHeaders:: + If true, insert the DoSFilter headers into the response. + Defaults to true. +trackSessions:: + If true, usage rate is tracked by session if a session exists. + Defaults to true. +remotePort:: + If true and session tracking is not used, then rate is tracked by IP+port (effectively connection). + Defaults to false. +ipWhitelist:: + A comma-separated list of IP addresses that will not be rate limited. +managedAttr:: + If set to true, then this servlet is set as a ServletContext attribute with the filter name as the attribute name. + This allows a context external mechanism (for example, JMX via ContextHandler.MANAGED_ATTRIBUTES) to manage the configuration of the filter. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/error-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/error-handler.adoc new file mode 100644 index 00000000000..474f4a35407 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/error-handler.adoc @@ -0,0 +1,33 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[error-handler]] +=== Error Handler + +[[error-handler-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.ErrorHandler` +* Maven Artifact: org.eclipse.jetty:jetty-server +* Javadoc: {JDURL}/org/eclipse/jetty/server/handler/ErrorHandler.html +* Xref: {JXURL}/org/eclipse/jetty/server/handler/ErrorHandler.html + +[[error-handler-usage]] +==== Usage + +A handler that is used to report errors from servlet contexts and webapp contexts to report error conditions. +Primarily handles setting the various servlet spec specific response headers for error conditions. +Can be customized by extending, for more information on this see xref:custom-error-pages[]. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/gzip-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/gzip-filter.adoc new file mode 100644 index 00000000000..6a28a075d3d --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/gzip-filter.adoc @@ -0,0 +1,85 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[gzip-filter]] +=== Gzip Handler + +[[gzip-filter-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.gzip.GzipHandler` +* Maven Artifact: org.eclipse.jetty:jetty-servlets +* Javadoc: +{JDURL}/org/eclipse/jetty/server/handler/gzip/GzipHandler.html +* Xref: {JXURL}/org/eclipse/jetty/server/handler/gzip/GzipHandler.html + +[[gzip-filter-usage]] +==== Usage + +The Jetty GzipHandler is a compression handler that you can apply to any dynamic resource (servlet). +It fixes many of the bugs in commonly available compression filters: it works with asynchronous servlets; it handles all ways to set content length. +We have tested it with Jetty continuations and suspending requests. +Some user-agents might be excluded from compression to avoid common browser bugs (yes, this means IE!). + +The GzipHandler is added to the entire server by the etc/jetty-gzip.xml file from the gzip.mod module. +It may also be added to individual contexts in a context xml file. + +[[gzip-filter-rules]] +==== Gzip Rules + +GZIP Handler will gzip or deflate the content of a response if: + +* It is mapped to a matching path +* The request method is configured to support gzip +* The request is not from an excluded User-Agent +* accept-encoding header is set to either gzip, deflate or a combination of those +* The response status code is >=200 and <300 +* The content length is unknown or more than the minGzipSize initParameter or the minGzipSize is 0(default) +* The content-type does not match an excluded mime-type +* No content-encoding is specified by the resource + +If both gzip and deflate are specified in the accept-encoding header, then gzip will be used. + +Compressing the content can greatly improve the network bandwidth usage, but at a cost of memory and CPU cycles. +The link:#default-servlet[DefaultServlet] is capable of serving pre-compressed static content, which saves memory and CPU. +By default, the GzipHandler will check to see if pre-compressed content exists, and pass the request through to be handled by the DefaultServlet. + +[[gzip-filter-init]] +==== Gzip Configuration + +minGzipSize:: + Content will only be compressed if content length is either unknown or greater than minGzipSize. +checkGzExists:: + True by default. If set to false, the handler will not check for pre-compressed content. +compressionLevel:: + The compression level used for deflate compression. (0-9). +includedMethods:: + List of HTTP methods to compress. If not set, only GET requests are compressed. +includedMimeTypes:: + List of mime types to compress. +excludedMimeTypes:: + List of mime types not to compress. +excludedAgentPatterns:: + A list of regex patterns for User-Agent names from which requests should not be compressed. +excludedPaths:: + List of paths to exclude from compression. + Does a String.startsWith(String) comparison to check if the path matches. + If it does match -> no compression. + To match subpaths use excludePathPatterns instead. +includedPaths:: + List of paths to consider for compression. +includePaths:: + List of paths to definitely consider for compression. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/ipaccess-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/ipaccess-handler.adoc new file mode 100644 index 00000000000..9c23294d427 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/ipaccess-handler.adoc @@ -0,0 +1,73 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[ipaccess-handler]] +=== IP Access Handler + +[[ipaccess-handler-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.IPAccessHandler` +* Maven Artifact: org.eclipse.jetty:jetty-server +* Javadoc: {JDURL}/org/eclipse/jetty/server/handler/IPAccessHandler.html +* Xref: {JXURL}/org/eclipse/jetty/server/handler/IPAccessHandler.html + +[[ipaccess-handler-usage]] +==== Usage + +Controls access to the wrapped handler by the real remote IP. +Control is provided by white/black lists that include both internet addresses and URIs. +This handler uses the real internet address of the connection, not one reported in the forwarded for headers, as this cannot be as easily forged. + +Typically, the black/white lists will be used in one of three modes: + +* Blocking a few specific IPs/URLs by specifying several black list entries. +* Allowing only some specific IPs/URLs by specifying several white lists entries. +* Allowing a general range of IPs/URLs by specifying several general white list entries, that are then further refined by several specific black list exceptions. + +An empty white list is treated as match all. +If there is at least one entry in the white list, then a request must match a white list entry. +Black list entries are always applied, so that even if an entry matches the white list, a black list entry will override it. + +Internet addresses may be specified as absolute address or as a combination of four octet wildcard specifications (a.b.c.d) that are defined as follows. + +* nnn - an absolute value (0-255) +* mmm-nnn - an inclusive range of absolute values, with following shorthand notations: +** nnn- => nnn-255 +** -nnn => 0-nnn +** - => 0-255 +* a,b,... - a list of wildcard specifications + +Internet address specification is separated from the URI pattern using the "|" (pipe) character. +URI patterns follow the servlet specification for simple * prefix and suffix wild cards (e.g. /, /foo, /foo/bar, /foo/bar/*, *.baz). + +Earlier versions of the handler used internet address prefix wildcard specification to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.). +They also used the first "/" character of the URI pattern to separate it from the internet address. +Both of these features have been deprecated in the current version. + +Examples of the entry specifications are: + +* 10.10.1.2 - all requests from IP 10.10.1.2 +* 10.10.1.2|/foo/bar - all requests from IP 10.10.1.2 to URI /foo/bar +* 10.10.1.2|/foo/* - all requests from IP 10.10.1.2 to URIs starting with /foo/ +* 10.10.1.2|*.html - all requests from IP 10.10.1.2 to URIs ending with .html +* 10.10.0-255.0-255 - all requests from IPs within 10.10.0.0/16 subnet +* 10.10.0-.-255|/foo/bar - all requests from IPs within 10.10.0.0/16 subnet to URI /foo/bar +* 10.10.0-3,1,3,7,15|/foo/* - all requests from IPs addresses with last octet equal to 1,3,7,15 in subnet 10.10.0.0/22 to URIs starting with /foo/ + +Earlier versions of the handler used internet address prefix wildcard specification to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.). +They also used the first "/" character of the URI pattern to separate it from the internet address. +Both of these features have been deprecated in the current version. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/moved-context-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/moved-context-handler.adoc new file mode 100644 index 00000000000..3e40d61ad5a --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/moved-context-handler.adoc @@ -0,0 +1,74 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[moved-context-handler]] +=== Moved Context Handler + +[[moved-context-handler-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.MovedContextHandler` +* Maven Artifact: org.eclipse.jetty:jetty-server +* Javadoc: +{JDURL}/org/eclipse/jetty/server/handler/MovedContextHandler.html +* Xref: +{JXURL}/org/eclipse/jetty/server/handler/MovedContextHandler.html + +[[moved-context-handler-usage]] +==== Usage + +You can use the MovedContextHandler to relocate or redirect a context that has changed context path and/or virtual hosts. + +You can configure it to _permanently_ redirect the old URL to the new URL, in which case Jetty sends a Http Status code of 301 to the browser with the new URL. +Alternatively, you can make it non-permanent, in which case Jetty sends a 302 Http Status code along with the new URL. + +In addition, as with any other context, you can configure a list of virtual hosts, meaning that this context responds only to requests to one of the listed host names. + +Suppose you have a context deployed at /foo, but that now you want to deploy at the root context / instead. + +* First you reconfigure and redeploy the context on Jetty. +* Next you need a way to redirect all the browsers who have bookmarked /foo to the new path. +You create a new context xml file in $JETTY_HOME/contexts and configure the MovedContextHandler to do the redirection from /foo to /. + +Here's an example. +This is a permanent redirection, which also preserves pathinfo and query strings on the redirect: + +[source,xml] +---- + + + + + + /foo + / + true + false + false + + + + 209.235.245.73 + 127.0.0.73 + acme.org + www.acme.org + server.acme.org + + + + + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/proxy-servlet.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/proxy-servlet.adoc new file mode 100644 index 00000000000..3b3881ac3c4 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/proxy-servlet.adoc @@ -0,0 +1,81 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[proxy-servlet]] +=== Proxy Servlet + +[[proxy-servlet-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.proxy.ProxyServlet` +* Maven Artifact: org.eclipse.jetty:jetty-proxy +* Javadoc: {JDURL}/org/eclipse/jetty/proxy/ProxyServlet.html +* Xref: {JXURL}/org/eclipse/jetty/proxy/ProxyServlet.html + +[[proxy-servlet-usage]] +==== Usage + +An asynchronous servlet that forwards requests to another server either as a standard web reverse proxy (as defined by RFC2616) or as a transparent reverse proxy. Internally it uses the async jetty-client. + +To facilitate JMX monitoring, the HttpClient instance is set as context attribute, prefixed with the servlet's name and exposed by the mechanism provided by ContextHandler.MANAGED_ATTRIBUTES. + +[[proxy-servlet-init]] +==== Init Parameters + +The following init parameters may be used to configure the servlet: + +hostHeader:: + forces the host header to a particular value +viaHost:: + the name to use in the Via header: Via: http/1.1 +whiteList:: + comma-separated list of allowed proxy hosts +blackList:: + comma-separated list of forbidden proxy hosts + + +In addition, there are a number of init parameters that can be used to configure the HttpClient instance used internally for the proxy. + +maxThreads:: + Default Value: 256 ++ +The max number of threads of HttpClient's Executor + +maxConnections:: + Default Value: 32768 ++ +The max number of connections per destination. +RFC 2616 suggests that 2 connections should be opened per each destination, but browsers commonly open 6 or more. If this HttpClient is used for load testing, it is common to have only one destination (the server to load test), and it is recommended to set this value to a high value (at least as much as the threads present in the executor). + +idleTimeout:: + Default Value: 30000 ++ +The idle timeout in milliseconds that a connection can be idle, that is without traffic of bytes in either direction. + +timeout:: + Default Value: 60000 ++ +The total timeout in milliseconds for the request/response conversation. + +requestBufferSize:: + Default Value: 4096 ++ +The size of the request buffer the request is written into. + +responseBufferSize:: + Default Value: 4096 ++ +The size of the response buffer the response is written into. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/qos-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/qos-filter.adoc new file mode 100644 index 00000000000..35da1e96c2f --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/qos-filter.adoc @@ -0,0 +1,171 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[qos-filter]] +=== Quality of Service Filter + +[[qos-filter-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.servlets.QoSFilter` +* Maven Artifact: org.eclipse.jetty:jetty-servlets +* Javadoc: {JDURL}/org/eclipse/jetty/servlets/QoSFilter.html +* Xref: {JXURL}/org/eclipse/jetty/servlets/QoSFilter.html + +[[qos-filter-usage]] +==== Usage + +Jetty supports Continuations, which allow non-blocking handling of HTTP requests, so that threads can be allocated in a managed way to provide application specific Quality of Service (QoS). +The QoSFilter is a utility servlet filter that implements some QoS features. + +[[qos-understanding]] +==== Understanding the Problem + +===== Waiting for Resources + +Web applications frequently use JDBC Connection pools to limit the simultaneous load on the database. +This protects the database from peak loads, but makes the web application vulnerable to thread starvation. +Consider a thread pool with 20 connections, being used by a web application that that typically receives 200 requests per second and each request holds a JDBC connection for 50ms. +Such a pool can service on average 200*20*1000/50 = 400 requests per second. + +However, if the request rate rises above 400 per second, or if the database slows down (due to a large query) or becomes momentarily unavailable, the thread pool can very quickly accumulate many waiting requests. +If, for example, the website is slashdotted or experiences some other temporary burst of traffic and the request rate rises from 400 to 500 requests per second, then 100 requests per second join those waiting for a JDBC connection. +Typically, a web server's thread pool contains only a few hundred threads, so a burst or slow DB need only persist for a few seconds to consume the entire web server's thread pool. +This is called thread starvation. +The key issue with thread starvation is that it effects the entire web application, and potentially the entire web server. +Even if the requests using the database are only a small proportion of the total requests on the web server, all requests are blocked because all the available threads are waiting on the JDBC connection pool. +This represents non graceful degradation under load and provides a very poor quality of service. + +===== Prioritizing Resources + +Consider a web application that is under extreme load. +This load might be due to a popularity spike (slashdot), usage burst (Christmas or close of business), or even a denial of service attack. +During such periods of load, it is often desirable not to treat all requests as equals, and to give priority to high value customers or administrative users. + +The typical behaviour of a web server under extreme load is to use all its threads to service requests and to build up a backlog of unserviced requests. +If the backlog grows deep enough, then requests start to timeout and users experience failures as well as delays. + +Ideally, the web application should be able to examine the requests in the backlog, and give priority to high value customers and administrative users. +But with the standard blocking servlet API, it is not possible to examine a request without allocating a thread to that request for the duration of its handling. +There is no way to delay the handling of low priority requests, so if the resources are to be reallocated, then the low priority requests must all be failed. + +[[qos-applying]] +==== Applying the QoSFilter + +The Quality of Service Filter (QoSFilter) uses Continuations to avoid thread starvation, prioritize requests and give graceful degradation under load, to provide a high quality of service. +When you apply the filter to specific URLs within a web application, it limits the number of active requests being handled for those URLs. +Any requests in excess of the limit are suspended. When a request completes handling the limited URL, one of the waiting requests resumes and can be handled. +You can assign priorities to each suspended request, so that high priority requests resume before lower priority requests. + +===== Required JARs + +To use the QoS Filter, these JAR files must be available in WEB-INF/lib: + +* $JETTY_HOME/lib/ext/jetty-util.jar +* $JETTY_HOME/lib/ext/jetty-servlets.jar–contains QoSFilter + +===== Sample Configuration + +Place the configuration in a webapp's web.xml or jetty-web.xml. +The default configuration processes ten requests at a time, servicing more important requests first, and queuing up the rest. +This example processes fifty requests at a time: + +[source,xml] +---- + + + QoSFilter + org.eclipse.jetty.servlets.QoSFilter + + maxRequests + 50 + + + + +---- + +[[qos-filter-init]] +===== Configuring QoS Filter Parameters + +A semaphore polices the "maxRequests" limit. +The filter waits a short time while attempting to acquire the semaphore. +The "waitMs" init parameter controls the wait, avoiding the expense of a suspend if the semaphore is shortly available. +If the semaphore cannot be obtained, Jetty suspends the request for the default suspend period of the container or the value set as the "suspendMs" init parameter. + +The QoS filter uses the following init parameters: + +maxRequests:: + the maximum number of requests to be serviced at a time. The default is 10. +maxPriority:: + the maximum valid priority that can be assigned to a request. + A request with a high priority value is more important than a request with a low priority value. The default is 10. +waitMS:: + waitMS–length of time, in milliseconds, to wait while trying to accept a new request. + Used when the maxRequests limit is reached. + Default is 50 ms. +suspendMS:: + length of time, in milliseconds, that the request will be suspended if it is not accepted immediately. + If not set, the container's default suspend period applies. Default is -1 ms. +managedAttr:: + If set to true, then this servlet is set as a ServletContext attribute with the filter name as the attribute name. + This allows a context external mechanism (for example, JMX via ContextHandler.MANAGED_ATTRIBUTES) to manage the configuration of the filter. + +===== Mapping to URLs + +You can use the `` syntax to map the QoSFilter to a servlet, either by using the servlet name, or by using a URL pattern. +In this example, a URL pattern applies the QoSFilter to every request within the web application context: + +[source,xml] +---- + + + QoSFilter + /* + + + +---- + +===== Setting the Request Priority + +Requests with higher values have a higher priority. +The default request priorities assigned by the QoSFilter are: + +* 2 -- For any authenticated request +* 1 -- For any request with a non-new valid session +* 0 -- For all other requests + +To customize the priority, subclass QoSFilter and then override the getPriority(ServletRequest request) method to return an appropriate priority for the request. +You can then use this subclass as your QoS filter. +Here's a trivial example: + +[source,java] +---- + +public class ParsePriorityQoSFilter extends QoSFilter + { + protected int getPriority(ServletRequest request) + { + String p = ((HttpServletRequest)request).getParameter("priority"); + if (p!=null) + return Integer.parseInt(p); + return 0; + } + } + + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/resource-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/resource-handler.adoc new file mode 100644 index 00000000000..149221b4d00 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/resource-handler.adoc @@ -0,0 +1,56 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[resource-handler]] +=== Resource Handler + +[[resource-handler-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.ResourceHandler` +* Maven Artifact: org.eclipse.jetty:jetty-server +* Javadoc: {JDURL}/org/eclipse/jetty/server/handler/ResourceHandler.html +* Xref: {JXURL}/org/eclipse/jetty/server/handler/ResourceHandler.html + +[[resource-handler-usage]] +==== Usage + +This handler will serve static content and handle If-Modified-Since headers and is suitable for simple serving of static content. + +____ +[IMPORTANT] +There is no caching done with this handler so if you are looking for a more featureful way of serving static content look to the xred:default-servlet[]. +____ + +____ +[NOTE] +Requests for resources that do not exist are let pass (Eg no 404's). +____ + +==== Improving the Look and Feel + +The resource handler has a default stylesheet which you can change by calling `setStyleSheet(String location)` with the location of a file on the system that it can locate through the resource loading system. +The default css is called jetty-dir.css and is located in the jetty-util package, pulled as a classpath resource from the jetty-util jar when requested through the ResourceHandler. + +==== Embedded Example + +The following is an example of a split fileserver, able to serve static content from multiple directory locations. +Since this handler does not return 404's on content you are able to iteratively try multiple resource handlers to resolve content. + +[source,java] +---- +include::{SRCDIR}/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SplitFileServer.java[] +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/rewrite-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/rewrite-handler.adoc new file mode 100644 index 00000000000..dd94db93b07 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/rewrite-handler.adoc @@ -0,0 +1,146 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[rewrite-handler]] +=== Rewrite Handler + +The RewriteHandler matches a request against a set of rules, and modifies the request accordingly for any rules that match. The most common use is to rewrite request URIs, but it is capable of much more: rules can also be configured to redirect the response, set a cookie or response code on the response, modify the header, etc. + +[[rewrite-handler-metadata]] +==== Info + +* Classname: org.eclipse.jetty.rewrite.handler.RewriteHandler +* Maven artifact: org.eclipse.jetty:jetty-rewrite +* Javadoc: {JDURL}/org/eclipse/jetty/rewrite/handler/RewriteHandler.html +* Xref: {JXURL}/org/eclipse/jetty/rewrite/handler/RewriteHandler.html + +The standard Jetty distribution bundle contains the `jetty-rewrite` link:#startup-modules[module], so all you need to do is to enable it using one of the link:#start-jar[module commands], eg: + +.... + +$ java -jar start.jar --add-to-startd=rewrite + +.... + +_____ +[NOTE] +If you are running the standard Jetty distribution with the sample test webapp, there will be a demo of the rewrite module at http://localhost:8080/test/rewrite/ +_____ + +==== Usage + +The rewrite module enables the following jetty xml config file on the execution path: + +[source,xml] +---- +include::{SRCDIR}/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml[] +---- + +As the commented out code shows, you configure the RewriteHandler by adding various rules. + +There is an example of link:#rewrite-rules[rules] configuration in the standard distribution in the `demo-base/etc/demo-rewrite-rules.xml` file: + +[source,xml] +---- +include::{SRCDIR}/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/demo-rewrite-rules.xml[] +---- + +===== Embedded Example + +This is an example for embedded Jetty, which does something similar to the configuration file example above: + +[source,java] +---- + + Server server = new Server(); + + RewriteHandler rewrite = new RewriteHandler(); + rewrite.setRewriteRequestURI(true); + rewrite.setRewritePathInfo(false); + rewrite.originalPathAttribute("requestedPath"); + + RedirectPatternRule redirect = new RedirectPatternRule(); + redirect.setPattern("/redirect/*"); + redirect.setReplacement("/redirected"); + rewrite.addRule(redirect); + + RewritePatternRule oldToNew = new RewritePatternRule(); + oldToNew.setPattern("/some/old/context"); + oldToNew.setReplacement("/some/new/context"); + rewrite.addRule(oldToNew); + + RewriteRegexRule reverse = new RewriteRegexRule(); + reverse.setRegex("/reverse/([^/]*)/(.*)"); + reverse.setReplacement("/reverse/$2/$1"); + rewrite.addRule(reverse); + + server.setHandler(rewrite); + + +---- + +[[rewrite-rules]] +==== Rules + +There are several types of rules that are written extending useful base rule classes. + +===== PatternRule + +Matches against the request URI using the servlet pattern syntax. + +link:{JXURL}/org/eclipse/jetty/rewrite/handler/CookiePatternRule.html[CookiePatternRule]:: + Adds a cookie to the response. +link:{JXURL}/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.html[HeaderPatternRule]:: + Adds/modifies a header in the response. +link:{JXURL}/org/eclipse/jetty/rewrite/handler/RedirectPatternRule.html[RedirectPatternRule]:: + Redirects the response. +link:{JXURL}/org/eclipse/jetty/rewrite/handler/ResponsePatternRule.html[ResponsePatternRule]:: + Sends the response code (status or error). +link:{JXURL}/org/eclipse/jetty/rewrite/handler/RewritePatternRule.html[RewritePatternRule]:: + Rewrite the URI by replacing the matched request path with a fixed string. + +===== RegexRule + +Matches against the request URI using regular expressions. + +link:{JXURL}/org/eclipse/jetty/rewrite/handler/RedirectRegexRule.html[RedirectRegexRule]:: + Redirect the response. +link:{JXURL}/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.html[RewriteRegexRule]:: + Rewrite the URI by matching with a regular expression. + (The replacement string may use Template:$n to replace the nth capture group.) + +===== HeaderRule + +Match against request headers. Match either on a header name + specific value, or on the presence of a header (with any value). + +link:{JXURL}/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRule.html[ForwardedSchemaHeaderRule]:: + Set the scheme on the request (defaulting to https). + +===== Others + +Oddball rules that defy classification. + +link:{JXURL}/org/eclipse/jetty/rewrite/handler/MsieSslRule.html[MsieSslRule]:: + Disables the keep alive for SSL from IE5 or IE6. +link:{JXURL}/org/eclipse/jetty/rewrite/handler/LegacyRule.html[LegacyRule]:: + Implements the legacy API of RewriteHandler + +===== RuleContainer + +Groups rules together. The contained rules will only be processed if the conditions for the RuleContainer evaluate to true. + +link:{JXURL}/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainer.html[VirtualHostRuleContainer]:: + Groups rules that apply only to a specific virtual host or a set of virtual hosts diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/shutdown-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/shutdown-handler.adoc new file mode 100644 index 00000000000..ed3dc44d7d8 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/shutdown-handler.adoc @@ -0,0 +1,71 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[shutdown-handler]] +=== Shutdown Handler + +[[shutdown-handler-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.ShutdownHandler` +* Maven Artifact: org.eclipse.jetty:jetty-server +* Javadoc: {JDURL}/org/eclipse/jetty/server/handler/ShutdownHandler.html +* Xref: {JXURL}/org/eclipse/jetty/server/handler/ShutdownHandler.html + +[[shutdown-handler-usage]] +==== Usage + +A handler that shuts the server down on a valid request. +Used to do "soft" restarts from Java. +If _exitJvm is set to true a hard System.exit() call is being made. + +This is an example of how you can setup this handler directly with the Server, it can be added as a part of handler chain or collection as well. + +[source,java] +---- + + Server server = new Server(8080); + HandlerList handlers = new HandlerList(); + handlers.setHandlers(new Handler[] + { someOtherHandler, new ShutdownHandler(server,"secret password") }); + server.setHandler(handlers); + server.start(); + + +---- + +And this is an example that you can use to call the shutdown handler from within java. + +[source,java] +---- + + public static void attemptShutdown(int port, String shutdownCookie) { + try { + URL url = new URL("http://localhost:" + port + "/shutdown?token=" + shutdownCookie); + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + connection.setRequestMethod("POST"); + connection.getResponseCode(); + logger.info("Shutting down " + url + ": " + connection.getResponseMessage()); + } catch (SocketException e) { + logger.debug("Not running"); + // Okay - the server is not running + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc new file mode 100644 index 00000000000..4e549adb978 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc @@ -0,0 +1,125 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[statistics-handler]] +=== Statistics Handler + +[[statistics-handler-metadata]] +==== Info + +* Classname: `org.eclipse.jetty.server.handler.StatisticsHandler` +* Maven Artifact: org.eclipse.jetty:jetty-server +* Javadoc: +{JDURL}/org/eclipse/jetty/server/handler/StatisticsHandler.html +* Xref: {JXURL}/org/eclipse/jetty/server/handler/StatisticsHandler.html + +[[statistics-handler-usage]] +==== Usage + +Jetty currently has two levels of request statistic collection: + +* Subclasses of AbstractConnector class optionally can collect statistics about connections as well as number of requests. +* The StatisticsHandler class may be used to collect request statistics. + +In addition to that, subclasses of AbstractSessionHandler class optionally can collect session statistics. + +AbstractConnector and AbstractSessionHandler statistics are turned off by default and must either be configured manually for each instance or +turned on via JMX interface. +The Statistics Handler is not included in default Jetty configuration, and needs to be configured manually. + +_____ +[NOTE] +To view statistics, you have to be able to connect to Jetty using either JConsole or some other JMX agent. See xref:using-jmx[] for more information. +_____ + +[[connector-statistics]] +==== Connector statistics + +Detailed statistics on connection duration and number of requests are only collated when a connection is closed. +The current and maximum number of connections are the only "live" statistics. +To learn how to turn on connector statistics please see Jetty Statistics tutorial, although this is not recommended and it is best to use a JMX agent to select statistics only when needed. + +The following example shows how to turn on connector statistics in jetty xml. +This example comes from within `jetty-http.xml`. + +[source,xml] +---- + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + +---- + +[[request-statistics]] +==== Request Statistics + +To collect request statistics a StatisticsHandler must be configured as one of the handlers of the server. +Typically this can be done as the top level handler, but you may choose to configure a statistics handler for just one context by creating a context configuration file. +Please note that `jetty-stats.xml` has to appear in the command line after the main Jetty configuration file as shown below. +It should be able to be uncommented in the start.ini file. + +.... +$ java -jar start.jar OPTIONS=default etc/jetty.xml etc/jetty-stats.xml + +.... + +Alternately, if you are making multiple changes to the Jetty configuration, you could include statistics handler configuration into your own jetty xml configuration. +The following fragment shows how to configure a top level statistics handler: + +[source,xml] +---- + + + + + + + + + +---- + +[[session-statistics]] +==== Session Statistics + +Session handling is built into Jetty for any servlet or webapp context. +Detailed statistics on session duration are only collated when a session is closed. +The current, minimum, and maximum number of sessions are the only "live" statistics. +The session statistics are enabled by default and do not need to be configured. diff --git a/jetty-documentation/src/main/asciidoc/administration/fastcgi/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/fastcgi/chapter.adoc new file mode 100644 index 00000000000..20f7b6c5ced --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/fastcgi/chapter.adoc @@ -0,0 +1,21 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[fastcgi]] +== FastCGI Support + +include::fastcgi-intro.adoc[] +include::configuring-fastcgi.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc b/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc new file mode 100644 index 00000000000..294e0919d8a --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc @@ -0,0 +1,176 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[configuring-fastcgi]] +=== Configuring Jetty for FastCGI + +In this section you will see how to configure Jetty to serve WordPress via FastCGI. + +The first step is to have WordPress installed in your server machine, for example under `/var/www/wordpress`. +For more information about how to install WordPress, please refer to the https://codex.wordpress.org/Installing_WordPress[WordPress Installation Guide]. + +The second step is to install `php-fpm` and make sure it is configured to listen on a TCP socket; typically it is configured to listen to `localhost:9000`. + +The third step is to install Jetty, for example under `/opt/jetty`, called in the following `$JETTY_HOME`. +Refer to xref:jetty-downloading[] for more information about how to install Jetty. + +The fourth step is to create a Jetty base directory (see xref:startup-base-and-home[]), called in the following `$JETTY_BASE`, where you setup the configuration needed to support FastCGI in Jetty, and configure the `fcgi`, `http` and `deploy` modules, so that Jetty will be able to accept HTTP requests from browsers, convert them in FastCGI, and proxy them to `php-fpm`: + +.... +$ mkdir -p /usr/jetty/wordpress +$ cd /usr/jetty/wordpress +$ java -jar $JETTY_HOME/start.jar --add-to-module=fcgi,http,deploy + +.... + +Therefore `$JETTY_BASE=/usr/jetty/wordpress`. + +The fifth step is to deploy the web application that provides the proxying of client requests to the FastCGI server, `php-fpm`. +Typically this is done by deploying a `*.war` file in the `$JETTY_BASE/webapps` directory, but in case of FastCGI there is really nothing of this web application that you have to write: all the work is already done for you by the Jetty developers. +Therefore you just need to deploy a Jetty XML file that configures the web application directly. +Copy and paste the following content as `$JETTY_BASE/webapps/jetty-wordpress.xml` + +[source,xml] +---- + + + + + + /var/www/wordpress + + + / + + + index.php + + + + org.eclipse.jetty.fcgi.server.proxy.TryFilesFilter + /* + + + + + + + files + $path /index.php?p=$path + + + + + + + default + + + org.eclipse.jetty.servlet.DefaultServlet + + + + dirAllowed + false + + + + / + + + + org.eclipse.jetty.fcgi.server.proxy.FastCGIProxyServlet + *.php + + proxyTo + http://localhost:9000 + + + prefix + / + + + scriptRoot + + + + scriptPattern + (.+?\\.php) + + + + + +---- + +Explanation of this file content: + +* At line 6 it is specified the WordPress installation directory, in this example `/var/www/wordpress` (as defined in the first step). +* At line 9 it is specified the context path at which WordPress will be served, in this example at the root context path `/`. +* At line 10 it is specified the resource base of the context, also set to the WordPress installation directory. This allows Jetty to serve static resources directly from the WordPress installation directory. +* At line 12 it is specified the welcome file as `index.php`, so that Jetty can perform the proper redirects in case of URIs ending with the `/` character. +* At line 15 it is specified the `TryFilesFilter`, a Servlet Filter that has been inspired by the http://wiki.nginx.org/HttpCoreModule#try_files[try_files] functionality offered by Nginx. +This filter tries to serve the resource from the file system first, and if the resource is not found it forwards the request as `index.php?p=$path`, which will match the proxy servlet defined below. +Refer to the link:{JDURL}/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.html[TryFilesFilter] documentation for further information. +* At line 29 it is specified Jetty's `DefaultServlet` to serve static content such as CSS files, JavaScript files, etc. `DefaultServlet` will serve these files by looking in the resource base of the context, defined at line 10 (see above). +* At line 47 it is specified the `FastCGIProxyServlet`, a Servlet that proxies HTTP requests arriving from clients to FastCGI requests to the FastCGI server. +* At line 52 it is specified the TCP address of the FastCGI server (`php-fpm`), where HTTP requests are forwarded as FastCGI requests. +* At line 60 it is specified once again the WordPress installation directory, so that the `FastCGIProxyServlet` can pass this information to the FastCGI server. +* At line 64 it is specified a regular expression that matches request URIs performed to this servlet, in addition to the standard URL mapping defined by Servlet at line 49. +Refer to the link:{JDURL}/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.html[FastCGIProxyServlet] documentation for further information. + +The last step is to start Jetty (see xref:startup[]) and hit `http://localhost:8080` with your browser and enjoy WordPress: + +.... +$ cd $JETTY_BASE +$ java -jar /opt/jetty/start.jar + +.... + +[[configuring-fastcgi-http2]] +==== Configuring Jetty to Proxy HTTP/2 to FastCGI + +In order to configure Jetty to listen for HTTP/2 requests from clients that are HTTP/2 enabled and forward them to the FastCGI server as FastCGI requests, you need to enable the `http2` module, which in turn will require a TLS connector and consequently a keystore to read the key material required by TLS. + +Enabling the `http2` is really simple; in additions to the modules you have enabled above, add the `http2` module: + +.... +$ cd $JETTY_BASE +$ java -jar $JETTY_HOME/start.jar --add-to-start=http2 + +.... + +The command above adds the `http2` module (and its dependencies) to the existing modules and uses the default Jetty keystore to provide the key material required by TLS. +You will want to use your own keystore with your own private key and certificate for your own domain. + +Remember that by adding the `http2` module, you will start two JVMs: one that reads the configuration, and one that has the ALPN boot boot jar in the boot classpath, as explained in xref:http2-configuring[]. + +Since now your site will run over TLS, you need to make sure that the WordPress URL is also configured so. +If you have followed the steps of the link:#configuring-fastcgi[previous section], your WordPress site is served at `http://localhost:8080`. +You will need to change that to be `https://localhost:8443` from the WordPress administration web interface, or follow the http://codex.wordpress.org/Changing_The_Site_URL[WordPress instructions] to do so without using the administration web interface. + +The minimal modules required to run WordPress with Jetty on HTTP/2 are therefore: `http2`, `http`, `fcgi` and `deploy`. +These will setup a clear text connector on port 8080 for HTTP/1.1 and a TLS connector on port 8443 for HTTP/2 and HTTP/1.1. + +At this point, you can start Jetty (see xref:startup[]), hit `http://localhost:8080` with your browser and enjoy WordPress via HTTP/2 using a HTTP/2 enabled browser: + +.... +$ cd $JETTY_BASE +$ java -jar $JETTY_HOME/start.jar + +.... + +If you don't have a HTTP/2 enabled browser, WordPress will still be available over plain HTTP/1.1. diff --git a/jetty-documentation/src/main/asciidoc/administration/fastcgi/fastcgi-intro.adoc b/jetty-documentation/src/main/asciidoc/administration/fastcgi/fastcgi-intro.adoc new file mode 100644 index 00000000000..2399dbcb462 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/fastcgi/fastcgi-intro.adoc @@ -0,0 +1,34 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[fastcgi-intro]] +=== FastCGI Introduction + +FastCGI is a network protocol primarily used by a _web server_ to communicate to a __FastCGI server__. +FastCGI servers are typically used to serve web content generated by dynamic web languages, primarily http://www.php.net/[PHP], but also Python, Ruby, Perl and others. + +Web servers that supports FastCGI are, among others, http://httpd.apache.org/[Apache] and http://nginx.org/[Nginx], and Jetty. +Web servers typically act as proxies, converting HTTP requests that they receive from clients (browsers) to FastCGI requests that are forwarded to the FastCGI server. +The FastCGI server spawns the dynamic web language interpreter, passing it the information contained in the FastCGI request and a dynamic web language script is executed, producing web content, typically HTML. +The web content is then formatted into a FastCGI response that is returned to the web server, which converts it to a HTTP response that is then returned to the client. + +The most well known FastCGI server is the http://php-fpm.org/[PHP FastCGI Process Manager], or `php-fpm`. +In the following we will assume that `php-fpm` is used as FastCGI server. + +Jetty can be configured to act as a web server that supports FastCGI, replacing the functionality that is normally provided by Apache or Nginx. +This allows users to leverage Jetty features such as HTTP/2, the unique support that Jetty provides for HTTP/2 Push, Jetty's scalability, and of course Jetty's native support for Java Web Standards such as Servlets, JSPs, etc. + +With such configuration, users can deploy their Java Web Applications in Jetty, but also serve their http://wordpress.com/[WordPress] site or blog or their https://drupal.org/[Drupal] site without having to install and manage multiple web servers. diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/chapter.adoc new file mode 100644 index 00000000000..8b361373031 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/http2/chapter.adoc @@ -0,0 +1,24 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[http2]] +== HTTP/2 + +include::introduction.adoc[] +include::enabling-http2.adoc[] +include::configuring-http2.adoc[] +include::configuring-push.adoc[] +include::configuring-haproxy.adoc[] \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-haproxy.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-haproxy.adoc new file mode 100644 index 00000000000..7ed3f8b7343 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-haproxy.adoc @@ -0,0 +1,201 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[http2-configuring-haproxy]] +=== Configuring HAProxy and Jetty + +Typical website deployments have Apache (or Nginx) configured as reverse proxy to talk to one or more backend Jetty instances. +This configuration cannot be used for HTTP/2 because Apache does not yet support HTTP/2 (nor does Nginx). + +http://haproxy.org[HAProxy] is an open source solution that offers load balancing and proxying for TCP and HTTP based application, and can be used as a replacement for Apache (or Nginx) when these are used as reverse proxies, and has the major benefit that supports HTTP/2. +It also offers load balancing and a ton of other features, so you can probably use it as a replacement for Apache (or Nginx). + +The deployment proposed here will have HAProxy play the role that Apache (or Nginx) usually do: to perform the TLS offloading (that is, decrypt and encrypt TLS) and then forwarding the now clear-text traffic to a backend Jetty server, speaking either HTTP/1.1 or HTTP/2. + +The instructions that follow are for Linux. + +[[http2-haproxy-install]] +==== Installing HAProxy + +You will need HAProxy 1.5 or later, because it provides support for SSL and ALPN, both required by HTTP/2. Most Linux distributions have the HAProxy package available to be installed out of the box. For example on Ubuntu 15.04: + +[source,shell] +---- +$ sudo apt-get install haproxy + +---- + +Alternatively you can download the HAProxy source code and build it on your environment, by following the README bundled with the HAProxy source code tarball. + +____ +[NOTE] +HAProxy supports ALPN only if built with OpenSSL 1.0.2 or greater. +Alternatively, HAProxy supports NPN when built with OpenSSL 1.0.1 or greater. +You must upgrade OpenSSL if you have a version earlier than 1.0.1. + +Use `haproxy -vv` to know with which OpenSSL version HAProxy has been built. +____ + +[[http2-haproxy-ssl]] +==== Setup SSL for HAProxy + +HAProxy will perform the TLS decryption and encryption much more efficiently than a Java implementation. + +HAProxy will need a single file containing the X509 certificates and the private key, all in https://en.wikipedia.org/wiki/X.509[PEM format], with the following order: + +1. The site certificate; this certificate's Common Name refers to the site domain (for example: CN=*.webtide.com) and it's signed by Certificate Authority #1. +2. The Certificate Authority #1 certificate; this certificate may be signed by Certificate Authority #2. +3. The Certificate Authority #2 certificate; this certificate may be signed by Certificate Authority #3; and so on until the Root Certificate Authority. +4. The Root Certificate Authority certificate. +5. The private key corresponding to the site certificate. + +Let's use `keytool` to generate a self signed certificate: + +[source,shell] +---- +$ keytool -genkeypair -keyalg RSA -keystore keystore.p12 -storetype pkcs12 -storepass storepwd -ext SAN=DNS:domain.com +What is your first and last name? +[Unknown]: *.domain.com +What is the name of your organizational unit? +[Unknown]: Unit +What is the name of your organization? +[Unknown]: Domain +What is the name of your City or Locality? +[Unknown]: Torino +What is the name of your State or Province? +[Unknown]: TO +What is the two-letter country code for this unit? +[Unknown]: IT +Is CN=*.domain.com, OU=Unit, O=Domain, L=Torino, ST=TO, C=IT correct? +[no]: yes + +---- + +The above command will generate a self signed certificate and private key for `domain.com` and subdomains, stored in the `keystore.p12` file in PKCS#12 format. +We need to extract the certificate and the private key in PEM format. + +To extract the certificate into `certificate.pem`: + +[source,shell] +---- +$ keytool -exportcert -keystore keystore.p12 -storetype pkcs12 -storepass storepwd -rfc -file certificate.pem + +---- + +To export the private key into `private_key.pem`: + +[source,shell] +---- +$ openssl pkcs12 -in keystore.p12 -nodes -nocerts -out private_key.pem -passin pass:storepwd + +---- + +At this point you just need to concatenate the two files into one, in the correct order: + +[source,shell] +---- +$ cat certificate.pem private_key.pem > domain.pem + +---- + +The `domain.pem` file will be used later by HAProxy. + +[[http2-haproxy-cfg]] +==== HAProxy Configuration File + +Now we can setup `haproxy.cfg` to configure HAProxy. +This is a minimal configuration: + +.... +global +tune.ssl.default-dh-param 1024 + +defaults +timeout connect 10000ms +timeout client 60000ms +timeout server 60000ms + +frontend fe_http +mode http +bind *:80 +# Redirect to https +redirect scheme https code 301 + +frontend fe_https +mode tcp +bind *:443 ssl no-sslv3 crt domain.pem ciphers TLSv1.2 alpn h2,http/1.1 +default_backend be_http + +backend be_http +mode tcp +server domain 127.0.0.1:8282 + +.... + +The HAProxy configuration file works in the following way. +The `fe_http` front-end accepts connections on port 80 and redirects them to use the `https` scheme. + +The `fe_https` front-end accepts connections on port 443 and it is where the TLS decryption/encryption happens. +You must specify the path to the PEM file containing the TLS key material (the `crt domain.pem` part), the ciphers that are suitable for HTTP/2 (the `ciphers TLSv1.2` part), and the ALPN (or NPN if you are using old OpenSSL versions) protocols supported (the `alpn h2,http/1.1` part). +This front-end then forwards the now decrypted bytes to the back-end in `mode tcp`. The `mode tcp`) means that HAProxy will not try to interpret the bytes as HTTP/1.1 but just opaquely forward them to the back-end. + +The `be_http` back-end will forward (again in `mode tcp`) the clear-text bytes to a Jetty connector that talks clear-text HTTP/2 and HTTP/1.1 on port 8282. + +[[http2-haproxy-jetty]] +==== Setup Jetty for HTTP/2 and HTTP/1.1 + +The Jetty setup follows the usual steps of having Jetty installed in the `JETTY_HOME` directory, creating a `JETTY_BASE` directory and initializing it using Jetty's command line tools. +You must enable the `http2c` module, that is the module that speaks clear-text HTTP/2. +Since the `http2c` module depends on the `http` module, the `http` module will be enabled transitively, and the final setup will therefore support both HTTP/2 and HTTP/1.1 in clear text. + +Additionally, you will also enable the `deploy` module to be able to deploy a sample web application: + +[source,shell] +---- +$ JETTY_BASE=haproxy-jetty-http2 +$ mkdir $JETTY_BASE +$ cd $JETTY_BASE +$ java -jar $JETTY_HOME/start.jar --add-to-start=http2c,deploy + +---- + +Now let's deploy a demo web application and start Jetty: + +[source,shell] +---- +$ cd $JETTY_BASE +$ cp $JETTY_HOME/demo-base/webapps/async-rest.war $JETTY_BASE/webapps/ +$ java -jar $JETTY_HOME/start.jar jetty.http.host=127.0.0.1 jetty.http.port=8282 + +---- + +Now you can browse https://domain.com/async-rest (replace `domain.com` with your own domain, or with `localhost`, to make this example work). + +____ +[NOTE] +You want the Jetty connector that listens on port 8282 to be available only to HAProxy, and not to remote clients. +For this reason, you want to specify the `jetty.http.host` property on the command line (or in `start.ini` to make this setting persistent) to bind the Jetty connector only on the loopback interface (127.0.0.1), making it available to HAProxy but not to remote clients. +If your Jetty instance runs on a different machine and/or on a different (sub)network, you may want to adjust both the back-end section of the HAProxy configuration file and the `jetty.http.host` property to match accordingly. +____ + +Browsers supporting HTTP/2 will connect to HAProxy, which will decrypt the traffic and send it to Jetty. +Likewise, HTTP/1.1 clients will connect to HAProxy, which will decrypt the traffic and send it to Jetty. + +The Jetty connector, configured with the `http2c` module (and therefore transitively with the `http` module) is able to distinguish whether the incoming bytes are HTTP/2 or HTTP/1.1 and will handle the request accordingly. + +The response is relayed back to HAProxy, which will encrypt it and send it back to the remote client. + +This configuration offers you efficient TLS offloading, HTTP/2 support and transparent fallback to HTTP/1.1 for clients that don't support HTTP/1.1. diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc new file mode 100644 index 00000000000..b4a6298c8ab --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc @@ -0,0 +1,64 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[http2-configuring]] +=== Configuring HTTP/2 + +Enabling the HTTP/2 module in the jetty server does not create a HTTP/2 specific connector, but rather it adds a HTTP/2 Connection factory to an +existing connector. +Thus configuring HTTP/2 is a combination of configuring common properties on the connector and HTTP/2 specific properties on the connection factory. +The modules and XML files involved can be seen with the following commands: + +[source,shell] +---- +$ java -jar $JETTY_HOME/start.jar --list-modules + ... + 1) protonego-boot + ... + 2) http ${jetty.base}/start.d/http.ini + 2) ssl ${jetty.base}/start.d/ssl.ini + 3) alpn ${jetty.base}/start.d/alpn.ini + 3) http2c ${jetty.base}/start.d/http2c.ini + ... + 4) http2 ${jetty.base}/start.d/http2.ini + 5) https ${jetty.base}/start.d/https.ini + +$ java -jar $JETTY_HOME/start.jar --list-config + ... + ${jetty.home}/etc/jetty-ssl.xml + ${jetty.home}/etc/jetty-ssl-context.xml + ${jetty.home}/etc/jetty-alpn.xml + ${jetty.home}/etc/jetty-http2c.xml + ${jetty.home}/etc/jetty-http.xml + ... + ${jetty.home}/etc/jetty-http2.xml + ${jetty.home}/etc/jetty-https.xml + +---- + +The common properties associated with connectors (host,port, timeouts, etc.) can be set in the module ini files (or start.ini if --add-to-start was used): `${jetty.base}/start.d/http.ini` `${jetty.base}/start.d/ssl.ini`. +These properties are instantiated in the associated XML files: `${jetty.home}/etc/jetty-http.xml`; `${jetty.home}/etc/jetty-ssl.xml`, plus the SSL keystore is instantiated in `${jetty.home}/etc/jetty-ssl-context.xml`. + +HTTP/2 specific properties can be set in the module ini files: `${jetty.base}/start.d/http2.ini`; `${jetty.base}/start.d/http2c.ini`, which are instantiated in the associated XML files: `${jetty.home}/etc/jetty-http2.xml`; `${jetty.home}/etc/jetty-http2c.xml`. +Currently there are very few HTTP/2 configuration properties and the default values are reasonable: + +.HTTP/2 Configuration Properties +[cols=",",options="header",] +|======================================================================= +|Property |Description +|jetty.http2.maxConcurrentStreams |The maximum number of concurrently open streams allowed on a single HTTP/2 connection (default 1024). Larger values increase parallelism but cost a memory commitment. +|jetty.http2.initialStreamSendWindow |The initial flow control window size for a new stream (default 65535). Larger values may allow greater throughput but also risk head of line blocking if TCP/IP flow control is triggered. +|======================================================================= diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-push.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-push.adoc new file mode 100644 index 00000000000..58200766413 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-push.adoc @@ -0,0 +1,65 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[http2-configuring-push]] +=== Configuring HTTP/2 Push + +HTTP/2 Push is a mechanism that allows the server to send multiple resources to the client for a single client request. +This will reduce the amount of round-trips necessary to retrieve all the resources that make up a web page, and can significantly improve the page load time. + +HTTP/2 Push can be automated in your application by simply configuring a link:{JDURL}/org/eclipse/jetty/servlets/PushCacheFilter.html[`PushCacheFilter`] in your `web.xml`, in this way: + +[source,xml] +---- + + + + + ... + + + PushFilter + org.eclipse.jetty.servlets.PushCacheFilter + true + + + PushFilter + /* + + + ... + + + + +---- + +`PushCacheFilter` analyzes the HTTP requests for resources that arrive to your web application. +Some of these requests contain the HTTP `Referrer` header that points to a resource that has been requested previously. +This allows the `PushCacheFilter` to organize resources in _primary_ resources (those referenced by the `Referrer` header) and _secondary_ resources (those that have the `Referer` header). + +`PushCacheFilter` associates secondary resources to primary resources. +Only secondary resources that have been requested within a time window from the request of the primary resource are associated with the primary resource. + +`PushCacheFilter` can be configured with the following `init-params`:: +* `associatePeriod`: the time window, in milliseconds, within which a request for a secondary resource will be associated to a primary resource. +* `maxAssociations`: the max number of secondary resources that may be associated to a primary resource. + diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc new file mode 100644 index 00000000000..ccd1ca3e32f --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc @@ -0,0 +1,70 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[http2-enabling]] +=== Enabling HTTP/2 + +This section is written assuming that a jetty base directory is being used and a demo jetty base that support HTTP/1, HTTPS/1 and deployment from a webapps directory can be created with the commands: + +.... +$ JETTY_BASE=http2-demo +$ mkdir $JETTY_BASE +$ cd $JETTY_BASE +$ java -jar $JETTY_HOME/start.jar --add-to-startd=http,https,deploy +.... + +The commands above create a `$JETTY_BASE` directory called `http2-demo`, and initializes the `http,` `https` and `deploy` modules (and their dependencies) to run a typical Jetty Server on port 8080 (for HTTP/1) and 8443 (for HTTPS/1). +Note that the https module downloads a demo keystore file with a self signed certificate, which needs to be replaced by a Certificate Authority issued certificate for real deployment. + +To add HTTP/2 to this demo base, it is just a matter of enabling the http2 module with the following command: + +[source,shell] +---- +$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2 +---- + +This command does not create a new connector, but instead simply adds the HTTP/2 protocol to the existing HTTPS/1 connector, so that it now supports both protocols on port 8443. +To do this, it also transitively enables the ALPN module for protocol negotiation. +The support for each protocol can be seen in the info logging when the server is started: + +[source,shell] +---- +$ java -jar $JETTY_HOME/start.jar +... +2015-06-17 14:16:12.549:INFO:oejs.ServerConnector:main: Started ServerConnector@34c9c77f{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} +2015-06-17 14:16:12.782:INFO:oejs.ServerConnector:main: Started ServerConnector@711f39f9{SSL,[ssl, alpn, h2, h2-17, http/1.1]}{0.0.0.0:8443} +... +---- + +This log shows that port 8080 supports only HTTP/1.1 (which by specification includes HTTP/1.0 support), while port 8443 supports the SSL protocol, with ALPN negotiation to select between several versions of HTTP/2 (h2 & the draft h2-17) and HTTP/1.1. +What is not shown, is that http/1.1 is the default ALPN protocol, so that if a client connects that does not speak ALPN, then HTTP/1.1 will be assumed. + +A browser can now be pointed at `https://localhost:8443/` and if it supports HTTP/2 then it will be used (often indicated by a lightening bolt icon in the address bar). +Note that a browser pointed at this server with URL starting with `http://localhost:8080/` will still talk HTTP/1.1, as HTTP/2 has not been enabled on the plain text connector. + +HTTP/2 can be enabled on the plain text connector and the server restarted with the following command: + +[source,shell] +---- +$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2c +$ java -jar $JETTY_HOME/start.jar +... +2015-06-17 14:16:12.549:INFO:oejs.ServerConnector:main: Started ServerConnector@6f32cd1e{HTTP/1.1,[http/1.1, h2c, h2c-17]}{0.0.0.0:8080} +2015-06-17 14:16:12.782:INFO:oejs.ServerConnector:main: Started ServerConnector@711f39f9{SSL,[ssl, alpn, h2, h2-17, http/1.1]}{0.0.0.0:8443} +... +---- + +However, no major browser currently supports plain text HTTP/2, so the 8080 port will only be able to use HTTP/2 with specific clients (eg curl) that use the upgrade mechanism or assume HTTP/2 diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/introduction.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/introduction.adoc new file mode 100644 index 00000000000..660cb1b8a86 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/http2/introduction.adoc @@ -0,0 +1,42 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[http2-introduction]] +=== Introducing HTTP/2 + +Jetty supports both a client and a server implementation for the HTTP/2 protocol as defined by http://tools.ietf.org/html/rfc7540[RFC 7540]. + +The requirements for running HTTP/2 are JDK 8 or greater, and typically also ALPN support (see xref:alpn-chapter[]). + +A server deployed over TLS (SSL) normally advertises the HTTP/2 protocol via the TLS extension Application Layer Protocol Negotiation link:#alpn[(ALPN)]. + +____ +[IMPORTANT] +To use HTTP/2 in Jetty via a TLS connector you need to add the link:#alpn-starting[ALPN boot Jar in the boot classpath.] +This is done automatically when using the jetty distributions start.jar module system, but must be configured directly otherwise. +____ + +[[http2-modules]] +==== Jetty HTTP/2 Sub Projects + +The Jetty HTTP/2 implementation consists of the following sub-projects (each producing a jar): + +1. `http2-common`: contains the HTTP/2 API and a partial implementation shared across other modules. +2. `http2-hpack`: contains the HTTP/2 HPACK implementation for HTTP header compression. +3. `http2-server`: provides the server-side implementation of HTTP/2. +4. `http2-client`: provides the implementation of HTTP/2 client with a low level HTTP/2 API, dealing with HTTP/2 streams, frames, etc. +5. `http2-http-client-transport`: provides the implementation of the HTTP/2 transport for `HttpClient` (see xref:http-client[]). +Applications can use the higher level API provided by `HttpClient` to send HTTP requests and receive HTTP responses, and the HTTP/2 transport will take care of converting them in HTTP/2 format (see also https://webtide.com/http2-support-for-httpclient/[this blog entry]). \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/jmx/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/jmx/chapter.adoc new file mode 100644 index 00000000000..243f2aed698 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/jmx/chapter.adoc @@ -0,0 +1,22 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[jmx-chapter]] +== JMX + +include::using-jmx.adoc[] +include::jetty-jconsole.adoc[] +include::jetty-jmx-annotations.adoc[] \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/jmx/images/jconsole1.jpg b/jetty-documentation/src/main/asciidoc/administration/jmx/images/jconsole1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..332d603d32b1d719be603d599a93ab2b8ae034a7 GIT binary patch literal 16550 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 literal 0 HcmV?d00001 diff --git a/jetty-documentation/src/main/asciidoc/administration/jmx/images/jconsole2.jpg b/jetty-documentation/src/main/asciidoc/administration/jmx/images/jconsole2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aaac114ffee8a5354e41f2fd370ca6b80259c5f6 GIT binary patch literal 143745 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
  • qjcG7lHTRzRW_^OVO7v&e^Xa1g?CIy=N^dIIAN+z(fQ|Dj2AL=eS$I0t= zKm7$B9>itag}EnU#JYX8d1_-M6`u`WR3(VtRbYAf@I64_zoQDgBfd;V< z?bNL2!znAjQX8>%pg*re{Nc8IcMQb8Gu2|qPZE3umt)=;I!3a+1e*;rE`FvB`nNuroJ@c|V!vBk>*>EGS zhL&-cz#|&wJHF@I1hZ(A4~-1{(>JEE{%?*Fy8BdnnFtD>pOFmcYP;)yV@Ot1h}6*9 zRljfccO}C)ckbN|97I@vII5WQ3G}4jEQ8O(hbEX_Wf*{X^HjWAL;E(ip>6t#UjHS& z99aFoqZ19~yAIb&wi#4Z4BaS+jH}e^1G|JN!(a9%s(OS!Ba>wd!-m4piRa#t&|XKW zu@hQ%j#%j@pp@H1p91nuvbLRzmweDz`hillbUCc|sqr5-ukq*;(}h{{ z;hlo3dY=H}FmK83WBA7Oqnw$1AR%0>hvR{bWRP&HrR}j+rWF(z)?tA%(RK@0+7lEH zv`AMaLWL#(HFmlEO9N81&L!GEVIM4&Tlr|4y>zn8TMs!Th)zuZPN|1tp7%XB>lxBaI&+K`L@tgXQ}e7 zNKvGMO}X?3owSKRHoip~E>yd>WXn>Wtq`l)syp8kt63Bm^gQnMW2$+yn|DUD-AAiS zo8^G_X~Z17O&wM_(R^MW_Ftyb6W0(#?qoc+X>akIvmE}cxIMXIev27E$j|UpXofm#(-T31p!Yb-l5v=I~A6J zqx85(TR?&6x3_WtPJTV1Ers-roQl4*T{W%7i^ysOwSUd-OE$8%i(*V!72)F>br+C! z%K33m*CqBdkSn{|Ax}CaO)W8lNzxN0hDow9VKPcqj+$ZOFGrn84a$F`^r^&L%YKh^ zTG{~689FNjT4|f+mAPWer+B+*S=~G%d3;r7|BS@dsY=GU`(U=LCArS|0jgQ$IY~gS zA2qFvtOl-FYKX^@D36$ix6aHv7{DDS&|Hq}uzcAi)Bh4u%te!GGra32R{OPbNS1dP z)^=IHmK_2KIyB#bnBS0_p7hNgLGh{E`6SF+vDqHQUPHqJt{uc)A!Isr}J$ zN7md+KGj1Vwpy$^6J{cjWKQF514r`OmYYS>gm!6l`QF$KX$(Dv)_z<9R&RYM<)@9{ zAD4HEin#PZGPsr_Cu==)tn;v7ZeD6^=FIHJUhM3jn??O5*Q{yQ*de3RUfE`Lk)ck4 zL$=M6NRfHRPCJHDjcKO}9m>RmPfu-qxd-#pee?O+zB}d4kMy`o$?^-xJi{#TKme@% z3cMPPF*vsVw;;2QAuMZxUmP!A1jm650)AyhKOEtH||CM)SQ+ z;1+vW zNz(C;DIBxUiI+*>Eq84TTFCl`p&fCL8Z}mtC6!C^QpZ@UPtP~+%4pfk^Igm?eHV99 zEANX>vP&%aOyVYww_pFoW9ld#{j>D@g R8&=*(THp5{IVa-wk)Al9pdCPk_t&N z$he(Nn@bg89?`Y-$u}HUAF-nNTOfGE%M)f|QYT+s9B6 z`~!I!1lZ3_&9pz!=iy;xIh+w=*;*MRJqrSnb`+F;nn|h$3h-xh2RQk?RStS&^6`Lg zi7k5E{xEh|cS$OL>*S4oM9B}DDFyAgy&zTQ7EdU`iL-c|E^Y2k7@4wvV$P=>Ze*%m zFsGmPbipmMuHW`3uIE?4XTRb~g&EGBcEs&dMLb191*ILS)L^CkDv?jsC+9kMg%g2B z5!b;2MXF!bb__zh)&JtPS#!&E%xw&2(!Y?7zTf1B&so^37xH4q_5C85^=_F^@s7W@ zJUvb-+;ZE^iY+QHEWW1GsC6YwdeA@29;}xadtu;a;WBOIh)}6|I&UN6YpeB^TeLV8 zRPfVh%s^~6ke#K!-ZfcYLJ`uyE~eZR=vvhgrhK2?e|>Ht2{%oYBB&XP-ItAo{}wG1 z4LsxoIM47EQ(0u8a~8+oXo~=gik!mH?tG|O{H&Q zC)P`_o$h~3Oo1++6_f(uH&hVnM|SLhf$UFyV5w5A`yvs71WcUHfh(7zU1p$k%=xJE z7~)zZ=X=MlBdLDZac!l2Z zxn<=#(_s{A!TmVTekO%4u$q8V3cm;4i?K&8!rYl zMdR9L>>o?aaLNB%)e#W+TpkehndW2aQ&Lf6%@&cd$8I}4c*{RJj+Lk7aSS$8KI<8C0r>>O#;` z$3t$@`L)v{LwPI7JncFG)(9lc*=zXtT(nFw!5tQ-Jlb*8L{x~a&LVaF7e3_}u>ci}vgO1f!mcXZ&w%Tk-V|%AX0=Lg$ath` zw5GJ4k|rudd6Fh4WH-N7O_Md7{Dd*53UcX+$JF9&3B@*z)~`GWdwo-spR^-3w3Qhj0$PcFB6!#WGG07gU{>MNsSOQDOlc*Q zsY~~zvyr%rrh37*ZPo$_*ff*Nb0@$7$cuAjm$#wS>DJONVg-47CECQoQw);Qi6ikI zGVhNjg8Y>Hgh~aA0QbqWO2^|U%(-*uzKSatolkiQl}_YZ_BG^|l4MEVE<6swTXY|7 zRDnm?D8*sCY1}mIv$U!fFwyS?Z>ov`MS6ZtlR#MN^@qN$cZulw&7B$~1G|*>s78YI^(HP-Hm?Y4!1WzakB~Hs82cC6a%3e zj(%E|!#=&uRp~hqrX$w_UvoMPH#6DRjzh+BQZU0O2^8W6=1f|8a*&%JOd#Gwt3O@k z0T+S&O6I7fI5HH)UUa&*^}Tm(c|noGzR>buc4vYEmyC`VVA)B*O2t?U^h|kG>cLhW z4By`Rc2#()XZ0nL6xy!|+uXjS8Q@?^Ag|_KP6or$nQSuAVVLHlCP9Su)k{q$ade6*<>-an49c zsm_p?=h{t=cJc~1cEK`!)+gLCRahsS5dK5IlDVv;X9GJwMmZrZcH;zF`5~Ang>Pl~ zN#^5q#B-v`c8_DpR$d_nV_4qxq%;m$80&CDc1oKH_N#Fv;AT+ux&7R|-|aQpvHZ?d zQYo{lA89vQBZW9F2uBS^?gZ4*<}jH=(}TS4riCl=c>7Qm?Y7u0L@QfDJS;g)LDc)| z@-gxtq+pJEslhcpny)bOyE3Smq^Dd+XinOYi3y;W^ydP)mA%zVIjvM@JuYCHvVhS= ztF*(OUX#&g__VG{k@oBech~#B(XcU1wbWHC8aeDZc|ct3xN;?3hBnpyUYL5fP8Vuq zT`NrdTV9x14rPb7(bKT!Gm#Upj(Q)a&&1ST zJam4*X1lu@9z2auN8486#6Es^ekX#lwB@f<(i{A1tXrTU6O8%IoPvy>C3ep9Ga%C1 zSX7Eyo+rqd14}xP@^F}PphUakp&VNO*RJQ=Jm-#j0+8dAk%Em7Ws`4Wqhg3t)}$oN zX|8?{c$lg0&}S%4R8KJo^*WS2`(->xZh$!Ys|c=WeJH!WcE>PsaFToQ#Yza=YassU zS?>7;Z?FXYz=QUn+F{!6940j-1(Gh7$2qp<;bkBtaYHzhWPQPbo)GWXI_sN+lvpkMbg4?!)yGC2;S>>bu9Rj;8Y z9LsM63}>bY$jeC2UOa1uRL;KcNCo#JAG}Nwf)5FRqZXIo zuh+%XGBD7k&~R^i_K%gAW4cYsk6e96|AVA>y1dpE z_eo?}aROKO{zI;$BDoDh$%EIH?r_Gh1Xc2rOk&pP5kX8jOvJ(0!9({X)B%Fw*PS+a zdl`T|Q?*Ak@YpgqB=`|$yNoD8T#cq?>O}l*$km2*Z)3(SWpc=0^CeBua8D7mHDhd! z_x9Bh(=GUl>S`SDX6;y32(eNr)H>A9*QnANl276lgMplLtbJ)UCPD*wOL7$=rGVG}sJGy- z_}n!Z7_TvLFe}xMtEskkF9rlyY|>^!M-84j5%JiYev%W0H|4+gT*GWTk(*!{M&EqT z5f}wE%P5wih3cdY8MgsCUKbCb=F#oWu!fFla$20sb0k^kqYL8i+PYL{N!WmB-T_HoxtOUd)Ur76qM~Ng)!3T(WiyXL zt80;UTeF%VC3_;RQ+mx(8Ej8{!BiyYSX#o`L?Ot~`k6cbFk>BFTk>aK-Lr{asgPO| z@N&Kz4PEkgNQ?fD`{O=RWv-wEf3ew~xn_K(B9_r$K#R)b*_ixyrrc?-M1+L`KGURR z_~Zg~vY9{~Z3-NnXFhUh0Idr@Fjp`AK!DekV$<0ToZ%tg*HrNH4R|oO{4mXi5IC2G5gooF!mpy($@D8F&JdT zD8BpbHH@iy_W9E(T1`^y>oX0YE6`K$aBP6L&EAvUVk~(1B zk6Aotq5~Ci-f$qNs`Il5O6|sn!|E;Tg*GI9KEU|oR#jBzXn?3s#8WJdkNBAKq?+n|A7^vw}S|j7VwNO+9HicO6P<> zmo@C=sZ$3oHRT1Amoa~GwK4=X!{qa0D$2oEQ-@UAnHCq>PWa*tG-ZSrl^|AguLbVT zf^Nb`PC$)D`Bt9xjGP;Qk=+l+6Gy%%g<;udp&pV{jFpA?gs#}agZju1`B)bD-2^Yh zOO{6Y37V2WvfO}xuYxyfIouy{?4Z8ov?E(V8RDO{V5OrVzAy4^THlmh&a*?G@WvUn zX2r0`7Bb{hv`fFbVW$rNf-*#riOy&@Q}E=E=YAAI4?oS2VIL8N-hVV=n5>rAF#l~N zPpv?zMStXa{jK$q03s%LRHNQ7Vu|muQ|~gj#fG$8(x!A+T-&K90KuP1(zQYP}oFM-T+N)95CtS-eNs=3dpcy~GEc*llEb4m)VNJQjh z@^Oz;ekF7cuK}`QrE@(bjfkk1jj__vgrR!Z?dkqBnPqrd`IHi>;s^$Dxq7(i^?Xhl zr*TU2~#Hp5oW@Y(L=ZFD;^BB|+{1CmWj)AM0CFH^q|S{82(xmG)(r4(9ob z2;r`!1TU>qhM{$l){s7jT@tkQaa|I6SY~CIX;{%ypH`zTE@DVV@fVn7~b$WbOYj4qYwl7aD1!AS2=S=$i{4mxGoB6>^hVb z^D=^bFZ;4NzcLiHclbL((3clDI#;@BwX{zIwcgLHhzTtw!_Fcv)wm)LKzilD%Q|{4 z*h+Qa`1)yJBp0-u<`@xwA_I~EdUu$!p~+`_F(dEF*Hc)@_-{zF%M%lKUVp#xZG@7_#= z3Ms`^|CnzkBk9@mp@+fpV*ce-ZcPX)C6e|#B+Jt&Lz zp^S|^*-`I!F@IYPaEMB^!uY>=`i`cXnxKl@f7(K;o-hFK%koqiww z^g3cJ(W!ERsb1`8pIXhEzimm--f!dSGhdNo&2TOiHRyt+#XQAHzlu;bn^Mq4ez_Um zeIiX)JD;7Yp_bc-?|kM?n6Cc0=Q5&TNMo50hc^ z_Hm3y(!Ukd*#AIr|^jJm^0R@l8EJ`k2c=$9Z0Z39xv7eO+I>a1`!eh&J)MNKZDv zq>FawvKJD^^KTaTLR@c+KkwB$L&v&K#^qnIOBs`0(VKj$tG9pgCif!^U}r|QP`rD% z_%L;w1D-jNWcKy7+sCa>JOBL4`LC@W^`-(cuza;XbmmTf=R*6J_5YmW$;6qd+fC$~ zOG8IpMZCzSD~?RY*j@PlYKEVj|6c(By>$7l^dILf)NJED2Dck8JbI6`B0lp<-f#>Q z^=>x)?54UrO+lQ#rYL=U^#l=N1ByKE*~FcfPFz{++*u~$7)S0l9xGY*M8gxEKfa=P zJT=GFKHrJ<5DM*(xwe6>o3i{LJhtfIq03`njX#UhJI(&Oj_<`<4-!-ia?mRzY&Q;_1eZz%J=^ez zz@6;C3F!6yFX0;xv%h$6?@YpveKo%QXR7}H$O3ER+*g9Dy8Qo1(g(^-G z-gZo9{JdJy`oBW_+2dS6^|v}dU^TW2Mf;&ruW_XpS8wK0|04s8Lir72^XyQv!`BUt zxs%tna=)k}Jt!s%pRC8iu7vsuNM7UJ)3a2^`xpN7q@EZfQz3h={!7*(lImu~58W{F znVu}x)*OmO%N&E{;oT100m|~Gt8Sjw3u%J%HqPBPVdb4z@_1CxNhOK>jwV=U+Ry7} z>#;h&J>#Y}LXMkfSg8=klsy^{Fd%26gv8{9%!|5d5OoV>9rdQserJEi#m~b12uV)X zzz1owp45H@zm4{cRXssI3!(dqNBf?xSYRRIl}nbwNb`Z}u=7C5t<;Fba5;qYGjFgt zx=v9aT{_f&5McL5r21*{eR1Pq$*UAf$gB3r*wT+jJU9gJ3byP)WTU>KRt~33h7nqh zH@R;(E|hlkvGIjxL7NOAZ@4c)wvV2wBJLiHGil;tD?e`){Lk4U9XrVmF6gEA&59 z5FdZaYjGM~w!~)67B7f{E68KEp{r>+=HQ2!X~R(dY=z4T+_3Oek;MSvn6@D{A%DWg zj3cg@MZRptrmv+n&-yRk=k9l(%<#i8^gr<1GnxsVgEgTH(5bdd1_}s*?aUfJR79C8QsRq*ZuOGUaMhjB_4!Q1e%+tVz(3(+JY26 zg!lc^$tl)q)A%ZUA$Q-)VkesXlN##xrw=*HxUx+Fn$#=^dv0bk(*Sv;lkAf;2bg7j zoz7i0_pV4V~uEK1I${+e2h|2+8x!iD_)1aRr) zawIOec`AM6UgFr(W5jr%uH*mKz}}ZCR6wdwSKKAm4Clvpwz?`NJz7^_;OIR`EayyP zdBL=?{CcBELf^#G*#}Ew^a+;z2V9sTUz#$9$|X(|Qnr)Wl32~>p?huFPf`aLwN58b zjT<+{9)t~xap$WLWp~`UB|p0x+;aJ?mT~o!El+?tCeP_(yGqrn@P{vxuqezHaMQd$wuxnd2D466!~k6^y9w&h(a$Vm5q4nx*`e z!l}MB_0=FocANZ3aRzE>XkBjm`D zkIme^c=7JcE=|8+rU7uEZ4~rl>qiz(Y6MWNNoDpp*Ks6%#yp&XgTKBQUNDx&gWt@Y zFgjeJx)BX^s}yf#7@y}Ww=#^RsL36GhJCsP^&F2|z7e;ccNSmGM4$5#>QzT2awfL7_S?BAb_!{xlz_GxlK$^mUtQgn!5OWW3$lzEdyRHibgE z#VUd4%?AUJz90#Q?BxsTjE#4uoCHSoquRSh|Fo1NQ@HE3mEJP>w-M`mWbkNzU@djJ z=EV&1m@5A!6^17V@A9NxZ2|HsVx3AULu5_;Zt@3Hb92QhV-G&%*5JZ!$G#>_??CPj z0Lm}#w&}$eH3hdVAv2+GBotNqr-BA7cqR2_OJIrS#|6x{?!{lcG3)T$GJy^Ox#LesEa{gJv>3fXW)#` zEsMQ;2GGNP+PNwAy|i4q@9($t=)^*|!LK#lG2X9KUe?FJoEJ?C37nssFQsEU z*0eN#k;-v((kyzpe2Q>)bjWO8XXF=nQ(F7Uwkhg@yLGo$gK1t4Rl)P+;vP9xDLCC| zdT=3=(x4?MH^g)E#U~k*LYGcpHWy#`wfS4uVcO0-7dM>rcoep~m%Ez{5p(GG`#N0Y zmEUsdg;g)l{nqeh0AJ@UTiPg*ZzT^R&6$2q5-{c)=C>75J(>$)9unWWUfD(1B)#Fa zc~_3kyesN)uk3#|+QH)UXL5g-Ggj6PXO>)Bxi0pWGULl^3gZbaKJSa$@y4jZpti~} zkdfrO59ZgAp+aD88zGKvjL{L2RCSLrL&Go!! z@xlm7tU$y$aC{)7(xCXO)GBbmxU!y&-(;GUw}f&io@r+|RI8C-8qLR5G8|LnAFxr# zwQd3yX-g~ha1)6a_Y=G^_qZmo)SiY=v!Kp1%qHLuc@(VxWUcIg)0p}fD?4+MJ%=um znGB>kZ_j`}2<tMvoR%lLbL z4hOn!AeMjeapUrEz#gmC4AP>@)+~t`O+&fqesnbiLv~~mCvzmT|0-a$a@9z$ za2=}5&{QgIar%9j=9kOZ$|rd%G>p9YNNmI+AvxjFikA@$^;TduPX>*?@zy&i_0#-% zyMkJ5s1VR4kIB-&J}9#?1?ALqWne60ts3}>457~(P^IccvVP71BP?J7-Pl~oYy0Vm zKi5aOX7%fXC&mJ+7tMAwW%eeJ$6pP|50b3hv=?vhCO}i|2vPC7Abr4LRG@;FOnRna zl}DdqDp#q9DsHUzp}Fvi;Q(B;xQLq3oIr)Z$n07+mP{DfWS=W#9ltQ0wmw!>z63AK zwmYa^3Wx_YJ-IW)3{VHWfkRhgEoTd5M4HO6{1)$2oe$$I=h)#5*3VxcQE7%g$j4cu zPe>eNQde!^5Jl+gcYG*ea{K5U&R6AS;YGVSApY)h6<&{N>S1U?MtCjC(W|p~r2aCZ zzje(e9q=wSHC<~JN^Tis@SYsfS$sTCyqMTZqG%kye4zad%0s+Gwvzg$n{n~0qG6m_ z;(OEhqN(eqJ?jquodARguBJRzSZVYAq_en+zE8I?FOoDe3-hPQD;{%^$HpH7im~@! zv2La}@s@wG_ZLst?d@>>@z9c$y6_=_v2tJKhr3nJ3eejjCDp2IK{3Cu3j?BhcGYW| zi&&F13>X*^?ay>3&Qe1XNh#ES@q8k8F|R%7hGt*~Oyj@lSwRyl!Z0=X?AQl+p7Pk> zoq;y!~2H5QXQOL(H21{C{UoK z*flS%6E<~1K?740FBen~X^{b+da|)?QgJq5RM%we5)&aR$y;XgCQ*+8Pk0ED`eu@zDzE=sg771d}x$aHl=9wAKaPhUh?1$R$|yFgVcdu7u4!+1|?>X{^EH_Qi4#W4$0_=^Q#Uu7n$nRajd(5QY+WR zU9wRc-$QDpD6AFs1q8u_`pJJC|FBm7&3BE(@jYj!LFTV7oTXJWQy@H%_j843oMNdn zo;fW@J#!uGfM@b-4hljT_-rY_o?lh65G!&?fF(Vtlt%1sjMQKpq$LgxYiI_IOoe?h zaS5ga8~BT-uQT3yEe#-v>My6#?7MOi-D&;9D26L~?Pzd)f3sqF&9MCKWK?CYzA*gZ z4}jFmZJarU22PRNJlnf3k9<1?Qi7gF-%Dta1e zlUE0lt*u-y2n&j-og3yaNZ)#Q3DCxSi)Px+Zx=wqI(aS>qTlZtQ;)~-88BvLAtrB0+aExvry@U=8pTp8JS)*s|l>-c6v7Q(c>_#-LL z`gUh10dszrRch??1HV(8)d$S`t~aYI;dSmCsUMvL>s?}}3(}xbbKlMxdiE)&DXW6A zrzo4E1#v>%7NY0D)fi@|CL>tu)py?Wj}Q3_KcQF?Kj^hvLD*%DhhpjgXVz@$ngRN> zn+av%mB$fHB+ZnjoY^xq@OWW>uvnn=NQ9NdSLP*+b@9_YjDdV-`gVEFM}g^PvIL|^ zD8r5^N-tCA{?ifjs1ofmw5(CVU5xDDh6|3)GL(mPk}Pq|()o;pts-}6saz*N#iUnt zF_$QjvQbmI}?du%$jvd_dJOy>slN2{LYP}JFEZZb~w}t za@I>B54r|&^tgzAd#a@uml#0N%t&3ZOQO5qTJlVEcuk4#h&Dgr!Vvw;aDWT5^x04vZTimtvq%?^5Qrnwn1 zQRgCtrepQ-nH{Zz-Zw0NhN3T$By4odx;Y0(L!P_jmsABYe6{uxSK?H7!#CltN16Ce zo156q7WT;GPX@Mcs_7T(`H}3%h1M00Hc7YsVpmhO#im;vm1A~2_^_lLkpd8Zl*AYU zyl+IkoNStLoMxWN8Jk{l!mD*5L&5*#_^Qz>*}*Gln47>cMO=EPnd-AtZCy?f(%t$u zEs{+lCg{(vun$-w&A)hBL>k*V43Y#mnvqWNRT7q@yI}59+d$h$^gu`t(K6W{Qa8lr_Nd)Wgqp@*1;~ zvuRQ$P)Rq)M!ib8l7)+$vb!o0-qBuDjqN|R{2W#uS=FQsYYplEHlAWN7bHdGmUSG= z2?i3OgMm3MQWmD6U}yflESB*VbGKEevBw0_*@W?w^>LR{>3nn2=xdaF2kYQw*Z_=u zG=!{R5-EPDc{`H71+1|dtGYv>B zxtugKh2E_Rle+G`btbB3e^2&E1#2Fka4YVW%U9zGhbHj(hw;%~;nXU~FkYvd_68Dn(#i-lz- z6m6>wI}ZehR7ZnEmNT~qCGUhDUoSD(Q;cGz2jgG7^!;W7rhWm1mV_rpuXNlF?Uju` z@Cvbu7Cka>AFqLQ**^Exn0RI8X&lk^EA3Njpq+7&Sod=EIDK1h@`yR_SH3N3C2n)0 zgq&YN>dsGQQTGLsD;JyzmOzS3i|}TdE_C&%$BAjSMKa2lX&Zcn7Pd)UZo>H4hkr{k znsw`Odxbd8_&}>reEB^$h^yU|(4kT^mRA#JruBBcfCfB6<1Hd!NFsSs$G?qU<`L-j z0UvIn-pO|mjZ!dl==M<~)f~!kV>%;N90T7TEBW2;QxR#@KfmcumO6;!H|K|&m#eNz z0lIh?#=Y9@bGA-{+QGz8!m^8U6Dzevet{gr{ER~Q1bM(p$9`B9O}uT0n) zJ>ODFdQ!pW0x z50Q9+Z#5gW9yH*?^xi5DLpX-K&?YwoDYme?WVFx+nM9xhknUq{Dt!@FnOV~DB%P&# znL3Ivb938|bT%QV36uTb5l@F!k`=GUf(&W+{KTinp6j@VG7**9ROJo2$N~j_%`0O` z)%(_7jpSSil^{;egfu3nS;bF3tP7bPIA7HXm*=;Rsvq(sqGEOH3E4-@3hH6<{}_PF z&O_fnL=uV8+j_;>9LZmD7X^F8vnm!Q=iETIQYxhyRQ1XiT2JVlqYV7DD#rc6%BV{r zk=7MD(IG0VYF%50ibBUyRhYz%j5w7a zpS*xj+8Y-+PT(naGKNzqH_K>34Kc%gBwcC=$Z2DoV%3N6TBoz=8+%6jdPmC3@swY` zLOf%CJOq8++_&;X<5d$iXo2=3m36mQ*|y}xyFmf}@Ggh$kOw_E!}_aNdmaI|XZZTg z8{9cPXr%m&2tC*B6MOlH5p%>g^GYwtCy2gh>~?{>=djsLeT=TpM9!VqFV9WzYVHZt zmM7lT^?=`jSPY%v3idP3UBzj`M()bn_-V9s`4{5s88HA!K%}d=t;hS8iUxM1amC7u z@q;e?!3=@xfRiC;X~dA2-2Jl3Tm#Y^^^dbNif}BAcCps5 z!PhaHa3=*4^&lDU-z)d6(EAxD_nsvlj%9V-0(qWK6Fv|U{+!Y@t}RBKohTcG_1}NY zrQ;qZT#~=%Q)h->`sVJxE~C6v;h|SoCl$Tn%eIXmgK<=i{gIluXGNfKVhDM!_^|v} zQTkN>@Q?YEqh8`K0nprsQVvGfz?lagPFQ8o_Am`S&a~f^gT}VeswdGhl6BVhLik;I ze}f2VK5DX5i1zmTk{$aL)9h)&os=Vh)6sh3gBo`;XZ}Yv3cOqVQhLWsBlSm!bz4*x zHk)axCH)3+zF>pnST^e@^?HrVtAEJK5A8mplw9+A%#j)EazFKmTz*Od{hMCaMIqribh!0c=3~|v&{KsID31PS ztZMmv2IcRCnA-IQS!G}rzU5^|fF3wM$Jh7kReF`-MvrBUWJX-+l>Nq{=?DJeaTNH? z41Ey#^diTV`mPAXJhL}ta$4-q?JZzHZ?^$C6_^(ek5v*Y%%a_l6^*bOB(tG?2RMA_ zs@bT}lkiX2+tgC~XIqM50HJqUG+^M_-s zuT}!n-6Z9PZT0a4MN25`gM2PMLL(=QMt?YVDfQpTF*+LC;|tbK%Z&*U|0MbjWu_U zjl()oS>v<~k}r26G#mpJnj^#pc2iwx*A+K&`PWqB?jGstb81YoE{h9dv`z{V%kL)l zf(#CwQ1t|n_x0{>&!4IZMO-8Hk>00TuD8OjN>@kU z|2bint2of~Rp<*Sl&>hwAI`^5`6hHb?$(7pM|bs+AwIqRv>u>KGq2X%`qEe>k(bmM zJU(fr{3ZD=zz_H;1n_Ox4|2uq8vXp&xA)W6uJoIodu=m0;G_iD5C#bUnRm2cs3!I~f1G$&%ZmwzJ36mY7gE6Jh(cU30eH-4uL1Wp7)T&SH&(B|c;96nhI&;lPux+NO(&$?M=wmo&h zf@}_$*;Ijjx!BLlF5KDqte9@iUSG%0l%jkzt?Y+5m++xL$c~N_|19^3<@12-XZEJt zt#{!wZ~v#)`~Rply#9~QL!&==#RtH{9~J`pz`uA3HyO3wbg{yc$#657vW``Bk>mf> z-d9J(xh;Eklq5hn5G=S`aEBlvI88(F&{%>)2Y1iGodkD+OXKbYZQPpe{vUSG)GEs$coaciCRbnM+uA@KRQVZ0^QV+4+yX z@)<}G6+cW?KCr5qc_DL+OC8+TFP?BE4IYwHX2PF~ zXt^LBYsQ4s;wDbgZHmMFuw}|59tKZ@m#qpy!~?NC1;yq4EfD}|u9+R9tJ!(T)}~Vb zshg&kQ!UZOMfBa=ptH)#%V;CKWb==BSv{Q})1M6}GbIaz4~Yb5Q4r*6B(@ zP0_tOpk{;xB?FgE@RNbDyq$5HcE%c6nop&AcjEM&%b&JApJnwkP)9Y`tD0v-IA-S6 zCC)^AE1DHFYn%oONsO4~WYvs1Pkt>dsLvgIymEf^9wa7@cw)bibZRmGvHV5^`>q|) z<@-AVVIHL|6o9A9jobhC!PWoLNUj6>X8p6mxz2c9q{r7BHuzMi#hLUKQSMQ!=K$2> ztJk_iOE&D1u1E?1IG1RqU_SX5b>&oFUJEPNF6>xDY}cA-MXo)WTdQdNyNw?lxj_RbUT9MGi1f0LZnwKtQZWXSqftDo=j% z6LL#yyDGYAis+iTc9%!;Uj^}9`A&ts@(EjxuWB~KbStlVTeg?TT$D^N0#UGYPum(6 zubeZ->%vmLrq98rtQ9lv{(?eBn*Dd+{-Zwv_GfrEA^W)teu>*JKCNgpSk?FgfDZOA z@#SXU{}p4;6fO{cd&wdC$Yrm?+~zrPfIf$4r0tciAINgM>-j-W+!hZoY92u5q3fq( zf`ZuTL^jQokTxom{jfays}I2F)1JXX9q0^lf2w1PylXG`pU`#@5?p2Kr~+l!coAgC zp(&x!MaliD$-Enu9zrVrc4eB3@=A{{AXOOS?WR7Ab$%af^SqIT`0TN0RlvH!m%Vn_ zRrH*~10et)tKiGOlS}kp`_+FiGwE+AoOztH=8~V5Cy>6=rdY=+xi07{m?txGmht*+ z!g!IJ*CP4>43$v9&uPFWY_2}g5N@T*bA!H@zNH}^aA8}q=P5ECjOwImm+#6-%veGM z4WLYVjfJ4r4^bPBEo&tme@OK!`%gw*Dk#PvGBm5-7*-_hRj`fo2PL+#Z*qt*^#`h; zgOB(@^u(MxJy?B*&6u`hpUmtqgQOjh3L-wmTHk6kh1?gN>{~c>R^n5n2 z1_mP5u+4q~+%h+yF^|fTFGK{FX^|2~kwpO56t{7;hy&N5+^TKMP^9jfNvdjV(4&Jb z5$0~j;%Q;_HrM(Q>MV?;s(XLK1bvZ7LbT&pfkaC-8jsz@6Z4EdP#|8UF3lQWi(=?HxH;{&C8}XZ@5`{QN50(LuK`)MfnVn$D(b?x+qo9T#$%J z&={zqp{b$5Y=2Z)xi8BjF)EEKZyy1X4|k(B`@D-`aK~+Wk!YeUQ+CiU=uVO8eH6kw zMi08+ot*2?fuNbV6#{RMLa$ftnOyo#M(2|AX%O;ZjzE;d*BqYqy&cbMqyIe$|8sN7 z({i`?#dy`J@B0V^brcTTnQ#lAlln-?4aC$ELVcr1<%RWh_K>KLR4GJdGErq6>wL~Q z*+d(XeaHni+UX`cp9;%hfrgqFb$a;&8air_BJg>C^5wTNvPR;)u7(z>B0-`qT+A+$ha)T&R**@${`4v=n$+3BzEc!9CZx_x&;c+tOANa7bxR!QRTXk{ca>IxxfEV8ap--A^swS^!t%vXekc2EIm)L zz4*FCh)p;_ndbJ}%_uZ&i#RY6*_&iBu~w(9qWYRT_#O{A(8L9Wp3#iohaLL&hxF_0 zqAwXyDK1iLk!YVXU$i7cm0YQiry@C|X*TVtKpQZlB|%DV_w-EKe&@47!pwLMefZG6 zlj&+*xPG&Fa6wL<$}dy2PGfx1X~>gBaECx$R$Ik_EnN`1O4Zjfm-Q2C{iFs>qp$0Q z;PQuz@XXG>#~l$!<}8WHmvJFl3w<-0AX9`?`&{kTDF|$J@-o}bl@2kYWrg48XM|n~ zlR&Gkjt#GV5*#eeYfAboNd?!+w_3fP5AEYgY$O41TNB`d?(Mz^ag(+y574d#$u{AZ z?NNnre|0j=kjIJ(cTif_VUtzy3veCT@VxoU)6m+^Y&qh4x6D>ZAMW7}D8@s?ddM&mnwrSWN04bXGtt^9lo?qg2b zd*&F*mQs!#Cy(X5ni9B%&uEOiYz21v_#(Jkm5Wzfqom#^ysFdhM2wc`ad;k5+Rh~5 zGf(lU_0<$l7bH3EOyv~pYN&CKDO5pnyoZc#K=)?1yZDr$y4lbu3Y42}P-pMq^2<+) zSGo777|Bl+^mumxXWwZUpSztvis4&)ro}T;4sc0(I0(E^yeljGKL3&ycekHpXDfwURlDZtC?N7U`C(EiEsY~1?}PcAR6biSlu-`vy*khfLeTb zD8uqWb)Q-Ud-iM(NKFqHH>Qf;={GQgVam~g91^telI1PHG)F3QD2<`WX3yS7VfMj_ zW!9Rfde1zkFtX?mc z8b(ca{@wgEPT?Z$c|sY8UkO#k0a-`$yJFtJwWLF*Bpv&pfll(e;@awp8T-*w2=u9! zjtl06bE6@Z`VXkX;<8ZIN6H{v7KcW+=e1$4ao>8GvL8?@r^mK4WHQ;b;$2e+x03ll zlB$v=yq+;5*eoZ7d#q%#9^ZgOz?;QczbA0}J3?uu81LAjinlj7*k!&Db9y0|>ZDnK z%9?hFCg9$uJ5EqEF?kQ)dXhwu@=iY@%S}h!4wH)N%r=-Q#L)*!3}{MZ!8nhV?F&gnqNjrDJYyiYZE1mbem;=`yD4><2LeYoji zhkPoYm`ts$Y@8S7mg4=>Y#h>#`@U-1O3>as*w}isZYO9f=tNk^kRobdZieH#Gs|W7 zkoA zL;aYc#c70qqWv0hCB zcE7~nh@6Hw54)-VjMYxoGPA%JNUlHm0(r0R$U#OIfjiJMy%!~uR0AV9e!-0=uolkW z;d^^ozawUD}7;;IYGcflF#QcMs(f3zx4a2*CCW>bvelsJNsq|n$mEe1SJ8i*T- z%;`<2QHy#I8rQ^+__qy)?g@QG@M~v&^6;Q)#`<;pctzf37XsE;u%s%8mNJ_+FrhYh zH15st4q>^!e`K1@Vo$XtVYM8*okzE&$O$rCS|Zk{9k@Kc~&K{Y@t>U6M`Uew<3@lhv{2wVx9eB7(DA@gatb|WZz>3wFpm>bQHwZ$f!Lfw1+ zI61vt_*Vxb;{F#~b#}-ltxM1%w@H;Wl-!tp0ZaHSOo5u(dRvPAKtT^WoL@8(-!7s$ zdS#q%>kha#1RaJJUj3^SW+JhFnfJWz@5nT?Y)N<#Q{=K+Q^6O(#Fkc5q)B+hVUQm} z(%{n}3SIqv_{#~(FVpJ|{YmN7<8jh6=bwP`q>Zn+9|5>As( zAgwx3Wd-`8R!`DJ!J_9w+u17C01WeLRO+=@0ZVmDYbVpGL0btKi4Cz1QN|SH2Z?ft zqY%^n0t|b&9vg)OW9ct?=I8wra7tUH1^)@iQ1gu7+n$EL17P_>=Uq>TyZxu3>lSSU z=t!aYxAGG7_A^c_F_jjoJKhg=pBE26PxII$w~o|Y8`Rmfb7o^8lF%5lY&-*uN)Y@%ziyJv^+#1{{QoSIgET&D|WlBzZoDyK@orXdx? zs6JK!CW7}_(}VC0LwOQOl`~`d=w%0q55ykApQ{iLbhE3nd>)zTk+KOKBO~9J4Dx>B zF8)SDXmOO7CEOM_d=!s{fz*$(J#yCu&}vCI2<)y?YA5LYZgIN2P(|8ko@0^A69i@L zlhe}Bj+6lLE-xyryYjx4QvCSsO;lY-Sb(MMB!0nmsL9qY?@0IO(u|ys%Tuf~Xx5ld z@j9F?$bwFwRg&R;qtXvBbqb1^l6+E>85v2CatWIT7M=UjK#8?381M};C@EX2OWrAI z?-i>*e*d!&8_9-Dme_L*|DBRVCWwVaZ2gl4Xxdu_QxYUmZ(?ndqdSL^*7VtuJzO4| zXX3D;RxSjy zSYuy$-DyMxmIovW&(f)|P-eOg?aJ>+>nEVI*^m5EG^6c;@iNHmL5P>O^s(RrEdaoM zUQck?^M0JrhsBy~iv(j)JH!aNkUs5VAR58AstTtx(PTw`2y4f#Y6EBoSJU!7-P4!C zv-$qI*;;vn{srUCjYw5Bc~8FngsVl$u(APOmhNrS6!0k2qj~QA+VvPleea{H+9?M@ z>9l$}ki~uZj&n6iF?nwr8u^cbnarUOiAYJU%9$0hzyp(-Ipw7MmZ0AfamWqU75!aF z7WwxnV6{QX7EENQQf(Xuwu&He@`@R0O6@>Z#<(N#BIt+oZ?i!io!Q9 z9zeb*$b!Y&0Bs*Qi|v|B>&~Vx&QHq49&3B2J{#kZvwYhsKWGU`;7PUBI&UBpAC+)P zI!_=@o7f7R;y((#v}&N_rCo7va%P-?6moAju%u<#kA!{88&yfKod{kH&9<)5WZ$wP zW|QhIrC#GSHWMX%=ck-N5TM+*5Dg2lS+Ere8zK75E#rm6yD#w~y{1Vy?K+j^DG42< z81>JmOr2KHBrmy#AYUUBO6`$S-j7VfVsnXlYNWB+c>M~0A2cu~4&TzmZx42TdPG*K z1!|ib*}_t!HiQ^vTCge78OTs(@NY*7HfK6GBVMo+g(nOd&=b!&7W;e~zLeVCvxDw5 zTe%rOu73de&R7C*cVaeZkt|`_0g@bzunY=`4TD7N3N~T*)v;$`=s~eqR-Ah1aZwTE zn*^b;6kX0_?23tN4fm&BNLk^nD&}RY4e=I67B`UeCJNR&XtQu%1dNW$Zfz1$8PDWB zWP};pn+Ua5R85l37t|2%U=4+qx=_MJjND?`LA*u1Q?q>ANJ+9t?8L- zcoAE{@DIoU%8aOvjoXSTh&AIeDpMDnSC;)_u4Ra7NfGm*qy#aBxE@@c;+AwhG1s2_ zdeDdzT>7`zV!?RG9&Zki0#BJURb5S02I-s;o>FAjmpNK6VqaQTobMlrIlD5faw>#m=q z;Gdx`&3zZN!95~{M4Dyh=jL+Cov7^E)n}-WSCs((c6ePA)Bj%in@C4PvAfBdp6CC& z&0I(**|k~JmoziRlUHNMERsjfxjth@0bilX#e&TEREV>!%+2~DcJZLA<19I*8R?qY z2KZ-RCyO3~X~bV=0l{1nT_*%pzRi4h=MNqk7~Xe(SiAPU3tZk!>hbQ~_XTP)BHep5 zW|%B!eDzdVZFW+c>}w?=)vutbchh%|e6~NQzMKrz4Q*{0#VVI_-ZSQK<$Aa}_!B^Y z`=i$~e2;U#eeiPG(ZmX%Dm?qiBa#c|#t||S&*v(3A~Qs~-Nh#LZhCTVaWO3cG%~ZQ z%kMJh9^St*|0Lihzdad|p65$V@ty1a#7QrIXsaAD*1v4*gJHeg`#hP_c<0UO4R$jd zXp_`JP8Ebr&wcDnyh4IKjrgRU5}X&-JPuxR)qG?kyUDJJ;*!QB{KSADlil*e-oA}u zf6n^uAsdO%UbD2Z zZnC?foVtpZ&Q4Lzq|Ao?M(e}obJB#VuXtED+1=C)uhUs=?y8EtlS^DUnbRC~#Y^W~ zUEk{Zc3t1vkpKT|$S=7t5AWUB7O*S=gB%i99fZ_U*?LI3cV3%RgYtz-q5!dg9 zh25h|ty30N0R2YgW@}@^%CU0BSHtE*9qv-=SU&D>Tv1NJE_`w=|Ks%f6W`Q1*WuiS zSon0-Pk_^k6*7NU*{k88W=C@#1Iwc&N>mti<%Rj@j~PX0&b3Z*R_HHVUU0=1S)X!$b_RsKiaXFzXThA+^3agi#=SrP?0ND_$C7q_@6I3w%G}rntXYe=UWNkXIU_B! za-vlaM5<~%aDOP*eSG^vf3UNmz0rVSS#3bIEMpq8t;D>zp}~?3Bq{425-c;s5s#++ zF7#r)2*;jw$7x&C1g(vp?&{gSbT&xK`%8WiYyrOYc)ptExt_GtpMcSamtJ(9DC8Fz zp508>$3Fp+uynT6BaO+Q09P#$l^JcTA1N0&KLM{T$Sf2qE}GI9cmJb|Nu`dS{RC7* zyw($5FR8dbs&>zx*qvwK)rFsJZ7ak7%!bkwVBc zlVdlOI=~p#3;q)brn^h_hl(bW8Nl^T(_Gf*?#8%k^AR;=jqdnbaKpC<&w+;w6`u8l z2*=JX`{~gXNR@30PexIBoAc<3(e_CY`^M^`IP-V2g-moJ9m}rHime^!Q&k2@CRQCA zzQTfU<^?R2NL3~?Svurr^@U?9+_7RQKwq3oH4w916hs98ydj{&XYCbF4)M3=aqs;6`w*`BqTv?inzB z_xab6@piw$qlrNCx%zQQx$aEEa{sP@k%chJs3Uy?F&hDZ?LDrP`|Fs|O`kBZ08iOu zUfrO@JWqcW361hH%%1n!Pt%3|a7x5;0~~QKdPMOP5a8_gISR?^el?m$|LQ~b_Q!Y5 z02|lWXg6r|(?6%x1Ape=X+NaR{vNsr$p-(S5L|h6xXUzgGpOP!JPP9lP>H^DVqL`^Oux6 z<#FYAexJY7x$%hf2F*76=etJy4~`yP^~7GU3mc=(cTj`L{okjjlKAwn9$zh@u0}Ih zaw_}teoMhMR^}y-QOjHkn_L1rWB|c_0Kws$fZh45{X*?iH?G$2@U`}P|Gk|erMLZr zdecxQv;Jg-@>;QXuF9yO1w7s||J18*`nS>nkdVM~e&n=Hzg?@_gg~aqIe{xf+|1gHN* zFwtt@@ORJ8z8FwmJ_DeoX{2jtUeXJeIhHs)v=v=~-xTrhBDq zBlr!9f+6!II>(l9|L>%|W~(2x8gx^O@V5|&6Df>i3CBDLI0D2o6LcK7uY630yG@f9 zpD`P2+U)Ugp>JF>r(i1w&WCC(Se#^!uw8N08ZBZRE!cvBguw*}JsFizI1o}=7abGX z&Wqh{V_A7ru0XUpWpR*PJ_3o@bEPr!=C0T=bl#0mjjqwG@CKSd(c z#w&DP6^PQZp8k%;TxAmf2_U7-tTqw5*5oP_OY%>Ob_1k%zrmGN!3z}+);bz|`s~9| zh(H>79h~lCXzg2Q5zCP4kqa~bKPf>Kl~&f-kf=0N&_^Mmwap^+vk4a}*poGk9fywR zkX^T@8$lcJ7bR!zOglAVYj-Vbmp{hO52_etUUm0eQ%$_fxu9QMStGnPvRwKXbyFNc z6ST+Gu9C?^5!0Jdul`N(Ng4C!S#Un?CCE3$7oXJ}r@s zZ2ybO<`Kf#S+7H743pQ5ZzPk@O>W@ZiHO=2fbKlEF4F*Or5>*zy#0%^&&l=HX(FH( zMU60p%g1+0m}<}jr777j)U5bSTR^+nCNkjDzo_W(@4%Xj<+UH4YbrU`)=4H=n*Auz z^11IDwRP&4S-K%Id*1&=jV7i(c0AHf{s}-0(f(HXx61$HMZ8`4w`S+o?A+S?ziqv@ z8}99f`wzG6zslQzGTrcLf6abz4BG0)O(hP_2g$F6V+AZ8X)V`!q9@JQS~@D$v{}2; z4q_#t+;p5~lkwHfV|$+}jD0ndrb$ohm|4QA?SQn}m&u)d?g%uWvFrjA6ry8@6ZbKz zlA36JrlQ8*9CbGOZ#oc$AE0A(aLq76na9y=edqvX!Q6s_7GqQn2WlefDr%?+HS&cz?p1) zCTRszAE9;XFd=V*hnS#SaMx!R#ZTKXd{d~X*t&B1qHIBOdg7QHC47t=scNa{_JFuEf4wpEDagaFu9V6-#1opjm-E z0gi~^2fkb4eUl=u9q{{@Mb$txrEx*FZ_GoRV|@s0nxL3JoIXiGK{oQjO7q!vcPn{_ z8>fd*fMT_Nk`Yh!oFc9JzU%`$W=<)JV#ov63CcC+s7WNEs^(*3S4oD&o*U)cOW%+;}&bJpIinSkd9AjN62p|iS)*B*X(|k2 zV|CoB>vnZ{QU1?boZFZ2?_0{Px^7MV?aug@BXa9V-1=R&j>N4aaqCFj9)fPqjQ>kV zYy(YV=|$5b|IJBcF)VcHM87O~!Imyw)trks3{Jd(sP-^PfOfEv%7EyMH(un(Msrvf zIhms>IkQXDth8cT)IiUEIn`rlZVB%VJzW>mptkKJCBfvUQq+joVqi}tFie(OP` element to the plugin ``: + +[source,xml] +---- + + org.eclipse.jetty + jetty-maven-plugin + @project.version@ + + 10 + src/etc/jetty-jmx.xml + + + +---- + +[[enabling-jmxconnectorserver-for-remote-access]] +==== Enabling JMXConnectorServer for Remote Access + +There are two ways of enabling remote connectivity so that JConsole can connect to visualize MBeans. + +* Use the `com.sun.management.jmxremote` system property on the command line. +Unfortunately, this solution does not play well with firewalls and it is not flexible. +* Use Jetty's `ConnectorServer` class. +To enable use of this class, uncomment the correspondent portion in `etc/jetty-jmx.xml,` like this: + +[source,xml] +---- + + + + rmi + + + /jndi/rmi://:/jmxrmi + + + org.eclipse.jetty.jmx:name=rmiconnectorserver + + + +---- + +This configuration snippet starts an RMIRegistry and a JMXConnectorServer both on port 1099 (by default), so that firewalls should open just that one port to allow connections from JConsole. + +[[securing-remote-access]] +==== Securing Remote Access + +JMXConnectorServer several options to restrict access. +For a complete guide to controlling authentication and authorization in JMX, see https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization[Authentication and Authorization in JMX RMI connectors] in Luis-Miguel Alventosa's blog. + +To restrict access to the JMXConnectorServer, you can use this configuration, where the `jmx.password` and `jmx.access` files have the format specified in the blog entry above: + +[source,xml] +---- + + + + + rmi + + + /jndi/rmi://:/jmxrmi + + + + + + jmx.remote.x.password.file + + /resources/jmx.password + + + + jmx.remote.x.access.file + + /resources/jmx.access + + + + + org.eclipse.jetty.jmx:name=rmiconnectorserver + + + + +---- + +[[custom-monitor-applcation]] +==== Custom Monitor Application + +Using the JMX API, you can also write a custom application to monitor your Jetty server. +To allow this application to connect to your Jetty server, you need to uncomment the last section of your `etc/jetty-jmx.xml` configuration file and optionally modify the endpoint name. +Doing so creates a JMX HTTP connector and registers a JMX URL that outputs to the `Stderr` log. + +You should provide the URL that appears in the log to your monitor application in order to create an ` MBeanServerConnection.` +You can use the same URL to connect to your Jetty instance from a remote machine using JConsole. +See the link:{GITBROWSEURL}/jetty-jmx/src/main/config/etc/jetty-jmx.xml[configuration file] for more details. diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/chapter.adoc new file mode 100644 index 00000000000..2e6677c2088 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/chapter.adoc @@ -0,0 +1,27 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[jndi]] +== Configuring JNDI + +Jetty supports `java:comp/env` lookups in webapps. This is an optional +feature for which you need to do some setup. + +include::quick-jndi-setup.adoc[] +include::using-jndi.adoc[] +include::jndi-configuration.adoc[] +include::jndi-embedded.adoc[] +include::jndi-datasources.adoc[] \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-configuration.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-configuration.adoc new file mode 100644 index 00000000000..fb8cf3563cd --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-configuration.adoc @@ -0,0 +1,382 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[jndi-configuration]] +=== Configuring JNDI + +[[configuring-jndi-env-entries]] +==== Configuring JNDI `env-entries` + +Sometimes it is useful to pass configuration information to a webapp at +runtime that you either cannot or cannot conveniently code into a +`web.xml env-entry`. In such cases, you can use `org.eclipse.jetty.plus.jndi.EnvEntry`, and even override an entry of +the same name in ` web.xml`. + +[source,xml] +---- + + + mySpecialValue + 4000 + true + +---- + +This example defines a virtual `env-entry` called `mySpecialValue` with +value `4000` that is xref:jndi-name-scope[scoped] to the JVM. It is put +into JNDI at ` java:comp/env/mySpecialValue` for _every_ web app +deployed. Moreover, the boolean argument indicates that this value +overrides an `env-entry` of the same name in `web.xml`. If you don't +want to override, omit this argument, or set it to `false`. + +The Servlet Specification allows binding only the following object types +to an `env-entry`: + +* java.lang.String +* java.lang.Integer +* java.lang.Float +* java.lang.Double +* java.lang.Long +* java.lang.Short +* java.lang.Character +* java.lang.Byte +* java.lang.Boolean + +That being said, Jetty is a little more flexible and allows you to also +bind custom POJOs, +http://docs.oracle.com/javase/1.5.0/docs/api/javax/naming/Reference.html[`javax.naming.References`] +and +http://docs.oracle.com/javase/1.5.0/docs/api/javax/naming/Referenceable.html[`javax.naming.Referenceables`]. +Be aware that if you take advantage of this feature, your web +application is __not portable__. + +To use the `env-entry` configured above, use code in your +`servlet/filter/etc.`, such as: + +[source,java] +---- +import javax.naming.InitialContext; + +public class MyClass { + + public void myMethod() { + + InitialContext ic = new InitialContext(); + Integer mySpecialValue = (Integer)ic.lookup("java:comp/env/mySpecialValue"); + ... + } +} +---- + +[[configuring-resource-refs-and-resource-env-refs]] +==== Configuring `resource-refs` and `resource-env-refs` + +You can configure any type of resource that you want to refer to in a +`web.xml` file as a `resource-ref` or `resource-env-ref`, using the ` + org.eclipse.jetty.plus.jndi.Resource` type of naming entry. You +provide the scope, the name of the object (relative to `java:comp/env`) +and a POJO instance or a `javax.naming.Reference` instance or +`javax.naming.Referenceable` instance. + +The http://jcp.org/aboutJava/communityprocess/pr/jsr244/index.html[J2EE +Specification] recommends storing DataSources in `java:comp/env/jdbc`, +JMS connection factories under `java:comp/env/jms`, JavaMail connection +factories under ` + java:comp/env/mail` and URL connection factories under +`java:comp/env/url`. For example: + +.DataSource Declaration Conventions +[cols=",,",options="header",] +|======================================================================= +|Resource Type |Name in `jetty.xml` |Environment Lookup +|javax.sql.DataSource |jdbc/myDB |java:comp/env/jdbc/myDB + +|javax.jms.QueueConnectionFactory |jms/myQueue +|java:comp/env/jms/myQueue + +|javax.mail.Session |mail/myMailService +|java:comp/env/mail/myMailService +|======================================================================= + +[[configuring-datasources]] +==== Configuring DataSources + +Here is an example of configuring a `javax.sql.DataSource`. Jetty can +use any DataSource implementation available on its classpath. In this +example, the DataSource is from the http://db.apache.org/derby[Derby] +relational database, but you can use any implementation of a +`javax.sql.DataSource`. This example configures it as scoped to a web +app with the id of __wac__: + +[source,xml] +---- + + + + jdbc/myds + + + test + create + + + + +---- + +The code above creates an instance of +`org.apache.derby.jdbc.EmbeddedDataSource`, calls the two setter methods +`setDatabaseName("test"),` and `setCreateDatabase("create"),` and binds +it into the JNDI scope for the web app. If you do not have the +appropriate `resource-ref` set up in your `web.xml`, it is available +from application lookups as ` + java:comp/env/jdbc/myds`. + +Here's an example `web.xml` declaration for the datasource above: + +[source,xml] +---- + + jdbc/myds + javax.sql.DataSource + Container + +---- + +To look up your DataSource in your `servlet/filter/etc.`: + +[source,java] +---- +import javax.naming.InitialContext; +import javax.sql.DataSource; + +public class MyClass { + + public void myMethod() { + + InitialContext ic = new InitialContext(); + DataSource myDS = (DataSource)ic.lookup("java:comp/env/jdbc/myds"); + + ... + } +} +---- + +____ +[NOTE] +Careful! When configuring Resources, ensure that the type of object you configure matches the type of object you expect to look up in `java:comp/env`. +For database connection factories, this means that the object you register as a Resource _must_ implement the `javax.sql.DataSource` interface. +____ + +For more examples of datasource configurations, see +xref:jndi-datasource-examples[]. + +[[configuring-jms-queues-topics-connectionfactories]] +==== Configuring JMS Queues, Topics and ConnectionFactories + +Jetty can bind any implementation of the JMS destinations and connection +factories. You just need to ensure the implementation Jars are available +on Jetty's classpath. Here is an example of binding an +http://activemq.apache.org[ActiveMQ] in-JVM connection factory: + +[source,xml] +---- + + + + jms/connectionFactory + + + vm://localhost?broker.persistent=false + + + + +---- + +The entry in `web.xml` would be: + +[source,xml] +---- + + jms/connectionFactory + javax.jms.ConnectionFactory + Container + +---- + +TODO: put in an example of a QUEUE from progress demo + +[[configuring-mail-with-jndi]] +==== Configuring Mail + +Jetty also provides infrastructure for access to `javax.mail.Sessions` +from within an application: + +[source,xml] +---- + + + + mail/Session + + + fred + OBF:1xmk1w261z0f1w1c1xmq + + + XXX + me@me + true + + + + + + +---- + +This setup creates an instance of the ` + org.eclipse.jetty.jndi.factories.MailSessionReference` class, calls +its setter methods to set up the authentication for the mail system, and +populates a set of Properties, setting them on the ` + MailSessionReference` instance. The result is that an application +can look up ` java:comp/env/mail/Session`  at runtime and obtain access +to a `javax.mail.Session`  that has the necessary configuration to +permit it to send email via SMTP. + +____ +[TIP] +You can set the password to be plain text, or use Jetty's link:#configuring-security-secure-passwords[Secure Password Obfuscation] (OBF:) mechanism to make the config file a little more secure from prying eyes. +Remember that you cannot use the other Jetty encryption mechanisms of MD5 and Crypt because they do not allow you to recover the original password, which the mail system requires. +____ + +[[configuring-xa-transactions]] +==== Configuring XA Transactions + +If you want to perform distributed transactions with your resources, you +need a _transaction manager_ that supports the JTA interfaces, and that +you can look up as `java:comp/UserTransaction` in your webapp. Jetty +does not ship with one as standard, but you can plug in the one you +prefer. You can configure a transaction manager using the +link:{JDURL}/org/eclipse/jetty/plus/jndi/Transaction.html[JNDI +Transaction] object in a Jetty config file. The following example +configures the http://www.atomikos.com/[Atomikos] transaction manager: + +[source,xml] +---- + + + + + +---- + +[[configuring-links]] +==== Configuring Links + +Generally, the name you set for your `Resource` should be the same name +you use for it in `web.xml`. For example: + +In a context xml file: + +[source,xml] +---- + + + + jdbc/mydatasource + + + test + create + + + + +---- + +In `web.xml`: + +[source,xml] +---- + + jdbc/mydatasource + javax.sql.DataSource + Container + + com.acme.JNDITest + myDatasource + + +---- + +However, you can refer to it in `web.xml` by a different name, and link +it to the name in your ` + org.eclipse.jetty.plus.jndi.Resource` by using an +`org.eclipse.jetty.plus.jndi.Link`. For the example above, you can refer +to the `jdbc/mydatasource` resource as ` + jdbc/mydatasource1` as follows: + +In a context xml file declare `jdbc/mydatasource`: + +[source,xml] +---- + + + + jdbc/mydatasource + + + test + create + + + + +---- + +Then in a `WEB-INF/jetty-env.xml` file, link the name +`jdbc/mydatasource` to the name you want to reference it as in +`web.xml`, which in this case is `jdbc/mydatasource1`: + +[source,xml] +---- + + + jdbc/mydatasource1 + jdbc/mydatasource + +---- + +Now you can refer to `jdbc/mydatasource1` in the `web.xml` like this: + +[source,xml] +---- + + jdbc/mydatasource1 + javax.sql.DataSource + Container + + com.acme.JNDITest + myDatasource + + +---- + +This can be useful when you cannot change a JNDI resource directly in +the `web.xml` but need to link it to a specific resource in your +deployment environment. diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc new file mode 100644 index 00000000000..bb263f2d409 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc @@ -0,0 +1,447 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[jndi-datasource-examples]] +=== Datasource Examples + +Here are examples of configuring a JNDI datasource for various +databases. + +____ +[NOTE] +Read xref:configuring-datasources[] in xref:jndi-configuration[] for more information about configuring datasources. +____ + +All of these examples correspond to a `resource-ref` in `web.xml`. + +[source,xml] +---- + + + My DataSource Reference + jdbc/DSTest + javax.sql.DataSource + Container + + + +---- + +These examples assume that all of the datasources are declared at the +JVM scope, but you can use other scopes if desired. You can configure +all JNDI resources in a `jetty.xml` file or in a ` + WEB-INF/jetty-env.xml` file, or a context XML file. See the section +xref:jndi-where-to-declare[] for more information. + +____ +[IMPORTANT] +You must provide Jetty with the libraries necessary to instantiate the datasource you have configured by putting the corresponding Jar in `JETTY_HOME/lib/ext`. +____ + +[[pooling-datasources]] +==== Pooling DataSources + +Pooling datasources enables connection pooling, which lets you reuse an +existing connection instead of creating a new connection to the +database. This is highly efficient in terms of memory allocation and +speed of the request to the database. We highly recommend this option +for production environments. + +The following is a list of the pooled datasource examples we have worked +with in the past: + +* xref:hikaricp-datasource[] +* xref:bonecp-datasource[] +* xref:c3p0-datasource[] +* xref:dbcp-datasource[] +* xref:atomikos-datasource[] +* xref:mysql-pooled-datasource[] +* xref:postgreSQL-pooled-datasource[] +* xref:DB2-pooled-datasource[] + +[[hikaricp-datasource]] +===== HikariCP + +Connection pooling, available at +http://search.maven.org/remotecontent?filepath=com/zaxxer/HikariCP/1.4.0/HikariCP-1.4.0.jar[HikariCP +Download]. All configuration options for HikariCP are described here: +https://github.com/brettwooldridge/HikariCP[HikariCP documentation]. + +[source,xml] +---- + + + + jdbc/DSTest + + + + + 5 + 20 + com.mysql.jdbc.jdbc2.optional.MysqlDataSource + jdbc.user + jdbc.pass + + url + jdbc.url + + + + + + + + +---- + +[[bonecp-datasource]] +===== BoneCP + +Connection pooling, available at +http://jolbox.com/index.html?page=http://jolbox.com/download.html[BoneCP +Download]. All configuration options for BoneCP are described here: +http://jolbox.com/bonecp/downloads/site/apidocs/com/jolbox/bonecp/BoneCPDataSource.html[BoneCP +API]. + +[source,xml] +---- + + + + jdbc/DSTest + + + com.mysql.jdbc.Driver + jdbc.url + jdbc.user + jdbc.pass + 5 + 50 + 5 + 30 + + + + + +---- + +[[c3p0-datasource]] +===== c3p0 + +Connection pooling, available at +http://central.maven.org/maven2/c3p0/c3p0/0.9.1.2/c3p0-0.9.1.2.jar[c3p0 +Jar]. + +[source,xml] +---- + + + + jdbc/DSTest + + + org.some.Driver + jdbc.url + jdbc.user + jdbc.pass + + + + + +---- + +[[dbcp-datasource]] +===== DBCP + +Connection pooling, available at +http://central.maven.org/maven2/commons-dbcp/commons-dbcp/1.2/commons-dbcp-1.2.jar[dbcp +Jar]. + +[source,xml] +---- + + + + jdbc/DSTest + + + org.some.Driver + jdbc.url + jdbc.user + jdbc.pass + + + + + + +---- + +[[atomikos-datasource]] +===== Atomikos 3.3.2+ + +Connection pooling + XA transactions. + +[source,xml] +---- + + + + jdbc/DSTest + + + 2 + 50 + com.mysql.jdbc.jdbc2.optional.MysqlXADataSource + DSTest + + + url + jdbc:mysql://localhost:3306/databasename + + + user + some_username + + + password + some_password + + + + + + + +---- + +[[mysql-pooled-datasource]] +===== MySQL + +Implements `javax.sql.DataSource, + javax.sql.ConnectionPoolDataSource.` + +[source,xml] +---- + + + + jdbc/DSTest + + + jdbc:mysql://localhost:3306/databasename + user + pass + + + + + +---- + +[[postgreSQL-pooled-datasource]] +===== PostgreSQL + +Implements `javax.sql.ConnectionPoolDataSource` + +[source,xml] +---- + + + + jdbc/DSTest + + + user + pass + dbname + localhost + 5432 + + + + + + +---- + +[[DB2-pooled-datasource]] +===== DB2 + +Implements `javax.sql.ConnectionPoolDataSource` + +[source,xml] +---- + + + + jdbc/DSTest + + + dbname + user + pass + servername + 50000 + + + + + +---- + +[[non-pooling-datasources]] +==== Non-pooling DataSources + +If you are deploying in a production environment, we highly recommend +using a Pooling DataSource. Since that is not always an option we have a +handful of examples for non-pooling datasources listed here as well. + +The following is a list of the non-pooled datasource examples: + +* xref:sql-server-2000-datasource[] +* xref:oracle-9i10g-datasource[] +* xref:postgreSQL-datasource[] +* xref:sybase-datasource[] +* xref:DB2-datasource[] + +[[sql-server-2000-datasource]] +===== SQL Server 2000 + +Implements `javax.sql.DataSource, + javax.sql.ConnectionPoolDataSource.` + +[source,xml] +---- + + + jdbc/DSTest + + + user + pass + dbname + localhost + 1433 + + + +---- + +[[oracle-9i10g-datasource]] +===== Oracle 9i/10g + +Implements `javax.sql.DataSource, + javax.sql.ConnectionPoolDataSource.` + +[source,xml] +---- + + + jdbc/DSTest + + + thin + jdbc:oracle:thin:@fmsswdb1:10017:otcd + xxxx + xxxx + true + + + + MinLimit + 5 + + + + + + + +---- + +For more information, refer to: +http://docs.oracle.com/cd/B14117_01/java.101/b10979/conncache.htm[Oracle +Database JDBC documentation]. + +[[postgreSQL-datasource]] +===== PostgreSQL + +Implements `javax.sql.DataSource.` + +[source,xml] +---- + + + jdbc/DSTest + + + user + pass + dbname + localhost + 5432 + + + +---- + +[[sybase-datasource]] +===== Sybase + +Implements `javax.sql.DataSource.` + +[source,xml] +---- + + + jdbc/DSTest + + + dbname + user + pass + servername + 5000 + + + +---- + +[[DB2-datasource]] +===== DB2 + +Implements `javax.sql.DataSource.` + +[source,xml] +---- + + + jdbc/DSTest + + + dbname + user + pass + servername + 50000 + + + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc new file mode 100644 index 00000000000..28520465035 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc @@ -0,0 +1,146 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[jndi-embedded]] +=== Using JNDI with Jetty Embedded + +==== Setting up the Classpath + +In addition to the jars that you require for your application, and the +jars needed for core Jetty, you will need to place the following jars +onto your classpath: + +.... +jetty-jndi.jar +jetty-plus.jar +.... + +If you are using transactions, you will also need the javax.transaction +api. You can +http://download.eclipse.org/jetty/orbit/javax.transaction_1.1.1.v201004190952.jar/dist/[obtain +this jar] from http://download.eclipse.org/jetty/orbit[the Jetty +dependencies site.] + +If you wish to use mail, you will also need the javax.mail api and +implementation. You can +http://download.eclipse.org/jetty/orbit/javax.mail.glassfish_1.4.1.v201005082020.jar/dist/[obtain +this jar] from +thehttp://download.eclipse.org/jetty/orbit/javax.mail.glassfish_1.4.1.v201005082020.jar/dist/[Jetty +dependencies site]. Note that this jar also requires the +javax.activation classes, which you can also +http://download.eclipse.org/jetty/orbit/javax.activation_1.1.0.v201105071233.jar/dist/[obtain] +from the http://download.eclipse.org/jetty/orbit/[Jetty dependencies +site]. + +==== Example Code + +Here is an example class that sets up some JNDI entries and deploys a +webapp that references these JNDI entries in code. We'll use some mocked +up classes for the transaction manager and the DataSource in this +example for simplicity: + +[source,java] +---- +import java.util.Properties; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.webapp.WebAppContext; + +/** + * ServerWithJNDI + * + * + */ +public class ServerWithJNDI +{ + public static void main(String[] args) throws Exception + { + + //Create the server + Server server = new Server(8080); + + //Enable parsing of jndi-related parts of web.xml and jetty-env.xml + org.eclipse.jetty.webapp.Configuration.ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server); + classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration"); + + //Create a WebApp + WebAppContext webapp = new WebAppContext(); + webapp.setContextPath("/"); + webapp.setWar("./my-foo-webapp.war"); + server.setHandler(webapp); + + //Register new transaction manager in JNDI + //At runtime, the webapp accesses this as java:comp/UserTransaction + org.eclipse.jetty.plus.jndi.Transaction transactionMgr = new org.eclipse.jetty.plus.jndi.Transaction(new com.acme.MockUserTransaction()); + + //Define an env entry with Server scope. + //At runtime, the webapp accesses this as java:comp/env/woggle + //This is equivalent to putting an env-entry in web.xml: + // + // woggle + // java.lang.Integer + // 4000 + // + org.eclipse.jetty.plus.jndi.EnvEntry woggle = new org.eclipse.jetty.plus.jndi.EnvEntry(server, "woggle", new Integer(4000), false); + + + //Define an env entry with webapp scope. + //At runtime, the webapp accesses this as java:comp/env/wiggle + //This is equivalent to putting a web.xml entry in web.xml: + // + // wiggle + // 100 + // java.lang.Double + // + //Note that the last arg of "true" means that this definition for "wiggle" would override an entry of the + //same name in web.xml + org.eclipse.jetty.plus.jndi.EnvEntry wiggle = new org.eclipse.jetty.plus.jndi.EnvEntry(webapp, "wiggle", new Double(100), true); + + //Register a reference to a mail service scoped to the webapp. + //This must be linked to the webapp by an entry in web.xml: + // + // mail/Session + // javax.mail.Session + // Container + // + //At runtime the webapp accesses this as java:comp/env/mail/Session + org.eclipse.jetty.jndi.factories.MailSessionReference mailref = new org.eclipse.jetty.jndi.factories.MailSessionReference(); + mailref.setUser("CHANGE-ME"); + mailref.setPassword("CHANGE-ME"); + Properties props = new Properties(); + props.put("mail.smtp.auth", "false"); + props.put("mail.smtp.host","CHANGE-ME"); + props.put("mail.from","CHANGE-ME"); + props.put("mail.debug", "false"); + mailref.setProperties(props); + org.eclipse.jetty.plus.jndi.Resource xxxmail = new org.eclipse.jetty.plus.jndi.Resource(webapp, "mail/Session", mailref); + + + // Register a mock DataSource scoped to the webapp + //This must be linked to the webapp via an entry in web.xml: + // + // jdbc/mydatasource + // javax.sql.DataSource + // Container + // + //At runtime the webapp accesses this as java:comp/env/jdbc/mydatasource + org.eclipse.jetty.plus.jndi.Resource mydatasource = new org.eclipse.jetty.plus.jndi.Resource(webapp, "jdbc/mydatasource", + new com.acme.MockDataSource()); + + server.start(); + server.join(); + } +} +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc new file mode 100644 index 00000000000..e10dffcdcea --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc @@ -0,0 +1,56 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[jndi-quick-setup]] +=== Quick Setup + +If you are using the standard distribution of Jetty, you must enable the +*jndi* link:#startup-modules[module] to obtain jetty's jndi +implementation, and the *plus* link:#startup-modules[module] which +provides classes for interacting with jndi. As the *plus* module depends +on the *jndi* module, you only need to enable the *plus* module to +enable both. Assuming you have jetty +link:#startup-base-and-home[installed] in /opt/jetty, and you have made +a link:#startup-base-and-home[jetty base] in /opt/jetty/my-base, do: + +[source,bash] +---- +cd /opt/jetty +cd my-base +java -jar $JETTY_HOME/start.jar --add-to-startd=plus + +---- + +You can now start Jetty and use JNDI within your webapps. See +link:#using-jndi[Using JNDI] for information on how to add entries to +the JNDI environment that Jetty can look up within webapps. + +If you have extra jars associated with your jndi resources, for example +a database driver jar, and you haven't made a custom +link:#startup-modules[module] for it, you can put the jars into your +link:#startup-base-and-home[jetty base] `ext/` directory. You will then +need to enable the *ext* module to ensure the jars in the `ext/` +directory are on the classpath. Assuming you have jetty +link:#startup-base-and-home[installed] in /opt/jetty, and you have made +a link:#startup-base-and-home[jetty base] in /opt/jetty/my-base, do: + +[source,bash] +---- +cd /opt/jetty +cd my-base +java -jar $JETTY_HOME/start.jar --add-to-startd=ext + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/using-jndi.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/using-jndi.adoc new file mode 100644 index 00000000000..224f4f0acf8 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/using-jndi.adoc @@ -0,0 +1,195 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[using-jetty-jndi]] +=== Working with Jetty JNDI + +==== Defining the web.xml + +You can configure naming resources to reference in a `web.xml` file and +access from within the `java:comp/env` naming environment of the webapp +during execution. Specifically, you can configure support for the +following `web.xml` elements: + +[source,xml] +---- + + + + + + +---- + +link:#configuring-jndi-env-entries[Configuring env-entries] shows you +how to set up overrides for ` + env-entry` elements in `web.xml`, while +link:#configuring-resource-refs-and-resource-env-refs[Configuring +`resource-refs` and `resource-env-refs`] discusses how to configure +support resources such as `javax.sql.DataSource`. + +You can also plug a JTA `javax.transaction.UserTransaction` +implementation into Jetty so that webapps can look up +`java:comp/UserTransaction` to obtain a distributed transaction manager: +see link:#configuring-xa-transactions[Configuring XA Transactions]. + +[[defining-jndi-naming-entries]] +==== Declaring Resources + +You must declare the objects you want bound into the Jetty environment +so that you can then hook into your webapp via `env-entry, + resource-ref` and `resource-env-refs` in `web.xml`. You create +these bindings by using declarations of the following types: + +`org.eclipse.jetty.plus.jndi.EnvEntry`:: + for `env-entry` type of entries +`org.eclipse.jetty.plus.jndi.Resource`:: + for all other type of resources +`org.eclipse.jetty.plus.jndi.Transaction`:: + for a JTA manager +`org.eclipse.jetty.plus.jndi.Link`:: + for link between a `web.xml` resource name and a naming entry + +Declarations of each of these types follow the same general pattern: + +[source,xml] +---- + + + + + + + + +---- + +You can place these declarations into three different files, depending +on your needs and the link:#jndi-name-scope[scope] of the resources +being declared. + +[[jndi-where-to-declare]] +==== Deciding Where to Declare Resources + +You can define naming resources in three places: + +jetty.xml:: + Naming resources defined in a `jetty.xml` file are + link:#jndi-name-scope[scoped] at either the JVM level or the Server + level. The classes for the resource must be visible at the Jetty + container level. If the classes for the resource only exist inside + your webapp, you must declare it in a `WEB-INF/jetty-env.xml` file. +WEB-INF/jetty-env.xml:: + Naming resources in a `WEB-INF/jetty-env.xml` file are + link:#jndi-name-scope[scoped] to the web app in which the file + resides. While you can enter JVM or Server scopes if you choose, we do + not recommend doing so. The resources defined here may use classes + from inside your webapp. This is a Jetty-specific mechanism. +context xml file:: + Entries in a context xml file should be link:#jndi-name-scope[scoped] + at the level of the webapp to which they apply, although you can + supply a less strict scoping level of Server or JVM if you choose. As + with resources declared in a `jetty.xml` file, classes associated with + the resource must be visible on the container's classpath. + +[[jndi-name-scope]] +==== Scope of Resource Names + +Naming resources within Jetty belong to one of three different scopes, +in increasing order of restrictiveness: + +JVM scope:: + The name is unique across the JVM instance, and is visible to all + application code. You represent this scope by a `null` first parameter + to the resource declaration. For example: + + +[source,xml] +---- + + + + jms/connectionFactory + + + vm://localhost?broker.persistent=false + + + + + +---- +Server scope:: + The name is unique to a Server instance, and is only visible to code + associated with that instance. You represent this scope by referencing + the Server instance as the first parameter to the resource + declaration. For example: + + +[source,xml] +---- + + + + + jms/connectionFactory + + + vm://localhost?broker.persistent=false + + + + + + +---- +Webapp scope:: + The name is unique to the WebAppContext instance, and is only visible + to code associated with that instance. You represent this scope by + referencing the WebAppContext instance as the first parameter to the + resource declaration. For example: + + +[source,xml] +---- + + + + + jms/connectionFactory + + + vm://localhost?broker.persistent=false + + + + + + +---- + +[[binding-objects-into-jetty-jndi]] +==== What Can Be Bound as a Resource? + +You can bind four types of objects into a Jetty JNDI reference: + +* An ordinary POJO instance. +* A +http://docs.oracle.com/javase/1.5.0/docs/api/javax/naming/Reference.html[javax.naming.Reference] +instance. +* An object instance that implements the +http://docs.oracle.com/javase/1.5.0/docs/api/javax/naming/Referenceable.html[javax.naming.Referenceable] +interface. +* A link between a name as referenced in `web.xml` and as referenced in +the Jetty environment. + diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc new file mode 100644 index 00000000000..d7c61a4a71f --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc @@ -0,0 +1,21 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[configuring-logging]] +== Jetty Logging + +This chapter discusses various options for configuring logging. + diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc new file mode 100644 index 00000000000..6f8db30a5b4 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc @@ -0,0 +1,99 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[configuring-jetty-logging]] += Configuring Jetty Logging + +Jetty provides logging via its own `org.eclipse.jetty.util.log.Logger` +layer, and does not natively use any existing Java logging framework. +All logging events, produced via the Jetty logging layer, have a name, a +level, and a message. The name is a FQCN (fully qualified class name) +similar to how all existing Java logging frameworks operate. + +Jetty logging, however, has a slightly different set of levels that it +uses internally: + +WARN:: + For events serious enough to inform and log, but not fatal. +INFO:: + Informational events. +DEBUG:: + Debugging events (very noisy). +IGNORE:: + Exception events that you can safely ignore, but useful for some + people. You might see this level as DEBUG under some Java logging + framework configurations, where it retains the _ignore_ phrase + somewhere in the logging. + +____ +[NOTE] +Jetty logging produces no FATAL or SEVERE events. +____ + +[[selecting-log-framework]] +== Selecting the Log Framework + +Configure the Jetty logging layer via the +`org.eclipse.jetty.util.log.Log` class, following +link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java[these +rules]. + +1. Load Properties +* First from a Classpath Resource called `jetty-logging.properties` (if +found). +* Then from the `System.getProperties()`. +2. Determine the log implementation. +* If property `org.eclipse.jetty.util.log.class` is defined, load the +class it defines as the logger implementation from the server classpath. +* If the class `org.slf4j.Logger` exists in server classpath, the Jetty +implementation becomes `org.eclipse.jetty.util.log.Slf4jLog`. +* If no logger implementation is specified, default to +`org.eclipse.jetty.util.log.StdErrLog`. + +____ +[NOTE] +You can create your own custom logging by providing an implementation of +the link:{JDURL}org/eclipse/jetty/util/log/Logger.html[Jetty Logger +API]. For an example of a custom logger, see +link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java[JavaUtilLog.java]. +____ + +[[configuring-jetty-stderrlog]] +== The jetty-logging.properties file + +By default, the internal Jetty Logging discovery mechanism will load +logging specific properties from a classpath resource called +`jetty-logging.properties` and then initialize the Logging from a +combination of properties found in that file, along with any System +Properties. + +A typical jetty-logging.properties file will include at least the +declaration of which logging implementation you want to use by defining +a value for the `org.eclipse.jetty.util.log.class` property. + +Examples for various logging frameworks can be found later in this +documentation. + +* Default Logging with link:#default-logging-with-stderrlog[Jetty's +StdErrLog] +* Using link:#example-logging-log4j[Log4j via Slf4jLog] +* Using link:#example-logging-logback[Logback via Slf4jLog] +* Using java.util.logging via Slf4jLog +* Using java.util.logging via Jetty's JavaUtilLog +* Capturing link:#example-slf4j-multiple-loggers[Multiple Logging +Frameworks via Slf4jLog] +* link:#example-logging-logback-centralized[Centralized Logging with +Logback and Sfl4jLog] diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc new file mode 100644 index 00000000000..f0ce7bbcda8 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc @@ -0,0 +1,123 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[configuring-jetty-request-logs]] += Configuring Jetty Request Logs + +Request logs are a record of the requests that the server has processed. +There is one entry per request received, and commonly in the standard +NCSA format, so you can use tools like +http://en.wikipedia.org/wiki/Webalizer[Webalizer] to analyze them +conveniently. + +[[constructing-request-log-entry]] +== Constructing a Request Log Entry + +A standard request log entry includes the client IP address, date, +method, URL, result, size, referrer, and user agent, for example: + +.... +123.4.5.6 - - [27/Aug/2004:10:16:17 +0000] + "GET /jetty/tut/XmlConfiguration.html HTTP/1.1" + 200 76793 "http://localhost:8080/jetty/tut/logging.html" + "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040614 Firefox/0.8" +.... + +[[implementing-request-log]] +== Implementing a Request Log + +Jetty provides an implementation called _`NCSARequestLog`_ which +supports the NCSA format in files that you can roll over on a daily +basis. + +The http://logback.qos.ch/[Logback Project] offers +http://logback.qos.ch/access.html[another implementation] of a +RequestLog interface, providing rich and powerful HTTP-access log +functionality. + +If neither of these options meets your needs, you can implement a custom +request logger by implementing Jetty's +link:{JDURL}/org/eclipse/jetty/server/RequestLog.html[`RequestLog.java`] +interface and plugging it in similar to the NCSARequestLog, as shown +below. + +[[configuring-request-log]] +== Configuring a Request Log + +To configure a single request log for the entire Jetty Server instance: + +[source,xml] +---- + + + + /var/log/jetty/yyyy_mm_dd.request.log + true + false + GMT + + + +---- + +The equivalent code is: + +[source,java] +---- +NCSARequestLog requestLog = new NCSARequestLog("/var/logs/jetty/jetty-yyyy_mm_dd.request.log"); +requestLog.setAppend(true); +requestLog.setExtended(false); +requestLog.setLogTimeZone("GMT"); + +server.setRequestLog(requestLog); +---- + +This configures a request log in `$JETTY_HOME/logs` with filenames +including the date. Old log files are kept for 90 days before being +deleted. Existing log files are appended to and the extended NCSA format +is used in the GMT timezone. + +To examine many more configuration options, see +link:{JDURL}/org/eclipse/jetty/server/NCSARequestLog.html[NCSARequestLog.java] + +[[configuring-separate-request-log-for-web-application]] +== Configuring a Separate Request Log For a Web Application + +To configure a separate request log for a web application, add the +following to the context XML file. + +[source,xml] +---- + + ... + + + + + + /test-yyyy_mm_dd.request.log + yyyy_MM_dd + GMT + 90 + true + + + + + + ... + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc new file mode 100644 index 00000000000..c30bf1cc60e --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc @@ -0,0 +1,150 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[default-logging-with-stderrlog]] += Default Logging with Jetty's StdErrLog + +If you do nothing to configure your own logging framework, then Jetty +will default to using an internal `org.eclipse.jetty.util.log.StdErrLog` +implementation. This will output all logging events to STDERR (aka +System.err). + +Simply use Jetty and you get StdErrLog based logging output. + +Included in the Jetty distribution is a logging module that is capable +of performing simple capturing of all STDOUT and STDERR output to a file +that is rotated daily. + +To enable on the command line: + +[source,bash] +---- +[my-base]$ java -jar /opt/jetty/start.jar --module=logging +---- + +You can also include the `--module=logging` command in your +`${jetty.base}/start.ini` + +[source,bash] +---- +[my-base]$ java -jar /opt/jetty/start.jar --add-to-start=logging +---- + +The default configuration for logging output will create a file +`${jetty.logs}/yyyy_mm_dd.stderrout.log` which allows you to configure +the output directory by setting the `jetty.logs` property to a path of +your choice. + +If you want a more advanced configuration of your logging output, +consider using your logging library of choice. + +The recommended way to configure StdErrLog is to create a +`${jetty.home}/resources/jetty-logging.properties` file, specify the Log +implementation to StdErrLog and then setup your logging levels. + +[source,properties] +---- +# Configure Jetty for StdErrLog Logging +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog +# Overall Logging Level is INFO +org.eclipse.jetty.LEVEL=INFO +# Detail Logging for WebSocket +org.eclipse.jetty.websocket.LEVEL=DEBUG +---- + +There are a number of properties you can define in here that will affect +the StdErrLog behavior. + +`.LEVEL=`:: + Sets the logging level for all loggers within the `name` specified to + the level, which can be (in increasing order of restriction) `ALL`, + `DEBUG`, `INFO`, `WARN`, `OFF`. The name (or hierarchy) can be a + specific fully qualified class or a package namespace, for example, + `org.eclipse.jetty.http.LEVEL=DEBUG` is a package namespace approach + to turn all loggers in the Jetty HTTP package to DEBUG level, and + `org.eclipse.jetty.io.ChanelEndPoint.LEVEL=ALL` turns on all logging + events for the specific class, including `DEBUG`, `INFO`, `WARN` (and + even special internally ignored exception classes). If more than one + system property specifies a logging level, the most specific one + applies. +`.SOURCE=`:: + Named Logger specific, attempts to print the Java source file name and + line number from where the logging event originated. Name must be a + fully qualified class name (this configurable does not support package + name hierarchy). Default is false. Be aware that this is a slow + operation and has an impact on performance. +`.STACKS=`:: + Named Logger specific, controls the display of stacktraces. Name must + be a fully qualified class name (this configurable does not support + package name hierarchy). + + + Default is true. +`org.eclipse.jetty.util.log.stderr.SOURCE=`:: + Special Global Configuration. Attempts to print the Java source file + name and line number from where the logging event originated. Default + is false. +`org.eclipse.jetty.util.log.stderr.LONG=`:: + Special Global Configuration. When true, outputs logging events to + STDERR using long form, fully qualified class names. When false, uses + abbreviated package names. + + + Default is false. + + + Example when set to false: + + +.... +2014-06-03 14:36:16.013:INFO:oejs.Server:main: jetty-9.2.0.v20140526 +2014-06-03 14:36:16.028:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/opt/jetty/demo-base/webapps/] at interval 1 +2014-06-03 14:36:16.051:INFO:oejsh.ContextHandler:main: Started o.e.j.s.h.MovedContextHandler@7d256e50{/oldContextPath,null,AVAILABLE} +2014-06-03 14:36:17.880:INFO:oejs.ServerConnector:main: Started ServerConnector@34f2d11a{HTTP/1.1}{0.0.0.0:8080} +2014-06-03 14:36:17.888:INFO:oejs.Server:main: Started @257ms +.... + + + Example when set to true: + + +.... +2014-06-03 14:38:19.019:INFO:org.eclipse.jetty.server.Server:main: jetty-9.2.0.v20140526 +2014-06-03 14:38:19.032:INFO:org.eclipse.jetty.deploy.providers.ScanningAppProvider:main: Deployment monitor [file:/opt/jetty/demo-base/webapps/] at interval 1 +2014-06-03 14:38:19.054:INFO:org.eclipse.jetty.server.handler.ContextHandler:main: Started o.e.j.s.h.MovedContextHandler@246d8660{/oldContextPath,null,AVAILABLE} +2014-06-03 14:38:20.715:INFO:org.eclipse.jetty.server.ServerConnector:main: Started ServerConnector@59f625be{HTTP/1.1}{0.0.0.0:8080} +2014-06-03 14:38:20.723:INFO:org.eclipse.jetty.server.Server:main: Started @243ms +.... + +Deprecated Parameters: + +These parameters existed in prior versions of Jetty, and are no longer +supported. They are included here for historical (and search engine) +reasons. + +`org.eclipse.jetty.util.log.DEBUG`:: + Formerly used to enable DEBUG level logging on any logger used within + Jetty (not just Jetty's own logger). + + + Replaced with using the logger implementation specific configuration + and level filtering. +`org.eclipse.jetty.util.log.stderr.DEBUG`:: + Formerly used to enable DEBUG level logging on the internal Jetty + StdErrLog implementation. + + + Replaced with level specific equivalent: example: + `org.eclipse.jetty.LEVEL=DEBUG` +`DEBUG`:: + Ancient debugging flag that turned on all debugging, even non-logging + debugging. + + + Jetty no longer uses because many third party libraries employ this + overly simple property name, which would generate far too much console + output. diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc new file mode 100644 index 00000000000..1b70fd1669a --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc @@ -0,0 +1,89 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[example-logging-log4j]] += Example: Logging with Apache Log4j + +It is possible to have the Jetty Server logging configured so that Log4j +controls the output of logging events produced by Jetty. This is +accomplished by configuring Jetty for logging to +http://logging.apache.org/log4j/[Apache Log4j] via +http://slf4j.org/manual.html[Slf4j] and the +http://slf4j.org/manual.html#swapping[Slf4j binding layer for Log4j]. + +A convenient replacement `logging` module has been created to bootstrap +your `${jetty.base}` directory for logging with log4j. + +.... +[mybase]$ mkdir modules +[mybase]$ cd modules + +[modules]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/log4j-1.2/logging.mod + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 720 100 720 0 0 2188 0 --:--:-- --:--:-- --:--:-- 2188 +[modules]$ cd .. + +[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging +INFO: logging initialised in ${jetty.base}/start.ini (appended) +MKDIR: ${jetty.base}/logs +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-log4j12/1.6.6/slf4j-log4j12-1.6.6.jar to lib/logging/slf4j-log4j12-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/log4j/log4j/1.2.17/log4j-1.2.17.jar to lib/logging/log4j-1.2.17.jar +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/log4j-1.2/log4j.properties to resources/log4j.properties +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/log4j-1.2/jetty-logging.properties to resources/jetty-logging.properties +INFO: resources initialised transitively +INFO: resources enabled in ${jetty.base}/start.ini + +[mybase]$ java -jar /opt/jetty-dist/start.jar +.... + +The replacement `logging.mod` performs a number of tasks. + +1. `mybase` is a `${jetty.base}` directory +2. The jetty-distribution is unpacked (and untouched) into +`/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this +demonstration. +3. The `curl` command downloads the replacement `logging.mod` and puts +it into the `${jetty.base}/modules/` directory for use by mybase only. +4. The `start.jar --add-to-start=logging` command performs a number of +steps to make the logging module available to the `${jetty.base}` +configuration. +1. The `--module=logging` command is added to the +`${jetty.base}/start.ini` configuration +2. Required `${jetty.base}` directories are created: +`${jetty.base}/logs` and `${jetty.base}/resources` +3. Required libraries are downloaded (if not present already): +slf4j-api, slf4j-log4j, and log4j itself. ++ +The libraries are put in the `${jetty.base}/lib/logging/` directory. +4. Required configuration files are downloaded (if not present +already): `jetty-logging.properties`, and `log4j.properties` ++ +The configuration files are put in the `${jetty.base}/resources/` +directory. +5. At this point you have your `mybase` configured so that the jetty +server itself will log using log4j, using the log4j configuration found +in `mybase/resources/log4j.properties` + +You can verify the server classpath by using the `start.jar + --list-config` command. + +In essence, Jetty is now configured to emit its own logging events to +slf4j, and slf4j itself is using the static log binder found in +slf4j-log4j12.jar. Making all Jetty + Slf4j + Log4j events emitted by +the Jetty server go to Log4j for routing (to console, file, syslog, +etc...) diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc new file mode 100644 index 00000000000..1b96f53dfa3 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc @@ -0,0 +1,109 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[example-logging-java-util-logging-native]] += Example: Logging with Java's java.util.logging via JavaUtilLog + +It is possible to have the Jetty Server logging configured so that +`java.util.logging` controls the output of logging events produced by +Jetty. + +This example demonstrates how to configuring Jetty for logging to +`java.util.logging` via Jetty's own JavaUtilLog implementation. + +____ +[IMPORTANT] +While this is a valid setup, the Jetty project recommends always using the link:#example-logging-java-util-logging[slf4j to java.util.logging configuration] for memory and performance reasons. +(this naive implementation is very non-performant and is not guaranteed to exist in the future) +____ + +A convenient replacement `logging` module has been created to bootstrap +your `${jetty.base}` directory for logging with java.util.logging. + +.... +[mybase]$ mkdir modules +[mybase]$ cd modules + +[modules]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-native/logging.mod + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 623 100 623 0 0 1879 0 --:--:-- --:--:-- --:--:-- 1876 +[modules]$ cd .. + +[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging +INFO: logging initialised in ${jetty.base}/start.ini (appended) +MKDIR: ${jetty.base}/logs +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-native/jetty-logging.xml to etc/jetty-logging.xml +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-native/logging.properties to resources/logging.properties +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-native/jetty-logging.properties to resources/jetty-logging.properties +INFO: resources initialised transitively +INFO: resources enabled in ${jetty.base}/${jetty.base} + +[mybase]$ java -jar /opt/jetty-dist/start.jar +.... + +The replacement `logging.mod` performs a number of tasks. + +1. `mybase` is a `${jetty.base}` directory +2. The jetty-distribution is unpacked (and untouched) into +`/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this +demonstration. +3. The `curl` command downloads the replacement `logging.mod` and puts +it into the `${jetty.base}/modules/` directory for use by mybase only. +4. The `start.jar --add-to-start=logging` command performs a number of +steps to make the logging module available to the `${jetty.base}` +configuration. +1. The `--module=logging` command is added to the +`${jetty.base}/start.ini` configuration +2. Required `${jetty.base}` directories are created: +`${jetty.base}/logs` and `${jetty.base}/resources` +3. Required configuration files are downloaded (if not present +already): `jetty-logging.properties`, and `logging.properties` ++ +The configuration files are put in the `${jetty.base}/resources/` +directory. +4. Required `java.util.logging` initialization commands are downloaded +(if not present already): `jetty-logging.xml` ++ +The xml file is put in the `${jetty.base}/etc/` directory. +5. At this point you have your `mybase` configured so that the jetty +server itself will log using java.util.logging, using the +java.util.logging configuration found in +`mybase/resources/logging.properties` + +You can verify the server classpath by using the `start.jar + --list-config` command. + +In essence, Jetty is now configured to use +`org.eclipse.jetty.util.log.JavaUtilLog`, which emit its own logging +events to java.util.logging. Making all Jetty + java.util.logging events +emitted by the Jetty server go to java.util.logging for routing (to +console, file, etc...) + +If you have any custom java.util.logging handlers that you want to use, +put the implementation jar in your `${jetty.base}/lib/logging/` +directory and reference them in the +`${jetty.base}/resources/logging.properties` file. + +____ +[NOTE] +`java.util.logging` is configured via the `${jetty.base}/resources/logging.properties` file during a valid startup of Jetty. +This means that if there is any startup errors that occur before `java.util.logging` is configured, they will likely be lost and/or not routed through your configuration. +(Other logging frameworks are more reliable in that they always initialize and configure on first use, unlike java.util.logging) ++ +While it is possible to configure java.util.logging sooner, even at JVM startup, the example demonstrated here does not show this technique. +For more information consult the http://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html[official java.util.logging.LogManager javadoc documentation from Oracle]. +____ \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc new file mode 100644 index 00000000000..b4fb5da1aa5 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc @@ -0,0 +1,112 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[example-logging-java-util-logging]] += Example: Logging with Java's java.util.logging via Slf4j + +It is possible to have the Jetty Server logging configured so that +`java.util.logging` controls the output of logging events produced by +Jetty. + +This example demonstrates how to configuring Jetty for logging to +`java.util.logging` via http://slf4j.org/manual.html[Slf4j] and the +http://slf4j.org/manual.html#swapping[Slf4j binding layer for +java.util.logging]. If you want to use the built-in native JavaUtilLog +implementation, see #example-logging-java-util-logging-native + +A convenient replacement `logging` module has been created to bootstrap +your `${jetty.base}` directory for logging with java.util.logging. + +.... +[mybase]$ mkdir modules +[mybase]$ cd modules + +[modules]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-slf4j/logging.mod + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 826 100 826 0 0 2468 0 --:--:-- --:--:-- --:--:-- 2473 +[modules]$ cd .. + +[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging +INFO: logging initialised in ${jetty.base}/start.ini (appended) +MKDIR: ${jetty.base}/logs +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-jdk14/1.6.6/slf4j-jdk14-1.6.6.jar to lib/logging/slf4j-jdk14-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-slf4j/jetty-logging.xml to etc/jetty-logging.xml +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-slf4j/logging.properties to resources/logging.properties +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-slf4j/jetty-logging.properties to resources/jetty-logging.properties +INFO: resources initialised transitively +INFO: resources enabled in ${jetty.base}/start.ini + +[mybase]$ java -jar /opt/jetty-dist/start.jar +.... + +The replacement `logging.mod` performs a number of tasks. + +1. `mybase` is a `${jetty.base}` directory +2. The jetty-distribution is unpacked (and untouched) into +`/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this +demonstration. +3. The `curl` command downloads the replacement `logging.mod` and puts +it into the `${jetty.base}/modules/` directory for use by mybase only. +4. The `start.jar --add-to-start=logging` command performs a number of +steps to make the logging module available to the `${jetty.base}` +configuration. +1. The `--module=logging` command is added to the +`${jetty.base}/start.ini` configuration +2. Required `${jetty.base}` directories are created: +`${jetty.base}/logs` and `${jetty.base}/resources` +3. Required libraries are downloaded (if not present already): +slf4j-api, and slf4j-jdk14. ++ +The libraries are put in the `${jetty.base}/lib/logging/` directory. +4. Required configuration files are downloaded (if not present +already): `jetty-logging.properties`, and `logging.properties` ++ +The configuration files are put in the `${jetty.base}/resources/` +directory. +5. Required `java.util.logging` initialization commands are downloaded +(if not present already): `jetty-logging.xml` ++ +The xml file is put in the `${jetty.base}/etc/` directory. +5. At this point you have your `mybase` configured so that the jetty +server itself will log using java.util.logging, using the +java.util.logging configuration found in +`mybase/resources/logging.properties` + +You can verify the server classpath by using the `start.jar + --list-config` command. + +In essence, Jetty is now configured to emit its own logging events to +slf4j, and slf4j itself is using the static log binder found in +slf4j-jdk14.jar. Making all Jetty + Slf4j + java.util.logging events +emitted by the Jetty server go to java.util.logging for routing (to +console, file, etc...) + +If you have any custom java.util.logging handlers that you want to use, +put the implementation jar in your `${jetty.base}/lib/logging/` +directory and reference them in the +`${jetty.base}/resources/logging.properties` file. + +____ +[NOTE] +`java.util.logging` is configured via the `${jetty.base}/resources/logging.properties` file during a valid startup of Jetty. +This means that if there is any startup errors that occur before `java.util.logging` is configured, they will likely be lost and/or not routed through your configuration. +(Other logging frameworks are more reliable in that they always initialize and configure on first use, unlike java.util.logging) ++ +While it is possible to configure java.util.logging sooner, even at JVM startup, the example demonstrated here does not show this technique. +For more information consult the http://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html[official java.util.logging.LogManager javadoc documentation from Oracle]. +____ \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc new file mode 100644 index 00000000000..e86cd1d3ee1 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc @@ -0,0 +1,166 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[example-logging-logback-centralized]] += Example: Centralized Logging with Logback + +The term _Centralized Logging_ refers to a forced logging configuration +for the Jetty Server and all web applications that are deployed on the +server. It routes all logging events from the web applications to a +single configuration on the Server side. + +The example below shows how to accomplish this with Jetty and Slf4j, +using Logback to manage the final writing of logs to disk. + +____ +[IMPORTANT] +This mechanism forces all webapps to use the server's configuration for logging, something that isn't 100% appropriate for all webapps. ++ +An example would be having Jenkins-CI deployed as an webapp, if you force its logging configuration to the server side, you lose the ability on http://jenkins-ci.org/[Jenkins-CI] to see the logs from the various builds (as now those logs are actually going to the main server log). +____ + +This configuration is essentially the multiple logger configuration with +added configuration to the deployers to force a WebAppClassLoader change +to use the server classpath over the webapps classpath for the logger +specific classes. + +The technique used by this configuration is to provide an +link:{JDURL}org/eclipse/jetty/deploy/AppLifeCycle.Binding.html[AppLifeCycle.Binding] +against the +link:{JDURL}/org/eclipse/jetty/deploy/AppLifeCycle.html[`"deploying"` +node] that modifies the +link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#addSystemClass(java.lang.String)[WebAppContext.addSystemClass(String)] +for the common logging classes. (See +https://github.com/jetty-project/jetty-webapp-logging/blob/master/src/main/java/org/eclipse/jetty/webapp/logging/CentralizedWebAppLoggingBinding.java[org.eclipse.jetty.logging.CentralizedWebAppLoggingBinding] +for actual implementation) + +A convenient replacement `logging` module has been created to bootstrap +your `${jetty.base}` directory for capturing all Jetty server logging +from multiple logging frameworks into a single logging output file +managed by logback. + +.... +[mybase]$ mkdir modules +[mybase]$ cd modules + +[modules]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/logging.mod + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 1416 100 1416 0 0 4241 0 --:--:-- --:--:-- --:--:-- 4252 + +[master]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/centralized/webapp-logging.mod + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 660 100 660 0 0 2032 0 --:--:-- --:--:-- --:--:-- 2037 +[modules]$ cd .. + +[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging,webapp-logging +INFO: logging initialised in ${jetty.base}/start.ini (appended) +MKDIR: ${jetty.base}/logs +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.6.6/log4j-over-slf4j-1.6.6.jar to lib/logging/log4j-over-slf4j-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/jul-to-slf4j/1.6.6/jul-to-slf4j-1.6.6.jar to lib/logging/jul-to-slf4j-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar to lib/logging/jcl-over-slf4j-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar +DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/logback.xml to resources/logback.xml +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.properties to resources/jetty-logging.properties +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.xml to etc/jetty-logging.xml +INFO: resources initialised transitively +INFO: resources enabled in ${jetty.base}/start.ini +INFO: webapp-logging initialised in ${jetty.base}/start.ini (appended) +DOWNLOAD: http://central.maven.org/maven2/org/eclipse/jetty/jetty-webapp-logging/9.0.0/jetty-webapp-logging-9.0.0.jar to lib/webapp-logging/jetty-webapp-logging-9.0.0.jar +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/jetty-webapp-logging/master/src/main/config/etc/jetty-webapp-logging.xml to etc/jetty-webapp-logging.xml +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/jetty-webapp-logging/master/src/main/config/etc/jetty-mdc-handler.xml to etc/jetty-mdc-handler.xml +INFO: deploy initialised transitively +INFO: deploy enabled in ${jetty.base}/start.ini +INFO: logging initialised transitively +INFO: resources initialised transitively +INFO: resources enabled in ${jetty.base}/start.ini + +[mybase]$ java -jar /opt/jetty-dist/start.jar +.... + +The replacement `logging.mod` performs a number of tasks. + +1. `mybase` is a `${jetty.base}` directory +2. The jetty-distribution is unpacked (and untouched) into +`/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this +demonstration. +3. The `curl` command downloads the replacement `logging.mod` and puts +it into the `${jetty.base}/modules/` directory for use by mybase only. +4. The `start.jar + --add-to-start=logging,webapp-logging` command performs a number +of steps to make the logging module available to the `${jetty.base}` +configuration. +1. Several entries are added to the `${jetty.base}/start.ini` +configuration +1. `--module=logging` is added to enable the logging module +2. `--module=webapp-logging` is added to enable the webapp-logging +module +2. Required `${jetty.base}` directories are created: +`${jetty.base}/logs` and `${jetty.base}/resources` +3. Required logging libraries are downloaded (if not present already): +* slf4j-api.jar - API jar for Slf4j (used by most of the rest of the +jars) +* log4j-over-slf4j.jar - Slf4j jar that captures all log4j emitted +logging events +* jul-to-slf4j.jar - Slf4j jar that captures all java.util.logging +events +* jcl-over-slf4j.jar - Slf4j jar that captures all commons-logging +events +* logback-classic.jar - the Slf4j adapter jar that routes all of the +captured logging events to logback itself. +* logback-core.jar - the logback implementation jar, that handles all of +the filtering and output of the logging events. ++ +These libraries are put in the `${jetty.base}/lib/logging/` directory. +4. Required webapp-logging library are downloaded (if not present +already): +* jetty-webapp-logging.jar - the jetty side deployment manger +app-lifecycle bindings for modifying the WebAppClassloaders of deployed +webapps. ++ +This library is put in the `${jetty.base}/lib/webapp-logging/` +directory. +5. Required configuration files are downloaded (if not present +already): `jetty-logging.properties`, and `logback.xml` ++ +The configuration files are put in the `${jetty.base}/resources/` +directory. +6. Required initialization commands are downloaded (if not present +already): `jetty-logging.xml`, `jetty-webapp-logging.xml`, and +`jetty-mdc-handler.xml` ++ +These xml files are put in the `${jetty.base}/etc/` directory. +5. At this point you have your `mybase` configured so that the jetty +server itself will log using slf4j, and all other logging events from +other Jetty Server components (such as database drivers, security +layers, jsp, mail, and other 3rd party server components) are routed to +logback for filtering and output. ++ +All webapps deployed via the DeploymentManager have their +WebAppClassLoader modified to use server side classes and configuration +for all logging implementations. + +You can verify the server classpath by using the `start.jar + --list-config` command. + +In essence, Jetty is now configured to emit its own logging events to +slf4j, and various slf4j bridge jars are acting on behalf of log4j, +java.util.logging, and commons-logging, routing all of the logging +events to logback (a slf4j adapter) for routing (to console, file, +etc...) diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-sifting.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-sifting.adoc new file mode 100644 index 00000000000..480c82e6854 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-sifting.adoc @@ -0,0 +1,48 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[example-logging-logback-sifting]] += Example: MDC Based Sifting of Logs with Logback + +This page describes how to create log files at the server level and name +them based on an arbitrary context. You do this with SLF4J + Logback + +Jetty Webapp Logging in the mix. Find example projects for this feature +at github: + +.... +https://github.com/jetty-project/jetty-and-logback-example +.... + +.GitHub Example Project +[cols=",",options="header",] +|======================================================================= +|Modules |Description +|/jetty-distro-with-logback-basic/ |Configures the jetty distribution +with logback enabled at the server level with an example logback +configuration. + +|/jetty-distro-with-logback-sifting/ |Configures the jetty distribution +with logback, centralized webapp logging, an MDC handler, and a sample +logback configuration that performs sifting based on the incoming Host +header on the requests. + +|/jetty-slf4j-mdc-handler/ |Provides the SLF4J MDC key/value pairs that +Jetty needs to perform the sample sifting. + +|/jetty-slf4j-test-webapp/ |A sample webapp+servlet that accepts +arbitrary values on a form POST and logs them via SLF4J, so that you can +see the results of this example. +|======================================================================= diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc new file mode 100644 index 00000000000..bb896837da5 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc @@ -0,0 +1,86 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[example-logging-logback]] += Example: Logging with Logback + +It is possible to have the Jetty Server logging configured so that +Logback controls the output of logging events produced by Jetty. This is +accomplished by configuring Jetty for logging to `Logback`, which uses +http://slf4j.org/manual.html[Slf4j] and the +http://logback.qos.ch/[Logback Implementation for Slf4j]. + +A convenient replacement `logging` module has been created to bootstrap +your `${jetty.base}` directory for logging with logback. + +.... +[mybase]$ mkdir modules +[mybase]$ cd modules + +[modules]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/logging.mod + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 742 100 742 0 0 2196 0 --:--:-- --:--:-- --:--:-- 2201 +[modules]$ cd .. + +[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging +INFO: logging initialised in ${jetty.base}/start.ini (appended) +MKDIR: ${jetty.base}/logs +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar +DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/logback.xml to resources/logback.xml +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/jetty-logging.properties to resources/jetty-logging.properties + +[mybase]$ java -jar /opt/jetty-dist/start.jar +.... + +The replacement `logging.mod` performs a number of tasks. + +1. `mybase` is a `${jetty.base}` directory +2. The jetty-distribution is unpacked (and untouched) into +`/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this +demonstration. +3. The `curl` command downloads the replacement `logging.mod` and puts +it into the `${jetty.base}/modules/` directory for use by mybase only. +4. The `start.jar --add-to-start=logging` command performs a number of +steps to make the logging module available to the `${jetty.base}` +configuration. +1. The `--module=logging` command is added to the +`${jetty.base}/start.ini` configuration +2. Required `${jetty.base}` directories are created: +`${jetty.base}/logs` and `${jetty.base}/resources` +3. Required libraries are downloaded (if not present already): +slf4j-api, logback-core, and logback-classic. ++ +The libraries are put in the `${jetty.base}/lib/logging/` directory. +4. Required configuration files are downloaded (if not present +already): `jetty-logging.properties`, and `logback.xml` ++ +The configuration files are put in the `${jetty.base}/resources/` +directory. +5. At this point you have your `mybase` configured so that the jetty +server itself will log using logback, using the logback configuration +found in `mybase/resources/logback.xml` + +You can verify the server classpath by using the `start.jar + --list-config` command. + +In essence, Jetty is now configured to emit its own logging events to +slf4j, and slf4j itself is using the static log binder found in +logback-classic.jar. Making all Jetty + Slf4j + Logback events emitted +by the Jetty server go to Logback for routing (to console, file, syslog, +etc...) diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc new file mode 100644 index 00000000000..6bf8ab85b36 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc @@ -0,0 +1,200 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[example-slf4j-multiple-loggers]] += Example: Capturing Multiple Logging Frameworks with Slf4j + +This page describes how to configure Jetty for capturing multiple +logging frameworks logging events into a single logging implementation +handled by Slf4j. + +When using Slf4j, you can configure a single logging solution for the +variety of logging libraries available in common use. With careful +setup, you can support all of the following logging APIs at the same +time, with a single configuration file to control the output of events +produces by these APIs. + +Logging APIs that Slf4j supports: + +* Slf4j API +* Logback API +* Apache Log4j 1.2 +* JDK 1.4 Logging (aka `java.util.logging`) +* Apache Commons Logging + +To accomplish this you must make some careful choices, starting with a +single underlying logging framework. This decision guides the rest of +your choices about JARs to place on the Server classpath. + +.Slf4j Logging Grid +[width="100%",cols="25%,25%,25%,25%",options="header",] +|======================================================================= +|Logging API |Slf4j Binding Jar |Slf4j Adapter Jar |Underlying Logging +Framework +|Logback API |n/a |logback-classic.jar |logback-core.jar + +|Log4j +|http://slf4j.org/legacy.html#log4j-over-slf4j[log4j-over-slf4j.jar] +|slf4j-log4j12.jar |log4j.jar + +|JDK 1.4 Logging +|http://slf4j.org/legacy.html#jul-to-slf4j[jul-to-slf4j.jar] +|slf4j-jdk14.jar |(Core Java Classlib) + +|Commons Logging +|http://slf4j.org/legacy.html#jcl-over-slf4j[jcl-over-slf4j.jar] +|slf4j-jcl.jar |commons-logging.jar +|======================================================================= + +Logging API:: + The Logging API that you are either capturing events from and/or using + to write out those events (for example, to disk). +Slf4j Binding JAR:: + Special JARs, created and maintained by the Slf4j project, that + pretend to be the various Logging API implementation classes, but + instead just route that Logging API's events to Slf4j to handle. + + + There MAY be multiple Slf4j binding JARs present on the classpath at + the same time. + + + For a single logging API, if you choose to use the Slf4j binding JAR, + then you MUST NOT include the SLf4j adapter JAR or underlying logging + framework in the classpath as well. +Slf4j Adapter Jar:: + These JARs are created and maintained by the Slf4j project and route + Slf4j logging events to a specific underlying logging framework. + + + There MUST NOT be multiple Slf4j adapter JARs present on the classpath + at the same time. + + + Logging events that these adapter JARs capture can come from direct + use of the Slf4j API or via one of the Slf4j binding JAR + implementations. +Underlying Logging Framework:: + This is the last leg of your configuration, the implementation that + processes, filters, and outputs the logging events to the console, + logging directory on disk, or whatever else the underlying logging + framework supports (like Socket, SMTP, Database, or even SysLog in the + case of Logback). + + + ____ + [CAUTION] + There MUST NOT be multiple underlying logging frameworks on the classpath. + If there are, the Slf4j framework fails to load. + ____ ++ + ____ + [NOTE] + Some third party libraries provide their own implementations of common logging APIs; be careful not to accidentally include an underlying logging framework. ++ + For example, if you are using SpringSource you likely have a `com.springsource.org.apache.log4j.jar` along with a `log4j.jar`, which have the same classes in them. + In this example, use the `com.springsource.org.apache.log4j.jar` version and exclude the `log4j.jar`, as the SpringSource version includes extra metadata suitable for using SpringSource. + ____ + +The following sections use Logback as the underlying Logging framework. +This requires using `logback-classic.jar` and `logback-core.jar`, and +excluding any other Slf4j adapter JAR or underlying logging framework. + +It also requires including the other Slf4j binding JARs in the +classpath, along with some special initialization for +`java.util.logging`. + +A convenient replacement `logging` module has been created to bootstrap +your `${jetty.base}` directory for capturing all Jetty server logging +from multiple logging frameworks into a single logging output file +managed by logback. + +.... +[mybase]$ mkdir modules +[mybase]$ cd modules + +[modules]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/logging.mod + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 1293 100 1293 0 0 3693 0 --:--:-- --:--:-- --:--:-- 3694 +[modules]$ cd .. + +[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging +INFO: logging initialised in ${jetty.base}/start.ini (appended) +MKDIR: ${jetty.base}/logs +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.6.6/log4j-over-slf4j-1.6.6.jar to lib/logging/log4j-over-slf4j-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/jul-to-slf4j/1.6.6/jul-to-slf4j-1.6.6.jar to lib/logging/jul-to-slf4j-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar to lib/logging/jcl-over-slf4j-1.6.6.jar +DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar +DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/logback.xml to resources/logback.xml +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.properties to resources/jetty-logging.properties +DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.xml to etc/jetty-logging.xml +INFO: resources initialised transitively +INFO: resources enabled in ${jetty.base}/start.ini + +[mybase]$ java -jar /opt/jetty-dist/start.jar +.... + +The replacement `logging.mod` performs a number of tasks. + +1. `mybase` is a `${jetty.base}` directory +2. The jetty-distribution is unpacked (and untouched) into +`/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this +demonstration. +3. The `curl` command downloads the replacement `logging.mod` and puts +it into the `${jetty.base}/modules/` directory for use by mybase only. +4. The `start.jar --add-to-start=logging` command performs a number of +steps to make the logging module available to the `${jetty.base}` +configuration. +1. The `--module=logging` command is added to the +`${jetty.base}/start.ini` configuration +2. Required `${jetty.base}` directories are created: +`${jetty.base}/logs` and `${jetty.base}/resources` +3. Required libraries are downloaded (if not present already): +* slf4j-api.jar - API jar for Slf4j (used by most of the rest of the +jars) +* log4j-over-slf4j.jar - Slf4j jar that captures all log4j emitted +logging events +* jul-to-slf4j.jar - Slf4j jar that captures all java.util.logging +events +* jcl-over-slf4j.jar - Slf4j jar that captures all commons-logging +events +* logback-classic.jar - the Slf4j adapter jar that routes all of the +captured logging events to logback itself. +* logback-core.jar - the logback implementation jar, that handles all of +the filtering and output of the logging events. ++ +These libraries are put in the `${jetty.base}/lib/logging/` directory. +4. Required configuration files are downloaded (if not present +already): `jetty-logging.properties`, and `logback.xml` ++ +The configuration files are put in the `${jetty.base}/resources/` +directory. +5. Required `java.util.logging` initialization commands are downloaded +(if not present already): `jetty-logging.xml` ++ +The xml file is put in the `${jetty.base}/etc/` directory. +5. At this point you have your `mybase` configured so that the jetty +server itself will log using slf4j, and all other logging events from +other Jetty Server components (such as database drivers, security +layers, jsp, mail, and other 3rd party server components) are routed to +logback for filtering and output. + +You can verify the server classpath by using the `start.jar + --list-config` command. + +In essence, Jetty is now configured to emit its own logging events to +slf4j, and various slf4j bridge jars are acting on behalf of log4j, +java.util.logging, and commons-logging, routing all of the logging +events to logback (a slf4j adapter) for routing (to console, file, +etc...) diff --git a/jetty-documentation/src/main/asciidoc/administration/npn/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/npn/chapter.adoc new file mode 100644 index 00000000000..96c882bf847 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/npn/chapter.adoc @@ -0,0 +1,18 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[npn-chapter]] +== NPN diff --git a/jetty-documentation/src/main/asciidoc/administration/npn/npn.adoc b/jetty-documentation/src/main/asciidoc/administration/npn/npn.adoc new file mode 100644 index 00000000000..4f943632954 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/npn/npn.adoc @@ -0,0 +1,303 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +How to build NPN +================ + +[[npn]] += + +[[npn-introduction]] +== Configuring NPN + +The Jetty project provides an implementation of the Transport Layer +Security (TLS) extension for Next Protocol Negotiation (NPN) for OpenJDK +7 (but not for OpenJDK 8 or greater - see xref:alpn-chapter[] for +using a TLS protocol negotiation extension with OpenJDK 8 or greater). +NPN allows the application layer to negotiate which protocol to use over +the secure connection. + +NPN currently negotiates using SPDY as an application level protocol on +port 443, and also negotiates the SPDY version. However, NPN is not +SPDY-specific in any way. Jetty's NPN implementation, although hosted +under the umbrella of the Jetty project, is independent of Jetty (the +servlet container); you can use it in any other Java network server. + +[[npn-starting]] +== Starting the JVM + +To enable NPN support, start the JVM as follows: + +[source,plain] +---- +java -Xbootclasspath/p: ... +---- + +where `path_to_npn_boot_jar` is the path on the file system for the NPN +Boot Jar file, for example, one at the Maven coordinates +org.mortbay.jetty.npn:npn-boot. + +Be aware that the current versions of the npn packages no longer align +with Jetty versions. Look at the dates in those file paths before +looking at the version number. + +[[npn-osgi]] +=== Starting in OSGi + +To use NPN in an OSGi environment, in addition to putting the NPN jar on +the boot classpath for the container, you will also need to deploy the +jetty-osgi-npn jar. This jar contains a Fragment-Host directive that +ensures the NPN classes will be available from the system bundle. + +You can download the jetty-osgi-npn jar from maven central: +http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-npn/ + +[[npn-understanding]] +== Understanding the NPN API + +Applications need to interact with NPN TLS extension protocol +negotiations. For example, server applications need to know whether the +client supports NPN, and client applications needs to know the list of +protocols the server supports, and so on. + +To implement this interaction, Jetty's NPN implementation provides an +API to applications, hosted at Maven coordinates +org.eclipse.jetty.npn:npn-api. You need to declare this dependency as +provided, because the npn-boot Jar already includes it (see the previous +section), and it is therefore available in the boot classpath. + +The API consists of a single class, +`org.eclipse.jetty.npn.NextProtoNego`, and applications need to register +instances of SSLSocket or SSLEngine with a ClientProvider or +ServerProvider (depending on whether the application is a client or +server application). Refer to NextProtoNego Javadocs and to the examples +below for further details about client and server provider methods. + +[[client-example]] +== Client Example + +[source,java] +---- +SSLContext sslContext = ...; +final SSLSocket sslSocket = (SSLSocket)context.getSocketFactory().createSocket("localhost", server.getLocalPort()); + +NextProtoNego.put(sslSocket, new NextProtoNego.ClientProvider() +{ + @Override + public boolean supports() + { + return true; + } + + @Override + public void unsupported() + { + NextProtoNego.remove(sslSocket); + } + + @Override + public String selectProtocol(List protocols) + { + NextProtoNego.remove(sslSocket); + return protocols.get(0); + } +}); +---- + +The NPN implementation calls `NextProtoNego.ClientProvider` methods +`supports()`, `unsupported()` and `selectProtocol(List)`, so +that the client application can: + +* decide whether to support NPN. +* know whether the server supports NPN. +* select one of the protocols the server supports. + +[[server-example]] +== Server Example + +The example for SSLEngine is identical, and you just need to replace the +SSLSocket instance with an SSLEngine instance. + +[source,java] +---- +final SSLSocket sslSocket = ...; +NextProtoNego.put(sslSocket, new NextProtoNego.ServerProvider() +{ + @Override + public void unsupported() + { + NextProtoNego.remove(sslSocket); + } + + @Override + public List protocols() + { + return Arrays.asList("http/1.1"); + } + + @Override + public void protocolSelected(String protocol) + { + NextProtoNego.remove(sslSocket); + System.out.println("Protocol Selected is: " + protocol); + } +}); +---- + +The NPN implementation calls `NextProtoNego.ServerProvider` methods +`unsupported()`, `protocols()` and `protocolSelected(String),` so that +the server application can: + +* know whether the client supports NPN. +* provide the list of protocols the server supports. +* know which protocol the client chooses. + +[[npn-implementation]] +== Implementation Details + +It is common that the NextProtoNego.ServerProvider and the +NextProtoNego.ClientProvider are implemented as (anonymous) inner +classes, and that their methods' implementations require references to +the the sslSocket (or sslEngine), either directly or indirectly. + +Since the NextProtoNego class holds [sslSocket/sslEngine, provider] +pairs in a `WeakHashMap`, if the value (that is, the provider +implementation) holds a strong (even indirect) reference to the key, +then the `WeakHashMap` entries are never removed, leading to a memory +leak. + +It is important that implementations of `NextProtoNego.ServerProvider` +and `NextProtoNego.ClientProvider` remove the `sslSocket` or `sslEngine` +when the negotiation is complete, like shown in the examples above. + +Be aware that declaring the SslConnection as a final local variable and +referencing it from within the anonymous NextProtoNego.ServerProvider +class generates a hidden field in the anonymous inner class, that may +cause a memory leak if the implementation does not call +`NextProtoNego.remove()`. + +[[npn-tests]] +== Unit Tests + +You can write and run unit tests that use the NPN implementation. The +solution that we use with Maven is to specify an additional command line +argument to the Surefire plugin: + +[source,xml] +---- + + + + 1.1.1.v20121030 + + + + + + maven-surefire-plugin + + + -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn-version}/npn-boot-${npn-version}.jar + + + + + ... + + + + +... + + +---- + +[[npn-debugging]] +== Debugging + +You can enable debug logging for the NPN implementation in this way: + +.... +NextProtoNego.debug = true; +.... + +Since the NextProtoNego class is in the boot classpath, we chose not to +use logging libraries because we do not want to override application +logging library choices; therefore the logging is performed directly on +`System.err.` + +[[npn-license-details]] +== License Details + +The NPN implementation relies on modification of a few OpenJDK classes +and on a few new classes that need to live in the `sun.security.ssl` +package. These classes are released under the same GPLv2+exception +license of OpenJDK. + +The NextProtoNego class is released under same license as the classes of +the Jetty project. + +[[npn-versions]] +== Versions + +The NPN implementation, relying on modifications of OpenJDK classes, +updates every time there are updates to the modified OpenJDK classes. + +.NPN vs. OpenJDK versions +[cols=",",options="header",] +|========================================================== +|NPN version |OpenJDK version +|1.0.0.v20120402 |1.7.0 - 1.7.0u2 - 1.7.0u3 +|1.1.0.v20120525 |1.7.0u4 - 1.7.0u5 +|1.1.1.v20121030 |1.7.0u6 - 1.7.0u7 +|1.1.3.v20130313 |1.7.0u9 - 1.7.0u10 - 1.7.0u11 +|1.1.4.v20130313 |1.7.0u13 +|1.1.5.v20130313 |1.7.0u15 - 1.7.0u17 - 1.7.0u21 - 1.7.0u25 +|1.1.6.v20130911 |1.7.0u40 - 1.7.0u45 - 1.7.0u51 +|1.1.8.v20141013 |1.7.0u55 - 1.7.0u60 - 1.7.0u65 - 1.7.0u67 +|1.1.9.v20141016 |1.7.0u71 - 1.7.0u72 +|1.1.10.v20150130 |1.7.0u75 - 1.7.0u76 - 1.7.0u79 +|1.1.11.v20150415 |1.7.0u80 +|========================================================== + +[[npn-build]] +== How to build NPN + +This section is for Jetty developers that need to update the NPN +implementation with the OpenJDK versions. + +Clone the OpenJDK repository with the following command: + +.... +$ hg clone http://hg.openjdk.java.net/jdk7u/jdk7u jdk7u +$ cd jdk7u +$ ./get_source.sh + +.... + +To update the source to a specific tag, use the following command: + +.... +$ ./make/scripts/hgforest.sh update + +.... + +The list of OpenJDK tags can be obtained from +http://hg.openjdk.java.net/jdk7u/jdk7u/tags[this page]. + +Then you need to compare and incorporate the OpenJDK source changes into +the modified OpenJDK classes at the +https://github.com/jetty-project/jetty-npn[NPN GitHub Repository]. diff --git a/jetty-documentation/src/main/asciidoc/administration/part.adoc b/jetty-documentation/src/main/asciidoc/administration/part.adoc new file mode 100644 index 00000000000..2b457b3d901 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/part.adoc @@ -0,0 +1,30 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + += Jetty Administration Guide + +include::startup/chapter.adoc[] +include::sessions/chapter.adoc[] +include::jndi/chapter.adoc[] +include::annotations/chapter.adoc[] +include::jmx/chapter.adoc[] +include::alpn/chapter.adoc[] +include::http2/chapter.adoc[] +include::fastcgi/chapter.adoc[] +include::extras/chapter.adoc[] +include::runner/chapter.adoc[] +include::tuning/chapter.adoc[] +include::logging/chapter.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/runner/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/runner/chapter.adoc new file mode 100644 index 00000000000..794a257a99a --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/runner/chapter.adoc @@ -0,0 +1,22 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[runner]] +== Jetty Runner + +This chapter explains how to use the jetty-runner to run your webapps without needing an installation of jetty. + +include::jetty-runner.adoc[] \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc b/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc new file mode 100644 index 00000000000..c9902684363 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc @@ -0,0 +1,322 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[jetty-runner]] +=== Use Jetty without an installed distribution + +The idea of the jetty-runner is extremely simple – run a webapp directly from the command line using a single jar and as much default configuration as possible. +Of course, if your webapp is not so straightforward, the jetty-runner has command line options which allow +you to customize the execution environment. + +[[jetty-runner-preparation]] +==== Preparation + +You will need the jetty-runner jar: + +1. http://central.maven.org/maven2/org/eclipse/jetty/jetty-runner/[Get] the jetty-runner jar, from http://search.maven.org/#browse[maven central] + +==== Deploying a simple context + +Let's assume we have a very simple webapp, that does not need any resources from its environment, nor any configuration apart from the defaults. +Starting it is as simple as doing the following: + +.... +> java -jar jetty-runner.jar simple.war +.... + +This will start jetty on port 8080, and deploy the webapp to "/". + +Your webapp does not have to be packed into a war, you can deploy a webapp that is a directory instead in the same way: + +.... +> java -jar jetty-runner.jar simple +.... + +In fact, the webapp does not have to be a war or even a directory, it can simply be a jetty link:#using-context-provider[context xml] file that describes your webapp: + +.... +> java -jar jetty-runner.jar simple-context.xml +.... + +____ +[NOTE] +When using a context xml file, the application being deployed is not even required to be a fully-fledged webapp. It can simply be a Jetty link:#what-is-a-context[context]. +____ + +==== Deploying multiple contexts + +If you have more than one webapp that must be deployed, simply provide them all on the command line. +You can control the context paths for them using the "--path" parameter. +Here's an example of deploying 2 wars (although either or both of them could be unpacked directories instead): + +.... +> java -jar jetty-runner.jar --path /one my1.war --path /two my2.war +.... + +If you have context xml files that describe your webapps, you can fully configure your webapps in them, and hence you don't need to use the command line switches. +Just provide the list of context files like so: + +.... +> java -jar jetty-runner.jar my-first-context.xml my-second-context.xml my-third-context.xml + +.... + +____ +[NOTE] +The command line switches override configuration file settings. So, for example, you could set the context path for the webapp inside the context xml file, and use the --path switch to override it on the command line. +____ + + +===== Changing the default port + +By default the jetty-runner will listen on port 8080. +You can easily change this on the command line using the "--port" command. +Here's an example that runs our simple.war on port 9090: + +.... +> java -jar jetty-runner.jar --port 9090 simple.war +.... + +===== Using jetty.xml files + +Instead of, or in addition to using command line switches, you can use one or more jetty.xml files to configure the environment for your webapps. +Here's an example where we apply two different jetty.xml files: + +.... +> java -jar jetty-runner.jar --config jetty.xml --config jetty-https.xml simple.war +.... + +____ +[NOTE] +Switches on the command line take precedence over those defined in configuration files, so you can use the command line as overrides. +____ + +===== Full configuration reference + +You can see the fill set of configuration options using the --help switch: + +.... +> java -jar jetty-runner.jar --help +.... + +Here's what the output will look like: + +[source,plain] +---- + +Usage: java [-Djetty.home=dir] -jar jetty-runner.jar [--help|--version] [ server opts] [[ context opts] context ...] +Server opts: + --version - display version and exit + --log file - request log filename (with optional 'yyyy_mm_dd' wildcard + --out file - info/warn/debug log filename (with optional 'yyyy_mm_dd' wildcard + --host name|ip - interface to listen on (default is all interfaces) + --port n - port to listen on (default 8080) + --stop-port n - port to listen for stop command + --stop-key n - security string for stop command (required if --stop-port is present) + [--jar file]*n - each tuple specifies an extra jar to be added to the classloader + [--lib dir]*n - each tuple specifies an extra directory of jars to be added to the classloader + [--classes dir]*n - each tuple specifies an extra directory of classes to be added to the classloader + --stats [unsecure|realm.properties] - enable stats gathering servlet context + [--config file]*n - each tuple specifies the name of a jetty xml config file to apply (in the order defined) +Context opts: + [[--path /path] context]*n - WAR file, web app dir or context xml file, optionally with a context path + +---- + +Printing the version::: + Print out the version of jetty and then exit immediately. ++ +.... +> java -jar jetty-runner.jar --version + +.... + +Configuring a request log::: + Cause jetty to write a request log with the given name. + If the file is prefixed with yyyy_mm_dd then the file will be automatically rolled over. + Note that for finer grained configuration of the link:{JDURL}/org/eclipse/jetty/server/NCSARequestLog.html[request log], you will need to use a jetty xml file instead. ++ +.... +> java -jar jetty-runner.jar --log yyyy_mm_dd-requests.log my.war + +.... + +Configuring the output log::: + Redirect the output of jetty logging to the named file. + If the file is prefixed with yyyy_mm_dd then the file will be automatically rolled over. ++ +.... +> java -jar jetty-runner.jar --out yyyy_mm_dd-output.log my.war + +.... + +Configuring the interface for http::: + Like jetty standalone, the default is for the connectors to listen on all interfaces on a machine. + You can control that by specifying the name or ip address of the particular interface you wish to use with the --host argument: ++ +.... +> java -jar jetty-runner.jar --host 192.168.22.19 my.war + +.... + +Configuring the port for http::: + The default port number is 8080. + To link:#how-to-configure-connectors[configure a https connector], use a jetty xml config file instead. ++ +.... +> java -jar jetty-runner.jar --port 9090 my.war + +.... + +Configuring stop::: + You can configure a port number for jetty to listen on for a stop command, so you are able to stop it from a different terminal. + This requires the use of a "secret" key, to prevent malicious or accidental termination. + Use the --stop-port and --stop-key parameters as arguments to the jetty-runner: ++ +.... +> java -jar jetty-runner.jar --stop-port 8181 --stop-key abc123 + +.... ++ +Then, to stop jetty from a different terminal, you need to supply the same port and key information. +For this you'll either need a local installation of jetty, the link:#jetty-maven-plugin[jetty-maven-plugin], the link:#jetty-ant[jetty-ant plugin], or write a custom class. +Here's how to use a jetty installation to perform a stop: ++ +.... +> java -jar start.jar --stop-port 8181 --stop-key abc123 --stop + +.... + +Configuring the container classpath::: + With a local installation of jetty, you add jars and classes to the container's classpath by putting them in the $JETTY_HOME/lib directory. + With the jetty-runner, you can use the --lib, --jar and --classes arguments instead to achieve the same thing. ++ +--lib adds the location of a directory which contains jars to add to the container classpath. +You can add 1 or more. Here's an example of configuring 2 directories: ++ +.... +> java -jar jetty-runner.jar --lib /usr/local/external/lib --lib $HOME/external-other/lib my.war + +.... ++ +--jar adds a single jar file to the container classpath. +You can add 1 or more. +Here's an example of configuring 3 extra jars: ++ +.... +> java -jar jetty-runner.jar --jar /opt/stuff/jars/jar1.jar --jar $HOME/jars/jar2.jar --jar /usr/local/proj/jars/jar3.jar my.war + +.... ++ +--classes add the location of a directory containing classes to add to the container classpath. +You can add 1 or more. +Here's an example of configuring a single extra classes dir: ++ +.... +> java -jar jetty-runner.jar --classes /opt/stuff/classes my.war + +.... + +Gathering statistics::: + If statistics gathering is enabled, then they are viewable by surfing + to the context /stats. You may optionally protect access to that + context with a password. Here's an example of enabling statistics, + with no password protection: ++ +.... +> java -jar jetty-runner.jar --stats unsecure my.war + +.... ++ +If we wished to protect access to the /stats context, we would provide the location of a jetty realm configuration file containing authentication and authorization information. +For example, we could use the following example realm file from the jetty distribution: ++ +.... +jetty: MD5:164c88b302622e17050af52c89945d44,user +admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin +other: OBF:1xmk1w261u9r1w1c1xmq,user +plain: plain,user +user: password,user +# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password +digest: MD5:6e120743ad67abfbc385bc2bb754e297,user + +.... ++ +Assuming we've copied it into the local directory, we would apply it like so ++ +.... +> java -jar jetty-runner.jar --stats realm.properties my.war + +.... ++ +After surfing to http://localhost:8080/ a few times, we can surf to the stats servlet on http://localhost:8080/stats to see the output: ++ +.... +Statistics: +Statistics gathering started 1490627ms ago + +Requests: +Total requests: 9 +Active requests: 1 +Max active requests: 1 +Total requests time: 63 +Mean request time: 7.875 +Max request time: 26 +Request time standard deviation: 8.349764752888037 + + +Dispatches: +Total dispatched: 9 +Active dispatched: 1 +Max active dispatched: 1 +Total dispatched time: 63 +Mean dispatched time: 7.875 +Max dispatched time: 26 +Dispatched time standard deviation: 8.349764752888037 +Total requests suspended: 0 +Total requests expired: 0 +Total requests resumed: 0 + + +Responses: +1xx responses: 0 +2xx responses: 7 +3xx responses: 1 +4xx responses: 0 +5xx responses: 0 +Bytes sent total: 1453 + + +Connections: +org.eclipse.jetty.server.ServerConnector@203822411 +Protocols:http/1.1 +Statistics gathering started 1490606ms ago +Total connections: 7 +Current connections open: 1 +Max concurrent connections open: 2 +Total connections duration: 72883 +Mean connection duration: 12147.166666666666 +Max connection duration: 65591 +Connection duration standard deviation: 23912.40292977684 +Total messages in: 7 +Total messages out: 7 + + +Memory: +Heap memory usage: 49194840 bytes +Non-heap memory usage: 12611696 bytes +.... + diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc new file mode 100644 index 00000000000..dcf732b7f03 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc @@ -0,0 +1,25 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[session-management]] +== Session Management + +include::setting-session-characteristics.adoc[] +include::using-persistent-sessions.adoc[] +include::session-clustering-jdbc.adoc[] +include::session-clustering-mongodb.adoc[] +include::session-clustering-infinispan.adoc[] +include::session-clustering-gcloud-datastore.adoc[] \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-gcloud-datastore.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-gcloud-datastore.adoc new file mode 100644 index 00000000000..a6175fd5cdb --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-gcloud-datastore.adoc @@ -0,0 +1,219 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[session-clustering-gcloud-datastore]] +=== Session Clustering with Google Cloud Datastore + +Jetty can support session clustering by persisting sessions to +https://cloud.google.com/datastore/docs/concepts/overview[Google Cloud +Datastore]. Each Jetty instance locally caches sessions for which it has +received requests, writing any changes to the session through to the +Datastore as the request exits the server. Sessions must obey the +Serialization contract, and servlets must call the +Session.setAttribute() method to ensure that changes are persisted. + +The persistent session mechanism works in conjunction with a load +balancer that supports stickiness. Stickiness can be based on various +data items, such as source IP address or characteristics of the session +ID or a load-balancer specific mechanism. For those load balancers that +examine the session ID, the Jetty persistent session mechanism appends a +node ID to the session ID, which can be used for routing. + +==== Configuration + +There are two components to session management in Jetty: a session ID +manager and a session manager. + +* The session ID manager ensures that session IDs are unique across all +webapps hosted on a Jetty instance, and thus there can only be one +session ID manager per Jetty instance. +* The session manager handles the session lifecycle +(create/update/invalidate/expire) on behalf of a web application, so +there is one session manager per web application instance. + +These managers also cooperate and collaborate with the +`org.eclipse.jetty.server.session.SessionHandler` to enable +cross-context dispatch. + +==== The gcloud-sessions Module + +When using the jetty distribution, to enable Cloud Datastore session +persistence, you will first need to enable the `gcloud-sessions` +link:#startup-modules[module] for your link:#creating-jetty-base[base] +using the --add-to-start or --add-to-startd argument to the +link:#startup-overview[start.jar]. + +As part of the module installation, the necessary jars will be +dynamically downloaded and installed to your `${jetty.base}/lib/gcloud` +directory. If you need to up or downgrade the version of the jars, then +you can delete the jars that were automatically installed and replace +them. Once you've done that, you will need to prevent jetty's startup +checks from detecting the missing jars. To do that, you can use +`--skip-file-validation=glcoud-sessions` argument to start.jar on the +command line, or place that line inside `${jetty.base}/start.ini` to +ensure it is used for every start. + +===== Configuring the GCloudSessionIdManager + +The gcloud-sessions module will have installed file called +`${jetty.home}/etc/jetty-gcloud-sessions.xml`. This file configures an +instance of the GCloudSessionIdManager that will be shared across all +webapps deployed on that server. It looks like this: + +[source,xml] +---- +include::{SRCDIR}/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/jetty-gcloud-session-store.xml[] +---- + +You configure it by setting values for properties. The properties will +either be inserted as commented out in your `start.ini`, or your +`start.d/gcloud-sessions.ini` file, depending on how you enabled the +module. + +The only property you always need to set is the name of the node in the +cluster: + +jetty.gcloudSession.workerName:: + The name that uniquely identifies this node in the cluster. This value + will also be used by the sticky load balancer to identify the node. + Don't forget to change the value of this property on *each* node on + which you enable gcloud datastore session clustering. + +Which other properties you need to set depends on the execution +environment: + +====== Running Within Google Infrastructure + +When you upload your webapp to run in Compute Engine, you do not need to +set any other properties for jetty. If you follow the instructions in +the https://cloud.google.com/datastore/docs/activate[Cloud Datastore +documentation], all authorizations etc will be provided by the runtime +environment. + +====== Running Externally to Google Infrastructure + +When your app is executing outside of Google, you can either contact a +remote Cloud Datastore instance, or a +https://cloud.google.com/datastore/docs/tools/devserver[local test dev +server] provided by the sdk. The choice determines which properties you +need to set: + +Contacting an sdk dev server for testing::: + In this case, you need to set up either some _System_ properties or + _environment variables_ - NOT jetty properties! + + + DATASTORE_DATASET;; + This must be the name of your (test) project. + DATASTORE_HOST;; + This is the url of the dev server as described at + https://cloud.google.com/datastore/docs/tools/devserver#setting_environment_variables. + An example may be "http://localhost:9999" +Contacting a remote Cloud Datastore::: + In this case, you need to provide all of the authentication and + authorization information explicitly via jetty properties in the ini + file: + + + jetty.gcloudSession.projectId;; + This is the name of your project. + jetty.gcloudSession.p12File;; + This is the location of the p12 key file that is associated with + your project. + jetty.gcloudSession.serviceAccount;; + This is the email address that defines your service account for the + Cloud Datastore. + jetty.gcloudSession.password;; + This is the password associated with the p12 key file. + +===== Configuring the GCloudSessionManager + +As mentioned elsewhere, there should be one GCloudSessionManager per +context (ie webapp). It will need to reference the single +GCloudSessionIdManager from which it derives the Cloud Datastore +configuration information. + +The way you configure a GCloudSessionManager depends on whether you're +configuring from a context xml file or a `jetty-web.xml` file or code. +The basic difference is how you get a reference to the Jetty +`org.eclipse.jetty.server.Server` instance. + +From a context xml file, you reference the Server instance as a Ref: + +[source,xml] +---- + + + + + + + + + + + + + + + + 600 + + + + +---- + +From a `WEB-INF/jetty-web.xml` file, you can reference the Server +instance directly: + +[source,xml] +---- + + + + + + + + + + + + + + + 600 + + + + +---- + +The GCloudSessionManager supports the following configuration setters: + +scavengeIntervalSec:: + Time in seconds between runs of a scavenger task that looks for + expired old sessions to delete. The default is 10 minutes. If set to + 0, no scavenging is done. +staleIntervalSec:: + The length of time a session can be in memory without being checked + against the cluster. A value of 0 indicates that the session is never + checked against the cluster - the current node is considered to be the + master for the session. +maxQueryResults:: + The maximum number of results to return for a query to find expired + sessions. For efficiency it is important to limit the size of the + result. The default is 100. If 0 or negative numbers are set, the + default is used instead. diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-infinispan.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-infinispan.adoc new file mode 100644 index 00000000000..1e7524e3b21 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-infinispan.adoc @@ -0,0 +1,238 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[session-clustering-infinispan]] +=== Session Clustering with Infinispan + +Jetty can support session clustering by persisting sessions to +http://www.infinispan.org[Infinispan]. Each Jetty instance locally +caches sessions for which it has received requests, writing any changes +to the session through to Infinispan as the request exits the server. +Sessions must obey the Serialization contract, and servlets must call +the Session.setAttribute() method to ensure that changes are persisted. + +The persistent session mechanism works in conjunction with a load +balancer that supports stickiness. Stickiness can be based on various +data items, such as source IP address or characteristics of the session +ID or a load-balancer specific mechanism. For those load balancers that +examine the session ID, the Jetty persistent session mechanism appends a +node ID to the session ID, which can be used for routing. + +==== Configuration + +There are two components to session management in Jetty: a session ID +manager and a session manager. + +* The session ID manager ensures that session IDs are unique across all +webapps hosted on a Jetty instance, and thus there can only be one +session ID manager per Jetty instance. +* The session manager handles the session lifecycle +(create/update/invalidate/expire) on behalf of a web application, so +there is one session manager per web application instance. + +These managers also cooperate and collaborate with the +`org.eclipse.jetty.server.session.SessionHandler` to enable +cross-context dispatch. + +==== The infinispan Module + +When using the jetty distribution, to enable Infinispan session +persistence, you will first need to enable the `infinispan` +link:#startup-modules[module] for your link:#creating-jetty-base[base] +using the --add-to-start or --add-to-startd argument to the +link:#startup-overview[start.jar]. + +As part of the module installation, the necessary infinispan jars will +be dynamically downloaded and installed to your +`${jetty.base}/lib/infinispan` directory. If you need to up or downgrade +the version of the infinispan jars, then you can delete the jars that +were automatically installed and replace them. Once you've done that, +you will need to prevent jetty's startup checks from detecting the +missing jars. To do that, you can use +`--skip-file-validation=infinispan` argument to start.jar on the command +line, or place that line inside `${jetty.base}/start.ini` to ensure it +is used for every start. + +You will also find the following properties, either in your base's +`start.d/infinispan.ini` file or appended to your `start.ini`, depending +on how you enabled the module: + +.... +## Unique identifier for this node in the cluster +jetty.infinispanSession.workerName=node1 +.... + +jetty.infinispanSession.workerName:: + The name that uniquely identifies this node in the cluster. This value + will also be used by the sticky load balancer to identify the node. + Don't forget to change the value of this property on *each* node on + which you enable infinispan session clustering. + +These properties are applied to the InfinispanSessionIdManager described +below. + +===== Configuring the InfinispanSessionIdManager + +The infinispan module will have installed file called +$\{jetty.home}/etc/jetty-infinispan.xml. This file configures an +instance of the InfinispanSessionIdManager that will be shared across +all webapps deployed on that server. It looks like this: + +[source,xml] +---- +include::{SRCDIR}/jetty-infinispan/src/main/config/etc/jetty-default-infinispan-store.xml[] +---- + +As you can see, you configure the Infinispan +http://infinispan.org/docs/7.1.x/user_guide/user_guide.html#_the_cache_apis[Cache] +instance that the InfinispanSessionIdManager should use in this file. By +default, the infinispan +http://infinispan.org/docs/7.1.x/getting_started/getting_started.html#_running_infinispan_on_a_single_node[Default +cache] instance is used (ie on the local node). You can instead use a +custom Cache setup - the jetty-infinispan.xml file shows you how to +configure a remote Cache (using the +http://infinispan.org/docs/7.1.x/user_guide/user_guide.html#_using_hot_rod_server[hotrod +java client]). + +The InfinispanSessionIdManager can be configured by calling setters: + +idleExpiryMultiple:: + Sessions that are not immortal, ie they have an expiry time, have + their ids stored into Infinispan with an + http://infinispan.org/docs/7.1.x/user_guide/user_guide.html#_expiration[idle + expiry timeout] equivalent to double the session's timeout. This + should be sufficient to ensure that a session id that is in-use by a + session is never accidentally removed. However, should you wish to, + you can configure this to any integral value to effectively increase + the + http://infinispan.org/docs/7.1.x/user_guide/user_guide.html#_expiration[idle + expiry] timeout. + +===== Configuring the InfinispanSessionManager + +As mentioned elsewhere, there should be one InfinispanSessionManager per +context (ie webapp). It will need to reference the single +InfinispanSessionIdManager configured previously for the Server. + +The way you configure a InfinispanSessionManager depends on whether +you're configuring from a context xml file or a `jetty-web.xml` file or +code. The basic difference is how you get a reference to the Jetty +`org.eclipse.jetty.server.Server` instance. + +From a context xml file, you reference the Server instance as a Ref: + +[source,xml] +---- + + + -org.eclipse.jetty.session.infinispan. + + + + + + + + + + + + + + + + + + + + + + + + + + 60 + + + + +---- + +From a `WEB-INF/jetty-web.xml` file, you can reference the Server +instance directly: + +[source,xml] +---- + + + -org.eclipse.jetty.session.infinispan. + + + + + + + + + + + + + + + + + + + + + + + + + 600 + + + + +---- + +The InfinispanSessionManager can be provided by calling setters: + +scavengeInterval:: + Time in seconds between runs of a scavenger task that looks for + expired old sessions to delete. The default is 10 minutes. +staleIntervalSec:: + The length of time a session can be in memory without being checked + against the cluster. A value of 0 indicates that the session is never + checked against the cluster - the current node is considered to be the + master for the session. + +===== Using HotRod + +If you're using the hotrod client - where serialization will be required +- you will need to ensure that the hotrod marshalling software works +with jetty classloading. To do this, firstly ensure that you have +included the lines containing the `prependServerClass` to your context +xml file as shown above. + +Then, create the file +`${jetty.base}/resources/hotrod-client.properties`. Add the following +line to this file: + +.... +infinispan.client.hotrod.marshaller=org.eclipse.jetty.session.infinispan.WebAppMarshaller +.... diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-jdbc.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-jdbc.adoc new file mode 100644 index 00000000000..6eb6ae7b96d --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-jdbc.adoc @@ -0,0 +1,271 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[session-clustering-jdbc]] +=== Session Clustering with a Database + +Jetty can support session clustering by persisting sessions to a shared +database. Each Jetty instance locally caches sessions for which it has +received requests, writing any changes to the session through to the +database as the request exits the server. Sessions must obey the +Serialization contract, and servlets must call the +Session.setAttribute() method to ensure that changes are persisted. + +The persistent session mechanism works in conjunction with a load +balancer that supports stickiness. Stickiness can be based on various +data items, such as source IP address or characteristics of the session +ID or a load-balancer specific mechanism. For those load balancers that +examine the session ID, the Jetty persistent session mechanism appends a +node ID to the session ID, which can be used for routing. + +In this type of solution, the database can become both a bottleneck and +a single point of failure. Jetty takes steps to reduce the load on the +database (discussed below), but in a heavily loaded environment you +might need to investigate other optimization strategies such as local +caching and database replication. You should also consult your database +vendor's documentation for information on how to ensure high +availability and failover of your database. + +==== Configuration + +There are two components to session management in Jetty: a session ID +manager and a session manager. + +* The session ID manager ensures that session IDs are unique across all +webapps hosted on a Jetty instance, and thus there can only be one +session ID manager per Jetty instance. +* The session manager handles the session lifecycle +(create/update/invalidate/expire) on behalf of a web application, so +there is one session manager per web application instance. + +These managers also cooperate and collaborate with the +`org.eclipse.jetty.server.session.SessionHandler` to enable +cross-context dispatch. + +==== The jdbc-session Module + +When using the jetty distribution, to enable jdbc session persistence, +you will first need to enable the jdbc-session +link:#startup-modules[module] for your link:#creating-jetty-base[base] +using the --add-to-start or --add-to-startd argument to the +link:#startup-overview[start.jar]. + +You will also find the following properties, either in your base's +start.d/jdbc-session.ini file or appended to your start.ini, depending +on how you enabled the module: + +.... +## Unique identifier for this node in the cluster +jetty.jdbcSession.workerName=node1 + +##Uncomment either the datasource name or driverClass and connectionURL +#jetty.jdbcSession.datasource=sessions +jetty.jdbcSession.driverClass=org.apache.derby.jdbc.EmbeddedDriver +jetty.jdbcSession.connectionURL=jdbc:derby:sessions;create=true +.... + +jetty.jdbcSession.workerName:: + The name that uniquely identifies this node in the cluster. This value + will also be used by the sticky load balancer to identify the node. + Don't forget to change the value of this property on *each* node on + which you enable jdbc session clustering. +jetty.jdbcSession.scavenge:: + The time in seconds between sweeps of a task which scavenges old + expired sessions. The default is 10 mins. We don't recommend you + increase the frequency bcause doing so increases the load on the + database with very little gain. +jetty.jdbcSession.datasource:: + The name of a javax.sql.DataSource that gives access to the database + that holds the session information. You should configure *either* this + or the jdbc driver information described next. +jetty.jdbcSession.datasource and jetty.jdbcSession.connectionURL:: + This is the name of the jdbc driver class, and a jdbc connection url + suitable for that driver. You should configure *either* this or the + jdbc datasource name described above. + +These properties are applied to the JDBCSessionIdManager described +below. + +===== Configuring the JDBCSessionIdManager + +The jdbc-session module will have installed file called +$\{jetty.home}/etc/jetty-jdbc-sessions.xml. This file configures an +instance of the JDBCSessionIdManager that will be shared across all +webapps deployed on that server. It looks like this: + +[source,xml] +---- +include::{SRCDIR}/jetty-server/src/main/config/etc/jetty-jdbc-session-store.xml[] +---- + +As well as uncommenting and setting up appropriate values for the +properties we discussed above, you will also need to edit this file and +uncomment *either* the datasource or the driver info elements. + +As Jetty configuration files are direct mappings of XML to Java, it is +straightforward to see how to do this in code, but here's an example +anyway: + +[source,java] +---- + +Server server = new Server(); + ... +JDBCSessionIdManager idMgr = new JDBCSessionIdManager(server); +idMgr.setWorkerName("node1"); +idMgr.setDriverInfo("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306/sessions?user=janb"); +idMgr.setScavengeInterval(600); +server.setSessionIdManager(idMgr); + +---- + +====== Configuring the Database Schema + +You may find it necessary to change the names of the tables and columns +that the JDBC Session management uses to store the session information. +The defaults used are: + +.Default Values for Session Id Table +[cols=",",] +|=========================== +|table name |JettySessionIds +|columns |id +|=========================== + +.Default Values for Session Table +[cols=",",] +|======================================================================= +|table name |JettySessions + +|columns |rowId, sessionId, contextPath, virtualHost, lastNode, +accessTime, lastAccessTime, createTime, cookieTime, lastSavedTime, +expiryTime, maxInterval, map +|======================================================================= + +To change these values, use the +link:{JDURL}/org/eclipse/jetty/server/session/SessionIdTableSchema.html[org.eclipse.jetty.server.session.SessionIdTableSchema] +and +link:{JDURL}/org/eclipse/jetty/server/session/SessionTableSchema.html[org.eclipse.jetty.server.session.SessionTableSchema] +classes. These classes have getter/setter methods for the table name and +all columns. + +Here's an example of changing the name of JettySessionsId table and its +single column. This example will use java code, but as explained above, +you may also do this via a jetty xml configuration file: + +[source,java] +---- +JDBCSessionIdManager idManager = new JDBCSessionIdManager(server); + +SessionIdTableSchema idTableSchema = new SessionIdTableSchema(); +idTableSchema.setTableName("mysessionids"); +idTableSchema.setIdColumn("theid"); +idManager.setSessionIdTableSchema(idTableSchema); +---- + +In a similar fashion, you can change the names of the table and columns +for the JettySessions table. *Note* that both the SessionIdTableSchema +and the SessionTableSchema instances are set on the JDBCSessionIdManager +class. + +[source,java] +---- +JDBCSessionIdManager idManager = new JDBCSessionIdManager(server); + +SessionTableSchema sessionTableSchema = new SessionTableSchema(); +sessionTableSchema.setTableName("mysessions"); +sessionTableSchema.setIdColumn("mysessionid"); +sessionTableSchema.setAccessTimeColumn("atime"); +sessionTableSchema.setContextPathColumn("cpath"); +sessionTableSchema.setCookieTimeColumn("cooktime"); +sessionTableSchema.setCreateTimeColumn("ctime"); +sessionTableSchema.setExpiryTimeColumn("extime"); +sessionTableSchema.setLastAccessTimeColumn("latime"); +sessionTableSchema.setLastNodeColumn("lnode"); +sessionTableSchema.setLastSavedTimeColumn("lstime"); +sessionTableSchema.setMapColumn("mo"); +sessionTableSchema.setMaxIntervalColumn("mi"); +idManager.setSessionTableSchema(sessionTableSchema); +---- + +===== Configuring the JDBCSessionManager + +As mentioned elsewhere, there should be one JDBCSessionManager per +context (ie webapp). It will need to reference the single +JDBCSessionIdManager configured previously for the Server. + +The way you configure a JDBCSessionManager depends on whether you're +configuring from a context xml file or a `jetty-web.xml` file or code. +The basic difference is how you get a reference to the Jetty +`org.eclipse.jetty.server.Server` instance. + +From a context xml file, you reference the Server instance as a Ref: + +[source,xml] +---- + + + + + + + + + + + + + + +---- + +From a `WEB-INF/jetty-web.xml` file, you can reference the Server +instance directly: + +[source,xml] +---- + + + + + + + + + + + + + + + +---- + +If you're embedding this in code: + +[source,java] +---- + +//assuming you have already set up the JDBCSessionIdManager as shown earlier +//and have a reference to the Server instance: + +WebAppContext wac = new WebAppContext(); + ... //configure your webapp context +JDBCSessionManager jdbcMgr = new JDBCSessionManager(); +jdbcMgr.setSessionIdManager(server.getSessionIdManager()); +SessionHandler sessionHandler = new SessionHandler(jdbcMgr); +wac.setSessionHandler(sessionHandler); +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-mongodb.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-mongodb.adoc new file mode 100644 index 00000000000..27b4355379b --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-clustering-mongodb.adoc @@ -0,0 +1,300 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[session-clustering-mongodb]] +=== Session Clustering with MongoDB + +Jetty can support session clustering by persisting sessions into +http://www.mogodb.org[MongoDB]. Each Jetty instance locally caches +sessions for which it has received requests, writing any changes to the +session through to the cluster as the request exits the server. Sessions +must obey the Serialization contract, and servlets must call the +Session.setAttribute() method to ensure that changes are persisted. + +The session persistence mechanism works in conjunction with a load +balancer that supports stickiness. Stickiness can be based on various +data items, such as source IP address or characteristics of the session +ID or a load-balancer specific mechanism. For those load balancers that +examine the session ID, the Jetty persistent session mechanism appends a +node ID to the session ID, which can be used for routing. + +In this type of solution, the traffic on the network needs to be +carefully watched and tends to be the bottleneck. You are probably +investigating this solution in order to scale to large amount of users +and sessions, so careful attention should be paid to your usage +scenario. Applications with a heavy write profile to their sessions will +consume more network bandwidth than profiles that are predominately read +oriented. We recommend using this session manager with largely read +based session scenarios. + +==== Configuration + +There are two components to session management in Jetty: a session ID +manager and a session manager. + +* The session ID manager ensures that session IDs are unique across all +webapps hosted on a Jetty instance, and thus there should only be one +session ID manager per Jetty instance. +* The session manager handles the session lifecycle +(create/update/invalidate/expire) on behalf of a web application, so +there is one session manager per web application instance. + +These managers also cooperate and collaborate with the +`org.eclipse.jetty.server.session.SessionHandler` to enable +cross-context dispatch. + +==== The nosql Module + +When using the jetty distribution, to enable the mongodb session +persistence mechanism, you will first need to enable the nosql +link:#startup-modules[module] for your link:#creating-jetty-base[base] +using the --add-to-start or --add-to-startd argument to the +link:#startup-overview[start.jar]. This module will automatically +download the mongodb-java-driver and install it to your base's lib/nosql +directory. + +As part of the module installation, the necessary mongo java driver jars +will be dynamically downloaded and installed to your +`${jetty.base}/lib/nosql` directory. If you need to up or downgrade the +version of these jars, then you can delete the jars that were +automatically installed and replace them. Once you've done that, you +will need to prevent jetty's startup checks from detecting the missing +jars. To do that, you can use `--skip-file-validation=nosql` argument to +start.jar on the command line, or place that line inside +`${jetty.base}/start.ini` to ensure it is used for every start. + +You will also find the following properties, either in your base's +start.d/nosql.ini file or appended to your start.ini, depending on how +you enabled the module: + +.... +## Unique identifier for this node in the cluster +jetty.nosqlSession.workerName=node1 + + +## Interval in seconds between scavenging expired sessions +jetty.nosqlSession.scavenge=1800 +.... + +The `jetty.nosqlSession.workerName` is the unique name for this jetty +Server instance. It will be used by the sticky load balancer to uniquely +identify the node. You should change this value on *each* node to which +you install mongodb session management. + +The `jetty.nosqlSession.scavenge` property defines the time in seconds +between runs of the scavengeer: the scavenger is a task which runs +periodically to clean out sessions that have expired but become stranded +in the database for whatever reason. + +These properties are substituted into the configuration of the +MongoDBSessionIdManager and MongoSessionManager. + +===== Configuring the MongoSessionIdManager + +The nosql module will have installed file called +$\{jetty.home}/etc/jetty-nosql.xml. This file configures an instance of +the MongoSessionIdManager that will be shared across all webapps +deployed on that server. It looks like this: + +[source,xml] +---- +include::{SRCDIR}/jetty-nosql/src/main/config/etc/jetty-mongo-session-store.xml[] +---- + +The MongoSessionIdManager needs access to a mongodb cluster, and the +jetty-nosql.xml file assumes the defaults of localhost and default +mongodb port. If you need to configure something else, you will need to +edit this file. Here's an example of a more complex setup to use a +remote mongodb instance: + +[source,xml] +---- + + + + + + + foo.example.com + 27017 + + + + + + + + HttpSessions + + sessions + + + + + + + + + + + + + + + + + + + + +---- + +As Jetty configuration files are direct mappings of XML to Java, it is +straightforward to see how to do this in code, but here's an example +anyway: + +[source,java] +---- + + Server server = new Server(); + ... + MongoSessionIdManager idMgr = newMongoSessionIdManager(server); + idMgr.setWorkerName("node1"); + idMgr.setScavengePeriod(1800); + server.setSessionIdManager(idMgr); + +---- + +The MongoSessionIdManager has slightly different options than some of +our more traditional session options. The MongoDBSessionIdManager has +the same scavenge timers which govern the setting of a valid session to +invalid after a certain period of inactivity. New to this session id +manager is the extra purge setting which governs removal from the +mongodb cluster. This can be configured through the 'purge' option. +Purge is by default set to true and by default runs daily for each node +on the cluster. Also able to be configured is the age in which an +invalid session will be retained which is set to 1 day by default. This +means that invalid sessions will be removed after lingering in the +mongodb instance for a day. There is also an option for purging valid +sessions that have not been used recently. The default time for this is +1 week. You can disable these behaviors by setting purge to false. + +scavengeDelay:: + How long to delay before periodically looking for sessions to + scavenge? +scavengePeriod:: + How much time after a scavenge has completed should you wait before + doing it again? +scavengeBlockSize:: + Number of session ids to which to limit each scavenge query. If you + have a very large number of sessions in memory then setting this to a + non 0 value may help speed up scavenging by breaking the scavenge into + multiple, queries. The default is 0, which means that all session ids + are considered in a single query. +purge (Boolean):: + Do you want to purge (delete) sessions that are invalid from the + session store completely? +purgeDelay:: + How often do you want to perform this purge operation? +purgeInvalidAge:: + How old should an invalid session be before it is eligible to be + purged? +purgeValidAge:: + How old should a valid session be before it is eligible to be marked + invalid and purged? Should this occur at all? +purgeLimit:: + Integer value that represents how many items to return from a purge + query. The default is 0, which is unlimited. If you have a lot of old + expired orphaned sessions then setting this value may speed up the + purge process. +preserveOnStop:: + Whether or not to retain all sessions when the session manager stops. + Default is `true`. + +===== Configuring a MongoSessionManager + +As mentioned elsewhere, there should be one MongoSessionManager per +context (ie webapp). It will need to reference the single +MongoSessionIdManager configured previously for the Server. + +The way you configure a +link:{JDURL}/org/eclipse/jetty/nosql/MongoSessionManager.html[org.eclipse.jetty.nosql.mongodb.MongoSessionManager] +depends on whether you're configuring from a +link:#deployable-descriptor-file[context xml] file or a +link:#jetty-web-xml-config[jetty-web.xml] file or code. The basic +difference is how you get a reference to the Jetty +`org.eclipse.jetty.server.Server` instance. + +From a context xml file, you reference the Server instance as a Ref: + +[source,xml] +---- + + + + + + + + + + + + + + + + + +---- + +From a `WEB-INF/jetty-web.xml` file, you can reference the Server +instance directly: + +[source,xml] +---- + + + + + + + + + + + + + + + +---- + +If you're embedding this in code: + +[source,java] +---- + +//assuming you have already set up the MongoSessionIdManager as shown earlier + //and have a reference to the Server instance: + + WebAppContext wac = new WebAppContext(); + ... //configure your webapp context + MongoSessionManager mongoMgr = new MongoSessionManager(); + mongoMgr.setSessionIdManager(server.getSessionIdManager()); + wac.setSessionHandler(new SessionHandler(mongoMgr)); + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/setting-session-characteristics.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/setting-session-characteristics.adoc new file mode 100644 index 00000000000..c8f57ef325d --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/setting-session-characteristics.adoc @@ -0,0 +1,295 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[setting-session-characteristics]] +=== Setting Session Characteristics + +To modify the session characteristics of a web application, you can use +the following parameters, applying them as in one of the example +configurations: + +[[using-init-parameters]] +==== Using Init Parameters + +Use these parameters to set session characteristics. + +.Init Parameters +[cols=",,",options="header",] +|======================================================================= +|Context Parameter |Default Value |Description +|org.eclipse.jetty.servlet.SessionCookie |JSESSIONID |Session cookie +name defaults to JSESSIONID, but can be set for a particular webapp with +this context param. + +|org.eclipse.jetty.servlet.SessionIdPathParameterName |jsessionid +|Session URL parameter name. Defaults to jsessionid, but can be set for +a particular webapp with this context param. Set to "none" to disable +URL rewriting. + +|org.eclipse.jetty.servlet.SessionDomain |- |Session Domain. If this +property is set as a ServletContext param, then it is used as the domain +for session cookies.If it is not set, then no domain is specified for +the session cookie. + +|org.eclipse.jetty.servlet.SessionPath |- |Session Path. If this +property is set as a ServletContext param, then it is used as the path +for the session cookie. If it is not set, then the context path is used +as the path for the cookie. + +|org.eclipse.jetty.servlet.MaxAge |-1 |Session Max Age. If this property +is set as a ServletContext param, then it is used as the max age for the +session cookie. If it is not set, then a max age of -1 is used. + +|org.eclipse.jetty.servlet.CheckingRemoteSessionIdEncoding |false |If +true, Jetty will add JSESSIONID parameter even when encoding external +urls with calls to encodeURL(). False by default. +|======================================================================= + +[[applying-init-parameters]] +===== Applying Init Parameters + +The following sections provide examples of how to apply the init +parameters. + +[[context-parameter-example]] +====== Context Parameter Example + +You can set these parameters as context parameters in a web +application's ` WEB-INF/web.xml` file: + +[source,xml] +---- + + + + ... + + org.eclipse.jetty.servlet.SessionCookie + XSESSIONID + + + org.eclipse.jetty.servlet.SessionIdPathParameterName + xsessionid + + ... + + + +---- + +[[web-application-examples]] +====== Web Application Examples + +You can configure init parameters on a web application, either in code, +or in a Jetty context xml file equivalent: + +[source,xml] +---- + + + /test + /webapps/test + + ... + + + org.eclipse.jetty.servlet.SessionCookie + XSESSIONID + + + org.eclipse.jetty.servlet.SessionIdPathParameterName + xsessionid + + + + +---- + +[[init-parameter-examples]] +====== SessionManager Examples + +You can configure init parameters directly on a `SessionManager` +instance, either in code or the equivalent in xml: + +[source,xml] +---- + + + /test + /webapps/test + + ... + + + + + XSESSIONID + xsessionid + + + + + + +---- + +==== Using Servlet 3.0 Session Configuration + +With the advent of http://jcp.org/en/jsr/detail?id=315[Servlet +Specification 3.0] there are new APIs for configuring session handling +characteristics. What was achievable before only via jetty-specific +link:#session-init-params[init-parameters] can now be achieved in a +container-agostic manner either in code, or via web.xml. + +[[session-cookie-configuration]] +===== SessionCookieConfiguration + +The +http://docs.oracle.com/javaee/6/api/javax/servlet/SessionCookieConfig.html[javax.servlet.SessionCookieConfig] +class can be used to set up session handling characteristics. For full +details, consult the +http://docs.oracle.com/javaee/6/api/javax/servlet/SessionCookieConfig.html[javadoc]. + +Here's an example of how you use it: this is a ServletContextListener +that retrieves the SessionCookieConfig and sets up some new values for +it when the context is being initialized: + +[source,java] +---- +import javax.servlet.SessionCookieConfig; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +public class TestListener implements ServletContextListener +{ + + public void contextInitialized(ServletContextEvent sce) + { + String comment = "This is my special cookie configuration"; + String domain = "foo.com"; + String path = "/my/special/path"; + boolean isSecure = true; + boolean httpOnly = false; + int maxAge = 30000; + String cookieName = "FOO_SESSION"; + + + SessionCookieConfig scf = sce.getServletContext().getSessionCookieConfig(); + + scf.setComment(comment); + scf.setDomain(domain); + scf.setHttpOnly(httpOnly); + scf.setMaxAge(maxAge); + scf.setPath(path); + scf.setSecure(isSecure); + scf.setName(cookieName); + } + + public void contextDestroyed(ServletContextEvent sce) + { + + } +} +---- + +You can also use web.xml to configure the session handling +characteristics instead: here's an example, doing exactly the same as we +did above in code: + +[source,xml] +---- + + + + + + This is my special cookie configuration + foo.com + false + 30000 + /my/special/path + true + FOO_SESSION + + + +---- + +[[session-tracking-modes]] +===== SessionTrackingModes + +In addition to the configuration of +link:#session-cookie-configuration[session cookies], since Servlet 3.0 +you can also use the +http://docs.oracle.com/javaee/6/api/javax/servlet/SessionTrackingMode.html[javax.servlet.SessionTrackingMode] +to configure session tracking. + +To determine what are the _default_ session tracking characteristics +used by the container, call: + +[source,java] +---- +javax.servlet.SessionContext.getDefaultSessionTrackingModes(); +---- + +This returns a java.util.Set of javax.servlet.SessionTrackingMode. The +_default_ session tracking modes for Jetty are: + +* http://docs.oracle.com/javaee/6/api/javax/servlet/SessionTrackingMode.html#COOKIE[SessionTrackingMode.COOKIE] +* http://docs.oracle.com/javaee/6/api/javax/servlet/SessionTrackingMode.html#URL[SessionTrackingMode.URL] + +To see which session tracking modes are actually in effect for this +Context, the following call returns a java.util.Set of +javax.servlet.SessionTrackingMode: + +.... +javax.servlet.SessionContext.getEffectiveSessionTrackingModes(); +.... + +To change the session tracking modes, call: + +[source,java] +---- +javax.servlet.SessionContext.setSessionTrackingModes(Set); +---- + +You may also set the tracking mode in web.xml, eg: + +[source,xml] +---- + + + + + URL + COOKIE + + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/using-persistent-sessions.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/using-persistent-sessions.adoc new file mode 100644 index 00000000000..9b90d77bb8b --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/using-persistent-sessions.adoc @@ -0,0 +1,125 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[using-persistent-sessions]] +=== Using Persistent Sessions + +It is sometimes useful to preserve existing Sessions across restarts of +Jetty. The +link:{JDURL}/org/eclipse/jetty/server/session/HashSessionManager.html[`HashSessionManager`] +supports this feature. If you enable persistence, the +`HashSessionManager` saves all existing, valid Sessions to disk before +shutdown completes. On restart, Jetty restores the saved Sessions. + +[[enabling-persistence]] +==== Enabling Persistence + +A SessionManager does just what its name suggests–it manages the +lifecycle and state of sessions on behalf of a webapp. Each webapp must +have its own unique SessionManager instance. Enabling persistence is as +simple as configuring the `HashSessionManager` as the SessionManager for +a webapp and telling it where on disk to store the sessions: + +[source,xml] +---- + + + . + . + . + + + + + your/chosen/directory/goes/here + + + + + . + . + . + + + +---- + +____ +[TIP] +If you want to persist the sessions from multiple webapps: +1. Configure a separate HashSessionManager for each. +2. Assign to each a different value for 'storeDirectory'. +____ + +The above example uses a configuration file suitable for the +link:{JDURL}/org/eclipse/jetty/deploy/providers/ContextProvider.html[ContextProvider], +thus you might want to check out xref:using-context-provider[]. + +[[delaying-session-load]] +==== Delaying Session Load + +You might need to ensure that the sessions are loaded AFTER the servlet +environment starts up (by default, Jetty eagerly loads sessions as part +of the container startup, but before it initializes the servlet +environment). For example, the Wicket web framework requires the servlet +environment to be available when sessions are activated. + +Using `SessionManager.setLazyLoad(true)`, Jetty loads sessions lazily +either when it receives the first request for a session, or the session +scavenger runs for the first time, whichever happens first. Here's how +the configuration looks in XML: + +[source,xml] +---- + + + + + true + + + + +---- + +[[enabling-persistence-for-jetty-maven-plugin]] +==== Enabling Persistence for the Jetty Maven Plugin + +To enable session persistence for the Jetty Maven plugin, set up the +HashSessionManager in the configuration section like so: + +[source,xml] +---- + + org.eclipse.jetty + jetty-maven-plugin + 9.0.0.RC2 (or current version) + + + + ${project.build.outputDirectory}/META-INF/webdefault.xml + ${jetty.contextRoot} + + + ${project.basedir}/target/jetty-sessions + 1 + + + + + + +---- diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc new file mode 100644 index 00000000000..03a490c091e --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc @@ -0,0 +1,27 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[startup]] +== Starting Jetty + +include::startup-overview.adoc[] +include::startup-xml-config.adoc[] +include::startup-classpath.adoc[] +include::startup-modules.adoc[] +include::startup-base-vs-home.adoc[] +include::start-jar.adoc[] +include::startup-unix-service.adoc[] +include::startup-windows-service.adoc[] \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/images/modules-9.3-simplified.dot b/jetty-documentation/src/main/asciidoc/administration/startup/images/modules-9.3-simplified.dot new file mode 100644 index 00000000000..ecc2962020b --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/startup/images/modules-9.3-simplified.dot @@ -0,0 +1,254 @@ +/* + * GraphViz Graph of Jetty Modules + * + * Jetty: http://eclipse.org/jetty/ + * GraphViz: http://graphviz.org/ + * + * To Generate Graph image using graphviz: + * $ dot -Tpng -Goverlap=false -o modules-9.png modules-9.3.dot + */ + +digraph modules { + node [color=gray, style=filled, shape=rectangle]; + node [fontname="Verdana", size="20,20"]; + graph [ + concentrate=false, + fontname="Verdana", + fontsize = 20, + rankdir = LR, + ranksep = 1.5, + nodesep = .5, + style = bold, + labeljust = l, + label = "Jetty Modules", + ssize = "20,40" + ]; + + /* Modules */ + + node [ labeljust = l ]; + + /* Level 0 */ + { rank = same; + "server" [ color="#66FFCC" label=< + +
    server
    >]; + "ext" [ color="#B8FFB8" label=< + +
    ext
    >]; + "jvm" [ color="#B8FFB8" label=< + +
    jvm
    >]; + "apache-jstl" [ color="#B8FFB8" label=< + +
    apache-jstl
    >]; + "client" [ color="#B8FFB8" label=< + +
    client
    >]; + "logging" [ color="#B8FFB8" label=< + +
    logging
    >]; + "resources" [ color="#B8FFB8" label=< + +
    resources
    >]; + "apache-jsp" [ color="#B8FFB8" label=< + +
    apache-jsp
    >]; + "protonego-boot" [ color="#B8FFB8" label=< + +
    protonego-boot
    >]; + } + + /* Level 1 */ + { rank = same; + "requestlog" [ color="#B8FFB8" label=< + +
    requestlog
    >]; + "servlet" [ color="#66FFCC" label=< + +
    servlet
    >]; + "gzip" [ color="#B8FFB8" label=< + +
    gzip
    >]; + "monitor" [ color="#B8FFB8" label=< + +
    monitor
    >]; + "rewrite" [ color="#B8FFB8" label=< + +
    rewrite
    >]; + "ssl" [ color="#B8FFB8" label=< + +
    ssl
    >]; + "security" [ color="#66FFCC" label=< + +
    security
    >]; + "setuid" [ color="#B8FFB8" label=< + +
    setuid
    >]; + "spring" [ color="#B8FFB8" label=< + +
    spring
    >]; + "stats" [ color="#B8FFB8" label=< + +
    stats
    >]; + "jmx" [ color="#B8FFB8" label=< + +
    jmx
    >]; + "http" [ color="#66FFCC" label=< + +
    http
    >]; + "debuglog" [ color="#B8FFB8" label=< + +
    debuglog
    >]; + "ipaccess" [ color="#B8FFB8" label=< + +
    ipaccess
    >]; + "jaas" [ color="#B8FFB8" label=< + +
    jaas
    >]; + "jndi" [ color="#B8FFB8" label=< + +
    jndi
    >]; + "lowresources" [ color="#B8FFB8" label=< + +
    lowresources
    >]; + } + + /* Level 2 */ + { rank = same; + "fcgi" [ color="#B8FFB8" label=< + +
    fcgi
    >]; + "jmx-remote" [ color="#B8FFB8" label=< + +
    jmx-remote
    >]; + "webapp" [ color="#66FFCC" label=< + +
    webapp
    >]; + "proxy" [ color="#B8FFB8" label=< + +
    proxy
    >]; + "alpn" [ color="#B8FFB8" label=< + +
    alpn
    >]; + "jaspi" [ color="#B8FFB8" label=< + +
    jaspi
    >]; + "http2c" [ color="#B8FFB8" label=< + +
    http2c
    >]; + "https" [ color="#B8FFB8" label=< + +
    https
    >]; + "servlets" [ color="#B8FFB8" label=< + +
    servlets
    >]; + } + + /* Level 3 */ + { rank = same; + "http2" [ color="#B8FFB8" label=< + +
    http2
    >]; + "plus" [ color="#B8FFB8" label=< + +
    plus
    >]; + "deploy" [ color="#66FFCC" label=< + +
    deploy
    >]; + "nosql" [ color="#B8FFB8" label=< + +
    nosql
    >]; + } + + /* Level 4 */ + { rank = same; + "annotations" [ color="#B8FFB8" label=< + +
    annotations
    >]; + } + + /* Level 5 */ + { rank = same; + "jdbc-sessions" [ color="#B8FFB8" label=< + +
    jdbc-sessions
    >]; + "infinispan" [ color="#B8FFB8" label=< + +
    infinispan
    >]; + "quickstart" [ color="#B8FFB8" label=< + +
    quickstart
    >]; + "jsp" [ color="#B8FFB8" label=< + +
    jsp
    >]; + "websocket" [ color="#B8FFB8" label=< + +
    websocket
    >]; + } + + /* Level 6 */ + { rank = same; + "jstl" [ color="#B8FFB8" label=< + +
    jstl
    >]; + "cdi" [ color="#B8FFB8" label=< + + +
    cdi
    (experimental)
    >]; + } + "alpn" -> "protonego-boot"; + "annotations" -> "plus"; + "cdi" -> "deploy"; + "cdi" -> "annotations"; + "cdi" -> "jsp"; + "debuglog" -> "server"; + "deploy" -> "webapp"; + "fcgi" -> "servlet"; + "fcgi" -> "client"; + "gzip" -> "server"; + "http" -> "server"; + "http2" -> "ssl"; + "http2" -> "alpn"; + "http2c" -> "http"; + "https" -> "ssl"; + "infinispan" -> "annotations"; + "infinispan" -> "webapp"; + "ipaccess" -> "server"; + "jaas" -> "server"; + "jaspi" -> "security"; + "jdbc-sessions" -> "annotations"; + "jdbc-sessions" -> "webapp"; + "jmx" -> "server"; + "jmx-remote" -> "jmx"; + "jndi" -> "server"; + "jsp" -> "servlet"; + "jsp" -> "annotations"; + "jsp" -> "apache-jsp"; + "jstl" -> "jsp"; + "jstl" -> "apache-jstl"; + "lowresources" -> "server"; + "monitor" -> "server"; + "monitor" -> "client"; + "nosql" -> "webapp"; + "plus" -> "security"; + "plus" -> "jndi"; + "plus" -> "webapp"; + "proxy" -> "servlet"; + "proxy" -> "client"; + "quickstart" -> "plus"; + "quickstart" -> "annotations"; + "requestlog" -> "server"; + "rewrite" -> "server"; + "security" -> "server"; + "servlet" -> "server"; + "servlets" -> "servlet"; + "setuid" -> "server"; + "spring" -> "server"; + "ssl" -> "server"; + "stats" -> "server"; + "webapp" -> "servlet"; + "webapp" -> "security"; + "websocket" -> "annotations"; +} + diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/images/modules-9.3-simplified.png b/jetty-documentation/src/main/asciidoc/administration/startup/images/modules-9.3-simplified.png new file mode 100644 index 0000000000000000000000000000000000000000..bf38325232e4a9f90daf9e62bd91bcc85869acef GIT binary patch literal 306780 zcmdpeby!vFxApd@#|8t$0xUud6cm&;5K$>90Rd5w2I&r)5KuxSH-ZXC3eshu2oloW z-6dV$SZqAM``r8I_uYGc&$rHb&f(x*YrXG$=Nxm)G3P!`lHwwp*6&(RB9S(UUb=9N zL|Ri#BCRW2`xk!GGh_J$|N8sZ6_E?1MdGjE%rH+9X)j6i!dV%Mfc^$c6WNZ;sTSKy zdk?N!<@+GqJD62G*m3{$H8kJWQ|)z@_0o z*NS^N-w?Xs9IPU9VfCZqOb0jr)is$rqJNEfWoO47i=c`Qt6~A`p)vkuMKjy#4AFz0 zd26v45@~Iyc-oq!pB((IIxhX>;PA+T@@K4^4J(&^D!=0&BK9*xJ@1D^UliL`sSwNZ zj3Rv-ab?OKYc&-<_Rn|En@D`l?%83gyECy~k5NNs7jdtH1K$SK)dQVPH2WBqp7qz( z))mALd-wj&{v!YCp&&k(;zwLMzx?ntsJbRNXe>{h=3EnalW>EHC7mcu|TDuA30Ci?Ng#Y>bhK+(90frIK=m=?liY^h`WZ3O(aJ)4I>j#rNsFe)TWjr-L_N<+G1~YdV!S!>@7&Kb zFEtEyrt9|)fBPCc+h-bGn{=5z;Dp`98!grw`$y)SyCfLy8TEEJT3;*(IG(UoW1%^k zx^;cit)}hnSMBfQly1q4>7^y#P*8o(wvFN;?_&;F?@@@g%PgOno+US3Pdbq}xEQ%m zvnjz^IW<)?n{y_xyfuMZz=fKtE?uD^Dot$E@AsTmaoFNyPx35M z*8gG=xVF$RBskXnR3tZdO(SPqgVeyTWKEmG(5gLUeXsK8ugUuIFTeNc8PBeqzA-;? z^0)M+BXi7&KXg2kH5Wq4XWnho*Upj{`zpbg(WTB$&D#=J{&~8rGgm%QAlP)SIJ#+m zp;Ii7E|%A9Xh*C)??iHhFma*<+eVg*TJhDdL&t1*@X7e@Yc3lGQ}({Nl#}aoRB>Xa zNhP}{$Df(+)IQTY1Md?@(j!Ew65c>?(^9ZLU>&x4>0S|ikQurwr;33h5fEn zd4CV<;L3~6@im_K;UpM&PhHLPrBcz7^~Wyo5sMWXzjv?dVVh}&rPXCosXSM~j1!4j zLtkd8=38E8+qG03@NvzUtw?V(ercb|mw0-(du7|hD}t)KgiGkgvK-y_m=v5H;R%x} z>U3v4QuEmNr+sDpA>+33;IY4D2Yue>Q!vJ%x24{{$TeBRvbB>%W%}pg)v9z}G~QQt za}U&p#=3G&`hRWA7$~pnlB<#}Y2s7}-oG;~>0>}PvmbrQ zA~N3<9xc&lue5mo;oslcRp;7V+?$3i=Hg}Rb3r~moIDG2^$&}of=)4?p|ILu}$p_66&!kbD?^j33d`wkvj5UZHEy%g&X zia!#Dy~Ecp+*(foVxN@Ya2 zkmCAuMaBY`0nzXF_oWTtHE(JwUz0JC zeHyvlKFz{E+0{Vyb6FC%==8(rQ6=x};!kH+&Vo~D2)=FQxj;V}lA)Y(e9v;gm#+dF zay)F~exE-`b!0AYrMP(J9>Zcs-)(o_RbqEeUnhG6dFN}`$qk(iY!-^bH^#bj^chX9 z=SE#Mn%0gSlJ%t=jO4awJNcMZ$p7SVjXv`x%bvig=AD9qp;~?K>N1p8OGG+~hne-7 zXopR8w669i+sEceMEuDxem56BPLHIGuZV85*B==SnRaP?Xg!c!H8Cjnxr~kVFw0>T zgX`J*euc>>P(VsZEY7T=)} zEcLrHjvJr8J14hTH)GBdEv;=kk*JY9@mmLJMnvj&`%wwz-h-`WTb&B~{#msI1-HvL z1NUp}pUt`#g_-M@M@e10dolE`D-XGG+B|knAN+FUOf%9 zi(@|~&*)8VOt?)SLS-qX^0sK)b~%KC&8G7f1gCSu?Y&-lZMRV#&MB10$#w6uu0Ix# zWc?(faybz_zl$6+g{-c`sB12hKHHQfc$h^;L!yrVtIQ2roBfT{I;)8_ge$w@-mb+N zn+op8%j>W7R>W4NDfj8yrj2L5HpuL^O21b-xbvOjA7A-s;~Xa#-#8M%N8O1KgGHK7V!N4@}cVQtO-XW zk<6q-W#V}h0|yU1s6J48fHz-!lE(Y|GKjZbpo=eSM7>$)ydF266_@unj zYT;v---A=d^$P{sL&8@E7^qJ*W|WwxAb-p+(JS!opufZ4Ss4jA=%>m#b@#N=qS67h?ESl^8S75D0Y>mzI>JRwhc0R z6U+8K`kf`$z*yDK^B7-*`1j=0Db>ZPs`mzR-ZU=@>~zd}FCk-!3JPfTMaImO$(m=G zXv~e~DFtOLIQ0!#O~*|AND*|8%xQ^a|AUTZVv1ZnCW>J__GAWODI@98K%Yjf>W^v) zS_-`l1Y*{Qj8w{-E=YB?p8D3|Zo(5?mX_Gp>Z58uYWgE0a?|p2HU}Dw92&98-yr?Y zHE?@&eP`CmLp7;2N_+D1^PH>R_FX<~@JahmO?e?V$W-?s|E?(IOfKh;8iS%D{V6>) z1F-ztR`dy(ky}l-Dlv%aTCV!@@QO&)p{X%9iD>SZdPl%86v-B!oqWgnO6N1zQb^DR za0a8iLrRSOhIwX_Z(l!H7KB1rovC`vE=49q=QGw!Hrv*j>ifi4YHy^ZGzSCk#TU^p za$62NEuWZ+mmX`~=k%}}HkaqhymVdx)INzQWdFc;9{;c zST$N97CYEHI+8b%e(%l8KWMA>L2dqtp}VV#Dg#o=Nh)b;3ks78mh1NIR#;HSDKVL= zdc>${(=I1hIn7knpQnCSMX@W8y#p&2swYrYm3&sF7N3+%e6YN_!yBh{FQtiuzwM`# zE&totSRpItUvl98XiEF{c`Zj7KY@58QhNA7HU;`< zAokh*Edwv;)x)fv^Y>ARk&HZ}2qU}G%Qx1}dqIV%q@J2cNS)CYqv)sqLs|EqEb~6| zkCd^CCE~$<&Hd3@OB>RTcx+6UHI+*zXwmoZLF{@!1ti9_poYYz!g-@z9T%j2H@~IM z0yB)@}mexpCPQh#^=dCl^G^IL+oOiJ!gZhdM$yayy#VXnG4t|BRrcE6yh%Vz#Nt3w ztn|0#x-YS4Y*H}$gYIqZhDG`Lgxz;1)8ggl26;o9M2}9?+Q;rDXPrnqrYt{0rkn4A zd>6uc`QX;ec2o2X}+`LA5^Kge@F~1YE^I1+59IR@vJfDKdq9>`y~vTTK&}5-EBTYZkCg& zvq5#Oqg{)`bKB+B@7&Gl!@(RjuI!aqPK%~RnLYIv_Ptof2RC`1v?sS%#3*$$}sy6bD zY^}C;4Zp?SKfKT@znO452W<_rlhz>pRWX6X<&QqgZ)&{7J5@c^J_V(#iqU%h!6e-q zw;N_n>O{#h(^6ueI>;VzK#w${E~b#^uzsGWDOUVO7b{JpHs>*VFF~z%KE|36t9C@;luHYmOEFC}6e!@+EZxA?q_{jGz51zuJk%3C#uN;=$UXPP;R%MrLyj zKkXyDMy0ZvBOlN)Sg3t}wDXF9(pIKWex(85D(0bIZPc0F+;n=jdUNslcjqr~_+Fjd zxCBiVjUJkL{hAZv%JHVp+(KAiT&m|9O=6swZQ+u*a*#`;p}@-5z0gXx>EUEUMEa)L zhPc<}R1Gr)DYtyGB_ikKTm+T(Wbc7K2mL0OorTJGYPf^i$NQz8VWe%{&}=g=bthL* z!;Ey&^xLEz&22jwo6LIkgb%wUakq12_i!~e)SPUh^!v)0Xw@hRh6DYXt^niOWCQ!5 z%t^b2=`L^UE?erx$%!s~M&*-MQywjuv4ep;udXta=Nl60(%Y#$7l%Eq?L8Fn;>@`) zAM;*)!csR{l=|yhU-Y;?yUr6*C7YQvX;?Kk?N=w#z>sazR>R#o{->G9X7eALiP6i= zMBar#sHMsBd23WposJn!=Cl4;ZF>7DJA++=YOGF0lB~@@W%B!Y_pc%pQS6i3(HklE z7UrhS8!a{L>=sHy82K%Rn+>w2-(4G=o2t*XuO50jzPsF@G(PX`q{=SF#nDjqWb?dz zx%5VJmbtm?T^aluVS`*qGb2{b{449|D`E^?zE|;C6`sg+tLe-&|WL4pWz8rU?KDu%I_O)X@i?&uiL%u4@xId+@uC6Xc zQ~2scTjpfr>^F8h!-5mJbL}j1?L;?dy7NVlLtPdF!XYjX;bF1nu9JudXuh&>^Ig&QlIFe02TQ^{PLrz>SqcP6zd`1wb ztPB@43l!Zx<1?GDrV+Tt@MHUz4XD0@BpQ=t(DzrCWpbu-3`l!8|_w~?q z^k7GLjSFtNn6g#vu_i88WTfD8`T6L&Rn`v6N@*!U%re{PUjNi z#9YNHscYBb$3M%sxrb=B<~X(Gx@V8(A1*#U`AlEll(+lULpF=L>>GZvQ&-5 z)_#|X)bMj-G&U%Fnht7hre#FtwY`ki|G__0o9 z)S+XB)RK_SPDJuF6M&PhZLxo+o^IC8xs*4#Kj)cDs?X=|@LRd+D zuCwErEwkWnj#<%R?ojg~c5$-LBCu(neb}H`bIBU<#o6EGR)b!tx#RrD5*bVygX_rY zw*Ef4#VBxtW=6})X97!x0!GF-Ta!WC22anstyvfm`mLP)OSjCHuF<^gmp_%@$nYJG zGsa&Ec*V01nA%MH_)pg5{U~rW4_8&q$ZE~D(gOSnZIZcuJw>x5BsP0tCNefl@uOx* z>Dw#P5wOXzh*;!dxj~#Q9h>;ExFMB8E&!tzJV%Sz+Uw_ec*D39CR(AGS!?y1= zH8p3>oN?XFU6hxXS5(w^+nwLY*toAUdbh9?yqtq0YyPLxcwbdQ~m-wf))wL(*lu+QCV$!9uz*hm%*hX&>; zJ4>7FHeeCaAKueS&gjT{Ih&{pHNc0#s)sRjL24vVnxMDlxf%YoLY+?jWXF*3pT5ed zc5E>DA<;P3j`nqR&F=4w5Y+K#j0zkFQzkmk8HFu+t)>L8wKwXYV);Ia1Qhs;CwFMcc#l+t72^&AnxgXr!0=Z2ad(|U%pVBGs9OepJ z?EkGiwVptZ7M48=`SzKk3w=ZEDsdK=bJ#SgTWu2iZopm7zVtDRZC8i-?))UnIigQd z+QeMw&tm{WKi*rV^TEIcgC;dyPXvJ7+sVd_N4wP3H8N55s@lzUJTcwfi?+HAS$Q#Y zZ6S&_$;Z02AA4}ji^E^3y9)i2VHFwU#a0*gYl7=d-T5be6cd+0U6P)538Df(pKdol z)5EX_mSJ`wI|{Zs9ypdY)rv=C%SOs6k&_Z6a^&kLEpyV@l#(=S9BkLTsl>u|OLH)1 zju8c*gI`!wlQjyJVs86|IS&sHR_BRE>!Bn)ysvKJ(Kd0%1nY#m zg;`@kgmR({g=xXMg- zIRyi~0SZCqvRGa&iD_8o;BgP&w&IQ}fPJ{&*<)5m$VfQu;pkFtF`Kdr|1^ zAvU&|?ojv6qCj5b&H`TydrUT3Gchrl_EqvXJFMiHCm(P-9dh>J-#tMzC^z%z^xZAY zb`!UHCjgINyR6y4^dbD?qgGjGF*zIa6U<_Mdkk~7D5sfBPZ!(UXb{Xd2^vH-RGBRHN{&jd@LJ^P7ui&%vyk_+V+4H6R2XK?*W5}t) z^vGm5p3HL2A)w@Ze?swAr<}8E=*!<;@j)In?@xit9-Hwn=);WW6syuAy9 z_^nIdh)Tb^>dT>?kK6%BHK|s68VIJ-kY?Ifo2Y}ulu=&APrNF+wY3%N5)a~=9!PEq z0vh9Egl}vUKiz`e@-9rZQS%LdLTNv^6A8$nSHy8mu-xGzM*{GM_B>A(i6B1Pnctgs zbG3JMG1||KtXxCIhnvR6#>)8j5?dMob1&!F&8=^h}(gJ3mBO0?Uz0 zOeBawi}LFrb*B`hq)Ko)ym<77+qrgAEl-g?l+(>J$19a20FDRT`AUO^@bORjdvjJw zmO+D1NVtpqGB{+vIQwiTX9z1#Z+Pg;@1C(P!Nuw7+wK5g{j@c!aEmtGJ_d(fw+3nx zJ(%V%!bonbwo=hBwwc#11Af3K8D8{n(AuYF{3SdNOCu z^hSRB_DuxN;;>?+)p&13v=TS(lH?$Je>1hvcmkY>SPtO|DTW}^DrRP8lY;4b9jaGfph~@_S#rZORVnkE-JalKrt$D1zgJ-LSomgMcuAb(dbh=ZT zy`3bp@336d4sQK=tdChd;JTb#CHxj>M&#>G;t+&R!C@ttqOg(Syqn)ocK$pt3jp{1j9hk0@wx5Q@6XwwMuTTf&Fo{CPlJp*?zaVPp+ zl4n2zOK-M)cLkO2{Pp@gOrm__MnJ87=a&uax|LB1X(EKS8h!^>NiPP>Hd=NCf=_H> z6tDq1LEhPQ{N|_WE;8B2$7isFc>B36tt+bO?}DG*`SE@Y0IXfx12x4EO zK{hES`oWt6uu7pTFOTfx(yit!=Ht{T3Yed4vj60;0-rU29n-pqiQZ~ktdXq=wotVm zNX(ueFbEZK2gx}zR=~*)eD{Dt8*5^q(xE{NvBpstaK^a%*XyrOHYt6$B@DM% zvvJ3-WP_%^H|=_34U8c`!6E07*_4uW0l9I>$%2Nh7jQ>KMTPLv znGzoL3jLrdduJDy^XJZGWM)nd)M;pI_xAVm-TwXzsO$3QkqRdcFp!3Qe*XrwHnX&{ zQb{+91_{o}%7PzMmY35661jtb!B8lxmrk5GK^&$VJ#TqM1>Bi_^X6X}mc}Komp(-D zT6Luikj%!)x_0A6^e%bq7i<9VVPgKB?d^9oHCcJ+mOkikP3i^jmf02CXj zU0qlA^vM&mp+;pBR?5>lE?^VyJHR_tR8+8{UAuOnG+IRZ>8*%l;Xz)+<-l=UYZpn9 zcFUG63=9lUsp#Y5<3Y`h4Gm8mKfalsm}5tPPe-@_uUM5VEiLWr>_9t)U<4QhC76C= zM$h1&_y+2wPf7}0N3YsT&c-GKF_)Zd4zzf6;hYn0!n~NOx839pIQ4p$mjQ6-WJ0oM91Q`L6J5o_R&cP!h?+!=FP7=w0ZQnk%iubapk4nqR z{LdJ7foQ#zYb4yR3^*SW| zF)>m2&nxTH668qXjxj2kY1$R<19{E4^y{muswUgq1!Jx~CRbDJ>+O-&4L4b2;o-3w zZvK2!DJjEjK=J0yo4UGD2??A>DMOt?9l~%n+Hc;6<@*N)>JoK)UcIsac7=zBy9>-* z5)%_MA)pP{91FIvR|PnpkU&&`Lyei~I#n?n=#FjNaa`z+?|M-=TaY&Qz&nbHitx^7 zPEPCAu1zuO$amaw;MHo1vjtzpHie!cp2dRrQc+rzl$0Q zJ32aj0C8039q@iUw6}Loh%!|nDgIl4Bx%RMZ*|ggv>osmblUJ1;Q7Oc5BMCSCS(ck z5X2j0x6lLl&KVhv0&hViFB%(wx+pDe zToiC-aBz@^hbQDb0iJl++;Koh{$&VO5`yy|;kHQg5Lwt2KmGs{{KpX7Fa)bD_(t~J z=+6hMHxSFTo10?Ko+~XVxccW~j-T&FlO+A_a46incMrAL_h&oH;3P1OUhPMx?G(LO z$Xf~oIAYzVO?pjPh&o%Om>AXUEUhwT(ELBnvv&uAQ|OSRi;F+XjMwL%;t=SzZ7U<< z*J)|#4m-Ht?6$lX)JM3m!MIcVL6844D|`B=D+Ca>Hpc@G;#Kq@1d9gg2E}#p&FkU zsQdZyXy~6cr4xX#*aawq6VmgT{3v}#QU0m`wxO&Z+^wiY1Z{8F@gJ}8kxVE-7WE;gDg+#F=hxh65 z>831OG9T1~kdP3teyAA{kz;h{C}+dEjYfhbBQ7H&<8ute?#3Q^`l0&N zwtr<4hxo70K(E?I+H$Y>92*}Q=|M8Pdi5%5+Y8HHC25+Uwx@6mKoI`u%an=9L{V)F3b!Ox9}*0E2N@k(Ja<-(Br!Wy$h z2RdDUahA?bPA<&(dst_ANlbHg_*7(Hpm(vd8TxS0^L<6s-I7lszIq8CuH0K6FoQd?cEsiU(v>zn)Lwt;Df&reNJ zkMi>J?E{MCrWdNVN=Qr3hE+v}$g1Bi_@2gCZW|dnFlQ9j)Mdv`j_CeO&K4Jo^jl}X zjmA7TcE?c44=KaRoTP0*WQ*;cbXoTz(!_dW&Ln^TRNdSme`rK3b93`#coW^YvX{5t z_>+B$9h{cNW*!Z70v($^9N{3TPyFtYHaDL{nE3kneb323#X|RScxl1S^sCmafveVG zao@f%9X$93sp4bIjmd{;F6QiwgjoxAPnPM4K*hXDOOh24G1A+U?ulM?|RKy{ivwm5){F z?CgY_rdf=%+God`2bfoFQ8xW;dbL1|*^X1naIU0KB-ZM(wEw%L1A4UPx4+(Q>eZg* zpFI4%Et|ohp|ZBRz~cLpo%Da3vW|4r{?;pdXR!NQ!z13s0=K3FBMGS%)h5x?$4tsk zmD8UbC!braUoeif+7N3x)XV=Z<>J6Dzgj=$?acExX7w^N6LZFJG7)R9Bfz&hJ30As z=_$&{l%vSZn&~}!{`~nru5Q2ChZ%Ftwx(;Z!#TwH8y1ZQSoG)g+<$I8@}Ya8)ZE2j;1Adca_Fk zCU?eKxVaJVLV<%&|8Ne?nJkNKd@^k_$Cq3U!fSQW13?C0F0BO@aaC%>YC zZv-1Var^t}GiOAHGQSDyUueWY-=g|k@3^fq*=6OGb1ZpHg;Tp#j*e-)yQM4B&@HAi z__#rVmcxT{p+liqe!@WK_u|D^6UB(@6Z}1Dr4a*R;(CIoewx2*$nlUjVjtm**bA&- zb^r89h?^U1@&QB#alezI1jE@6p$R_}B7I9p6eEj6_bDhSfDi}>FD$eL1$mIv%1?$I8WJEEGEVVL{f#q20Y^z9jDpLxSdcjrc% zsrr@)a;P<vZfrK+`s@TVwZyxck)7NWgXVL5SkPK7LYy;YVF?50f*!MweM7H5 z{=;g^)%$qQl?J`>tvnIfd&YD+t|Qj=~CNWtbUlpYW_IR<-vVmboJGGb%=*PayiKEmstfohfMXees(I zlG3`o8%W;5H*YpW?u44a&&L-K7$}^(f+TYUZ5gy1QNLuv;Zc&^x_x`w)~yFcQF8DShAkv`Zaocg?7CaatbJ?$7tRn@tOFzV~{Us4i zzBNa6B}V?bD79xmFHc^sB9G$P;s=d$sc#p2t3{a%@O2>BsMys|HXAan&1*kuA$c(J zn)O3EQ;k+UMP!;*^*eWNWZ9fyW9uF5_$eQAV;aI5y1a>riGowj55a6EQ3jzeiW1_z zQu47Y`B++W;3fvXDd^K&TwJxa25DqAmB_uZ&CTB*I;U@{J4v(S-Bob-@I7c4bL&>e zS&ZB|d^qx7{M6w%yxE6c)s1pFJ0n%RL_?9A+o0@SAtW}GjWrNrbaZrH`hXA%9V#s; z>8XhH>882dF+JUnK#(cfFPqxQV^y=!5=@4+i@!sN#x==eL+5xQrw8X~P={8ZHg`|? z9e5n0$%4>_2$ASNvj8UH@n3e0kk~#31O(t^7FJefeU*iEb+hOyZ3DlR6vwXF(Y8RL zf##6##fzZ7+FDwPc+KrxH+cRab_g}}f(D^~UzWV6lM}ip4kdvsaSIe}e!DpfC>{Fx z`n|oq1nlR_ojv;*iwC3r^7ShUFaN+mJvFrwv=-3mfSU6GA{SB2F74uz62vXZEpNlZ zicwd9o38wO<7t%Kkl2ah&&wN4iSF+1Z7kxC9zVu%j`8x=0Zveyq7y_=dU)f7C2ihe z(Rn|E&|_l=4S3ad8k#vMi%6a!Z6s2D&ex~Z5MxmMj(~ijin*?+IMH2l8?OOq8C1u; z?l!^xPzEDI%j|V>a)LD)Q1L-BfV6QP!Z6`~Zx2CJIdY``$BP4S&TPZBCqY3f5OnE| zDwZScp$$8UF9`_hkFgfvEjxCc)~h|aa^*uPdbKs)6-7Hp4x^J@WP1jRIt%U12ALhT z8iY8&=J`6OXb6MHwTWRHbSU z1#+MveG<~z8mc|l2_>wD*iY~cxb|jIX3y!FnW7;6bgU3+bWeS1LiYs-Ga%00bJJt@ z@85?(ZGU%5K|eyf8U2dtYk&YdOm-C9JTWKr&OtFX)y{37gbeN;j^E3 z^MC&2HSH}2>{IVK{X8I`9-%--=cD%ZNup-SITJ#>CT(^H72AQgphXlT7p1p~iMmcC) zqH6&;6-Y!8hJ={TgJbA2F*DnZ=CRMjqzbLTWw*RmQ?1B{p^lzKBpI z+{B3 z)(oXN8uC5e-I}*I_MAR`=f~y}LlP;LhLLe-U|^uF zZ5tzF6XJnvH=~7PCXirBBlEs~JK{t4+VFdDH?MaZ#X&?depo)n@EG6A#~#Cy zg73V3{hA=`Xnuk`p{dl}+dBi2R@ z-sEr9eRQCl}PA9X&lgU0w1r zGQUB&(VidpN-ao3QMqLv_+4e*7PvyF1OA(cB7)MlJ{1!aL%@#;&DO2)_!EFoRjjH# zLU|kW)#F@T+n4WlBxF*y6TVkF2L>8qlzERHjm8-%!fPe5Ah1JT^m0HOA3b`6USuO8 z3=J$wF)UdGb7h3)eft0p6{(q>nt|^+nvtO7Nl6osfZs`w z^|iDPQS|?Cp1V0KEudc#>LjYZzNYL&kXx;m6~PZ2U0qGh%=D|{S_T`^yO3K@uA?^j z^<~M{!k-|`7__v0b3u*~yK<#2*?_oR)n;}e8NDE_+K&A~L)l4gIh)rw{aNtCKtE}Y0ywB;=Qxv&&*-|CY1uZgX zCx_~4Yh!MtjzR?&H0gehQwA0W_oDAzgT#S001Yi|AfM&v@18O=uw|sBm+?XJFT{E5 z2T)v~2Wl0OixniL&M<;@xlS z>u;Ewo3B~(6vG9`xe*{LI3T`#)WpAqu!>}ROf|~}{carDa{tMKpG#-8WIVKP zR|ftWoHX=BB)+W(ahY0_97F>WQyRRdPxk}b(LW{*A6MgFXoGltDlU#iizzKF4Lu|n zW3MC_1`Y(70zhB{B@q=VybV{l3EXK;5S|W*gOlDfHRU(%y!!C(O@wGhYYG7a2Wmc0 zD=Q+>_2uyf7V!X0L=vU7;b8u`^dxD)5b7Xka94Z#o-;;ofK~_r2j?`DK9Ha%hMJnt zA;%e4S64fNbK{zlK+6m&TSQ7qHCQHg30>UX#f8u__n~OSV975uAHfd>8#8%Np7f#! zi(Vvb?h^2M7w6rA#~bJXZPPtrWGE>FmuExNYoO#%wVzLX{kjE0G-Se)Cr>VSO^7Ce zP{r!itHlCNe*mF{W{U}=C4-7nl*f#FEnl8Jdq&9WDjC(keo0c~8X>J)TDycyJ32a2 z)6?tf>Zo@d-^<44j3wnaVUz*TbY5P*3I|NEhdP7o7H0hD{Q$>PJg&vp_K z8vgPrH6t816*4m7u%)GiI1oh5@_}$bFb{u;T>z4vF$y+*`__SkG?cxVMZEPK`gPl3 zTg=(S#l->FAwDQ6DJ@IC>TZRKD`<@~M5ozbp;OpoCjUTFtZ9*{PS(a_zH-Sn~oKEr(_BZ;opuoh$ zBmmuf_!Tuh&z-w>nF09W&LAYH9#0uG&cVLuH9`cL+q{(dXmd(WI(QJ%QQ%3C7Torn zA#y#d1cDJGr^WgCGZ@slTkr}wV;`P{OK2lND<8T_EC!x{R*M*LAP}qmMyk=b%F4>d z#w<`F6n-Y==3x{)UH0M@YSyr&*qwx$oSv2z#ABLYT6ztML2{jzmKNX-4=Y6H-g+Vm zhZ+&FY=6>cbTlQ;CF?irI&mupZVyUAzh}<{6k6VUJ@b+bngmc`LJ0aJZ*#USh3#HZ z*wCx^{>n9&sE&R8dds$L=Ls9OB{$jimA?InZ05Lx;bz_y3h28W(pD zV_uB5ze~{b1O%ZkL=f?}zIN*(pQP5R)vFVMtH>`HtUZi2s#hYS7u+7o2mi^Fz&4uOC3l1qDL>ZbJ1(MAp@g&dy`k z<31G?#UR^5TcD(4hthLfsAX=Xn+^0LWxai?j#du%DG?j$W-u2OJr7tOF*tf24P*Rb zxfjSv?Q9XeA0$RG?&fEJ36K!_#4R;7BEVUrzkE4|78|%0x&{jqbp~XcQ74=QajAdZ zH6rwQ3~3$N2{y0I&DB7bCH#m3{vCv#GNf(j3eZs_V~X}H_2GqjP@l5B1P|S~o9hS; zaJgrPn@W+kiHQtwz1^p@Y3S+aKd)h2PHB>gS7-lXdycXO#eO;ZY0D`>97G#2hJFiB z$#7xLlHy20zQnoi1MxVDT!V=P%>Imwj+PQbAZtlp#LyHPT$rQ7NC|`&LaD*UDhMoV zMKSvu(^O?;L`R&`nRMXT@0rKP&##9*dsGzKXPPZbH*|nIIoyQL^a1iwO%Qw$bQ9!Q zNQ($B%)p^GLMSiHjTP7U&=N0^)CVJYF*iSt<|)$8?j1Wc31EgJL?dL8S2QWHHCV5J z*uv$Yt#)k3-ish;NcRG;52`2V!X8A1bhJ6+2ZHrcua1kE`3c2GB^QwW*FN{~;JB6J zh*tj8>@57$nTUiw06r>spaJYpl=Btk<;xx#z8`Lo0al~;NIGmXd_!B5(@W*rK z&V6^IkBp9{XJBZ2eSQr={&Br`d8_4MWQsh7GkN9ftDJK0KCvi*OG2N-z+V{zidV08 zEF+NG3}0*$E6T zTqVFtv9YlcRk=3qx^w3a(Y>S`elw=n)_X;RMWM|O&I9QNOOYXN5l5>O0NVuCkD@MX zVMfQ)^xe|`O_4;D(!m>1i{1g?07vW6&0`^N5oQZu5U}ZPZoUT%2Cv^l&qF+mxKwg% zP6S6mI-=TjlBi$z?c0YCmb?gkr#4B?pG;P!@1BQar=DA)^52o8&4rXOEnp+Jj+5&9qjnEynr-Mh>8Z30{OoqvKXLZtojav37+pX2b= z>S_972y$8*bBE8BG-I#AWaZezwTQ&TfGD+l7S%@L6KWjX3HKFHcWSd?yB42cSPa zC52clu1`vM(}L&Jl!dkREHt+`@e?F3`ft>AsFNX6onJnQMk-;x;Xx>}M3RY(wa11D zadhd-A%^bcxZ{XA4XZ)V;UFB9xC}7kbl=>hHD}#)WfZiZ*N@jYaEwAMFd3{*g_cXl zuJVS$b7Zd3jC@KT9v`PaeJ>b=$fZk{AfpoQ*3sV6bH=Fs2O=55)enL=P+X%CqfEnQ zNOOoEm>%En2qC_ypru7H@XPoDhXICIA*EupZ2+0@B&s+{@4dMJV+F(8M@L67yETl} z=q?c`(WR~6dmdC&R7kxV+- zt^g1W6<=6h-{loZvj*)Lk3d!B40Y9fa1W6#U%;+Jr4Gi?RZL#yd90h9EteQbOAhs)$PY$}2tmxFfNe7%*=TFCEnD~Pll=@9u3&%T;MJHLLu{ZyN8GZN?bxve z96JW>0TWHrQ&Vx&T*Nkn^1y>)F?9?{i3?!@kmzsBRFapMUveyr$zgOFTbzXBf@2^3 z^CtH~#rqx|U0v{+RjXD(s8+*wCzcj>SxhVuCUJFz7Mns5)`%B*twXG@0>;xL5ITPP zK%c`%D~Uk+Gx(BQFgiJ40HDTz8X5`(a)?J#&ge#ohsqaf9LBj#FcGxm1B8un`|aCp z=uQ%YY82NM+Ih>>qInUDOFu-fq$IODcMdL@`1$kas1g*FlteCEpw#^&F9x`aI~e|N zSc@2$E((Z1M`#IsK!zK$?H7?9_VAd5qw|NY5tn2qASIiC+5;kP0VvB+{bJf@>DURk zgrrMYur~1uXzlW`=daYsS$Pd*97cOGGBWV3slLHM3UY^p?8j6AENn>hC&DD?mN!0% z`b?GpE<`7$bcd=xd@U)FT5?C6h`6{o22>H4L`A#oj$VhIEy6$I0+xWfjiWrmBe&ss zUeXwE3_kl1k21s=A=~`1m1U^o(_Z)?jbmKW|>uVkgINU7?NWGKi zfiuSpkDwiibsHiDM(ag21N~z8Kylnc8Elxj>eweJX#eHWI-({<8I37W!Uf-&Hh)?n zB9e<63>wlBFVimgt{}ZlZeMf(2b4h~os&Sc-ZK1EJ_R8#HMkyU(9ncHx%#Ytqt4G#1Duzyo^}eUz24vfeW> z;X}U)fMfl;d*8Boz1Iozv3+>-XcaGSItoABf-qTn%VGE|+M_s%)7Z#zYGP&ay=qq8 zr8)ehd8%$i__6Tc-~V24pT9CPGhaS)=(~uz$dwVINf|4=#XY|lhlweVnVA{L90=j< z#5v1h$`k!26k&KUx@b#U_T|3ecVGL$V&v<^#IDlrfEp5PLd;obxIj3@f-qZ(l@Y|I zCax&e_v#}&#%mpCtJE}_YhZlf*2%mckZ-1ZDRq|I}8&D<$Y^%lYi!4d-CXbUs*rc%YD{XsXSDqM9UQ^1s5?IxO}+y zUKS{CFbIa%!!EjeJ_og)SMKde?d8KPiRSrVi3wGuo~5RnOwq>XxH;s z?_#p+iLhJm6=eE&U&k)4U!1GAnLc0aGZcjZP|~UpM-lbbuCA`uRt~MwgY4|=rl#BF z{&I-FCL`0{-*1DHN3Ot^%v9j44wvhuJH)e#=V{D2$#+%wOh#H?yNq(oD^w;-^LMe- zi(zW1MgL0@Q{AK02xp5^@2|@23JMBB_>+;Ta3Vwz+m8VepyMDEUI;4~Atzj0=F0}@ zatwjxyWiN9{$8`Cu-7j-{o}E{CvN`wc-EQoVa9{@qZtQ9=UK*^Ml?k%g>gz28wwmn zn4tX--y1`c!y%`orxWgzf0fx&3{@#=EV%YSN$69;NoA9pjI(d?E%c34>P0h&`h8Hl zSjs3m`mk#vP&(lFz5GwTiSK=kF%#*)eRhkxb4*H#1?m{U2ShSd+e<)Ej}D)$4f>2V zocEfA5U8Z*OQTlFy)~ClEbO1!Fx}kZ`qcU1%ORzgO2_f2;iySiVBFcZ%a!IFrm zz%&4u6V>|lh|Z-1NlfMf8Ua$B-QBD__@0A(N#uK<7XkYiHQwFzd*z>T?}1y8TZjug z8{7L3l_%NlcMob@5Oh42-gm|04aP@eV^v$vTUlAb)tCfi@D=H#lD|m74?-P9R(pGT zwlz0zMg;BIgQ-S>_zUGl1Mx8Y1vO!%i^B>Mo7csG-O4;Rq5^I%jtPcwFWlvy-S}WJ zc}vuzpwGW)aUg5%rs6F{*V15rukBQzt0%0ng4DdYlf%|A z#BnlkNJpiqJ|k;7YiKfX9p3@L>I@}g;Vq15oF6g%rB3%Q{kHk!lb-tsQOf@ppm9*$ z+*Z^BqA$L1e%Xfg=ut6d&rF+)xVYn-oMRnr9tWY+2q5Klw6XIsL5GfulN2agnn07| z^FpKh#*HJ48X6k^hpIOL$8vkyxS!^Bqju7uA`J*>AcfGNA}LKmC>0t>Dr9OTnl#WP zLIWx(r6NiiBoUP;W698DsEqOb?#KSW-}gD*V;}q7fAu`~y4Sjf^E|I}$&VhbIGmbu z=|K)i;MucEGU;n>#>J^UnF$0o2@YjGnxeERs-owZ#3lY}=pG##|2-*8{4_Co|s#W&RB+dU4jHQKLg`-rrga zWNuGr$d|YJbU_DGTX*Q7;rl{D^LidAcGQ?L`FVL4FI_r6b?YU8pA!xgkj`1kC;@cJ z3{e#h!f5IGw|AF4Fz@2fJ;}4x4b8Ag@9?fFLw<$4v2L}$w*PjLX6?y(yTW>}1czmr zFP}VK+c+n^tZ(Ju$_GtR5_(87btYLh?eue-y7*QJJX(2c`sH%zAwym` z^zPM*`44)5vAU0V!q}+3%q5v9)hzfR8Ub+d9sms-n|9mWY(h?F(TjJ0*Zcd*=pf%_ zKGNJ-3b58id0LX3WxwB5eM^TMZT^#MxZ&ORtGSjdOz-E$AOB`pzkA`3TG#qo3)hp@ z3m3|&)+5~iT-4$D<;L`&UdM`FbgRABQftu|-;u6`ZDwX>7UMRRC3oFoO#nb5@8RJw za^y(<1;$kW06Q)wJbW?#lj{ZkRrnqLSAM5)y)IuS^`OfVNs{zeDu}?qWk?bTD?-Wh z8C(OfjhczTFFIMUw_e_;#n#4W`ml+MCwY8nR5+}(eS4P|yKIuY4h^|@Z?z*0AL#WEZ6{|L%XC}!C_#Q zAqt%LXAO#eZ_or*eqKj2V;pv#6)YMTyk0&k;(C%AU?)=rp%D=eD;UMJ{<@ zxA&nXX=)+z8vEFi)dOoo`V}p>R+QfD+6VKPUe=MTm;$~mQ{5@#jZ8XtI87F{0HCf&`u$G*We53{xQK-IdiBeF|2W5}OT-_5>EQWajYf4XT%UjfM`xK(TC7XWjs(giTC_8=^O3p~MHOnW=bSPkLA5V9h5BEJb=|5(%^2 z%~k_9nAc9*IAHDHx_Ahh+DlfRqkcQo&UYR_3upEAbxwY#D~TYH0lfbGy#{B))__yp z`mP1I4!=RyQ1$hz%v7hnV$^c&bVR#W0m+SvsZkfVy`>$p{*Z6lW$o`pRC2=gq)hL=vGY zyd`vCCy((Lx;uH$+gopYMIGKQfBv_B{{eeIj!`@4y8Tj^Fd_EJmARgm(3-)1Kt8WW z)B&E2oKb%OK#LSNh25()T*lX8}ZhJ$&<%D)94&} zqJ88r^j}Zrfl&Yo3LNH``_bnvNdd2gk`feT5M6$hehWt&x%kX9LMd$Vi2+(^#mLk_1X$kyX~a4P>TQ`QrI=fulrE)!HER+HG)C4Gj%YJ_g4)#DbLw zfG()_JLt_HMQld&n39ZZ6>9j7V z#;=0WMS&pW*>FKrSyn@B;3g3qNJExZ!oDR_CK4YJ?8 z+ng1;3l(tK8MK_M0DBn?nsvErDhaQ!ZJE=S&Z9~`HQ|P{Z`4;1`|rWad-ZT6@ooS;Q908431GV z03et3%y+MT)D2+c_RX77%tI0`D&FYbqeG2^Up`N52XMz^^|W>woZix*I_|=7D?zjI z*ywq}`PCa6=yyC~)afOSo;kgy4XM(8pI1ImCSkO(dk_qayirK?wixZY&Gy4ja?y&fcY0 z60Nrdbx}9SSTb>G(Ab=!r5r6unq#8HCc+?plH)1h7E7LxL4k?i@Rp&9TU~pI9(tLs zSn;i*!i9ZEWEWI~?4Bq&9i3L4;Be3R`kZKb6)AeH=C?c_`IId{s+%CpJ`gfCKU zT_$C2aP8&jt*;deJL+q^?9$xX~#7?bWJF*t7UpL~f%+4LdO&7Pe zb!dr;F|?08I5&J&obQsc>&gnV{iZkN?;rnX+tvP){=`aeXvkk=SfF%rqG7b*sYSCS z$4122KS=+1L@PPkVb6iUOiQcGXWDM(FzF~ydb#6^R^qGj#3SP^Pcmb&DW%Mb^53iW zvw?v61yi1+G1sP{QBTZe700lgBE5(uOPA*5=Pxrgl}DnzzDLd?Es?0-(-KFBT$Ih{ z0I!3Bo_)Yk>ym=uvSr&babPvTl6WESa&u+W?2lF~W!TX|uU}uAy+tYAx^??hd6kb_ zhoF!)f1Z)i(8(JIRSGUTaut+$lw(m*QS4LsAKINn63dq^T`EYZQ3-RLtgH$J2w2+{ zj(U`$VqUVB7cysLPfSMm=Dxz0W}kE6H=hm)GPSgvZ*t<&r7;e%+HIF*7mS+O{?~i(m7&*!jE8;_Pm;OMI*24j62uS* zQDbRuDeWv?Dw`2d`^J}JAb$|9L{I?eB}9TZCau>2A&iSV(ey0Jb>zr!Qt;6}%}|yq zP<{P;s3N^jpw2`%!ltA6V&Ll-r$Hn;4m}q_qHicV(4HOVWQvBB0nX-$ebD$Pq^ha0 zaUX}b?j$3Zts8sw?(N!TTBPpb3%(8=^tF8_jtgqeS)dCssivUtyr3XhD2XO4GBvf^ zu)$*K(v#=TQSi(b;7o59Gcb6tQn`^M(V-X+jJ%B(tyuBWdSb}&-%wi3TsjfB$PLS{}6@X@n`>i^cdmXbf$)?f)71%-~bV8v;fZQ8L3a6tf{4id`)@u zX#IKfPPM)VKpYmqKGW3=DN1K*s~RL>#W+)Tx2b7RQ99kOXXD@-L;K93Tf2VUm=@`A z$@{!K4uk`cwo0G>Hpp}~2uM8ya1*{kJmMPR$x_pKXLd+CNM?k@0O9S)zC$CgqO6Q5 z)2C0LPM$a+Y$egII-ZJ2xZ0hKf~ecIZhupo-NRZpS8?n2=}X%%it5<&=ZCjl1Y0?q zaUPE)HuxEhhV~;Iwm&z8P27N3j?^Yz>L9)%^!e50v2wDq-n8664-7PEVxM4oR%JxvM4O#B;v@xK&yLBg8c!) zN91~K3|G#|;QZlkvI7~5jEszMj#KAxjOlS7Jot-bC24z#EZ@QTC~uy#fB^J+;e)fn z_ma?|^hx|(o4BQp4NbL-1_2JJO?x>V!OWSfscuop4>L*Cnm45`KK!nU^?OC{g{gby zno;19g0~aYVf~J>ys}mVsh1fUt{TZojGzifNF=jw?_NqUI%H>lQ8<&{jvMUl9k*`v zKX9ONg@KZyVp^FK9h}Cn_oFtAD@ZCbzTxZ89N*otpQ?eTsQYzvJLpD#1G@{#8O^~y zk56lETMuGH)hAYmO#f6?cAHX|`svxTXW~PeGT+#k>6GT4^Da&u%Km1QGt?rhZTYV` zcD8%|ynSVAqPK>jg&jl*LFYfou8$BuYy^#}i3!v0TM$={5Hm_TtLPkWN5cDoG?n!4GhF*FMIUtsS{mWI z$!_PodeJ`u2_qmrBimP%EuC*>Nw94@uOf&f0yO1;oOsca zW|^5ym6Jn5)DNjl&wu_2IFVXm3Yxf{W`K-{`v8AYTG~2_5Aq@nk$uo{>+W|Qw?8&( zO|Po0(#nOn+FmZ*^h4Ti^S86Nj=X(d`cv_xqVh{cqaO3~k0;K#7hS8Xd(%EO?AY#q z3%574I;zjVZLmS!)w{Yiu=V`y943^tanBo4IZ&k>TLY9bs3}fjq4HTD%11t=jgPMmJ^ZTk&)qwZEMqV zj>Y`7>bK{$T6H`cOF@m#BrGXNSRmhUJ|Bn@=$XkF@o^JbKg!G$rcK!a%qC8nFhN{1 z?ES|<&wVQx8opp0DAbdG@f9Ph2x?ARlU+?ObQQl``dk}-=-a`D4`&BkdkoCA{>Q5( z-s6pjd1CXW>Wp$7h06-hiZ-veZ_58UU;^@kFom&W#@Le42uhGMLTb?)8Vn3afWUqN zt1Sg_El~ZI%0}QHDk}+Sd04v%IidLLjl6H1UB9rX=x8(LWhf|MLlpen+FGZ@D3m)+ zq3&t<)Yz=(hm5O4#rCp76!Oocq}HuPDK@eE8H;bqN=nV2AFUV{v?CwRksoM+BU=Vf za?Si~b^n2Rqkq)6wg$_w1xw8vBNs%Cjc!Uwu(p5SxWKMU4@9t%1Ei(De)%#PM?3<6 z!Q8n*l$70$vYxUJ^|YHzNT3o$lSoft?!0;3x^xjt&`?GamKH6lz_muxkP}ZfCP#uw zE?qhxrujOCk}x2AQ6L?_(<@hsPgX)rv+`haJVI2IUxqDA;+uEx7D+BOF_~^6`LiJ= zBb3cGa^&L=%N8y?8WdE%34h+Pii#d3dkFk0V**-lopIRpxP-59Yx&iYSoR$Ex7 zDn*U0?fI+9Z#@TYnP+v#iTh)hCjD*JOnq|9f4zB;=h!X#<*YseT+!I)RQ>{@F*Gbi z8z2h4#z+Ao{k*)vndLm7#CqTXhDMHIcS4uF+b+JNs3n?F`>HkyfZt@~DqAS&_3PK4 zN#@x$^N2~x54unSA>yDTevy_I85PCv*IENTTF;oVJNJD0^XCdmO5z~NlPF@_L%TC# z#OvD|Osm@boeCor{1%yDx?n-kyJ3#(7;;XXMyk*M*XNN=l6+BO?xbW@q zyAU&ny;g2(G##|$Cp>$R;}`$nt=-qmAiO%ubsjxTksYnQFFx2^-L>UoO-p>$`l@&L zu72=nj+VEaXE3j({FTO=$!an-Bcm3k`rjt)Lf0UeKoqqyt*c0{JUS*OWc;e#ets{& za2(aK@zQ&b5Wt3W1aHgSJ|iEp)MBBF-@bbnNOinqiTe+`x~RX$J?`V}71Vb5(xs=( zdCUs29?ndGkP`8^(bwM>-|@kdc~;SdjmcGan#&KmuoB~fltzy(D=r?7M;iQB;n?Oy zQNN;JebX#DX`LFfV%wryA(w1*Gj2Rs6~D*9Yt!7A0alUyA``F3FFPNq@Z#g!6(;&M zkFIr-H$AWXLZvCc|02nY7p^_>a^LXgfI^e|{fH9_TUFn?{oB?eBb}N`Vx?B!uxZn< zfB#KMK1-RSnS)D(&`~0jXYY#Jj8G4#$WK%;U^O(yLNW=x#@nU?s-rPf4f;lTqtZ38 zdi^hOj~XxGI2YZDW-~`c)mlegx#FDVw)N2tjtzDDBFQHSM`aZiD|y6iRZ9?X6~6FD z;u&?ewM83y+7_Jlw@_`}>Lsb+7hj@W^6^FR>&sz%n`Bx(PH9ke|8v|fTw$!e#lqq< z4>N-=tM4~?9H(&Yoy>xv%ToO#2@sl?9uJ*bON}MeAih%^iywkDQmMZdhNygxQD;*d zKYaXnB$X}1mB4jpB6LT{V99IY2Zu4r3jgo)(}m94bl^;G+cNMD&`HU=;C9?y>m;w;rYNfURQo*Uz=BNRnYCw5H;HuryQnS$Q&y(wadLz4^IUh zv7Y=^BTXqS+Us&_@A7_f%loMw#*TaTk>R|zpUk^R<-Vg>-3sZ42@Tq|lJbz`&68y~ zvfY!w_ZW~yPTSU6pG-FJZXj}c@ML&me`TU1$-{y@Xl~xb6aeHVo0GIP*~{n((l6i` zs>}WR`J`zKy5EkA?fNKHna18qrTS;HuKCXCr@9?% zQk_a+z<`swZ7sKk#oPd{`TD@~Z$9|a`}b3{wO7n7A4F1r7{o@)c>7i;8S!xw>bO}_ z4hC8d9d_~-rcdwS5RRE9^ClVPH=-jWYjUsESH1O*&nPN>pmhHDs=eL)8l}xQv?I#;K=LaO8e`k zc5eS7#ZgzU4y6!54FY@&T&qvN=zYqZQFkg7Ms09Xnk&=;-hEO_9PwWQ#6NcOr|Z|`Y3M%}sd zj@iV}(BgJAl{~RX&&cwD+gmj8z`Lj#gmOTn=d+X23Hrs_fHYz5+y2)D_&HBCxGw`cnr215LHdX;t4)-NnIpsWPOK7OUoObI!dD@Bjd1g zrJndXg>eifzui4N5KZa{fP%>R80fiR20 zr`?Z?RGd0>@bS^2y{2%>Fm0ZmI?0Zx0=#NUyZAi5pb!NDEg1e#3S7TFE@o5iyLUhG zZpl}^k=0z78ZYatuRSj50GPzrpFh2*u-TD$Se`Y=BWEPf2nn zvXI2d^bluAf|%f3j48hr7ODZ=;#fr zRz0$)ZpE5{Ml-;;cNkcS{}UUkCw|n6RN3@Y&-9=>^Rlw^Oe8&YJX#+$c3w1N=R^A; z0lx(`G!Eemc`?^0?swd|vEa<9QwIl4kW*GRqUsQnT(XSEuEVyl{%6s%xE`WK>}2)_ z{+l?iLdie>TJ*K5O2H3+PAJhEH);L6eDmhS%IC7B2;DL7_*=G`m_K#stC#yG73{b- zFWtuSchTO>YRI5p$D!n6-KhgzcxU1gJO+>q7d%cj^jER5V9F{c zN@99<7hon(7*bbu_Hw@-yUUOcAP!4gQ<&s&_HhZ#gw$vix*WPPJP=(pOinJkxLjB% zamr%LFGBgr^bgAKLk6kfVh>zuQo!E|3jV?YisPsEN>U6wE|3p-fj>bs>fT$*e<_aS z5Y99&{NPYzZfsapz8B|UyfwCn86u3lq&jV(E)M1)q6=pws!UENkmv?dWsG4j+vhLx|)MQ*y7*{ zVNvA$5YeLggbCQH)IrsdIy{=EzM7dc=|aF@{I^oDF9f#pb4{|Vp) z3_EY$2L75$Z84;`h}9k4g9Uyw(e?PFmCUR!S+)$YJj-59Gk7z+ZPUDK#6B6I%7N#H z?H2E^tVr@bn&I>48=Ov07%&C^(eO4pUVIY{*8n*j!3FjViy5Qbc zc{Y%i*4ZaEf^pU9(=})7`Eth(|5L5f@Ys%aK;PsI)m^3YeY6=#NuG1uhly*YndQ_~ zFbebNapum2SCtSdw9?It2a#6qZY}TAsymoZH$MQ5{Qfm49w#c@mK2;E{p>f zf6#XO#Vn5tiBeF01a~Qxj?Mc9Hc3{Xmj-Krd;u+}`1Hi zn!|P4$d;jPNQGUyIs_YEer?|#R3dVAIqLOOy&9-&=G0KVs_UMTii){HhP}%mB#OV9 zU%&Y9cF;uDeLE?J`Y^qP=eG+*Y+mmeIW{^H|DcfP~02bzOI z`&0CcKW)@?Pr$iz%IHaiRgJr~@$%PJ!lkmhx^h!Q>c=ZfWVWr%rJoW^y+1a<*#R zylGQGjJ0ldhYtDAXnu%NxQ6f|aMWg(QuuEVtb(Yh+^k5*udv6UqG42O{L=)aAhz9LRK)yu}Z|`dJq#YfI5c`W$^yd z3C-=+*_a#*#@)iY>L-praOB92?b};3y;`@j z2gJ`#1ul>YaCPLg_5^tW25y>tmMky@U^Jnk^a}V1Win5!sd*m_s-Pu$PuzP^SXlVt zg`t(zd1pQE?Taleqz4XshP9@VEq-N)Z}4(CG<&PFGZ}1TaGzOHel8aRu%6;aY+)ux zn=Ax_yPq7VAV^_ml+f}dRFCzyA1Hok9i0165fPeFQ&?MJta$ZmX4FYbJUDdt6X^yW za)sJ4SsSA0c03Ha?x7_(#Et?N8**s&00B!Qa!nWWzT%e)|8e5+%|-AcRYCrW@xp`WBDo6iZ(zpW&kd_8Qo zxIgL#q7b3>`QS<40rmnP{P;zR)WYJ9rWV^zF<2 zToZTz@SS%9Z_9F*aKv7lf zuV$sP>|OFCdzP|^4UU2!VcS<)o?^Tm5Bh*Vy=JlpHU&!k#zC$)ri)#6{flUg`R`N!?+< zc!!z<5C_cj+2n*3G>vmFce3|_ghUO8OrGRlHcfXmubsLrBV#@Z##z(*9ZT&y&MI-r z+7~CNv{cP*?iD_|;R8-UMA-AEPfvxV5(9mD%2}1a03O(n6u8-D-r9vTc)Vg>B*Zc( z3;DCG>@D3gkEEGOT>wk;YRyE!h%_n+L4SqweH@9XUm;&BokiBY^%EZo0nN$D{H|jO z6^jtPypx4KnyGol83|ru%2|}EPlUp8hM5`cl8iNb9)0B1W37ve3v?bR6j%v=H(mn} z2Rw9z1dT1#{iBs?$zMMI_)!?|V9i&`@648_Wf_df7jp($vDnW*PkI!@w$zWz;4&8#iphMQA3x#ILT|Gr0+Fc`;_rzWI_0&{A=04mkfJ9B4Sk6 zJ^h9ZX{s%ohw=@ac*WL^{r1RNd83&*!YB_)H(p!AG=$sUl*x?YW0oUCOot8>5244& zk|_Hri?)eFiJlLz7DJ$kPGyE<&rO@I5nz3Md0|B#TO8$KW<4;*JnxjMz^^W65=J5k%@0a?pDA6h{AXwIFJ8iv++AA8+p^&RI&6CkH-SNxg-uE0M5t zS2x){1gpIi1wa8<7V$q}aj zU0?l{YJ)D9=9?hNn`Z<%;BeQhR+oY2xbyOOn)0}DytD02PC$7wT-kH%*uU(mVB{LE zE5_w!W&-aij~Maj`Ey_KBU?bnQNsH?X7iFS#mtr{H5Wg0caSOMtW;*%W}(-xTs&p; z1vHm^OEp59IzRmNm<8vrUbrw_bBJE^PMTIDqh5O+(Wh{ez;R>`hh~T8RH7*#q|>Ri zD<4lSUU7Cy&hXU{w;pP6+6g61>`bDQ z{}Tqi@Hsh#ZQc19ox@;_ixPGm5f=#DG{7lAW}r!dm;>}@pgBwgtM(7@;(JmKd@_v* z=Y(sANV98Jucllm;g$=5-6x=72~)}FHCp014oWMg3^nGX9388{!jV!A$pEkw&|VUrPWpn9nI zegwgOi>5C`+e9>=U&BiIoU@cYikWi)_Ke&`MNyHvO{&QezkiGKL(kCQ0g{r{=M#tY z@Bi5L7D9fP$94!+4CZu_P*x~Cfd4dM4*$JrPM^DrKT@})r3DmUM%%?(eyxC@7B5Fx z!8;6@w)0YGD5#VBJ6;N0GEKm#kPuyff2t+)%4Q1|9C04!{U_D-7RVO+ilop`eSwCH zP{j{@36%)@sw1r5U~o=sNlt+2(KuidBB)Nhk8op0)sG(xv6og>8ixfwq+ltN{7ezrR>E7U&eNU9X7#;z*XAduT5L938>(?bJp7F79lOgjA%w+y0kwppYBw{BsrafY^tiS5c2qVFt?cm3zLSS0lESxt()oCB$Y#BY}75byEm%<@=< zr$=PaEg@lTV&XnPIKwhq?yVSd2qufjHBGy#U?25q5svCnzkRtc)95kt9|!^@6RP5NneRjXgpXFab9W* z2nyoTq5DYJC?DGS@@g}(&&2WLyZ7h;h9?)Sp9p1To#?U!@{cDW0-~E>%>`48x#b=0 zyOEd@c{&U%m8V#~uVCtMT~Bwe_P_wn@!kq+>!L0_rBK5b-A*Ukbig4?6Gv90 zKji%j$qhv8VH++xu*Qo`OlZg-c9dXUC8Vg8XjhDlj39AF1?xu$m+uiN0qfuzP{Y&O z4b^rTU%60Jbmh*S$y~LXwnlK`ARcg7sK}f(3!Xgb(tChjIifaUHj(0lB048K+wo98 zk)BAn9}duuA~c6?w|!}qX!Ur@`}ge&=p!dbEXKIOv!+xZ?+sQ|b;Vs_Ry$&52X}vZ z&1b2p;|CoiH!>eNSXw$qjNI7R?Cv&CB(b+SO7k5SK^(NL%=`!nzK#m&>f7K2i018{ z1~cr?6w~&xKV2N{rG*<3#Mh>L#O0Li&p5`Qu{~$_JT3taoG_>tM-=jtngF#K^8q>b zabT?hIPyyF8&ETBJ*q19H^nX)P}r_|^C&pk_au0(Hh7dGUR6z$fB1hD779bx5x2TW zb0isy1_Rqf^nzdrp18KhSQm+LVB>dP>&Wc~eSMjw{9crtyk}3R|4#=hYVGFNa2Ve( zw4$ke9Smp1qP&K^I5Btb+EoV+4nSsc6(@4{2m2L@8X_Vuf)758D3r4`>9i3|Boc4V z-_@6*5sUt>U9hovzwr(R5DpCoDVQqlMb%~srCPHHD&&IXW1V!gC0~nV%meF*gj~>CkdfkbQ9TD6;bm{wz+qt5crvw3b z`EtpkMYt{Y3O3%cb?f7cQ$!cM<&yp~CjAo7|K&?%ZSA2Nw>yZshZ4uZ7D2ox4eBMX z*hKkj(BAW6$0;lGmk@rkK;5n(?x*Z2EYy*eeF$yfEa&ZIYGpN?#$LMB%EaVCc=%(B z7BCMLC8c?k4en5O->)VneiUXt3=ph$NbcQHBw>Vj0Sty36{n$gIaug?IQ<+loABj= zwdheE{iekPDe>967c^--Nr+Px(Z55BKlPMVBlKTpi6ihP03TJ%@K?QL6XCA_p~e8| z5cY}Lu%|xaT(%ceqx=sagy@M*ru_}Z?ZK0SNt!>zy1VktA)xgM%%(xp!y!5nTiM5a zoV%15m}TIBSqV}pjSRhg`2T>`(ZPL0`G(NJJ)**Pt(OfBTe{t$(8D?Nb##2pkY4Hy zxqC({{Iku_^4PI&dsh+|7B5}8me^op^DjOi;sm4DEa>a8A7K!OSy=z8263^y_D0W|k(SvznWG0LNJBIO!1zrK_(D8aKLPgzJ#? z(ml5J=ys;}#pDt85YN85>8IG&wFE@9A-IOdd zFG^WFz?Bd)O%sE}~AX%+U_ zcTzD>0H6s&?f35^NA#wOu~%c@%fR5Ea#x9gGj1?@Bnth`D3pn{b(@gl`cMOBm5hyi zu_)>UAL(U1t`s{|tnYRs@3ddas&6Xhzc0cG3n+2P1I^-S7y-S_{0TAi+) zJ7eJ`-oa`jSy4~{@$VPi+gCUtj^)#Zf!B?Tw2DirTqBZ+Y3&(GB+k9Je*&VW`eoBX%RgVhS3;~ zfc*zEqVjpNK0vs8(f1bZ&*8z7#!Q=5@bcwB=fFOXEV@I`ZpY_`_BDHp-a&0TE&eW6 z3a7mcTRB-+H z0f-nQf-eTs^b5f>ZOtoOAgGGi>Jj~SRjj_1M~(2QcSzd*GQ>+7$Q72BP~!Anq7i$< zkC8(X#5(x)j-OUM;(rU3NeRGI9$J<@=qIwx^5@gsah0JkwW{0J(!XcPg>X>NXHTBg zG}Zh0_25qeD+0Qpk2;Wc{Ah>Jk#mm$w~4Y^mn*+xmB>A9=qj*?;rOEB6r3WduK>TOO|qnx zi?^B+rAaNoIJHZeWbP&jVZnwtu zZ2Do8NpW$%NOOX2&HK4T&48NaFZmM7D8xX5lJPb~SR(!sd;j_IkJL20UHNUO&o}fV zbM4j%Bp6Vr26PCPLt6s*fX|Y6vLNeK>K3((PY0jr4rv|KwA23evYw-PNi~9Oh_DLLB z|MGqR{(~NWn7mD`;NRQ&h*#1}t`AA5LfM)4*Lc#oz;i3In>N~ogcMBLx?uZ^$+rU1 zJ}f@9nANS=W6`(pft&mY#S3q((`|O|t2cDeAMj-Im-2Mq7rs*l)l|F+KjSxKt$Num z+fJ4P@1D7L%Hzk+Lf!H+cgC#oX#y4H06+u_V9u+?r!m;AReb;cmlY{4UI|$%);Vb& zog!6Z{`a=k=Lf}`Vs4mSXbo;!_~F8Z?qND^4qr?^54W z!SBVvv|dFrI;&pqRoZ#I+M=Pu(@tMx&a^EpN^*Mng8kDHr19$Gdks68=zu3htibY9 zi%&_OiIaCd;$&KO=X3egzjc-KlC4UUuew{D9)9}#@Y6c$zK=@2=6NlxrT2&r!Jt0` zFp#279Xo24d`+TeN8W;tSCFg=80@oM#=E=x6v^I6-7>r7^S0w$oY$aQl;k2^UvziC z9i^}Z`u&YSWr{9cxUh=i84ZO{u?lj#?jZ`BmniL=(AKF{I%RUT_4yUsoYD@AKAWOZ zQ$PMl%Y$W>%cgI)e6Bfq>FC1r#nB52w7u$H-k+2h^uqFF?!K$XPX_&sI;T7AuVUD^ z-2>HiCwcw6`XF)lht-jDmM?vOaML6gp8;i3UH(eFdDH9h~WBWA9Ncho%I=Ai@DLuQIIB>_2x2a7Z39z$#SNBWyc=2aMxX;z(n>rPnvI4(aG&H-` zkE)%EVm+RtqN$G1H_m+f_CN3{j45e68oCpcaakM569de@1uQ=C$wA|t#$>Pbl!BD4 zX6cbdI?*04E5Eb^WekjM-8%SNdCSS_+-Loxny1X0vh#}P#ZWfF|lH1E8(Y4ePf_`cuJM8#Z2?%j%yxeKGLnT zE@T_02P8S#rNwu#_w3Xgs8-^cTx(`euj|`ZoDB-hT~d@<=GfTW-1mEC(Yvg7#SU|V zeM@gl4Ia`Dxd&qm)Ji*GYv@kJ$H=$KKL!T^caAduvF?>av~|#C%Ldg1=dVJ7y7TOc zcxof@VtvS)rWTn(uVRO~Wu@tg?pMDN|24<0nNwX?mq4zhRZ5o058yjv0Y3uaNI<}< z)vIStKKQmQ9c+;_u8g{s1go&FgEHHyMR zuNEh_tv>QeJAJC-d|8L)=V2q~NDaGCJ&P~iVJo-dfG7cFqC@)I{F(reRrzX@rm3Y> zhL@S8l?TdpGcCK@HF1WPC&v~otG%NdxME4p`nJorm9{M{)u{X}Q#C-?rK&Mk|NP7} z`@Z++wenA&ZZR8*4`X9p@{hsyzS~nDgU8g>)PPGw?4FTs(LZ$3wv=llG8ViKOgG+? ztigxJEq!h4#J zo!1OlLr`PaH1(JtRgB_0>kF^TM5N);h}uQ>h@hrT~ZlPM+ zSL@7;D_1=%+B{+7gX@!qe*GGy9(*Y&sW3B>`#aY1Q4btTI-0wbYL>h^`lZb(PXEKt`AiNE4NH_u z3X9vFT+ni9)U7SHwx3=mwU{x1_mBS=qvdKPAr7l7wFxHNxGgww(xe**<%#zK1x1BC zb&r8T=@*${Tjo|%^Q779W2VKrgbxlo+FrI!>*oHu&b%>knajo55w*siHf8_#g}t=Q z7_d~5kvm7Hva~OU8a1{C|2#AN^s5hj@}<<;id(3Y+}(HVQu4BxX|YGwb!62nG^mz~ z3~z3o;W()fFRL#gnD& zzC6f28~?X_pYDVEt_Am9{Og^v^9?Q;%amJdWi~Z9=Mkn49v}W}XW>Tqy)9!=01B6h zp}Vp3T!-T}nojT!bah!NJ;UD>4auGzl5i^`hsf;Q@wIYk@aS`uwZB3)O-~G3l)We? z-bh}WDm)*LtPC#MR-+t+_7_j^$@b9Ecw2XN*cq>i$_JMdzhAgB^FiQF6Unka$EDjE z4=wmPZJJu!LW`u7b^CK-&#ksnN_3v@d~(Ujh=_~#*Ejb(d=Y4R zSSFC#U%yRG^%$MoDC5xDJzr|cVw1Xi7Blnb@?w*RZIknR{KeUcZDcI_D8a<|sQ%*D z*3AKxe=nP!T&n&?{kh`v-b2*wt1d-mJgfWX@TxcCRSf-|d0!)L**x)sbAlsB4A&x# z0i~BujD4`6z~OI=gLPu?yB$LuES6bK4jUJ?+G)DQR1@P(jV`NJT>uI|7#+Rg*}EWR zsSOm^|ZLY5vr&Lc? zc-z$9)5$CAPUu7RT`Ebtkvn#4FyGWt-&0gT)J?3#3zYQCQade zf9fi1Tbey7XRBp#Q%q)I^H`l|_s^1_Z91;D((%k&QZy=NR7`8In;j!X6`jNG$yqI5 zNxS^ew8ZHi6*nj_H`G7L9?Pd^uKVlP@MXhXMZaUm0-L@+b(pzH>-VbjS#F!GV|M}$ z!D%A-V@%`rya*}S1JF5mIT$&()c5_YI}`!`n0Hdb*(LnK6Qb?~!97@j9HzO69m(|) zvc6r8481C=IGTU1EM0kXlBc}6%j+*CB}fVxe9G=8pUiL@8lvmhe~^2`w##v{XTm}2 z^nRfvje+=ttNEY!$hW)EZ%GX}U5I$>XiuSO(mEfQUIvxg2upez>=a;wI~Vh7KJ$IT zIwgV^h+>cfuYB* z;dTfEI~P&?0JQu0;RUsHPAVm&gaJN3CUe^fMk4Z_5k(c*+ zdzq+)+n$xRb;$Yin;jgArswf1v;Ott8%QjKOQQq<^m5v=rG3I&F9LLa@Ss7$MIx;u zK@Ff=Q7vNu@`k%B?{55mzxNd=2+ojra9_M?{m{z}7&`Q2iDT>Uxl;aI@)w5T{5Z3l zqZo$L*T2}GFD&vM#I157SzllPLEMQ(P9S31U-xbZPAGa9>?HT)ki%eJ$RPo%akLtv zcwh*Byx5{RIaK)bcqgOl_=}r`xPlhRo2VV#wsvW z;f>*uGDc3W6gvnCr2igzjjNj*_n$c4`?w&fnOl>WBOx3#2>Qtm#eMKO$YH(I?$i6J z&PfY6oMlcM&{tQY@Pz=lk7&BsLF9afbHhGsYG^>}`QOvL;AyOq+)vYb*?7@n1FJxy zGg|Eq&;?o5?*Lg+)-b}LTf>e!CsZoCU)z>kD%jmr-gh22aG_r9gB&cYvSDhvcx2tZn5G1P@$ z!hZB@-UN9Kzay@AMBVp(cod&=YTcpVhlXt-nb-4I)m_dRKd2Wkoym+}zXXU2$Z2lr z*2l%gAKv8V;#r#e<_#?`XG%OSyoLuwB@hxEtRnAIV##k8T{#@J(`ee5;EwqjRcXH`)jo>VyWG&|1s%+WGQ74xN66voCW9tfLjV0czx=!iM9 znrF{Aqj+)OBEyMi4o*8<*ZjD}sOb77i9$QqLWivho6FtLZPn?UtG?OvL89)@zWWYM z=n%SLl|)e^JMm(8_#}Me(Gqm%uwpCa?J~qz5U!d`*$Na{JWnTbJPJ(??~lkBu3bR^ z)tTht#W`>u=v`YH1icg1UC5X#czvj*SD*_!;x)#3Sg+EAlv^L|lKoo!&i>m;FDT{I z-MZe~62^g7SAYBA!&zsfF1hyi=0tOmeEL?R1JI?s(!GpbwN_Odv{=NX~t3TD%9Foxm9Yxwbl}Zx~na0L55ZO<# zu{{6rVHfPDzL%Aq3<-&WNxv@$FT8WW1%z!2K`>^_yEkuy%fX1j+1XAw>1}G0kn(?f zbJ%= zqb)5RBl30tbtvHO*n*EAxje|I{bSFvvmnhTkhVvRxR97A=t!M4x!gPta(N(LME?cJNpPBkj!M8%52CliR#F(RUXisG-% zo+=WZOJ`xg5fNJu&m$~^RlfVL{}V0~S;M~X8Xgx1x3i6_7@ajOVV!1&d(_yBIeyRn zwcOOH_n3^J>?7z8l$1oxCZX7^Sixw_Rvd&Sg+R>RLdRZp5Ebs4R+?~>E4Nr{hBR;A z-n4$bTyQ7R!wbN_!_i<$O72x8>oKnQPmdnJxYmmnVfip$Gx$6=y%a>FNg%2L9=ygzF`yn3Uv@@QdviwFd9@P>4BJVjX z_1%LIwB=xl!NtM#_2SpQ1vnfsg$9W5I9I%-tIwdcf$fu)Zf>Yq4f%*=6U-*RvUmUf zS7$Y1ey@cVX4`W?7L3n`3ULJA|;qF&1fB)^mlH+W-=Mnw}Y!0>Y&>ics{$BrH0KG6|5Yd*MeVVCfkuIL;HDb&{w zB_WAKp-M=r-CSJ<4;jJ`Sp%xzkOd`_qW}NM(tp4JhI%O7Hr)HPfvY?tH;VeGG21~u zF?f>gAZh7@goOByO@l*EYP;0@?-#GC=O%7BCp~NsUi|cOM7JOFD!5{GXsRp zMuGmixAii@R*S-$6n}{L*{*09*w*l%EEyUiM8Dg%sfgmc_vy2J>sCBFP>h~{G2zgB z>`d%BiFF+aChr6>lMsfFoOahf5 zOyyNlV0FaZLyg;Rp+opNzL~0oU_&n~$bTWq1YbM^U)xpOR^G}Z*IL|jLR@c`-cQQ^ zZie|@r9nlV#x-W-LpEhF%7$}^nnaZJ};y!~?`#-e3g>NlT z{<+}bYl7kl7ls7xIp)^BGQNZ$1QG`^mpNQg#!wuKfW}9WA?H5sDe&ry2Jw|@p42cG zM0((q%g7LKP(W|AwPi4Y*)4lDbGx`sj;ATm8RSIDGECR= z!IxeS#^A8U*w&mmx*$Ao;DWqt!s`9J9zy1vx(-4(Mr|ZWc6;?&!Jxgc6wWL~9hzjO zA^+(=hDd!?RwQa&<=`M(c7(%ppSHi^GE`>=@Evz0|EhZX6`>BrZBxJzEP|3LPgmR6 z&=e#!ml7-)K0p=3Vi6@EtdXE1peLZU%NGJvjtaw z1z@bZay+F4ruAq;5%#UZeL-=W=$tBEMU04nfqh8!O7`{^2~WR}r@sRyMDK%~7ngGf z@#lZUe-2G1Z{?8EF4kY<+4*dS4zq#&{{FmQ7ncUw>wL42M9v+TvH`wqEAG1y+QWGM ze1s;nb`nxjaCsA%F~s&YF!0A!ZP6=)-jL6U#L?kXojTug5jBiu6Ik3_V?aYj-Ulxc zp4IsRe&6gDmQ(;h+E0QF!$He21Ayv7V#{QJR{hh}kfKCnhHaS^o8_a6Zm$&81Pt`F zX~9oyDyyopD}NyuU<7Qt%~;VKw9T|FqY3Y|d@aPwntvr36@Zau%!!oRT(f{A_lX?N zfDm;GWPJLpLd4|=+jUz@MCZm(jHRU50NSxT9xD$QC3#QRo`aGLUGHEnNJFbl4CAeM zzoHU}rx-(n`|D>>h!6%vBGa+T$}8?WSJEGmUJ|&`&cx*PIL+6z6AbbT&Fp~?GgDKH z5Jyu%o;b0@%uGm*OfGKNAYA8ctld+z1%C8)Y^-p!+LQLVE(y!FbmrAFSMEiH&}LbB_fkZ!iR9xZ9E&I}e0FHsYf^ z1ZfX$kcjlD8<^gk%R(S0NKaQ{%CmoF7rmpU-xD9xqlkS0Fz6+Hb5@W+3NPR8k)KN+ zCypBJtNxrh(6IhIzMdTlY;+OCe1>Rc+hf97b~&>=R?C;)-S(BiJyR;Y>pH8M&Egdy zmgh#%_uK54J7%=FSJzL-_t<>sVJ4`nU(Bg=b8~y2)9G$-a&mG)!cLrpPM#b<94?j| zl)6<)Uj8!Co%`(OSy%|wvtGF%aRR)@C>S-2-hag(_)*%u z8VZy9W2zJI1&u;WMTekA+Ip>Xj5$=}wN zrzrR$Fo404q)M4R+m?&&@ff%f7l-hERCcGV4k*PqZk!|Ff%g~ti}(t&lG|Dn&Yv%2 z$VRZ*5F)}*|0mEU+?(Tn9USp0}i9g^0fOlD*W{HDI9W&}^Rca^?&d2Mxd z_g=jcnRZ|RL+E5e3n(y{`?lGzf!Af#UTF@!R(9zs1sUtd-;dp{;rAzNCjLKkod;OXef$3}+ijE?qG6R)Mj?qZ8g9zSY{)Jv(M2JZSw=#)kWz?@ zh7r>62XXSm66M^3l~PS z6BQL7Ji<*rO;9}}*#G!#cJ4tKFhv}IRKdU!DHjWC>m5)| zU|cpiWStkJ_8gypBS%JXtg$|%vW{xj=?@t?6ibA(Lt1YdT{xb*W_K44f%nXgNAx#^ zOI))?mzm~_)sjZLb?XERgHXb(K6woOS5>mx*{p`4HawS>)=gk(5rpi95|hYUsbBVc zdLH3VNYHcw^ZtPlBgJ6_AH0XoUQSxth(Uuqr6!iw7lty4LR!?LM@@AZI;bx>`e`Ln zrfO5}zL3;r@g|8PplB3l{RRy(Apwi-ZJ+gT2{ai+ZlHVjTL?~wcfB5jwL9fqr%vv& z@-Cr~NtE6YzhTqyl9ctF6Rw-XU1W?5Bz0Q!IVDmmP%E@DYiR87D;!FQrRXFurO9Lr z>Lp~x`=$NA4L3A=L>a`yyCdlm&(>WM>RBX5FHX!dZ`)RfDu^%)7Y_#5y^LbSFrO?R zO5rq;j45^M6ciHDLqXwj-?1wj_OYp$8BSPJLK8+qi7n8nOl@>{46TU?YJ3=pAso%? zYg&5h(BOcIMZdZ!$1%7=G#-EL%{m?;lu1H@6S4=vpe4V>npEiV1R53&I{&f$V630^ zJF+Z&Hk)T{5Rzzf=f*m`-^I*PiLco#BvMw4>eYeKh<#*-AiK0LnETOWLPWP??Lq1W zM&$UHVuD3MQalmM_oBR`LIrih5b6gvljwBC@w|A^hx9@!)fQ>GL}FIKzy*XnWH?i? zLAX)WufYeimxAe0lx1IE-lpV8%3Q{&Po8{ADyF6NC^3;;l~ZMY2O$F7}f> zZQR|KbV@a4G+YSs`1^lBahJoGKON6Zk>cp!Fw5M$zs%%b* z-?77`s=PHqFu^gSuQdvHSt%*#aa2=CFw%hQ{w6;@Nb3Fk`HQqPk!XndR=gxW9-;SUy9L6Y?+7%*up_?8N{ZYC*;rZmstyCFLtwDlECC5=(%DsmFyX)XXzh_#p6! zoNW?`x>yFsDa7f5_zC|=+&M)3fVwc;#PpIMED8+Ik^3G0+;8+%#y`megQq-Q@+aMa zMk-oASFWU-9J$*pgz~c@VZ$Q#C`vKBT9c5OWBCOwc!sb2_6_~3efuYmA2Tt?6c~aO zM^lZGekqhU4JyI{3g0AWPF}Hk+;HVqwPiFUIWXU`KEoXCmjk3T9V{j zK|V>MADmeNVuS7uIe>@0#kfBex}b?!O1OPPy&m|&GZfG?1-|CC zldOQ@%I-;aLa1P@O%6X=w(M}Y%^BbY7U}X0Fyaiu0I># zs2Kxq?cXniPS|2V=OUoBRSAy?$q1+^HrJLk69<3D!p^CW*muA%6gp6wKRxe-gGq=7 z1S2d$Z5n}i6a^6D|LpXHr@WA zfdnKBC&e>5)bs3x3wt}>;9JzrQao;?yEC}d`(>(Qp!XTQ=)%kWE?k`A(Lo2mK8GWi;8E++sj<}=l|+6=?ERy*5QAivQNW00JbVHU z@Gn>{r64&~SSXWxFSw$5HVRSX?^;?~f}@PjvnAX)4Hz(hmXwmN)Q+-HMBf^`sC=(c ziD-{Nb(NXEyQISh{U_gdJC8Zd`?PO-bRxkbxSq7>D90&?UCvn0tF~49^N1xrP zE^^}QgU6)0ti_R2coD6cV-;s!3&S&Kj*H59BEnh>CyO(eG|{y_isTJ|WYCbxO4Db& zb4k!kjstyxX$!u!Wdxm$7lm=$*6$Zr_EYKJedYfEwKcvhPAGyk0^+zCfFIW--s@`K z>tJogGCqaKgm4tdF1GJ(3qS*wyp>!zc#7;or&)x=F$qP)LfUp_=T4pMPCX@07FYm; zag&)dkxPQJoIrk0g^!d$iIM7ZG3Gt1uc2H=H3Qef>PLNBlH{pU+l|(ROjm zJI=&W_`>S|Y@xl^obA1ivfJ3$mcT+B5)ZX2aeQ}cdF4LHPteq0GnaU%yBUN47X~!> z^Db*jNP`K$7^AW7o*L*DLjIDZfu1jMlCqPXt#n}5zp?q%j(?nSo}>Hz7+xnnWeDg5M*aWH=ZP-E8CW28H6Nv4KpKjP(rda z3c!*q=Vxmyx)Dr@qS5tdW3JjDU0uI(mzd?60l53*Nyy#1rwp{ER~UC3j7pT6+9$G6 zK0Dty-JwM%