Merge branch 'eugenp:master' into master

This commit is contained in:
Ulisses Lima 2022-03-22 18:04:53 -03:00 committed by GitHub
commit ec403bd427
136 changed files with 7166 additions and 195 deletions

34
apache-tomcat/pom.xml Normal file
View File

@ -0,0 +1,34 @@
<?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</groupId>
<artifactId>apache-tomcat</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>apache-tomcat</name>
<packaging>pom</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-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>

View 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

View File

@ -0,0 +1,5 @@
### Related articles
### Launch Example using Docker
$ docker-compose up

View 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
apache-tomcat/sso/pom.xml Normal file
View 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>

View 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" {
// };

View 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

View 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>

View File

@ -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>

View File

@ -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>

View 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

View 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 &quot;%r&quot; %s %b" />
</Host>
</Engine>
</Service>
</Server>

View 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>

View 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>

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Ping</title>
</head>
<body>
<a href="private/index.html">Start pinging</a>
</body>
</html>

View 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"/>
&nbsp;
<input type="reset" value="Reset"/>
</form>
</body>
</html>

View File

@ -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>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Ping - Pinging</title>
</head>
<body>
<a href="/pong/private/index.html">Pong!</a>
</body>
</html>

View File

@ -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>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Pong</title>
</head>
<body>
<a href="private/index.html">Start ponging</a>
</body>
</html>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Pong - Ponging</title>
</head>
<body>
<a href="/ping/private/index.html">Ping!</a>
</body>
</html>

View File

