JAVA-15787 Created new di-modules and server-modules
- Moved spring-freemarker to spring-web-modules
This commit is contained in:
31
server-modules/apache-tomcat/pom.xml
Normal file
31
server-modules/apache-tomcat/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>apache-tomcat</artifactId>
|
||||
<name>apache-tomcat</name>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>server-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
<module>sso</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
<defaultGoal>install</defaultGoal>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
24
server-modules/apache-tomcat/sso/.dockerignore
Normal file
24
server-modules/apache-tomcat/sso/.dockerignore
Normal file
@@ -0,0 +1,24 @@
|
||||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
README.md
|
||||
7
server-modules/apache-tomcat/sso/README.md
Normal file
7
server-modules/apache-tomcat/sso/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
### Related articles
|
||||
|
||||
- [SSO with Apache Tomcat](https://www.baeldung.com/apache-tomcat-sso)
|
||||
|
||||
### Launch Example using Docker
|
||||
|
||||
$ docker-compose up
|
||||
11
server-modules/apache-tomcat/sso/docker-compose.yml
Normal file
11
server-modules/apache-tomcat/sso/docker-compose.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
version: '3.4'
|
||||
|
||||
services:
|
||||
tomcatsso:
|
||||
image: tomcat:10-jdk17-openjdk-slim-buster
|
||||
volumes:
|
||||
- ./res/conf:/usr/local/tomcat/conf
|
||||
- ./webapps:/usr/local/tomcat/webapps
|
||||
ports:
|
||||
- 8080:8080
|
||||
command: ["catalina.sh", "run"]
|
||||
18
server-modules/apache-tomcat/sso/pom.xml
Normal file
18
server-modules/apache-tomcat/sso/pom.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung.apache_tomcat</groupId>
|
||||
<artifactId>sso</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>apache-tomcat</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
264
server-modules/apache-tomcat/sso/res/conf/catalina.policy
Normal file
264
server-modules/apache-tomcat/sso/res/conf/catalina.policy
Normal file
@@ -0,0 +1,264 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// ============================================================================
|
||||
// catalina.policy - Security Policy Permissions for Tomcat
|
||||
//
|
||||
// This file contains a default set of security policies to be enforced (by the
|
||||
// JVM) when Catalina is executed with the "-security" option. In addition
|
||||
// to the permissions granted here, the following additional permissions are
|
||||
// granted to each web application:
|
||||
//
|
||||
// * Read access to the web application's document root directory
|
||||
// * Read, write and delete access to the web application's working directory
|
||||
// ============================================================================
|
||||
|
||||
|
||||
// ========== SYSTEM CODE PERMISSIONS =========================================
|
||||
|
||||
|
||||
// These permissions apply to javac
|
||||
grant codeBase "file:${java.home}/lib/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to all shared system extensions
|
||||
grant codeBase "file:${java.home}/jre/lib/ext/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to javac when ${java.home} points at $JAVA_HOME/jre
|
||||
grant codeBase "file:${java.home}/../lib/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to all shared system extensions when
|
||||
// ${java.home} points at $JAVA_HOME/jre
|
||||
grant codeBase "file:${java.home}/lib/ext/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// This permission is required when using javac to compile JSPs on Java 9
|
||||
// onwards
|
||||
//grant codeBase "jrt:/jdk.compiler" {
|
||||
// permission java.security.AllPermission;
|
||||
//};
|
||||
|
||||
|
||||
// ========== CATALINA CODE PERMISSIONS =======================================
|
||||
|
||||
// These permissions apply to the daemon code
|
||||
grant codeBase "file:${catalina.home}/bin/commons-daemon.jar" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to the logging API
|
||||
// Note: If tomcat-juli.jar is in ${catalina.base} and not in ${catalina.home},
|
||||
// update this section accordingly.
|
||||
// grant codeBase "file:${catalina.base}/bin/tomcat-juli.jar" {..}
|
||||
grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" {
|
||||
permission java.io.FilePermission
|
||||
"${java.home}${file.separator}lib${file.separator}logging.properties", "read";
|
||||
|
||||
permission java.io.FilePermission
|
||||
"${catalina.base}${file.separator}conf${file.separator}logging.properties", "read";
|
||||
permission java.io.FilePermission
|
||||
"${catalina.base}${file.separator}logs", "read, write";
|
||||
permission java.io.FilePermission
|
||||
"${catalina.base}${file.separator}logs${file.separator}*", "read, write, delete";
|
||||
|
||||
permission java.lang.RuntimePermission "shutdownHooks";
|
||||
permission java.lang.RuntimePermission "getClassLoader";
|
||||
permission java.lang.RuntimePermission "setContextClassLoader";
|
||||
|
||||
permission java.lang.management.ManagementPermission "monitor";
|
||||
|
||||
permission java.util.logging.LoggingPermission "control";
|
||||
|
||||
permission java.util.PropertyPermission "java.util.logging.config.class", "read";
|
||||
permission java.util.PropertyPermission "java.util.logging.config.file", "read";
|
||||
permission java.util.PropertyPermission "org.apache.juli.AsyncMaxRecordCount", "read";
|
||||
permission java.util.PropertyPermission "org.apache.juli.AsyncOverflowDropType", "read";
|
||||
permission java.util.PropertyPermission "org.apache.juli.ClassLoaderLogManager.debug", "read";
|
||||
permission java.util.PropertyPermission "catalina.base", "read";
|
||||
|
||||
// Note: To enable per context logging configuration, permit read access to
|
||||
// the appropriate file. Be sure that the logging configuration is
|
||||
// secure before enabling such access.
|
||||
// E.g. for the examples web application (uncomment and unwrap
|
||||
// the following to be on a single line):
|
||||
// permission java.io.FilePermission "${catalina.base}${file.separator}
|
||||
// webapps${file.separator}examples${file.separator}WEB-INF
|
||||
// ${file.separator}classes${file.separator}logging.properties", "read";
|
||||
};
|
||||
|
||||
// These permissions apply to the server startup code
|
||||
grant codeBase "file:${catalina.home}/bin/bootstrap.jar" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
// These permissions apply to the servlet API classes
|
||||
// and those that are shared across all class loaders
|
||||
// located in the "lib" directory
|
||||
grant codeBase "file:${catalina.home}/lib/-" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
|
||||
// If using a per instance lib directory, i.e. ${catalina.base}/lib,
|
||||
// then the following permission will need to be uncommented
|
||||
// grant codeBase "file:${catalina.base}/lib/-" {
|
||||
// permission java.security.AllPermission;
|
||||
// };
|
||||
|
||||
|
||||
// ========== WEB APPLICATION PERMISSIONS =====================================
|
||||
|
||||
|
||||
// These permissions are granted by default to all web applications
|
||||
// In addition, a web application will be given a read FilePermission
|
||||
// for all files and directories in its document root.
|
||||
grant {
|
||||
// Required for JNDI lookup of named JDBC DataSource's and
|
||||
// javamail named MimePart DataSource used to send mail
|
||||
permission java.util.PropertyPermission "java.home", "read";
|
||||
permission java.util.PropertyPermission "java.naming.*", "read";
|
||||
permission java.util.PropertyPermission "javax.sql.*", "read";
|
||||
|
||||
// OS Specific properties to allow read access
|
||||
permission java.util.PropertyPermission "os.name", "read";
|
||||
permission java.util.PropertyPermission "os.version", "read";
|
||||
permission java.util.PropertyPermission "os.arch", "read";
|
||||
permission java.util.PropertyPermission "file.separator", "read";
|
||||
permission java.util.PropertyPermission "path.separator", "read";
|
||||
permission java.util.PropertyPermission "line.separator", "read";
|
||||
|
||||
// JVM properties to allow read access
|
||||
permission java.util.PropertyPermission "java.version", "read";
|
||||
permission java.util.PropertyPermission "java.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vendor.url", "read";
|
||||
permission java.util.PropertyPermission "java.class.version", "read";
|
||||
permission java.util.PropertyPermission "java.specification.version", "read";
|
||||
permission java.util.PropertyPermission "java.specification.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.specification.name", "read";
|
||||
|
||||
permission java.util.PropertyPermission "java.vm.specification.version", "read";
|
||||
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vm.specification.name", "read";
|
||||
permission java.util.PropertyPermission "java.vm.version", "read";
|
||||
permission java.util.PropertyPermission "java.vm.vendor", "read";
|
||||
permission java.util.PropertyPermission "java.vm.name", "read";
|
||||
|
||||
// Required for OpenJMX
|
||||
permission java.lang.RuntimePermission "getAttribute";
|
||||
|
||||
// Allow read of JAXP compliant XML parser debug
|
||||
permission java.util.PropertyPermission "jaxp.debug", "read";
|
||||
|
||||
// All JSPs need to be able to read this package
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat";
|
||||
|
||||
// Precompiled JSPs need access to these packages.
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.el";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime";
|
||||
permission java.lang.RuntimePermission
|
||||
"accessClassInPackage.org.apache.jasper.runtime.*";
|
||||
|
||||
// Applications using WebSocket need to be able to access these packages
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.websocket";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.websocket.server";
|
||||
};
|
||||
|
||||
|
||||
// The Manager application needs access to the following packages to support the
|
||||
// session display functionality. It also requires the custom Tomcat
|
||||
// DeployXmlPermission to enable the use of META-INF/context.xml
|
||||
// These settings support the following configurations:
|
||||
// - default CATALINA_HOME == CATALINA_BASE
|
||||
// - CATALINA_HOME != CATALINA_BASE, per instance Manager in CATALINA_BASE
|
||||
// - CATALINA_HOME != CATALINA_BASE, shared Manager in CATALINA_HOME
|
||||
grant codeBase "file:${catalina.base}/webapps/manager/-" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.ha.session";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.util";
|
||||
permission org.apache.catalina.security.DeployXmlPermission "manager";
|
||||
};
|
||||
grant codeBase "file:${catalina.home}/webapps/manager/-" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.ha.session";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.util";
|
||||
permission org.apache.catalina.security.DeployXmlPermission "manager";
|
||||
};
|
||||
|
||||
// The Host Manager application needs the custom Tomcat DeployXmlPermission to
|
||||
// enable the use of META-INF/context.xml
|
||||
// These settings support the following configurations:
|
||||
// - default CATALINA_HOME == CATALINA_BASE
|
||||
// - CATALINA_HOME != CATALINA_BASE, per instance Host Manager in CATALINA_BASE
|
||||
// - CATALINA_HOME != CATALINA_BASE, shared Host Manager in CATALINA_HOME
|
||||
grant codeBase "file:${catalina.base}/webapps/host-manager/-" {
|
||||
permission org.apache.catalina.security.DeployXmlPermission "host-manager";
|
||||
};
|
||||
grant codeBase "file:${catalina.home}/webapps/host-manager/-" {
|
||||
permission org.apache.catalina.security.DeployXmlPermission "host-manager";
|
||||
};
|
||||
|
||||
|
||||
// You can assign additional permissions to particular web applications by
|
||||
// adding additional "grant" entries here, based on the code base for that
|
||||
// application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files.
|
||||
//
|
||||
// Different permissions can be granted to JSP pages, classes loaded from
|
||||
// the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/
|
||||
// directory, or even to individual jar files in the /WEB-INF/lib/ directory.
|
||||
//
|
||||
// For instance, assume that the standard "examples" application
|
||||
// included a JDBC driver that needed to establish a network connection to the
|
||||
// corresponding database and used the scrape taglib to get the weather from
|
||||
// the NOAA web server. You might create a "grant" entries like this:
|
||||
//
|
||||
// The permissions granted to the context root directory apply to JSP pages.
|
||||
// grant codeBase "file:${catalina.base}/webapps/examples/-" {
|
||||
// permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
|
||||
// permission java.net.SocketPermission "*.noaa.gov:80", "connect";
|
||||
// };
|
||||
//
|
||||
// The permissions granted to the context WEB-INF/classes directory
|
||||
// grant codeBase "file:${catalina.base}/webapps/examples/WEB-INF/classes/-" {
|
||||
// };
|
||||
//
|
||||
// The permission granted to your JDBC driver
|
||||
// grant codeBase "jar:file:${catalina.base}/webapps/examples/WEB-INF/lib/driver.jar!/-" {
|
||||
// permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
|
||||
// };
|
||||
// The permission granted to the scrape taglib
|
||||
// grant codeBase "jar:file:${catalina.base}/webapps/examples/WEB-INF/lib/scrape.jar!/-" {
|
||||
// permission java.net.SocketPermission "*.noaa.gov:80", "connect";
|
||||
// };
|
||||
|
||||
// To grant permissions for web applications using packed WAR files, use the
|
||||
// Tomcat specific WAR url scheme.
|
||||
//
|
||||
// The permissions granted to the entire web application
|
||||
// grant codeBase "war:file:${catalina.base}/webapps/examples.war*/-" {
|
||||
// };
|
||||
//
|
||||
// The permissions granted to a specific JAR
|
||||
// grant codeBase "war:file:${catalina.base}/webapps/examples.war*/WEB-INF/lib/foo.jar" {
|
||||
// };
|
||||
208
server-modules/apache-tomcat/sso/res/conf/catalina.properties
Normal file
208
server-modules/apache-tomcat/sso/res/conf/catalina.properties
Normal file
@@ -0,0 +1,208 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#
|
||||
# List of comma-separated packages that start with or equal this string
|
||||
# will cause a security exception to be thrown when
|
||||
# passed to checkPackageAccess unless the
|
||||
# corresponding RuntimePermission ("accessClassInPackage."+package) has
|
||||
# been granted.
|
||||
package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.tomcat.
|
||||
#
|
||||
# List of comma-separated packages that start with or equal this string
|
||||
# will cause a security exception to be thrown when
|
||||
# passed to checkPackageDefinition unless the
|
||||
# corresponding RuntimePermission ("defineClassInPackage."+package) has
|
||||
# been granted.
|
||||
#
|
||||
# by default, no packages are restricted for definition, and none of
|
||||
# the class loaders supplied with the JDK call checkPackageDefinition.
|
||||
#
|
||||
package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,\
|
||||
org.apache.jasper.,org.apache.naming.,org.apache.tomcat.
|
||||
|
||||
#
|
||||
#
|
||||
# List of comma-separated paths defining the contents of the "common"
|
||||
# classloader. Prefixes should be used to define what is the repository type.
|
||||
# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
|
||||
# If left as blank,the JVM system loader will be used as Catalina's "common"
|
||||
# loader.
|
||||
# Examples:
|
||||
# "foo": Add this folder as a class repository
|
||||
# "foo/*.jar": Add all the JARs of the specified folder as class
|
||||
# repositories
|
||||
# "foo/bar.jar": Add bar.jar as a class repository
|
||||
#
|
||||
# Note: Values are enclosed in double quotes ("...") in case either the
|
||||
# ${catalina.base} path or the ${catalina.home} path contains a comma.
|
||||
# Because double quotes are used for quoting, the double quote character
|
||||
# may not appear in a path.
|
||||
common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
|
||||
|
||||
#
|
||||
# List of comma-separated paths defining the contents of the "server"
|
||||
# classloader. Prefixes should be used to define what is the repository type.
|
||||
# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
|
||||
# If left as blank, the "common" loader will be used as Catalina's "server"
|
||||
# loader.
|
||||
# Examples:
|
||||
# "foo": Add this folder as a class repository
|
||||
# "foo/*.jar": Add all the JARs of the specified folder as class
|
||||
# repositories
|
||||
# "foo/bar.jar": Add bar.jar as a class repository
|
||||
#
|
||||
# Note: Values may be enclosed in double quotes ("...") in case either the
|
||||
# ${catalina.base} path or the ${catalina.home} path contains a comma.
|
||||
# Because double quotes are used for quoting, the double quote character
|
||||
# may not appear in a path.
|
||||
server.loader=
|
||||
|
||||
#
|
||||
# List of comma-separated paths defining the contents of the "shared"
|
||||
# classloader. Prefixes should be used to define what is the repository type.
|
||||
# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
|
||||
# the "common" loader will be used as Catalina's "shared" loader.
|
||||
# Examples:
|
||||
# "foo": Add this folder as a class repository
|
||||
# "foo/*.jar": Add all the JARs of the specified folder as class
|
||||
# repositories
|
||||
# "foo/bar.jar": Add bar.jar as a class repository
|
||||
# Please note that for single jars, e.g. bar.jar, you need the URL form
|
||||
# starting with file:.
|
||||
#
|
||||
# Note: Values may be enclosed in double quotes ("...") in case either the
|
||||
# ${catalina.base} path or the ${catalina.home} path contains a comma.
|
||||
# Because double quotes are used for quoting, the double quote character
|
||||
# may not appear in a path.
|
||||
shared.loader=
|
||||
|
||||
# Default list of JAR files that should not be scanned using the JarScanner
|
||||
# functionality. This is typically used to scan JARs for configuration
|
||||
# information. JARs that do not contain such information may be excluded from
|
||||
# the scan to speed up the scanning process. This is the default list. JARs on
|
||||
# this list are excluded from all scans. The list must be a comma separated list
|
||||
# of JAR file names.
|
||||
# The list of JARs to skip may be over-ridden at a Context level for individual
|
||||
# scan types by configuring a JarScanner with a nested JarScanFilter.
|
||||
# The JARs listed below include:
|
||||
# - Tomcat Bootstrap JARs
|
||||
# - Tomcat API JARs
|
||||
# - Catalina JARs
|
||||
# - Jasper JARs
|
||||
# - Tomcat JARs
|
||||
# - Common non-Tomcat JARs
|
||||
# - Test JARs (JUnit, Cobertura and dependencies)
|
||||
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\
|
||||
annotations-api.jar,\
|
||||
ant-junit*.jar,\
|
||||
ant-launcher.jar,\
|
||||
ant.jar,\
|
||||
asm-*.jar,\
|
||||
aspectj*.jar,\
|
||||
bootstrap.jar,\
|
||||
catalina-ant.jar,\
|
||||
catalina-ha.jar,\
|
||||
catalina-ssi.jar,\
|
||||
catalina-storeconfig.jar,\
|
||||
catalina-tribes.jar,\
|
||||
catalina.jar,\
|
||||
cglib-*.jar,\
|
||||
cobertura-*.jar,\
|
||||
commons-beanutils*.jar,\
|
||||
commons-codec*.jar,\
|
||||
commons-collections*.jar,\
|
||||
commons-daemon.jar,\
|
||||
commons-dbcp*.jar,\
|
||||
commons-digester*.jar,\
|
||||
commons-fileupload*.jar,\
|
||||
commons-httpclient*.jar,\
|
||||
commons-io*.jar,\
|
||||
commons-lang*.jar,\
|
||||
commons-logging*.jar,\
|
||||
commons-math*.jar,\
|
||||
commons-pool*.jar,\
|
||||
derby-*.jar,\
|
||||
dom4j-*.jar,\
|
||||
easymock-*.jar,\
|
||||
ecj-*.jar,\
|
||||
el-api.jar,\
|
||||
geronimo-spec-jaxrpc*.jar,\
|
||||
h2*.jar,\
|
||||
hamcrest-*.jar,\
|
||||
hibernate*.jar,\
|
||||
httpclient*.jar,\
|
||||
icu4j-*.jar,\
|
||||
jakartaee-migration-*.jar,\
|
||||
jasper-el.jar,\
|
||||
jasper.jar,\
|
||||
jaspic-api.jar,\
|
||||
jaxb-*.jar,\
|
||||
jaxen-*.jar,\
|
||||
jdom-*.jar,\
|
||||
jetty-*.jar,\
|
||||
jmx-tools.jar,\
|
||||
jmx.jar,\
|
||||
jsp-api.jar,\
|
||||
jstl.jar,\
|
||||
jta*.jar,\
|
||||
junit-*.jar,\
|
||||
junit.jar,\
|
||||
log4j*.jar,\
|
||||
mail*.jar,\
|
||||
objenesis-*.jar,\
|
||||
oraclepki.jar,\
|
||||
oro-*.jar,\
|
||||
servlet-api-*.jar,\
|
||||
servlet-api.jar,\
|
||||
slf4j*.jar,\
|
||||
taglibs-standard-spec-*.jar,\
|
||||
tagsoup-*.jar,\
|
||||
tomcat-api.jar,\
|
||||
tomcat-coyote.jar,\
|
||||
tomcat-dbcp.jar,\
|
||||
tomcat-i18n-*.jar,\
|
||||
tomcat-jdbc.jar,\
|
||||
tomcat-jni.jar,\
|
||||
tomcat-juli-adapters.jar,\
|
||||
tomcat-juli.jar,\
|
||||
tomcat-util-scan.jar,\
|
||||
tomcat-util.jar,\
|
||||
tomcat-websocket.jar,\
|
||||
tools.jar,\
|
||||
websocket-api.jar,\
|
||||
wsdl4j*.jar,\
|
||||
xercesImpl.jar,\
|
||||
xml-apis.jar,\
|
||||
xmlParserAPIs-*.jar,\
|
||||
xmlParserAPIs.jar,\
|
||||
xom-*.jar
|
||||
|
||||
# Default list of JAR files that should be scanned that overrides the default
|
||||
# jarsToSkip list above. This is typically used to include a specific JAR that
|
||||
# has been excluded by a broad file name pattern in the jarsToSkip list.
|
||||
# The list of JARs to scan may be over-ridden at a Context level for individual
|
||||
# scan types by configuring a JarScanner with a nested JarScanFilter.
|
||||
tomcat.util.scan.StandardJarScanFilter.jarsToScan=\
|
||||
log4j-taglib*.jar,\
|
||||
log4j-web*.jar,\
|
||||
log4javascript*.jar,\
|
||||
slf4j-taglib*.jar
|
||||
|
||||
# String cache configuration.
|
||||
tomcat.util.buf.StringCache.byte.enabled=true
|
||||
#tomcat.util.buf.StringCache.char.enabled=true
|
||||
#tomcat.util.buf.StringCache.trainThreshold=500000
|
||||
#tomcat.util.buf.StringCache.cacheSize=5000
|
||||
31
server-modules/apache-tomcat/sso/res/conf/context.xml
Normal file
31
server-modules/apache-tomcat/sso/res/conf/context.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!-- The contents of this file will be loaded for each web application -->
|
||||
<Context>
|
||||
|
||||
<!-- Default set of monitored resources. If one of these changes, the -->
|
||||
<!-- web application will be reloaded. -->
|
||||
<WatchedResource>WEB-INF/web.xml</WatchedResource>
|
||||
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
|
||||
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
|
||||
|
||||
<!-- Uncomment this to enable session persistence across Tomcat restarts -->
|
||||
<!--
|
||||
<Manager pathname="SESSIONS.ser" />
|
||||
-->
|
||||
</Context>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<jaspic-providers xmlns="http://tomcat.apache.org/xml"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://tomcat.apache.org/xml jaspic-providers.xsd"
|
||||
version="1.0">
|
||||
<!-- No JASPIC providers configured by default -->
|
||||
</jaspic-providers>
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<xs:schema xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://tomcat.apache.org/xml"
|
||||
xmlns:jaspic="http://tomcat.apache.org/xml"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified"
|
||||
version="1.0">
|
||||
<xs:element name="jaspic-providers">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="provider" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="property" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="name" use="required" type="jaspic:propertyname" />
|
||||
<xs:attribute name="value" use="required" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="className" type="xs:string" />
|
||||
<xs:attribute name="layer" type="xs:string" />
|
||||
<xs:attribute name="appContext" type="xs:string" />
|
||||
<xs:attribute name="description" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="version" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:simpleType name="propertyname">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
90
server-modules/apache-tomcat/sso/res/conf/logging.properties
Normal file
90
server-modules/apache-tomcat/sso/res/conf/logging.properties
Normal file
@@ -0,0 +1,90 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
handlers = 1catalina.org.apache.juli.AsyncFileHandler, 2localhost.org.apache.juli.AsyncFileHandler, 3manager.org.apache.juli.AsyncFileHandler, 4host-manager.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler
|
||||
|
||||
.handlers = 1catalina.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler
|
||||
|
||||
############################################################
|
||||
# Handler specific properties.
|
||||
# Describes specific configuration info for Handlers.
|
||||
############################################################
|
||||
|
||||
1catalina.org.apache.juli.AsyncFileHandler.level = ALL
|
||||
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
|
||||
1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina.
|
||||
1catalina.org.apache.juli.AsyncFileHandler.maxDays = 90
|
||||
1catalina.org.apache.juli.AsyncFileHandler.encoding = UTF-8
|
||||
|
||||
2localhost.org.apache.juli.AsyncFileHandler.level = FINE
|
||||
2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
|
||||
2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost.
|
||||
2localhost.org.apache.juli.AsyncFileHandler.maxDays = 90
|
||||
2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8
|
||||
|
||||
3manager.org.apache.juli.AsyncFileHandler.level = FINE
|
||||
3manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
|
||||
3manager.org.apache.juli.AsyncFileHandler.prefix = manager.
|
||||
3manager.org.apache.juli.AsyncFileHandler.maxDays = 90
|
||||
3manager.org.apache.juli.AsyncFileHandler.encoding = UTF-8
|
||||
|
||||
4host-manager.org.apache.juli.AsyncFileHandler.level = FINE
|
||||
4host-manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
|
||||
4host-manager.org.apache.juli.AsyncFileHandler.prefix = host-manager.
|
||||
4host-manager.org.apache.juli.AsyncFileHandler.maxDays = 90
|
||||
4host-manager.org.apache.juli.AsyncFileHandler.encoding = UTF-8
|
||||
|
||||
java.util.logging.ConsoleHandler.level = FINE
|
||||
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
|
||||
java.util.logging.ConsoleHandler.encoding = UTF-8
|
||||
|
||||
org.apache.catalina.authenticator.level = FINE
|
||||
org.apache.catalina.authenticator.formatter = org.apache.juli.OneLineFormatter
|
||||
org.apache.catalina.authenticator.encoding = UTF-8
|
||||
|
||||
org.apache.catalina.Realm.level = FINE
|
||||
org.apache.catalina.Realm.formatter = org.apache.juli.OneLineFormatter
|
||||
org.apache.catalina.Realm.encoding = UTF-8
|
||||
|
||||
org.apache.catalina.realm.level = FINE
|
||||
org.apache.catalina.realm.formatter = org.apache.juli.OneLineFormatter
|
||||
org.apache.catalina.realm.encoding = UTF-8
|
||||
|
||||
############################################################
|
||||
# Facility specific properties.
|
||||
# Provides extra control for each logger.
|
||||
############################################################
|
||||
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = ALL
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler
|
||||
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.AsyncFileHandler
|
||||
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO
|
||||
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.AsyncFileHandler
|
||||
|
||||
# For example, set the org.apache.catalina.util.LifecycleBase logger to log
|
||||
# each component that extends LifecycleBase changing state:
|
||||
# org.apache.catalina.util.LifecycleBase.level = FINE
|
||||
|
||||
# To see debug messages in TldLocationsCache, uncomment the following line:
|
||||
#org.apache.jasper.compiler.TldLocationsCache.level = FINE
|
||||
|
||||
# To see debug messages for HTTP/2 handling, uncomment the following line:
|
||||
#org.apache.coyote.http2.level = FINE
|
||||
|
||||
# To see debug messages for WebSocket handling, uncomment the following line:
|
||||
#org.apache.tomcat.websocket.level = FINE
|
||||
151
server-modules/apache-tomcat/sso/res/conf/server.xml
Normal file
151
server-modules/apache-tomcat/sso/res/conf/server.xml
Normal file
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!-- Note: A "Server" is not itself a "Container", so you may not
|
||||
define subcomponents such as "Valves" at this level.
|
||||
Documentation at /docs/config/server.html
|
||||
-->
|
||||
<Server port="8005" shutdown="SHUTDOWN">
|
||||
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
|
||||
<!-- Security listener. Documentation at /docs/config/listeners.html
|
||||
<Listener className="org.apache.catalina.security.SecurityListener" />
|
||||
-->
|
||||
<!-- APR library loader. Documentation at /docs/apr.html -->
|
||||
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
|
||||
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
|
||||
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
|
||||
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
|
||||
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
|
||||
|
||||
<!-- Global JNDI resources
|
||||
Documentation at /docs/jndi-resources-howto.html
|
||||
-->
|
||||
<GlobalNamingResources>
|
||||
<!-- Editable user database that can also be used by
|
||||
UserDatabaseRealm to authenticate users
|
||||
-->
|
||||
<Resource name="UserDatabase" auth="Container"
|
||||
type="org.apache.catalina.UserDatabase"
|
||||
description="User database that can be updated and saved"
|
||||
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
|
||||
pathname="conf/tomcat-users.xml" />
|
||||
</GlobalNamingResources>
|
||||
|
||||
<!-- A "Service" is a collection of one or more "Connectors" that share
|
||||
a single "Container" Note: A "Service" is not itself a "Container",
|
||||
so you may not define subcomponents such as "Valves" at this level.
|
||||
Documentation at /docs/config/service.html
|
||||
-->
|
||||
<Service name="Catalina">
|
||||
|
||||
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
|
||||
<!--
|
||||
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
|
||||
maxThreads="150" minSpareThreads="4"/>
|
||||
-->
|
||||
|
||||
|
||||
<!-- A "Connector" represents an endpoint by which requests are received
|
||||
and responses are returned. Documentation at :
|
||||
HTTP Connector: /docs/config/http.html
|
||||
AJP Connector: /docs/config/ajp.html
|
||||
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
|
||||
-->
|
||||
<Connector port="8080" protocol="HTTP/1.1"
|
||||
connectionTimeout="20000"
|
||||
redirectPort="8443" />
|
||||
<!-- A "Connector" using the shared thread pool-->
|
||||
<!--
|
||||
<Connector executor="tomcatThreadPool"
|
||||
port="8080" protocol="HTTP/1.1"
|
||||
connectionTimeout="20000"
|
||||
redirectPort="8443" />
|
||||
-->
|
||||
<!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
|
||||
This connector uses the NIO implementation. The default
|
||||
SSLImplementation will depend on the presence of the APR/native
|
||||
library and the useOpenSSL attribute of the AprLifecycleListener.
|
||||
Either JSSE or OpenSSL style configuration may be used regardless of
|
||||
the SSLImplementation selected. JSSE style configuration is used below.
|
||||
-->
|
||||
<!--
|
||||
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
|
||||
maxThreads="150" SSLEnabled="true">
|
||||
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
|
||||
<SSLHostConfig>
|
||||
<Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
|
||||
type="RSA" />
|
||||
</SSLHostConfig>
|
||||
</Connector>
|
||||
-->
|
||||
|
||||
<!-- Define an AJP 1.3 Connector on port 8009 -->
|
||||
<!--
|
||||
<Connector protocol="AJP/1.3"
|
||||
address="::1"
|
||||
port="8009"
|
||||
redirectPort="8443" />
|
||||
-->
|
||||
|
||||
<!-- An Engine represents the entry point (within Catalina) that processes
|
||||
every request. The Engine implementation for Tomcat stand alone
|
||||
analyzes the HTTP headers included with the request, and passes them
|
||||
on to the appropriate Host (virtual host).
|
||||
Documentation at /docs/config/engine.html -->
|
||||
|
||||
<!-- You should set jvmRoute to support load-balancing via AJP ie :
|
||||
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
|
||||
-->
|
||||
<Engine name="Catalina" defaultHost="localhost">
|
||||
|
||||
<!--For clustering, please take a look at documentation at:
|
||||
/docs/cluster-howto.html (simple how to)
|
||||
/docs/config/cluster.html (reference documentation) -->
|
||||
<!--
|
||||
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
|
||||
-->
|
||||
|
||||
<!-- Use the LockOutRealm to prevent attempts to guess user passwords
|
||||
via a brute-force attack -->
|
||||
<Realm className="org.apache.catalina.realm.LockOutRealm">
|
||||
<!-- This Realm uses the UserDatabase configured in the global JNDI
|
||||
resources under the key "UserDatabase". Any edits
|
||||
that are performed against this UserDatabase are immediately
|
||||
available for use by the Realm. -->
|
||||
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
|
||||
resourceName="UserDatabase"/>
|
||||
</Realm>
|
||||
|
||||
<Host name="localhost" appBase="webapps"
|
||||
unpackWARs="true" autoDeploy="true">
|
||||
|
||||
<!-- SingleSignOn valve, share authentication between web applications
|
||||
Documentation at: /docs/config/valve.html -->
|
||||
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
|
||||
|
||||
|
||||
<!-- Access log processes all example.
|
||||
Documentation at: /docs/config/valve.html
|
||||
Note: The pattern used is equivalent to using pattern="common" -->
|
||||
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
|
||||
prefix="localhost_access_log" suffix=".txt"
|
||||
pattern="%h %l %u %t "%r" %s %b" />
|
||||
|
||||
</Host>
|
||||
</Engine>
|
||||
</Service>
|
||||
</Server>
|
||||
59
server-modules/apache-tomcat/sso/res/conf/tomcat-users.xml
Normal file
59
server-modules/apache-tomcat/sso/res/conf/tomcat-users.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<tomcat-users xmlns="http://tomcat.apache.org/xml"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
|
||||
version="1.0">
|
||||
<!--
|
||||
By default, no user is included in the "manager-gui" role required
|
||||
to operate the "/manager/html" web application. If you wish to use this app,
|
||||
you must define such a user - the username and password are arbitrary.
|
||||
|
||||
Built-in Tomcat manager roles:
|
||||
- manager-gui - allows access to the HTML GUI and the status pages
|
||||
- manager-script - allows access to the HTTP API and the status pages
|
||||
- manager-jmx - allows access to the JMX proxy and the status pages
|
||||
- manager-status - allows access to the status pages only
|
||||
|
||||
The users below are wrapped in a comment and are therefore ignored. If you
|
||||
wish to configure one or more of these users for use with the manager web
|
||||
application, do not forget to remove the <!.. ..> that surrounds them. You
|
||||
will also need to set the passwords to something appropriate.
|
||||
-->
|
||||
<!--
|
||||
<user username="admin" password="<must-be-changed>" roles="manager-gui"/>
|
||||
<user username="robot" password="<must-be-changed>" roles="manager-script"/>
|
||||
-->
|
||||
<!--
|
||||
The sample user and role entries below are intended for use with the
|
||||
examples web application. They are wrapped in a comment and thus are ignored
|
||||
when reading this file. If you wish to configure these users for use with the
|
||||
examples web application, do not forget to remove the <!.. ..> that surrounds
|
||||
them. You will also need to set the passwords to something appropriate.
|
||||
-->
|
||||
<!--
|
||||
<role rolename="tomcat"/>
|
||||
<role rolename="role1"/>
|
||||
<user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
|
||||
<user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
|
||||
<user username="role1" password="<must-be-changed>" roles="role1"/>
|
||||
-->
|
||||
<role rolename="admin"/>
|
||||
<user username="demo" password="demo" roles="admin"/>
|
||||
|
||||
</tomcat-users>
|
||||
59
server-modules/apache-tomcat/sso/res/conf/tomcat-users.xsd
Normal file
59
server-modules/apache-tomcat/sso/res/conf/tomcat-users.xsd
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<xs:schema xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://tomcat.apache.org/xml"
|
||||
xmlns:users="http://tomcat.apache.org/xml"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified"
|
||||
version="1.0">
|
||||
<xs:element name="tomcat-users">
|
||||
<xs:complexType>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="role">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="rolename" use="required" type="users:entityname" />
|
||||
<xs:attribute name="description" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="group">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="groupname" use="required" type="users:entityname" />
|
||||
<xs:attribute name="description" type="xs:string" />
|
||||
<xs:attribute name="roles" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="user">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="username" use="required" type="users:entityname" />
|
||||
<xs:attribute name="fullname" type="xs:string" />
|
||||
<xs:attribute name="password" type="xs:string" />
|
||||
<xs:attribute name="roles" type="xs:string" />
|
||||
<xs:attribute name="groups" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
<xs:attribute name="version" type="xs:string" />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:simpleType name="entityname">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
4742
server-modules/apache-tomcat/sso/res/conf/web.xml
Normal file
4742
server-modules/apache-tomcat/sso/res/conf/web.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd"
|
||||
id="ping"
|
||||
version="3.0">
|
||||
<display-name>Ping</display-name>
|
||||
|
||||
<security-constraint>
|
||||
<display-name>Ping Login Auth</display-name>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>PingRestrictedAccess</web-resource-name>
|
||||
<url-pattern>/private/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>admin</role-name>
|
||||
</auth-constraint>
|
||||
<user-data-constraint>
|
||||
<transport-guarantee>NONE</transport-guarantee>
|
||||
</user-data-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
|
||||
<login-config>
|
||||
<auth-method>FORM</auth-method>
|
||||
<form-login-config>
|
||||
<form-login-page>/logging.html</form-login-page>
|
||||
<form-error-page>/logging_error.html</form-error-page>
|
||||
</form-login-config>
|
||||
</login-config>
|
||||
|
||||
<filter>
|
||||
<filter-name>PingExpiresFilter</filter-name>
|
||||
<filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>ExpiresByType text/html</param-name>
|
||||
<param-value>access plus 0 seconds</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>PingExpiresFilter</filter-name>
|
||||
<url-pattern>/private/*</url-pattern>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
</web-app>
|
||||
9
server-modules/apache-tomcat/sso/webapps/ping/index.html
Normal file
9
server-modules/apache-tomcat/sso/webapps/ping/index.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ping</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="private/index.html">Start pinging</a>
|
||||
</body>
|
||||
</html>
|
||||
26
server-modules/apache-tomcat/sso/webapps/ping/logging.html
Normal file
26
server-modules/apache-tomcat/sso/webapps/ping/logging.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ping - Login</title>
|
||||
</head>
|
||||
<body>
|
||||
<form method="post" action="j_security_check">
|
||||
<table >
|
||||
<tr>
|
||||
<td>User name: </td>
|
||||
<td><input type="text" name="j_username"
|
||||
size="20"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Password: </td>
|
||||
<td><input type="password" name="j_password"
|
||||
size="20"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p></p>
|
||||
<input type="submit" value="Submit"/>
|
||||
|
||||
<input type="reset" value="Reset"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ping</title>
|
||||
</head>
|
||||
<body>
|
||||
Error logging in!
|
||||
<a href="index.html">Try again</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ping - Pinging</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="/pong/private/index.html">Pong!</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
|
||||
<display-name>Pong</display-name>
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
|
||||
<security-constraint>
|
||||
<display-name>Pong Login Auth</display-name>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>PongRestrictedAccess</web-resource-name>
|
||||
<url-pattern>/private/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>admin</role-name>
|
||||
</auth-constraint>
|
||||
<user-data-constraint>
|
||||
<transport-guarantee>NONE</transport-guarantee>
|
||||
</user-data-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
|
||||
|
||||
<login-config>
|
||||
<auth-method>DIGEST</auth-method>
|
||||
</login-config>
|
||||
|
||||
<filter>
|
||||
<filter-name>PongExpiresFilter</filter-name>
|
||||
<filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>ExpiresByType text/html</param-name>
|
||||
<param-value>access plus 0 seconds</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>PongExpiresFilter</filter-name>
|
||||
<url-pattern>/private/*</url-pattern>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
</web-app>
|
||||
9
server-modules/apache-tomcat/sso/webapps/pong/index.html
Normal file
9
server-modules/apache-tomcat/sso/webapps/pong/index.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Pong</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="private/index.html">Start ponging</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Pong - Ponging</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="/ping/private/index.html">Ping!</a>
|
||||
</body>
|
||||
</html>
|
||||
4
server-modules/netty/README.md
Normal file
4
server-modules/netty/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
### Relevant Articles:
|
||||
|
||||
- [HTTP/2 in Netty](https://www.baeldung.com/netty-http2)
|
||||
- [HTTP Server with Netty](https://www.baeldung.com/java-netty-http-server)
|
||||
33
server-modules/netty/pom.xml
Normal file
33
server-modules/netty/pom.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>netty</artifactId>
|
||||
<name>netty</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>server-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.conscrypt</groupId>
|
||||
<artifactId>conscrypt-openjdk-uber</artifactId>
|
||||
<version>${conscrypt-openjdk-uber.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<netty.version>4.1.48.Final</netty.version>
|
||||
<conscrypt-openjdk-uber.version>2.4.0</conscrypt-openjdk-uber.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.baeldung.http.server;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpContent;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpObject;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpUtil;
|
||||
import io.netty.handler.codec.http.LastHttpContent;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
public class CustomHttpServerHandler extends SimpleChannelInboundHandler<Object> {
|
||||
|
||||
private HttpRequest request;
|
||||
StringBuilder responseData = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void channelReadComplete(ChannelHandlerContext ctx) {
|
||||
ctx.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
|
||||
if (msg instanceof HttpRequest) {
|
||||
HttpRequest request = this.request = (HttpRequest) msg;
|
||||
|
||||
if (HttpUtil.is100ContinueExpected(request)) {
|
||||
writeResponse(ctx);
|
||||
}
|
||||
|
||||
responseData.setLength(0);
|
||||
responseData.append(RequestUtils.formatParams(request));
|
||||
}
|
||||
|
||||
responseData.append(RequestUtils.evaluateDecoderResult(request));
|
||||
|
||||
if (msg instanceof HttpContent) {
|
||||
HttpContent httpContent = (HttpContent) msg;
|
||||
|
||||
responseData.append(RequestUtils.formatBody(httpContent));
|
||||
responseData.append(RequestUtils.evaluateDecoderResult(request));
|
||||
|
||||
if (msg instanceof LastHttpContent) {
|
||||
LastHttpContent trailer = (LastHttpContent) msg;
|
||||
responseData.append(RequestUtils.prepareLastResponse(request, trailer));
|
||||
writeResponse(ctx, trailer, responseData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeResponse(ChannelHandlerContext ctx) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, CONTINUE, Unpooled.EMPTY_BUFFER);
|
||||
ctx.write(response);
|
||||
}
|
||||
|
||||
private void writeResponse(ChannelHandlerContext ctx, LastHttpContent trailer, StringBuilder responseData) {
|
||||
boolean keepAlive = HttpUtil.isKeepAlive(request);
|
||||
|
||||
FullHttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1, ((HttpObject) trailer).decoderResult()
|
||||
.isSuccess() ? OK : BAD_REQUEST, Unpooled.copiedBuffer(responseData.toString(), CharsetUtil.UTF_8));
|
||||
|
||||
httpResponse.headers()
|
||||
.set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
|
||||
if (keepAlive) {
|
||||
httpResponse.headers()
|
||||
.setInt(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content()
|
||||
.readableBytes());
|
||||
httpResponse.headers()
|
||||
.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
ctx.write(httpResponse);
|
||||
|
||||
if (!keepAlive) {
|
||||
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
|
||||
.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.baeldung.http.server;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
|
||||
public class HttpServer {
|
||||
|
||||
private int port;
|
||||
static Logger logger = LoggerFactory.getLogger(HttpServer.class);
|
||||
|
||||
public HttpServer(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
int port = args.length > 0 ? Integer.parseInt(args[0]) : 8080;
|
||||
|
||||
new HttpServer(port).run();
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.handler(new LoggingHandler(LogLevel.INFO))
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(new HttpRequestDecoder());
|
||||
p.addLast(new HttpResponseEncoder());
|
||||
p.addLast(new CustomHttpServerHandler());
|
||||
}
|
||||
});
|
||||
|
||||
ChannelFuture f = b.bind(port)
|
||||
.sync();
|
||||
f.channel()
|
||||
.closeFuture()
|
||||
.sync();
|
||||
|
||||
} finally {
|
||||
bossGroup.shutdownGracefully();
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.baeldung.http.server;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.DecoderResult;
|
||||
import io.netty.handler.codec.http.HttpContent;
|
||||
import io.netty.handler.codec.http.HttpObject;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.LastHttpContent;
|
||||
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
class RequestUtils {
|
||||
|
||||
static StringBuilder formatParams(HttpRequest request) {
|
||||
StringBuilder responseData = new StringBuilder();
|
||||
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri());
|
||||
Map<String, List<String>> params = queryStringDecoder.parameters();
|
||||
if (!params.isEmpty()) {
|
||||
for (Entry<String, List<String>> p : params.entrySet()) {
|
||||
String key = p.getKey();
|
||||
List<String> vals = p.getValue();
|
||||
for (String val : vals) {
|
||||
responseData.append("Parameter: ")
|
||||
.append(key.toUpperCase())
|
||||
.append(" = ")
|
||||
.append(val.toUpperCase())
|
||||
.append("\r\n");
|
||||
}
|
||||
}
|
||||
responseData.append("\r\n");
|
||||
}
|
||||
return responseData;
|
||||
}
|
||||
|
||||
static StringBuilder formatBody(HttpContent httpContent) {
|
||||
StringBuilder responseData = new StringBuilder();
|
||||
ByteBuf content = httpContent.content();
|
||||
if (content.isReadable()) {
|
||||
responseData.append(content.toString(CharsetUtil.UTF_8)
|
||||
.toUpperCase());
|
||||
responseData.append("\r\n");
|
||||
}
|
||||
return responseData;
|
||||
}
|
||||
|
||||
static StringBuilder evaluateDecoderResult(HttpObject o) {
|
||||
StringBuilder responseData = new StringBuilder();
|
||||
DecoderResult result = o.decoderResult();
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
responseData.append("..Decoder Failure: ");
|
||||
responseData.append(result.cause());
|
||||
responseData.append("\r\n");
|
||||
}
|
||||
|
||||
return responseData;
|
||||
}
|
||||
|
||||
static StringBuilder prepareLastResponse(HttpRequest request, LastHttpContent trailer) {
|
||||
StringBuilder responseData = new StringBuilder();
|
||||
responseData.append("Good Bye!\r\n");
|
||||
|
||||
if (!trailer.trailingHeaders()
|
||||
.isEmpty()) {
|
||||
responseData.append("\r\n");
|
||||
for (CharSequence name : trailer.trailingHeaders()
|
||||
.names()) {
|
||||
for (CharSequence value : trailer.trailingHeaders()
|
||||
.getAll(name)) {
|
||||
responseData.append("P.S. Trailing Header: ");
|
||||
responseData.append(name)
|
||||
.append(" = ")
|
||||
.append(value)
|
||||
.append("\r\n");
|
||||
}
|
||||
}
|
||||
responseData.append("\r\n");
|
||||
}
|
||||
return responseData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.baeldung.netty.http2;
|
||||
|
||||
import static io.netty.handler.logging.LogLevel.INFO;
|
||||
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import com.baeldung.netty.http2.client.Http2ClientResponseHandler;
|
||||
import com.baeldung.netty.http2.client.Http2SettingsHandler;
|
||||
import com.baeldung.netty.http2.server.Http2ServerResponseHandler;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpScheme;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
||||
import io.netty.handler.codec.http2.DelegatingDecompressorFrameListener;
|
||||
import io.netty.handler.codec.http2.Http2Connection;
|
||||
import io.netty.handler.codec.http2.Http2FrameCodecBuilder;
|
||||
import io.netty.handler.codec.http2.Http2FrameLogger;
|
||||
import io.netty.handler.codec.http2.Http2SecurityUtil;
|
||||
import io.netty.handler.codec.http2.HttpConversionUtil;
|
||||
import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandler;
|
||||
import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandlerBuilder;
|
||||
import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapterBuilder;
|
||||
import io.netty.handler.ssl.ApplicationProtocolConfig;
|
||||
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
|
||||
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
|
||||
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
|
||||
import io.netty.handler.ssl.ApplicationProtocolNames;
|
||||
import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.SslProvider;
|
||||
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||
|
||||
public class Http2Util {
|
||||
public static SslContext createSSLContext(boolean isServer) throws SSLException, CertificateException {
|
||||
|
||||
SslContext sslCtx;
|
||||
|
||||
SelfSignedCertificate ssc = new SelfSignedCertificate();
|
||||
|
||||
if (isServer) {
|
||||
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
|
||||
.sslProvider(SslProvider.JDK)
|
||||
.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
|
||||
.applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.ALPN,
|
||||
SelectorFailureBehavior.NO_ADVERTISE,
|
||||
SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2, ApplicationProtocolNames.HTTP_1_1))
|
||||
.build();
|
||||
} else {
|
||||
sslCtx = SslContextBuilder.forClient()
|
||||
.sslProvider(SslProvider.JDK)
|
||||
.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
|
||||
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
||||
.applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.ALPN,
|
||||
SelectorFailureBehavior.NO_ADVERTISE,
|
||||
SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2))
|
||||
.build();
|
||||
}
|
||||
return sslCtx;
|
||||
|
||||
}
|
||||
|
||||
public static ApplicationProtocolNegotiationHandler getServerAPNHandler() {
|
||||
ApplicationProtocolNegotiationHandler serverAPNHandler = new ApplicationProtocolNegotiationHandler(ApplicationProtocolNames.HTTP_2) {
|
||||
|
||||
@Override
|
||||
protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception {
|
||||
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
|
||||
ctx.pipeline()
|
||||
.addLast(Http2FrameCodecBuilder.forServer()
|
||||
.build(), new Http2ServerResponseHandler());
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Protocol: " + protocol + " not supported");
|
||||
}
|
||||
};
|
||||
return serverAPNHandler;
|
||||
|
||||
}
|
||||
|
||||
public static ApplicationProtocolNegotiationHandler getClientAPNHandler(int maxContentLength, Http2SettingsHandler settingsHandler, Http2ClientResponseHandler responseHandler) {
|
||||
final Http2FrameLogger logger = new Http2FrameLogger(INFO, Http2Util.class);
|
||||
final Http2Connection connection = new DefaultHttp2Connection(false);
|
||||
|
||||
HttpToHttp2ConnectionHandler connectionHandler = new HttpToHttp2ConnectionHandlerBuilder()
|
||||
.frameListener(new DelegatingDecompressorFrameListener(connection, new InboundHttp2ToHttpAdapterBuilder(connection).maxContentLength(maxContentLength)
|
||||
.propagateSettings(true)
|
||||
.build()))
|
||||
.frameLogger(logger)
|
||||
.connection(connection)
|
||||
.build();
|
||||
|
||||
ApplicationProtocolNegotiationHandler clientAPNHandler = new ApplicationProtocolNegotiationHandler(ApplicationProtocolNames.HTTP_2) {
|
||||
@Override
|
||||
protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
|
||||
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
|
||||
ChannelPipeline p = ctx.pipeline();
|
||||
p.addLast(connectionHandler);
|
||||
p.addLast(settingsHandler, responseHandler);
|
||||
return;
|
||||
}
|
||||
ctx.close();
|
||||
throw new IllegalStateException("Protocol: " + protocol + " not supported");
|
||||
}
|
||||
};
|
||||
|
||||
return clientAPNHandler;
|
||||
|
||||
}
|
||||
|
||||
public static FullHttpRequest createGetRequest(String host, int port) {
|
||||
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.valueOf("HTTP/2.0"), HttpMethod.GET, "/", Unpooled.EMPTY_BUFFER);
|
||||
request.headers()
|
||||
.add(HttpHeaderNames.HOST, new String(host + ":" + port));
|
||||
request.headers()
|
||||
.add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), HttpScheme.HTTPS);
|
||||
request.headers()
|
||||
.add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
|
||||
request.headers()
|
||||
.add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE);
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.baeldung.netty.http2.client;
|
||||
|
||||
import com.baeldung.netty.http2.Http2Util;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
|
||||
public class Http2ClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final SslContext sslCtx;
|
||||
private final int maxContentLength;
|
||||
private Http2SettingsHandler settingsHandler;
|
||||
private Http2ClientResponseHandler responseHandler;
|
||||
private String host;
|
||||
private int port;
|
||||
|
||||
public Http2ClientInitializer(SslContext sslCtx, int maxContentLength, String host, int port) {
|
||||
this.sslCtx = sslCtx;
|
||||
this.maxContentLength = maxContentLength;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
|
||||
settingsHandler = new Http2SettingsHandler(ch.newPromise());
|
||||
responseHandler = new Http2ClientResponseHandler();
|
||||
|
||||
if (sslCtx != null) {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
pipeline.addLast(sslCtx.newHandler(ch.alloc(), host, port));
|
||||
pipeline.addLast(Http2Util.getClientAPNHandler(maxContentLength, settingsHandler, responseHandler));
|
||||
}
|
||||
}
|
||||
|
||||
public Http2SettingsHandler getSettingsHandler() {
|
||||
return settingsHandler;
|
||||
}
|
||||
|
||||
public Http2ClientResponseHandler getResponseHandler() {
|
||||
return responseHandler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.baeldung.netty.http2.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http2.HttpConversionUtil;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
public class Http2ClientResponseHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(Http2ClientResponseHandler.class);
|
||||
private final Map<Integer, MapValues> streamidMap;
|
||||
|
||||
public Http2ClientResponseHandler() {
|
||||
streamidMap = new HashMap<Integer, MapValues>();
|
||||
}
|
||||
|
||||
public MapValues put(int streamId, ChannelFuture writeFuture, ChannelPromise promise) {
|
||||
return streamidMap.put(streamId, new MapValues(writeFuture, promise));
|
||||
}
|
||||
|
||||
public String awaitResponses(long timeout, TimeUnit unit) {
|
||||
|
||||
Iterator<Entry<Integer, MapValues>> itr = streamidMap.entrySet()
|
||||
.iterator();
|
||||
|
||||
String response = null;
|
||||
|
||||
while (itr.hasNext()) {
|
||||
Entry<Integer, MapValues> entry = itr.next();
|
||||
ChannelFuture writeFuture = entry.getValue()
|
||||
.getWriteFuture();
|
||||
|
||||
if (!writeFuture.awaitUninterruptibly(timeout, unit)) {
|
||||
throw new IllegalStateException("Timed out waiting to write for stream id " + entry.getKey());
|
||||
}
|
||||
if (!writeFuture.isSuccess()) {
|
||||
throw new RuntimeException(writeFuture.cause());
|
||||
}
|
||||
ChannelPromise promise = entry.getValue()
|
||||
.getPromise();
|
||||
|
||||
if (!promise.awaitUninterruptibly(timeout, unit)) {
|
||||
throw new IllegalStateException("Timed out waiting for response on stream id " + entry.getKey());
|
||||
}
|
||||
if (!promise.isSuccess()) {
|
||||
throw new RuntimeException(promise.cause());
|
||||
}
|
||||
logger.info("---Stream id: " + entry.getKey() + " received---");
|
||||
response = entry.getValue().getResponse();
|
||||
|
||||
itr.remove();
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
|
||||
Integer streamId = msg.headers()
|
||||
.getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text());
|
||||
if (streamId == null) {
|
||||
logger.error("HttpResponseHandler unexpected message received: " + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
MapValues value = streamidMap.get(streamId);
|
||||
|
||||
if (value == null) {
|
||||
logger.error("Message received for unknown stream id " + streamId);
|
||||
ctx.close();
|
||||
} else {
|
||||
ByteBuf content = msg.content();
|
||||
if (content.isReadable()) {
|
||||
int contentLength = content.readableBytes();
|
||||
byte[] arr = new byte[contentLength];
|
||||
content.readBytes(arr);
|
||||
String response = new String(arr, 0, contentLength, CharsetUtil.UTF_8);
|
||||
logger.info("Response from Server: "+ (response));
|
||||
value.setResponse(response);
|
||||
}
|
||||
|
||||
value.getPromise()
|
||||
.setSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MapValues {
|
||||
ChannelFuture writeFuture;
|
||||
ChannelPromise promise;
|
||||
String response;
|
||||
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(String response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public MapValues(ChannelFuture writeFuture2, ChannelPromise promise2) {
|
||||
this.writeFuture = writeFuture2;
|
||||
this.promise = promise2;
|
||||
}
|
||||
|
||||
public ChannelFuture getWriteFuture() {
|
||||
return writeFuture;
|
||||
}
|
||||
|
||||
public ChannelPromise getPromise() {
|
||||
return promise;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.baeldung.netty.http2.client;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http2.Http2Settings;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Http2SettingsHandler extends SimpleChannelInboundHandler<Http2Settings> {
|
||||
private final ChannelPromise promise;
|
||||
|
||||
public Http2SettingsHandler(ChannelPromise promise) {
|
||||
this.promise = promise;
|
||||
}
|
||||
|
||||
public void awaitSettings(long timeout, TimeUnit unit) throws Exception {
|
||||
if (!promise.awaitUninterruptibly(timeout, unit)) {
|
||||
throw new IllegalStateException("Timed out waiting for settings");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, Http2Settings msg) throws Exception {
|
||||
promise.setSuccess();
|
||||
|
||||
ctx.pipeline()
|
||||
.remove(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.baeldung.netty.http2.server;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.baeldung.netty.http2.Http2Util;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
|
||||
public final class Http2Server {
|
||||
|
||||
private static final int PORT = 8443;
|
||||
private static final Logger logger = LoggerFactory.getLogger(Http2Server.class);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SslContext sslCtx = Http2Util.createSSLContext(true);
|
||||
|
||||
EventLoopGroup group = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.option(ChannelOption.SO_BACKLOG, 1024);
|
||||
b.group(group)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.handler(new LoggingHandler(LogLevel.INFO))
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
if (sslCtx != null) {
|
||||
ch.pipeline()
|
||||
.addLast(sslCtx.newHandler(ch.alloc()), Http2Util.getServerAPNHandler());
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Channel ch = b.bind(PORT)
|
||||
.sync()
|
||||
.channel();
|
||||
|
||||
logger.info("HTTP/2 Server is listening on https://127.0.0.1:" + PORT + '/');
|
||||
|
||||
ch.closeFuture()
|
||||
.sync();
|
||||
} finally {
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.baeldung.netty.http2.server;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http2.DefaultHttp2DataFrame;
|
||||
import io.netty.handler.codec.http2.DefaultHttp2Headers;
|
||||
import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame;
|
||||
import io.netty.handler.codec.http2.Http2Headers;
|
||||
import io.netty.handler.codec.http2.Http2HeadersFrame;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
@Sharable
|
||||
public class Http2ServerResponseHandler extends ChannelDuplexHandler {
|
||||
|
||||
static final ByteBuf RESPONSE_BYTES = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8));
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
super.exceptionCaught(ctx, cause);
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if (msg instanceof Http2HeadersFrame) {
|
||||
Http2HeadersFrame msgHeader = (Http2HeadersFrame) msg;
|
||||
if (msgHeader.isEndStream()) {
|
||||
ByteBuf content = ctx.alloc()
|
||||
.buffer();
|
||||
content.writeBytes(RESPONSE_BYTES.duplicate());
|
||||
|
||||
Http2Headers headers = new DefaultHttp2Headers().status(HttpResponseStatus.OK.codeAsText());
|
||||
ctx.write(new DefaultHttp2HeadersFrame(headers).stream(msgHeader.stream()));
|
||||
ctx.write(new DefaultHttp2DataFrame(content, true).stream(msgHeader.stream()));
|
||||
}
|
||||
|
||||
} else {
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
|
||||
ctx.flush();
|
||||
}
|
||||
|
||||
}
|
||||
13
server-modules/netty/src/main/resources/logback.xml
Normal file
13
server-modules/netty/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,177 @@
|
||||
package com.baeldung.http.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpClientCodec;
|
||||
import io.netty.handler.codec.http.HttpContent;
|
||||
import io.netty.handler.codec.http.HttpContentDecompressor;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpObject;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.handler.codec.http.HttpUtil;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.LastHttpContent;
|
||||
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
|
||||
import io.netty.handler.codec.http.cookie.DefaultCookie;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
//Ensure the server class - HttpServer.java is already started before running this test
|
||||
public class HttpServerLiveTest {
|
||||
|
||||
private static final String HOST = "127.0.0.1";
|
||||
private static final int PORT = 8080;
|
||||
private Channel channel;
|
||||
private EventLoopGroup group = new NioEventLoopGroup();
|
||||
ResponseAggregator response = new ResponseAggregator();
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.group(group)
|
||||
.channel(NioSocketChannel.class)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(new HttpClientCodec());
|
||||
p.addLast(new HttpContentDecompressor());
|
||||
p.addLast(new SimpleChannelInboundHandler<HttpObject>() {
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
|
||||
response = prepareResponse(ctx, msg, response);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
channel = b.connect(HOST, PORT)
|
||||
.sync()
|
||||
.channel();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenPostSent_thenContentReceivedInUppercase() throws Exception {
|
||||
String body = "Hello World!";
|
||||
|
||||
DefaultFullHttpRequest request = createRequest(body);
|
||||
|
||||
channel.writeAndFlush(request);
|
||||
Thread.sleep(200);
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
assertEquals("HTTP/1.1", response.getVersion());
|
||||
|
||||
assertTrue(response.getContent()
|
||||
.contains(body.toUpperCase()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetSent_thenResponseOK() throws Exception {
|
||||
DefaultFullHttpRequest request = createRequest(null);
|
||||
|
||||
channel.writeAndFlush(request);
|
||||
Thread.sleep(200);
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
assertEquals("HTTP/1.1", response.getVersion());
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() throws InterruptedException {
|
||||
channel.closeFuture()
|
||||
.sync();
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
|
||||
private static DefaultFullHttpRequest createRequest(final CharSequence body) throws Exception {
|
||||
DefaultFullHttpRequest request;
|
||||
if (body != null) {
|
||||
request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/");
|
||||
request.content()
|
||||
.writeBytes(body.toString()
|
||||
.getBytes(CharsetUtil.UTF_8.name()));
|
||||
request.headers()
|
||||
.set(HttpHeaderNames.CONTENT_TYPE, "application/json");
|
||||
request.headers()
|
||||
.set(HttpHeaderNames.CONTENT_LENGTH, request.content()
|
||||
.readableBytes());
|
||||
} else {
|
||||
request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/", Unpooled.EMPTY_BUFFER);
|
||||
request.headers()
|
||||
.set(HttpHeaderNames.COOKIE, ClientCookieEncoder.STRICT.encode(new DefaultCookie("my-cookie", "foo")));
|
||||
}
|
||||
|
||||
request.headers()
|
||||
.set(HttpHeaderNames.HOST, HOST);
|
||||
request.headers()
|
||||
.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private static ResponseAggregator prepareResponse(ChannelHandlerContext ctx, HttpObject msg, ResponseAggregator responseAgg) {
|
||||
|
||||
if (msg instanceof HttpResponse) {
|
||||
HttpResponse response = (HttpResponse) msg;
|
||||
|
||||
responseAgg.setStatus(response.status()
|
||||
.code());
|
||||
|
||||
responseAgg.setVersion(response.protocolVersion()
|
||||
.text());
|
||||
|
||||
if (!response.headers()
|
||||
.isEmpty()) {
|
||||
Map<String, String> headers = new HashMap<String, String>();
|
||||
for (CharSequence name : response.headers()
|
||||
.names()) {
|
||||
for (CharSequence value : response.headers()
|
||||
.getAll(name)) {
|
||||
headers.put(name.toString(), value.toString());
|
||||
}
|
||||
}
|
||||
responseAgg.setHeaders(headers);
|
||||
}
|
||||
if (HttpUtil.isTransferEncodingChunked(response)) {
|
||||
responseAgg.setChunked(true);
|
||||
} else {
|
||||
responseAgg.setChunked(false);
|
||||
}
|
||||
}
|
||||
if (msg instanceof HttpContent) {
|
||||
HttpContent content = (HttpContent) msg;
|
||||
String responseData = content.content()
|
||||
.toString(CharsetUtil.UTF_8);
|
||||
|
||||
if (content instanceof LastHttpContent) {
|
||||
responseAgg.setContent(responseData + "} End Of Content");
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
return responseAgg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.baeldung.http.server;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ResponseAggregator {
|
||||
int status;
|
||||
String version;
|
||||
Map<String, String> headers;
|
||||
boolean isChunked;
|
||||
String content;
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public boolean isChunked() {
|
||||
return isChunked;
|
||||
}
|
||||
|
||||
public void setChunked(boolean isChunked) {
|
||||
this.isChunked = isChunked;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.baeldung.netty.http2.Http2Util;
|
||||
import com.baeldung.netty.http2.client.Http2ClientInitializer;
|
||||
import com.baeldung.netty.http2.client.Http2ClientResponseHandler;
|
||||
import com.baeldung.netty.http2.client.Http2SettingsHandler;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
|
||||
//Ensure the server class - Http2Server.java is already started before running this test
|
||||
public class Http2ClientLiveTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Http2ClientLiveTest.class);
|
||||
|
||||
private static final String HOST = "127.0.0.1";
|
||||
private static final int PORT = 8443;
|
||||
private SslContext sslCtx;
|
||||
private Channel channel;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
sslCtx = Http2Util.createSSLContext(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenRequestSent_thenHelloWorldReceived() throws Exception {
|
||||
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
Http2ClientInitializer initializer = new Http2ClientInitializer(sslCtx, Integer.MAX_VALUE, HOST, PORT);
|
||||
|
||||
try {
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.group(workerGroup);
|
||||
b.channel(NioSocketChannel.class);
|
||||
b.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
b.remoteAddress(HOST, PORT);
|
||||
b.handler(initializer);
|
||||
|
||||
channel = b.connect()
|
||||
.syncUninterruptibly()
|
||||
.channel();
|
||||
|
||||
logger.info("Connected to [" + HOST + ':' + PORT + ']');
|
||||
|
||||
Http2SettingsHandler http2SettingsHandler = initializer.getSettingsHandler();
|
||||
http2SettingsHandler.awaitSettings(60, TimeUnit.SECONDS);
|
||||
|
||||
logger.info("Sending request(s)...");
|
||||
|
||||
FullHttpRequest request = Http2Util.createGetRequest(HOST, PORT);
|
||||
|
||||
Http2ClientResponseHandler responseHandler = initializer.getResponseHandler();
|
||||
int streamId = 3;
|
||||
|
||||
responseHandler.put(streamId, channel.write(request), channel.newPromise());
|
||||
channel.flush();
|
||||
String response = responseHandler.awaitResponses(60, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals("Hello World", response);
|
||||
|
||||
logger.info("Finished HTTP/2 request(s)");
|
||||
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
channel.close()
|
||||
.syncUninterruptibly();
|
||||
}
|
||||
}
|
||||
22
server-modules/pom.xml
Normal file
22
server-modules/pom.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>server-modules</artifactId>
|
||||
<name>server-modules</name>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
<module>apache-tomcat</module>
|
||||
<module>netty</module>
|
||||
<module>undertow</module>
|
||||
<module>wildfly</module>
|
||||
</modules>
|
||||
</project>
|
||||
6
server-modules/undertow/README.md
Normal file
6
server-modules/undertow/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## Undertow
|
||||
|
||||
This module contains articles about JBoss Undertow
|
||||
|
||||
### Relevant Articles:
|
||||
- [Introduction to JBoss Undertow](https://www.baeldung.com/jboss-undertow)
|
||||
53
server-modules/undertow/pom.xml
Normal file
53
server-modules/undertow/pom.xml
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung.undertow</groupId>
|
||||
<artifactId>undertow</artifactId>
|
||||
<name>undertow</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>server-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-servlet</artifactId>
|
||||
<version>${undertow-servlet.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<!-- disabling shade plugin as it is causing issues with creating dependency-reduced-pom -->
|
||||
<!-- on the build server <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> -->
|
||||
<!-- <version>${maven-shade-plugin.version}</version> <executions> <execution> <phase>package</phase> -->
|
||||
<!--<goals> <goal>shade</goal> </goals> </execution> </executions> </plugin> -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>${maven-jar-plugin.version}</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.baeldung.undertow.SimpleServer</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<undertow-servlet.version>1.4.18.Final</undertow-servlet.version>
|
||||
<!--<maven-shade-plugin.version>2.4.3</maven-shade-plugin.version> -->
|
||||
<maven-jar-plugin.version>3.0.2</maven-jar-plugin.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.undertow;
|
||||
|
||||
import io.undertow.Undertow;
|
||||
import io.undertow.util.Headers;
|
||||
|
||||
public class SimpleServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Undertow server = Undertow.builder().addHttpListener(8080, "localhost").setHandler(exchange -> {
|
||||
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
|
||||
exchange.getResponseSender().send("Hello Baeldung");
|
||||
}).build();
|
||||
server.start();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.baeldung.undertow.ftp;
|
||||
|
||||
import io.undertow.Undertow;
|
||||
import io.undertow.server.handlers.resource.PathResourceManager;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static io.undertow.Handlers.resource;
|
||||
|
||||
public class FileServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
|
||||
.setHandler(resource(new PathResourceManager(Paths.get(System.getProperty("user.home")), 100))
|
||||
.setDirectoryListingEnabled(true))
|
||||
.build();
|
||||
server.start();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.baeldung.undertow.secure;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import io.undertow.security.idm.Account;
|
||||
import io.undertow.security.idm.Credential;
|
||||
import io.undertow.security.idm.IdentityManager;
|
||||
import io.undertow.security.idm.PasswordCredential;
|
||||
|
||||
public class CustomIdentityManager implements IdentityManager {
|
||||
|
||||
private final Map<String, char[]> users;
|
||||
|
||||
CustomIdentityManager(final Map<String, char[]> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(Account account) {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(Credential credential) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account verify(String id, Credential credential) {
|
||||
Account account = getAccount(id);
|
||||
if (account != null && verifyCredential(account, credential)) {
|
||||
return account;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean verifyCredential(Account account, Credential credential) {
|
||||
if (credential instanceof PasswordCredential) {
|
||||
char[] password = ((PasswordCredential) credential).getPassword();
|
||||
char[] expectedPassword = users.get(account.getPrincipal().getName());
|
||||
|
||||
return Arrays.equals(password, expectedPassword);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Account getAccount(final String id) {
|
||||
if (users.containsKey(id)) {
|
||||
return new Account() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Principal principal = () -> id;
|
||||
|
||||
@Override
|
||||
public Principal getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.baeldung.undertow.secure;
|
||||
|
||||
import io.undertow.Undertow;
|
||||
import io.undertow.io.IoCallback;
|
||||
import io.undertow.security.api.AuthenticationMechanism;
|
||||
import io.undertow.security.api.AuthenticationMode;
|
||||
import io.undertow.security.api.SecurityContext;
|
||||
import io.undertow.security.handlers.AuthenticationCallHandler;
|
||||
import io.undertow.security.handlers.AuthenticationConstraintHandler;
|
||||
import io.undertow.security.handlers.AuthenticationMechanismsHandler;
|
||||
import io.undertow.security.handlers.SecurityInitialHandler;
|
||||
import io.undertow.security.idm.IdentityManager;
|
||||
import io.undertow.security.impl.BasicAuthenticationMechanism;
|
||||
import io.undertow.server.HttpHandler;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SecureServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
final Map<String, char[]> users = new HashMap<>(2);
|
||||
users.put("root", "password".toCharArray());
|
||||
users.put("admin", "password".toCharArray());
|
||||
|
||||
final IdentityManager idm = new CustomIdentityManager(users);
|
||||
|
||||
Undertow server = Undertow.builder()
|
||||
.addHttpListener(8080, "localhost")
|
||||
.setHandler(addSecurity(SecureServer::setExchange, idm)).build();
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
private static void setExchange(HttpServerExchange exchange) {
|
||||
final SecurityContext context = exchange.getSecurityContext();
|
||||
exchange.getResponseSender().send("Hello " + context.getAuthenticatedAccount().getPrincipal().getName(), IoCallback.END_EXCHANGE);
|
||||
}
|
||||
|
||||
private static HttpHandler addSecurity(final HttpHandler toWrap, final IdentityManager identityManager) {
|
||||
HttpHandler handler = toWrap;
|
||||
handler = new AuthenticationCallHandler(handler);
|
||||
handler = new AuthenticationConstraintHandler(handler);
|
||||
final List<AuthenticationMechanism> mechanisms = Collections
|
||||
.singletonList(new BasicAuthenticationMechanism("Baeldung_Realm"));
|
||||
handler = new AuthenticationMechanismsHandler(handler, mechanisms);
|
||||
handler = new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, identityManager, handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.baeldung.undertow.socket;
|
||||
|
||||
import io.undertow.Undertow;
|
||||
import io.undertow.server.handlers.resource.ClassPathResourceManager;
|
||||
import io.undertow.websockets.core.AbstractReceiveListener;
|
||||
import io.undertow.websockets.core.BufferedTextMessage;
|
||||
import io.undertow.websockets.core.WebSocketChannel;
|
||||
import io.undertow.websockets.core.WebSockets;
|
||||
|
||||
import static io.undertow.Handlers.path;
|
||||
import static io.undertow.Handlers.resource;
|
||||
import static io.undertow.Handlers.websocket;
|
||||
|
||||
public class SocketServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
|
||||
.setHandler(path().addPrefixPath("/baeldungApp", websocket((exchange, channel) -> {
|
||||
channel.getReceiveSetter().set(getListener());
|
||||
channel.resumeReceives();
|
||||
})).addPrefixPath("/", resource(new ClassPathResourceManager(SocketServer.class.getClassLoader(),
|
||||
SocketServer.class.getPackage())).addWelcomeFiles("index.html")))
|
||||
.build();
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
private static AbstractReceiveListener getListener() {
|
||||
return new AbstractReceiveListener() {
|
||||
@Override
|
||||
protected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) {
|
||||
final String messageData = message.getData();
|
||||
for (WebSocketChannel session : channel.getPeerConnections()) {
|
||||
WebSockets.sendText(messageData, session, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
13
server-modules/undertow/src/main/resources/logback.xml
Normal file
13
server-modules/undertow/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
3
server-modules/wildfly/README.md
Normal file
3
server-modules/wildfly/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Relevant Articles:
|
||||
|
||||
- [How to Set Up a WildFly Server](https://www.baeldung.com/wildfly-server-setup)
|
||||
77
server-modules/wildfly/pom.xml
Normal file
77
server-modules/wildfly/pom.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>wildfly</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<name>wildfly</name>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- tag::actuator[] -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<!-- end::actuator[] -->
|
||||
<!-- tag::tests[] -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- end::tests[] -->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Dependencies>jdk.unsupported</Dependencies>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
40
server-modules/wildfly/src/main/java/hello/Application.java
Normal file
40
server-modules/wildfly/src/main/java/hello/Application.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package hello;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application extends SpringBootServletInitializer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(Application.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
|
||||
return args -> {
|
||||
|
||||
System.out.println("Let's inspect the beans provided by Spring Boot:");
|
||||
|
||||
String[] beanNames = ctx.getBeanDefinitionNames();
|
||||
Arrays.sort(beanNames);
|
||||
for (String beanName : beanNames) {
|
||||
System.out.println(beanName);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package hello;
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@RestController
|
||||
public class HelloController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String index() {
|
||||
return "Greetings from Spring Boot!";
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user