@ -5,3 +5,4 @@
- [Start Two Threads at the Exact Same Time in Java](https://www.baeldung.com/java-start-two-threads-at-same-time) - [Start Two Threads at the Exact Same Time in Java](https://www.baeldung.com/java-start-two-threads-at-same-time)
- [Volatile Variables and Thread Safety](https://www.baeldung.com/java-volatile-variables-thread-safety) - [Volatile Variables and Thread Safety](https://www.baeldung.com/java-volatile-variables-thread-safety)
- [Producer-Consumer Problem With Example in Java](https://www.baeldung.com/java-producer-consumer-problem) - [Producer-Consumer Problem With Example in Java](https://www.baeldung.com/java-producer-consumer-problem)
- [Acquire a Lock by a Key in Java](https://www.baeldung.com/java-acquire-lock-by-key)

View File

@ -0,0 +1,51 @@
package com.baeldung.producerconsumer;
public class Consumer implements Runnable {
private final DataQueue dataQueue;
private volatile boolean runFlag;
public Consumer(DataQueue dataQueue) {
this.dataQueue = dataQueue;
runFlag = true;
}
@Override
public void run() {
consume();
}
public void consume() {
while (runFlag) {
Message message;
if (dataQueue.isEmpty()) {
try {
dataQueue.waitOnEmpty();
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
if (!runFlag) {
break;
}
message = dataQueue.remove();
dataQueue.notifyAllForFull();
useMessage(message);
}
System.out.println("Consumer Stopped");
}
private void useMessage(Message message) {
if (message != null) {
System.out.printf("[%s] Consuming Message. Id: %d, Data: %f\n", Thread.currentThread().getName(), message.getId(), message.getData());
//Sleeping on random time to make it realistic
ThreadUtil.sleep((long) (message.getData() * 100));
}
}
public void stop() {
runFlag = false;
dataQueue.notifyAllForEmpty();
}
}

View File

@ -0,0 +1,59 @@
package com.baeldung.producerconsumer;
import java.util.LinkedList;
import java.util.Queue;
public class DataQueue {
private final Queue<Message> queue = new LinkedList<>();
private final int maxSize;
private final Object FULL_QUEUE = new Object();
private final Object EMPTY_QUEUE = new Object();
DataQueue(int maxSize) {
this.maxSize = maxSize;
}
public boolean isFull() {
return queue.size() == maxSize;
}
public boolean isEmpty() {
return queue.isEmpty();
}
public void waitOnFull() throws InterruptedException {
synchronized (FULL_QUEUE) {
FULL_QUEUE.wait();
}
}
public void waitOnEmpty() throws InterruptedException {
synchronized (EMPTY_QUEUE) {
EMPTY_QUEUE.wait();
}
}
public void notifyAllForFull() {
synchronized (FULL_QUEUE) {
FULL_QUEUE.notifyAll();
}
}
public void notifyAllForEmpty() {
synchronized (EMPTY_QUEUE) {
EMPTY_QUEUE.notifyAll();
}
}
public void add(Message message) {
synchronized (queue) {
queue.add(message);
}
}
public Message remove() {
synchronized (queue) {
return queue.poll();
}
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.producerconsumer;
public class Message {
private int id;
private double data;
public Message(int id, double data) {
this.id = id;
this.data = data;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getData() {
return data;
}
public void setData(double data) {
this.data = data;
}
}

View File

@ -0,0 +1,53 @@
package com.baeldung.producerconsumer;
public class Producer implements Runnable {
private final DataQueue dataQueue;
private volatile boolean runFlag;
private static int idSequence = 0;
public Producer(DataQueue dataQueue) {
this.dataQueue = dataQueue;
runFlag = true;
}
@Override
public void run() {
produce();
}
public void produce() {
while (runFlag) {
Message message = generateMessage();
while (dataQueue.isFull()) {
try {
dataQueue.waitOnFull();
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
if (!runFlag) {
break;
}
dataQueue.add(message);
dataQueue.notifyAllForEmpty();
}
System.out.println("Producer Stopped");
}
private Message generateMessage() {
Message message = new Message(++idSequence, Math.random());
System.out.printf("[%s] Generated Message. Id: %d, Data: %f\n", Thread.currentThread().getName(), message.getId(), message.getData());
//Sleeping on random time to make it realistic
ThreadUtil.sleep((long) (message.getData() * 100));
return message;
}
public void stop() {
runFlag = false;
dataQueue.notifyAllForFull();
}
}

View File

@ -0,0 +1,69 @@
package com.baeldung.producerconsumer;
import java.util.ArrayList;
import java.util.List;
import static com.baeldung.producerconsumer.ThreadUtil.*;
public class ProducerConsumerDemonstrator {
private static final int MAX_QUEUE_CAPACITY = 5;
public static void demoSingleProducerAndSingleConsumer() {
DataQueue dataQueue = new DataQueue(MAX_QUEUE_CAPACITY);
Producer producer = new Producer(dataQueue);
Thread producerThread = new Thread(producer);
Consumer consumer = new Consumer(dataQueue);
Thread consumerThread = new Thread(consumer);
producerThread.start();
consumerThread.start();
List<Thread> threads = new ArrayList<>();
threads.add(producerThread);
threads.add(consumerThread);
// let threads run for two seconds
sleep(2000);
// Stop threads
producer.stop();
consumer.stop();
waitForAllThreadsToComplete(threads);
}
public static void demoMultipleProducersAndMultipleConsumers() {
DataQueue dataQueue = new DataQueue(MAX_QUEUE_CAPACITY);
int producerCount = 3;
int consumerCount = 3;
List<Thread> threads = new ArrayList<>();
Producer producer = new Producer(dataQueue);
for(int i = 0; i < producerCount; i++) {
Thread producerThread = new Thread(producer);
producerThread.start();
threads.add(producerThread);
}
Consumer consumer = new Consumer(dataQueue);
for(int i = 0; i < consumerCount; i++) {
Thread consumerThread = new Thread(consumer);
consumerThread.start();
threads.add(consumerThread);
}
// let threads run for two seconds
sleep(2000);
// Stop threads
producer.stop();
consumer.stop();
waitForAllThreadsToComplete(threads);
}
public static void main(String[] args) {
demoSingleProducerAndSingleConsumer();
demoMultipleProducersAndMultipleConsumers();
}
}

View File

@ -0,0 +1,60 @@
package com.baeldung.producerconsumer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import static com.baeldung.producerconsumer.ThreadUtil.sleep;
public class SimpleProducerConsumerDemonstrator {
BlockingQueue<Double> blockingQueue = new LinkedBlockingDeque<>(5);
private void produce() {
while (true) {
double value = generateValue();
try {
blockingQueue.put(value);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
System.out.printf("[%s] Value produced: %f\n", Thread.currentThread().getName(), value);
}
}
private void consume() {
while (true) {
Double value;
try {
value = blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
// Consume value
System.out.printf("[%s] Value consumed: %f\n", Thread.currentThread().getName(), value);
}
}
private double generateValue() {
return Math.random();
}
private void runProducerConsumer() {
for (int i = 0; i < 2; i++) {
Thread producerThread = new Thread(this::produce);
producerThread.start();
}
for (int i = 0; i < 3; i++) {
Thread consumerThread = new Thread(this::consume);
consumerThread.start();
}
}
public static void main(String[] args) {
SimpleProducerConsumerDemonstrator simpleProducerConsumerDemonstrator = new SimpleProducerConsumerDemonstrator();
simpleProducerConsumerDemonstrator.runProducerConsumer();
sleep(2000);
System.exit(0);
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.producerconsumer;
import java.util.List;
public class ThreadUtil {
public static void waitForAllThreadsToComplete(List<Thread> threads) {
for(Thread thread: threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void sleep(long interval) {
try {
// Wait for some time to demonstrate threads
Thread.sleep(interval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@ -11,4 +11,5 @@ This module contains articles about date operations in Java.
- [How to determine day of week by passing specific date in Java?](https://www.baeldung.com/java-get-day-of-week) - [How to determine day of week by passing specific date in Java?](https://www.baeldung.com/java-get-day-of-week)
- [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year) - [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year)
- [Getting the Week Number From Any Date](https://www.baeldung.com/java-get-week-number) - [Getting the Week Number From Any Date](https://www.baeldung.com/java-get-week-number)
- [Subtract Days from a Date in Java](https://www.baeldung.com/java-subtract-days-from-a-date)
- [[<-- Prev]](/core-java-modules/core-java-date-operations-1) - [[<-- Prev]](/core-java-modules/core-java-date-operations-1)

View File

@ -0,0 +1,49 @@
package com.baeldung.subtractdays;
import static org.junit.Assert.assertEquals;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.joda.time.DateTime;
import org.junit.Test;
public class SubtractDaysFromDateUnitTest {
@Test
public void givenCalendarDate_whenSubtractingFiveDays_dateIsChangedCorrectly() {
Calendar calendar = Calendar.getInstance();
calendar.set(2022, Calendar.APRIL, 20);
calendar.add(Calendar.DATE, -5);
assertEquals(15, calendar.get(Calendar.DAY_OF_MONTH));
assertEquals(Calendar.APRIL, calendar.get(Calendar.MONTH));
assertEquals(2022, calendar.get(Calendar.YEAR));
}
@Test
public void givenJodaDateTime_whenSubtractingFiveDays_dateIsChangedCorrectly() {
DateTime dateTime = new DateTime(2022, 4, 20, 12, 0, 0);
dateTime = dateTime.minusDays(5);
assertEquals(15, dateTime.getDayOfMonth());
assertEquals(4, dateTime.getMonthOfYear());
assertEquals(2022, dateTime.getYear());
}
@Test
public void givenLocalDateTime_whenSubtractingFiveDays_dateIsChangedCorrectly() {
LocalDate localDateTime = LocalDate.of(2022, 4, 20);
localDateTime = localDateTime.minusDays(5);
assertEquals(15, localDateTime.getDayOfMonth());
assertEquals(4, localDateTime.getMonthValue());
assertEquals(2022, localDateTime.getYear());
}
}

View File

@ -2,3 +2,4 @@
- [Java ArrayIndexOutOfBoundsException](https://www.baeldung.com/java-arrayindexoutofboundsexception) - [Java ArrayIndexOutOfBoundsException](https://www.baeldung.com/java-arrayindexoutofboundsexception)
- [Java Missing Return Statement](https://www.baeldung.com/java-missing-return-statement) - [Java Missing Return Statement](https://www.baeldung.com/java-missing-return-statement)
- [Convert long to int Type in Java](https://www.baeldung.com/java-convert-long-to-int)

View File

@ -10,3 +10,4 @@ This module contains articles about core features in the Java language
- [Tiered Compilation in JVM](https://www.baeldung.com/jvm-tiered-compilation) - [Tiered Compilation in JVM](https://www.baeldung.com/jvm-tiered-compilation)
- [Fixing the “Declared package does not match the expected package” Error](https://www.baeldung.com/java-declared-expected-package-error) - [Fixing the “Declared package does not match the expected package” Error](https://www.baeldung.com/java-declared-expected-package-error)
- [Chaining Constructors in Java](https://www.baeldung.com/java-chain-constructors) - [Chaining Constructors in Java](https://www.baeldung.com/java-chain-constructors)
- [Difference Between POJO, JavaBeans, DTO and VO](https://www.baeldung.com/java-pojo-javabeans-dto-vo)

View File

@ -0,0 +1,48 @@
package com.baeldung.employee;
import java.io.Serializable;
import java.time.LocalDate;
public class EmployeeBean implements Serializable {
private static final long serialVersionUID = -3760445487636086034L;
private String firstName;
private String lastName;
private LocalDate startDate;
public EmployeeBean() {
}
public EmployeeBean(String firstName, String lastName, LocalDate startDate) {
this.firstName = firstName;
this.lastName = lastName;
this.startDate = startDate;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.employee;
import java.time.LocalDate;
public class EmployeeDTO {
private String firstName;
private String lastName;
private LocalDate startDate;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.employee;
import java.time.LocalDate;
import java.util.Objects;
public class EmployeePOJO {
private String firstName;
private String lastName;
private LocalDate startDate;
public EmployeePOJO(String firstName, String lastName, LocalDate startDate) {
this.firstName = firstName;
this.lastName = lastName;
this.startDate = startDate;
}
public String name() {
return this.firstName + " " + this.lastName;
}
public LocalDate getStart() {
return this.startDate;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.employee;
import java.time.LocalDate;
import java.util.Objects;
public class EmployeeVO {
private String firstName;
private String lastName;
private LocalDate startDate;
public EmployeeVO(String firstName, String lastName, LocalDate startDate) {
this.firstName = firstName;
this.lastName = lastName;
this.startDate = startDate;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public LocalDate getStartDate() {
return startDate;
}
@Override
public boolean equals(Object obj) {
return Objects.equals(firstName, this.firstName)
&& Objects.equals(lastName, this.lastName)
&& Objects.equals(startDate, this.startDate);
}
@Override
public int hashCode() {
return Objects.hash(firstName, lastName, startDate);
}
}

View File

@ -3,8 +3,9 @@ package com.baeldung.split;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.MatchResult;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -29,16 +30,11 @@ public class SplitStringEveryNthChar {
} }
public static List<String> usingPattern(String text, int n) { public static List<String> usingPattern(String text, int n) {
List<String> results = new ArrayList<>(); return Pattern.compile(".{1," + n + "}")
.matcher(text)
Pattern pattern = Pattern.compile(".{1," + n + "}"); .results()
Matcher matcher = pattern.matcher(text); .map(MatchResult::group)
while (matcher.find()) { .collect(Collectors.toList());
String match = text.substring(matcher.start(), matcher.end());
results.add(match);
}
return results;
} }
public static List<String> usingGuava(String text, int n) { public static List<String> usingGuava(String text, int n) {

3
jakarta-ee/README.md Normal file
View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Introduction to Jakarta EE MVC / Eclipse Krazo](https://www.baeldung.com/java-ee-mvc-eclipse-krazo)

View File

@ -1,28 +1,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>mvc-2.0</artifactId> <artifactId>jakarta-ee</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<name>jakarta-ee</name>
<packaging>war</packaging> <packaging>war</packaging>
<name>mvc-2.0</name>
<properties>
<jakartaee-api.version>9.0.0</jakartaee-api.version>
<krazo.version>2.0.0</krazo.version>
<jakarta.mvc-api.version>2.0.0</jakarta.mvc-api.version>
<junit.jupiter.version>5.8.2</junit.jupiter.version>
<local.glassfish.home>C:/glassfish6</local.glassfish.home>
<local.glassfish.user>admin</local.glassfish.user>
<local.glassfish.domain>mvn-domain</local.glassfish.domain>
<mockito.version>1.10.19</mockito.version>
<local.glassfish.passfile>
${local.glassfish.home}\\domains\\${local.glassfish.domain}\\config\\domain-passwords
</local.glassfish.passfile>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>jakarta.platform</groupId> <groupId>jakarta.platform</groupId>
@ -30,13 +15,11 @@
<version>${jakartaee-api.version}</version> <version>${jakartaee-api.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>jakarta.mvc</groupId> <groupId>jakarta.mvc</groupId>
<artifactId>jakarta.mvc-api</artifactId> <artifactId>jakarta.mvc-api</artifactId>
<version>${jakarta.mvc-api.version}</version> <version>${jakarta.mvc-api.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.krazo</groupId> <groupId>org.eclipse.krazo</groupId>
<artifactId>krazo-jersey</artifactId> <artifactId>krazo-jersey</artifactId>
@ -54,7 +37,6 @@
<version>${mockito.version}</version> <version>${mockito.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
@ -108,4 +90,19 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<properties>
<jakartaee-api.version>9.0.0</jakartaee-api.version>
<krazo.version>2.0.0</krazo.version>
<jakarta.mvc-api.version>2.0.0</jakarta.mvc-api.version>
<junit.jupiter.version>5.8.2</junit.jupiter.version>
<local.glassfish.home>C:/glassfish6</local.glassfish.home>
<local.glassfish.user>admin</local.glassfish.user>
<local.glassfish.domain>mvn-domain</local.glassfish.domain>
<mockito.version>1.10.19</mockito.version>
<local.glassfish.passfile>
${local.glassfish.home}\\domains\\${local.glassfish.domain}\\config\\domain-passwords
</local.glassfish.passfile>
</properties>
</project> </project>

View File

@ -4,3 +4,4 @@
- [Understanding the & 0xff Value in Java](https://www.baeldung.com/java-and-0xff) - [Understanding the & 0xff Value in Java](https://www.baeldung.com/java-and-0xff)
- [Determine if an Integers Square Root Is an Integer in Java](https://www.baeldung.com/java-find-if-square-root-is-integer) - [Determine if an Integers Square Root Is an Integer in Java](https://www.baeldung.com/java-find-if-square-root-is-integer)
- [Guide to Java BigInteger](https://www.baeldung.com/java-biginteger) - [Guide to Java BigInteger](https://www.baeldung.com/java-biginteger)
- [Automorphic Numbers in Java](https://www.baeldung.com/java-automorphic-numbers)

View File

@ -0,0 +1,31 @@
package com.baeldung.automorphicnumber;
public class AutomorphicNumber {
public static void main(String[] args) {
System.out.println(isAutomorphicUsingLoop(76));
System.out.println(isAutomorphicUsingMath(76));
}
public static boolean isAutomorphicUsingMath(int number) {
int square = number * number;
int numberOfDigits = (int) Math.floor(Math.log10(number) + 1);
int lastDigits = (int) (square % (Math.pow(10, numberOfDigits)));
return number == lastDigits;
}
public static boolean isAutomorphicUsingLoop(int number) {
int square = number * number;
while (number > 0) {
if (number % 10 != square % 10) {
return false;
}
number /= 10;
square /= 10;
}
return true;
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.automorphicnumber;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.jupiter.api.Test;
public class AutomorphicNumberUnitTest {
@Test
void givenANumber_whenPassed_thenShouldDetermineAutomorphicOrNot() {
int number1 = 76; // automorphic
int number2 = 16; // not automorphic
assertTrue(AutomorphicNumber.isAutomorphicUsingLoop(number1));
assertFalse(AutomorphicNumber.isAutomorphicUsingLoop(number2));
assertTrue(AutomorphicNumber.isAutomorphicUsingMath(number1));
assertFalse(AutomorphicNumber.isAutomorphicUsingMath(number2));
}
}

View File

@ -10,16 +10,23 @@ import com.twitter.util.Future;
import org.junit.Test; import org.junit.Test;
import scala.runtime.BoxedUnit; import scala.runtime.BoxedUnit;
import java.io.IOException;
import java.net.ServerSocket;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
public class FinagleIntegrationTest { public class FinagleIntegrationTest {
private static final int DEFAULT_PORT = 8079;
@Test @Test
public void givenServerAndClient_whenRequestSent_thenClientShouldReceiveResponseFromServer() throws Exception { public void givenServerAndClient_whenRequestSent_thenClientShouldReceiveResponseFromServer() throws Exception {
// given // given
int port = randomPort();
Service serverService = new LogFilter().andThen(new GreetingService()); Service serverService = new LogFilter().andThen(new GreetingService());
Http.serve(":8080", serverService); Http.serve(":" + port, serverService);
Service<Request, Response> clientService = new LogFilter().andThen(Http.newService(":8080")); Service<Request, Response> clientService = new LogFilter().andThen(Http.newService(":" + port));
// when // when
Request request = Request.apply(Method.Get(), "/?name=John"); Request request = Request.apply(Method.Get(), "/?name=John");
@ -37,4 +44,13 @@ public class FinagleIntegrationTest {
}) })
); );
} }
private int randomPort() {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
} catch (IOException e) {
return DEFAULT_PORT;
}
}
} }

View File

@ -3,9 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>copy-rename-maven-plugin</artifactId> <artifactId>copy-rename-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<name>copy-rename-maven-plugin</name> <name>copy-rename-maven-plugin</name>
<parent> <parent>

View File

@ -3,9 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven-antrun-plugin</name> <name>maven-antrun-plugin</name>
<parent> <parent>

View File

@ -3,9 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>maven-resources-plugin</artifactId> <artifactId>maven-resources-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven-resources-plugin</name> <name>maven-resources-plugin</name>
<parent> <parent>

View File

@ -4,13 +4,12 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 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> <modelVersion>4.0.0</modelVersion>
<artifactId>maven-dependency</artifactId> <artifactId>maven-dependency</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>maven-simple</artifactId> <artifactId>maven-simple</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
</parent> </parent>
<dependencyManagement> <dependencyManagement>

View File

@ -3,14 +3,24 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>core</artifactId> <artifactId>core</artifactId>
<name>core</name> <name>core</name>
<parent> <parent>
<artifactId>parent-project</artifactId> <artifactId>parent-project</artifactId>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</parent> </parent>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-core.version}</version>
</dependency>
</dependencies>
<properties>
<spring-core.version>4.3.30.RELEASE</spring-core.version>
</properties>
</project> </project>

View File

@ -4,6 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 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> <modelVersion>4.0.0</modelVersion>
<artifactId>parent-project</artifactId> <artifactId>parent-project</artifactId>
<version>1.0-SNAPSHOT</version>
<name>parent-project</name> <name>parent-project</name>
<packaging>pom</packaging> <packaging>pom</packaging>
@ -19,4 +20,17 @@
<module>webapp</module> <module>webapp</module>
</modules> </modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-core.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<spring-core.version>5.3.16</spring-core.version>
</properties>
</project> </project>

View File

@ -3,14 +3,13 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>service</artifactId> <artifactId>service</artifactId>
<name>service</name> <name>service</name>
<parent> <parent>
<artifactId>parent-project</artifactId> <artifactId>parent-project</artifactId>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</parent> </parent>
</project> </project>

View File

@ -3,14 +3,31 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>webapp</artifactId> <artifactId>webapp</artifactId>
<name>webapp</name> <name>webapp</name>
<packaging>war</packaging>
<parent> <parent>
<artifactId>parent-project</artifactId> <artifactId>parent-project</artifactId>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</parent> </parent>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
</properties>
</project> </project>

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Using Nginx as a Forward Proxy](https://www.baeldung.com/nginx-forward-proxy)

View File

@ -88,7 +88,7 @@
<rest-assured.version>3.3.0</rest-assured.version> <rest-assured.version>3.3.0</rest-assured.version>
<!-- plugins --> <!-- plugins -->
<thin.version>1.0.22.RELEASE</thin.version> <thin.version>1.0.22.RELEASE</thin.version>
<spring-boot.version>2.6.3</spring-boot.version> <spring-boot.version>2.6.4</spring-boot.version>
<aspectjweaver.version>1.9.1</aspectjweaver.version> <aspectjweaver.version>1.9.1</aspectjweaver.version>
</properties> </properties>

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Building a web app Using Fauna and Spring for Your First web Agency Client](https://www.baeldung.com/faunadb-spring-web-app)

View File

@ -1,21 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?> <?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" <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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>fauna</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>fauna</name>
<description>Blogging Service built with FaunaDB</description>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version> <version>2.6.2</version>
<relativePath /> <!-- lookup parent from repository --> <relativePath /> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>com.baeldung</groupId>
<artifactId>fauna-blog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>fauna-blog</name>
<description>Blogging Service built with FaunaDB</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -53,4 +53,8 @@
</plugins> </plugins>
</build> </build>
<properties>
<java.version>17</java.version>
</properties>
</project> </project>

View File

@ -4,6 +4,7 @@ This module contains articles about use of Queries in Hibernate.
### Relevant articles: ### Relevant articles:
- [JPA Criteria Queries](https://www.baeldung.com/hibernate-criteria-queries)
- [Criteria Queries Using JPA Metamodel](https://www.baeldung.com/hibernate-criteria-queries-metamodel) - [Criteria Queries Using JPA Metamodel](https://www.baeldung.com/hibernate-criteria-queries-metamodel)
- [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all) - [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all)
- [Hibernate Named Query](https://www.baeldung.com/hibernate-named-query) - [Hibernate Named Query](https://www.baeldung.com/hibernate-named-query)

View File

@ -14,6 +14,38 @@
</parent> </parent>
<dependencies> <dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${org.springframework.data.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>${tomcat-dbcp.version}</version>
</dependency>
<!-- validation -->
<!-- utils -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- test scoped -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.hibernate</groupId> <groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId> <artifactId>hibernate-core</artifactId>
@ -49,9 +81,13 @@
<artifactId>jmh-generator-annprocess</artifactId> <artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh-generator.version}</version> <version>${jmh-generator.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
<properties> <properties>
<org.springframework.version>5.0.2.RELEASE</org.springframework.version>
<org.springframework.data.version>1.10.6.RELEASE</org.springframework.data.version>
<tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version>
<mysql.version>6.0.6</mysql.version> <mysql.version>6.0.6</mysql.version>
<mariaDB4j.version>2.2.3</mariaDB4j.version> <mariaDB4j.version>2.2.3</mariaDB4j.version>
</properties> </properties>

View File

@ -0,0 +1,71 @@
package com.baeldung.hibernate.criteria;
import com.google.common.base.Preconditions;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence-h2.properties" })
@ComponentScan({ "com.baeldung.hibernate.criteria" })
public class PersistenceConfig {
@Autowired
private Environment env;
@Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.baeldung.hibernate.criteria" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
public DataSource dataSource() {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
return dataSource;
}
@Bean
public PlatformTransactionManager hibernateTransactionManager() {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", "false");
return hibernateProperties;
}
}

View File

@ -7,6 +7,12 @@
</encoder> </encoder>
</appender> </appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.springframework.transaction" level="WARN" />
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
<root level="INFO"> <root level="INFO">
<appender-ref ref="STDOUT" /> <appender-ref ref="STDOUT" />
</root> </root>

View File

@ -0,0 +1,21 @@
# jdbc.X
jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
jdbc.eventGeneratedId=sa
jdbc.user=sa
jdbc.pass=
# hibernate.X
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=create-drop
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
# hibernate.search.X
hibernate.search.default.directory_provider = filesystem
hibernate.search.default.indexBase = /data/index/default
# envers.X
envers.audit_table_suffix=_audit_log

View File

@ -0,0 +1,18 @@
package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.baeldung.hibernate.criteria.PersistenceConfig;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}

View File

@ -14,3 +14,7 @@ This module contains articles about MongoDB in Java.
- [How to Check Field Existence in MongoDB?](https://www.baeldung.com/mongodb-check-field-exists) - [How to Check Field Existence in MongoDB?](https://www.baeldung.com/mongodb-check-field-exists)
- [Get Last Inserted Document ID in MongoDB With Java Driver](https://www.baeldung.com/java-mongodb-last-inserted-id) - [Get Last Inserted Document ID in MongoDB With Java Driver](https://www.baeldung.com/java-mongodb-last-inserted-id)
- [Update Multiple Fields in a MongoDB Document](https://www.baeldung.com/mongodb-update-multiple-fields) - [Update Multiple Fields in a MongoDB Document](https://www.baeldung.com/mongodb-update-multiple-fields)
- [Update Documents in MongoDB](https://www.baeldung.com/mongodb-update-documents)
- [Check Collection Existence in MongoDB](https://www.baeldung.com/java-check-collection-existence-mongodb)
- [Case Insensitive Sorting in MongoDB](https://www.baeldung.com/java-mongodb-case-insensitive-sorting)
- [Push and Set Operations in Same MongoDB Update](https://www.baeldung.com/java-mongodb-push-set)

View File

@ -0,0 +1,15 @@
package com.baeldung.mongodb.dbref;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
@SpringBootApplication
@EnableMongoRepositories(basePackages = { "com.baeldung" })
public class DbRefApplication {
public static void main(String... args) {
SpringApplication.run(DbRefApplication.class, args);
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.mongodb.dbref;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import com.baeldung.mongodb.dbref.repository.PersonRepository;
@Component
public class DbRefTester implements ApplicationRunner {
private static final Logger logger = LoggerFactory.getLogger(DbRefTester.class);
@Autowired
private PersonRepository personRepository;
@Override
public void run(ApplicationArguments args) throws Exception {
logger.info("{}", personRepository.findAll());
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.mongodb.dbref.model;
import java.util.List;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "Person")
public class Person {
@Id
private String id;
private String name;
@DBRef
private List<Pet> pets;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Pet> getPets() {
return pets;
}
public void setPets(List<Pet> pets) {
this.pets = pets;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", pets=" + pets + "]";
}
}

View File

@ -0,0 +1,29 @@
package com.baeldung.mongodb.dbref.model;
public class Pet {
private String id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "Pet [id=" + id + ", name=" + name + "]";
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.mongodb.dbref.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.baeldung.mongodb.dbref.model.Person;
public interface PersonRepository extends MongoRepository<Person, String> {
}

View File

@ -0,0 +1,74 @@
package com.baeldung.mongodb.dbref;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.mongodb.dbref.model.Person;
import com.baeldung.mongodb.dbref.model.Pet;
import com.baeldung.mongodb.dbref.repository.PersonRepository;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext
public class DbRefIntegrationTest {
@Autowired
PersonRepository personRepository;
@Autowired
private MongoTemplate mongoTemplate;
@Test
public void givenPetsAndPersonInDatabase_whenListPersons_thenReferenceIsFetched() {
// given
DBObject catInDatabase = BasicDBObjectBuilder.start()
.add("name", "Loki")
.get();
DBObject dogInDatabase = BasicDBObjectBuilder.start()
.add("name", "Max")
.get();
mongoTemplate.save(catInDatabase, "Cat");
mongoTemplate.save(dogInDatabase, "Dog");
List<DBRef> petsReference = new ArrayList<DBRef>();
petsReference.add(new DBRef("Cat", catInDatabase.get("_id")));
petsReference.add(new DBRef("Dog", dogInDatabase.get("_id")));
DBObject personInDatabase = BasicDBObjectBuilder.start()
.add("name", "Bob")
.add("pets", petsReference)
.get();
mongoTemplate.save(personInDatabase, "Person");
// when
List<Person> persons = personRepository.findAll();
// then
assertThat(persons).hasSize(1);
Person person = persons.get(0);
assertEquals("Bob", person.getName());
List<Pet> pets = person.getPets();
assertThat(pets).hasSize(2);
assertThat(pets).anyMatch(pet -> "Loki".equals(pet.getName()));
assertThat(pets).anyMatch(pet -> "Max".equals(pet.getName()));
}
}

View File

@ -67,7 +67,6 @@
<start-class>com.baeldung.boot.Application</start-class> <start-class>com.baeldung.boot.Application</start-class>
<testcontainers.postgresql.version>1.10.6</testcontainers.postgresql.version> <testcontainers.postgresql.version>1.10.6</testcontainers.postgresql.version>
<postgresql.version>42.2.5</postgresql.version> <postgresql.version>42.2.5</postgresql.version>
<spring-boot.version>2.6.1</spring-boot.version> <!-- Temp downgrade due to spring-data-jpa issue. Fixing in JAVA-9857 -->
</properties> </properties>
</project> </project>

View File

@ -5,7 +5,6 @@ This module contains articles about Hibernate 5 with Spring.
### Relevant articles ### Relevant articles
- [Programmatic Transactions in the Spring TestContext Framework](https://www.baeldung.com/spring-test-programmatic-transactions) - [Programmatic Transactions in the Spring TestContext Framework](https://www.baeldung.com/spring-test-programmatic-transactions)
- [JPA Criteria Queries](https://www.baeldung.com/hibernate-criteria-queries)
- [Introduction to Hibernate Search](https://www.baeldung.com/hibernate-search) - [Introduction to Hibernate Search](https://www.baeldung.com/hibernate-search)
- [@DynamicUpdate with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-dynamicupdate) - [@DynamicUpdate with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-dynamicupdate)
- [Hibernate Second-Level Cache](http://www.baeldung.com/hibernate-second-level-cache) - [Hibernate Second-Level Cache](http://www.baeldung.com/hibernate-second-level-cache)

View File

@ -1460,7 +1460,7 @@
<assertj.version>3.21.0</assertj.version> <assertj.version>3.21.0</assertj.version>
<hamcrest.version>2.2</hamcrest.version> <hamcrest.version>2.2</hamcrest.version>
<hamcrest-all.version>1.3</hamcrest-all.version> <hamcrest-all.version>1.3</hamcrest-all.version>
<mockito.version>4.1.0</mockito.version> <mockito.version>4.4.0</mockito.version>
<byte-buddy.version>1.11.20</byte-buddy.version> <byte-buddy.version>1.11.20</byte-buddy.version>
<!-- logging --> <!-- logging -->

View File

@ -10,9 +10,8 @@
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId> <artifactId>reactive-systems</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent> </parent>
<dependencies> <dependencies>

View File

@ -10,9 +10,8 @@
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId> <artifactId>reactive-systems</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent> </parent>
<dependencies> <dependencies>

View File

@ -10,8 +10,9 @@
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId> <artifactId>parent-boot-2</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
</parent> </parent>
<modules> <modules>

View File

@ -10,9 +10,8 @@
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId> <artifactId>reactive-systems</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent> </parent>
<dependencies> <dependencies>

View File

@ -37,10 +37,6 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<!-- SpringDoc --> <!-- SpringDoc -->
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
@ -63,21 +59,6 @@
<artifactId>spring-restdocs-restassured</artifactId> <artifactId>spring-restdocs-restassured</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!--kotlin dependencies -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-kotlin</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -109,41 +90,6 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<!-- kotlin -->
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>${java.version}</jvmTarget>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins> </plugins>
<resources> <resources>
<resource> <resource>
@ -208,7 +154,6 @@
<properties> <properties>
<springdoc.version>1.6.4</springdoc.version> <springdoc.version>1.6.4</springdoc.version>
<asciidoctor-plugin.version>1.5.6</asciidoctor-plugin.version> <asciidoctor-plugin.version>1.5.6</asciidoctor-plugin.version>
<kotlin.version>1.6.0</kotlin.version>
<snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory> <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
</properties> </properties>

View File

@ -40,7 +40,8 @@ public class FooController {
public ResponseEntity<Foo> getFooById(@PathVariable("id") Long id) { public ResponseEntity<Foo> getFooById(@PathVariable("id") Long id) {
Optional<Foo> foo = repository.findById(id); Optional<Foo> foo = repository.findById(id);
return foo.isPresent() ? new ResponseEntity<>(foo.get(), HttpStatus.OK) : new ResponseEntity<>(HttpStatus.NOT_FOUND); return foo.map(value -> new ResponseEntity<>(value, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
} }
@PostMapping @PostMapping
@ -70,7 +71,7 @@ public class FooController {
@PutMapping("/{id}") @PutMapping("/{id}")
public ResponseEntity<Foo> updateFoo(@PathVariable("id") long id, @RequestBody Foo foo) { public ResponseEntity<Foo> updateFoo(@PathVariable("id") long id, @RequestBody Foo foo) {
boolean isFooPresent = repository.existsById(Long.valueOf(id)); boolean isFooPresent = repository.existsById(id);
if (!isFooPresent) { if (!isFooPresent) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND); return new ResponseEntity<>(HttpStatus.NOT_FOUND);

View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Set List of Objects in Swagger API Response](https://www.baeldung.com/java-swagger-set-list-response)

View File

@ -7,10 +7,7 @@
</encoder> </encoder>
</appender> </appender>
<logger name="org.springframework" level="DEBUG" /> <root level="WARN">
<logger name="org.springframework.transaction" level="WARN" />
<root level="INFO">
<appender-ref ref="STDOUT" /> <appender-ref ref="STDOUT" />
</root> </root>
</configuration> </configuration>

View File

@ -1,6 +1,32 @@
package com.baeldung.restdocopenapi.restdoc; package com.baeldung.restdocopenapi.restdoc;
import com.baeldung.restdocopenapi.Foo;
import com.baeldung.restdocopenapi.FooController;
import com.baeldung.restdocopenapi.FooRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.hateoas.MediaTypes;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.restdocs.constraints.ConstraintDescriptions;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static java.util.Collections.singletonList;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
@ -15,61 +41,47 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.requestF
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.util.StringUtils.collectionToDelimitedString; import static org.springframework.util.StringUtils.collectionToDelimitedString;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.hateoas.MediaTypes;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.restdocs.constraints.ConstraintDescriptions;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.baeldung.restdocopenapi.Application;
import com.baeldung.restdocopenapi.Foo;
import com.fasterxml.jackson.databind.ObjectMapper;
@ExtendWith({ RestDocumentationExtension.class, SpringExtension.class }) @ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
@SpringBootTest(classes = Application.class) @WebMvcTest(FooController.class)
public class SpringRestDocsUnitTest { class SpringRestDocsUnitTest {
private MockMvc mockMvc; private MockMvc mockMvc;
@MockBean
private FooRepository fooRepository;
@Autowired @Autowired
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
@BeforeEach @BeforeEach
public void setup(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) { void setup(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation)) .apply(documentationConfiguration(restDocumentation))
.build(); .build();
} }
@Test @Test
public void whenGetFoo_thenSuccessful() throws Exception { void whenGetAllFoo_thenSuccessful() throws Exception {
when(fooRepository.findAll())
.thenReturn(singletonList(new Foo(1, "Foo 1", "Foo 1")));
this.mockMvc.perform(get("/foo")) this.mockMvc.perform(get("/foo"))
.andDo(print())
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string(containsString("Foo 1"))) .andExpect(content().string(containsString("Foo 1")))
.andDo(document("getAllFoos")); .andDo(document("getAllFoos"));
} }
@Test @Test
public void whenGetFooById_thenSuccessful() throws Exception { void whenGetFooById_thenSuccessful() throws Exception {
ConstraintDescriptions desc = new ConstraintDescriptions(Foo.class); ConstraintDescriptions desc = new ConstraintDescriptions(Foo.class);
when(fooRepository.findById(1L))
.thenReturn(Optional.of(new Foo(1, "title", "body")));
this.mockMvc.perform(get("/foo/{id}", 1)) this.mockMvc.perform(get("/foo/{id}", 1))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andDo(document("getAFoo", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), .andDo(document("getAFoo", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()),
@ -79,7 +91,7 @@ public class SpringRestDocsUnitTest {
} }
@Test @Test
public void whenPostFoo_thenSuccessful() throws Exception { void whenPostFoo_thenSuccessful() throws Exception {
Map<String, Object> foo = new HashMap<>(); Map<String, Object> foo = new HashMap<>();
foo.put("id", 4L); foo.put("id", 4L);
foo.put("title", "New Foo"); foo.put("title", "New Foo");
@ -93,14 +105,18 @@ public class SpringRestDocsUnitTest {
} }
@Test @Test
public void whenDeleteFoo_thenSuccessful() throws Exception { void whenDeleteFoo_thenSuccessful() throws Exception {
this.mockMvc.perform(delete("/foo/{id}", 2)) this.mockMvc.perform(delete("/foo/{id}", 2))
.andExpect(status().isNoContent()) .andExpect(status().isNoContent())
.andDo(document("deleteFoo", pathParameters(parameterWithName("id").description("The id of the foo to delete")))); .andDo(document("deleteFoo", pathParameters(parameterWithName("id").description("The id of the foo to delete"))));
} }
@Test @Test
public void whenUpdateFoo_thenSuccessful() throws Exception { void whenUpdateFoo_thenSuccessful() throws Exception {
when(fooRepository.existsById(3L)).thenReturn(true);
when(fooRepository.save(any(Foo.class)))
.thenReturn(new Foo(3, "Updated Foo", "Body of updated Foo"));
ConstraintDescriptions desc = new ConstraintDescriptions(Foo.class); ConstraintDescriptions desc = new ConstraintDescriptions(Foo.class);
@ -115,6 +131,4 @@ public class SpringRestDocsUnitTest {
responseFields(fieldWithPath("id").description("The id of the updated foo" + collectionToDelimitedString(desc.descriptionsForProperty("id"), ". ")), responseFields(fieldWithPath("id").description("The id of the updated foo" + collectionToDelimitedString(desc.descriptionsForProperty("id"), ". ")),
fieldWithPath("title").description("The title of the updated foo"), fieldWithPath("body").description("The body of the updated foo")))); fieldWithPath("title").description("The title of the updated foo"), fieldWithPath("body").description("The body of the updated foo"))));
} }
} }

View File

@ -1,16 +1,16 @@
package com.baeldung.springdoc; package com.baeldung.springdoc;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit.jupiter.SpringExtension;
@RunWith(SpringRunner.class) @ExtendWith(SpringExtension.class)
@SpringBootTest @SpringBootTest
public class SpringContextTest { class SpringContextTest {
@Test @Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() { void whenSpringContextIsBootstrapped_thenNoExceptions() {
} }

Some files were not shown because too many files have changed in this diff Show More