diff --git a/web-modules/README.md b/web-modules/README.md new file mode 100644 index 0000000000..1329ce18db --- /dev/null +++ b/web-modules/README.md @@ -0,0 +1,3 @@ +## Web + +This module contains web modules. diff --git a/web-modules/apache-tapestry/README.md b/web-modules/apache-tapestry/README.md new file mode 100644 index 0000000000..e41345bada --- /dev/null +++ b/web-modules/apache-tapestry/README.md @@ -0,0 +1,3 @@ +### Relevant Articles + +- [Intro to Apache Tapestry](https://www.baeldung.com/apache-tapestry) diff --git a/web-modules/apache-tapestry/pom.xml b/web-modules/apache-tapestry/pom.xml new file mode 100644 index 0000000000..562cdff00c --- /dev/null +++ b/web-modules/apache-tapestry/pom.xml @@ -0,0 +1,152 @@ + + + 4.0.0 + apache-tapestry + 0.0.1-SNAPSHOT + apache-tapestry + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + + + + org.apache.tapestry + tapestry-core + ${tapestry.version} + + + + org.slf4j + slf4j-log4j12 + ${slf4j-release-version} + + + org.apache.tapestry + tapestry-webresources + ${tapestry.version} + + + + + + + + + + + + + org.testng + testng + ${testng-release-version} + test + + + org.apache.tapestry + tapestry-test + ${tapestry.version} + test + + + + javax.servlet + servlet-api + ${servlet-api-release-version} + provided + + + + org.apache.tapestry + tapestry-javadoc + ${tapestry.version} + provided + + + + + apache-tapestry + + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler.plugin.version} + + ${source.version} + ${target.version} + true + + + + org.apache.maven.plugins + maven-surefire-plugin + ${compiler.surefire.version} + + + Qa + + + + + + org.mortbay.jetty + maven-jetty-plugin + ${compiler.jetty.version} + + + + + + true + + + + tapestry.execution-mode + development + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.1 + + + + true + + + + + + + + + + jboss + http://repository.jboss.org/nexus/content/groups/public/ + + + + + 6.1.16 + 3.0.0-M5 + 3.8.1 + 11 + 11 + 5.8.2 + 2.5 + 6.8.21 + 1.7.19 + + + \ No newline at end of file diff --git a/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/components/Layout.java b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/components/Layout.java new file mode 100644 index 0000000000..5316bd9722 --- /dev/null +++ b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/components/Layout.java @@ -0,0 +1,16 @@ +package com.baeldung.tapestry.components; + +import org.apache.tapestry5.BindingConstants; +import org.apache.tapestry5.annotations.Parameter; +import org.apache.tapestry5.annotations.Property; + +/** + * Layout component for pages of application. + */ +public class Layout { + + @Property + @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL) + private String title; + +} diff --git a/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Error404.java b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Error404.java new file mode 100644 index 0000000000..c629b82d01 --- /dev/null +++ b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Error404.java @@ -0,0 +1,5 @@ +package com.baeldung.tapestry.pages; + +public class Error404 { + +} diff --git a/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Home.java b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Home.java new file mode 100644 index 0000000000..34e99a9cce --- /dev/null +++ b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Home.java @@ -0,0 +1,36 @@ +package com.baeldung.tapestry.pages; + +import java.util.Date; + +import org.apache.tapestry5.Block; +import org.apache.tapestry5.annotations.Log; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.services.ajax.AjaxResponseRenderer; +import org.slf4j.Logger; + +public class Home { + + @Property + private String appName = "apache-tapestry"; + + public Date getCurrentTime() { + return new Date(); + } + + @Inject + private Logger logger; + + @Inject + private AjaxResponseRenderer ajaxResponseRenderer; + + @Inject + private Block ajaxBlock; + + @Log + void onCallAjax() { + logger.info("Ajax call"); + ajaxResponseRenderer.addRender("ajaxZone", ajaxBlock); + } + +} diff --git a/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Index.java b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Index.java new file mode 100644 index 0000000000..7d9e9a1aaa --- /dev/null +++ b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Index.java @@ -0,0 +1,59 @@ +package com.baeldung.tapestry.pages; + + +import org.apache.tapestry5.Block; +import org.apache.tapestry5.EventContext; +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.annotations.InjectPage; +import org.apache.tapestry5.annotations.Log; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.ioc.annotations.Symbol; +import org.apache.tapestry5.services.HttpError; +import org.apache.tapestry5.services.ajax.AjaxResponseRenderer; +import org.slf4j.Logger; + +import java.util.Date; + +/** + * Start page of application apache-tapestry. + */ +public class Index { + @Inject + private Logger logger; + + @Inject + private AjaxResponseRenderer ajaxResponseRenderer; + + @Property + @Inject + @Symbol(SymbolConstants.TAPESTRY_VERSION) + private String tapestryVersion; + + @Inject + private Block block; + + // Handle call with an unwanted context + Object onActivate(EventContext eventContext) { + return eventContext.getCount() > 0 ? + new HttpError(404, "Resource not found") : + null; + } + + @Log + void onComplete() { + logger.info("Complete call on Index page"); + } + + @Log + void onAjax() { + logger.info("Ajax call on Index page"); + + ajaxResponseRenderer.addRender("middlezone", block); + } + + public Date getCurrentTime() { + return new Date(); + } + +} diff --git a/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Login.java b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Login.java new file mode 100644 index 0000000000..c5005f11f5 --- /dev/null +++ b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/pages/Login.java @@ -0,0 +1,42 @@ +package com.baeldung.tapestry.pages; + +import org.apache.tapestry5.alerts.AlertManager; +import org.apache.tapestry5.annotations.InjectComponent; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.corelib.components.Form; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.slf4j.Logger; + +public class Login { + @Inject + private Logger logger; + + @Inject + private AlertManager alertManager; + + @InjectComponent + private Form login; + + @Property + private String email; + + @Property + private String password; + + void onValidateFromLogin() { + if(email == null || password == null) { + alertManager.error("Email/Password is null"); + login.recordError("Validation failed"); + } + } + + Object onSuccessFromLogin() { + alertManager.success("Welcome! Login Successful"); + return Home.class; + } + + void onFailureFromLogin() { + alertManager.error("Please try again with correct credentials"); + } + +} diff --git a/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/AppModule.java b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/AppModule.java new file mode 100644 index 0000000000..2798e4a75b --- /dev/null +++ b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/AppModule.java @@ -0,0 +1,128 @@ +package com.baeldung.tapestry.services; + +import java.io.IOException; + +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.commons.MappedConfiguration; +import org.apache.tapestry5.commons.OrderedConfiguration; +import org.apache.tapestry5.http.services.Request; +import org.apache.tapestry5.http.services.RequestFilter; +import org.apache.tapestry5.http.services.RequestHandler; +import org.apache.tapestry5.http.services.Response; +import org.apache.tapestry5.ioc.ServiceBinder; +import org.apache.tapestry5.ioc.annotations.Contribute; +import org.apache.tapestry5.ioc.annotations.Local; +import org.apache.tapestry5.ioc.services.ApplicationDefaults; +import org.apache.tapestry5.ioc.services.SymbolProvider; +import org.slf4j.Logger; + +/** + * This module is automatically included as part of the Tapestry IoC Registry, it's a good place to + * configure and extend Tapestry, or to place your own service definitions. + */ +public class AppModule { + public static void bind(ServiceBinder binder) { + // binder.bind(MyServiceInterface.class, MyServiceImpl.class); + + // Make bind() calls on the binder object to define most IoC services. + // Use service builder methods (example below) when the implementation + // is provided inline, or requires more initialization than simply + // invoking the constructor. + } + + public static void contributeFactoryDefaults( + MappedConfiguration configuration) { + // The values defined here (as factory default overrides) are themselves + // overridden with application defaults by DevelopmentModule and QaModule. + + // The application version is primarily useful as it appears in + // any exception reports (HTML or textual). + configuration.override(SymbolConstants.APPLICATION_VERSION, "0.0.1-SNAPSHOT"); + + // This is something that should be removed when going to production, but is useful + // in the early stages of development. + configuration.override(SymbolConstants.PRODUCTION_MODE, false); + } + + public static void contributeApplicationDefaults( + MappedConfiguration configuration) { + // Contributions to ApplicationDefaults will override any contributions to + // FactoryDefaults (with the same key). Here we're restricting the supported + // locales to just "en" (English). As you add localised message catalogs and other assets, + // you can extend this list of locales (it's a comma separated series of locale names; + // the first locale name is the default when there's no reasonable match). + configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en"); + + // You should change the passphrase immediately; the HMAC passphrase is used to secure + // the hidden field data stored in forms to encrypt and digitally sign client-side data. + configuration.add(SymbolConstants.HMAC_PASSPHRASE, "change this immediately"); + } + + /** + * Use annotation or method naming convention: contributeApplicationDefaults + */ + @Contribute(SymbolProvider.class) + @ApplicationDefaults + public static void setupEnvironment(MappedConfiguration configuration) { + // Support for jQuery is new in Tapestry 5.4 and will become the only supported + // option in 5.5. + configuration.add(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER, "jquery"); + configuration.add(SymbolConstants.BOOTSTRAP_ROOT, "context:mybootstrap"); + } + + + /** + * This is a service definition, the service will be named "TimingFilter". The interface, + * RequestFilter, is used within the RequestHandler service pipeline, which is built from the + * RequestHandler service configuration. Tapestry IoC is responsible for passing in an + * appropriate Logger instance. Requests for static resources are handled at a higher level, so + * this filter will only be invoked for Tapestry related requests. + * + * + * Service builder methods are useful when the implementation is inline as an inner class + * (as here) or require some other kind of special initialization. In most cases, + * use the static bind() method instead. + * + * + * If this method was named "build", then the service id would be taken from the + * service interface and would be "RequestFilter". Since Tapestry already defines + * a service named "RequestFilter" we use an explicit service id that we can reference + * inside the contribution method. + */ + public RequestFilter buildTimingFilter(final Logger log) { + return new RequestFilter() { + public boolean service(Request request, Response response, RequestHandler handler) + throws IOException { + long startTime = System.currentTimeMillis(); + + try { + // The responsibility of a filter is to invoke the corresponding method + // in the handler. When you chain multiple filters together, each filter + // received a handler that is a bridge to the next filter. + + return handler.service(request, response); + } finally { + long elapsed = System.currentTimeMillis() - startTime; + + log.info("Request time: {} ms", elapsed); + } + } + }; + } + + /** + * This is a contribution to the RequestHandler service configuration. This is how we extend + * Tapestry using the timing filter. A common use for this kind of filter is transaction + * management or security. The @Local annotation selects the desired service by type, but only + * from the same module. Without @Local, there would be an error due to the other service(s) + * that implement RequestFilter (defined in other modules). + */ + @Contribute(RequestHandler.class) + public void addTimingFilter(OrderedConfiguration configuration, @Local RequestFilter filter) { + // Each contribution to an ordered configuration has a name, When necessary, you may + // set constraints to precisely control the invocation order of the contributed filter + // within the pipeline. + + configuration.add("Timing", filter); + } +} diff --git a/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/DevelopmentModule.java b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/DevelopmentModule.java new file mode 100644 index 0000000000..1c89587c53 --- /dev/null +++ b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/DevelopmentModule.java @@ -0,0 +1,24 @@ +package com.baeldung.tapestry.services; + +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.commons.MappedConfiguration; + +/** + * This module is automatically included as part of the Tapestry IoC Registry if tapestry.execution-mode + * includes development. + */ +public class DevelopmentModule { + public static void contributeApplicationDefaults( + MappedConfiguration configuration) { + // The factory default is true but during the early stages of an application + // overriding to false is a good idea. In addition, this is often overridden + // on the command line as -Dtapestry.production-mode=false + configuration.add(SymbolConstants.PRODUCTION_MODE, false); + + // The application version number is incorprated into URLs for some + // assets. Web browsers will cache assets because of the far future expires + // header. If existing assets are changed, the version number should also + // change, to force the browser to download new versions. + configuration.add(SymbolConstants.APPLICATION_VERSION, "0.0.1-SNAPSHOT-DEV"); + } +} diff --git a/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/QaModule.java b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/QaModule.java new file mode 100644 index 0000000000..d16e498a4b --- /dev/null +++ b/web-modules/apache-tapestry/src/main/java/com/baeldung/tapestry/services/QaModule.java @@ -0,0 +1,34 @@ +package com.baeldung.tapestry.services; + +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.commons.MappedConfiguration; +import org.apache.tapestry5.ioc.ServiceBinder; + +/** + * This module is automatically included as part of the Tapestry IoC Registry if tapestry.execution-mode + * includes qa ("quality assurance"). + */ +public class QaModule +{ + public static void bind(ServiceBinder binder) + { + // Bind any services needed by the QA team to produce their reports + // binder.bind(MyServiceMonitorInterface.class, MyServiceMonitorImpl.class); + } + + + public static void contributeApplicationDefaults( + MappedConfiguration configuration) + { + // The factory default is true but during the early stages of an application + // overriding to false is a good idea. In addition, this is often overridden + // on the command line as -Dtapestry.production-mode=false + configuration.add(SymbolConstants.PRODUCTION_MODE, false); + + // The application version number is incorprated into URLs for some + // assets. Web browsers will cache assets because of the far future expires + // header. If existing assets are changed, the version number should also + // change, to force the browser to download new versions. + configuration.add(SymbolConstants.APPLICATION_VERSION, "0.0.1-SNAPSHOT-QA"); + } +} diff --git a/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/components/Layout.tml b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/components/Layout.tml new file mode 100644 index 0000000000..baa17aef8e --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/components/Layout.tml @@ -0,0 +1,21 @@ + + + ${title} + + +
+
+
+ +
+
+
+
+ +
+
+

© Your Company

+
+
+ + diff --git a/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/logback.xml b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/logback.xml new file mode 100644 index 0000000000..2997ecb099 --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/logback.xml @@ -0,0 +1,13 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + diff --git a/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Error404.tml b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Error404.tml new file mode 100644 index 0000000000..b18492221e --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Error404.tml @@ -0,0 +1,11 @@ + + +
+
+

Requested page not found!

+
+
+ + diff --git a/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.properties b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.properties new file mode 100644 index 0000000000..4647845163 --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.properties @@ -0,0 +1 @@ +introMsg=Welcome to the Apache Tapestry Tutorial diff --git a/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.tml b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.tml new file mode 100644 index 0000000000..3dafb63f0a --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Home.tml @@ -0,0 +1,14 @@ + + +

Home! ${appName}

+

${message:introMsg}

+

${currentTime}

+

Call Ajax

+ + +
+

Rendered through Ajax

+

The current time is: ${currentTime}

+
+ + diff --git a/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.properties b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.properties new file mode 100644 index 0000000000..bc49edd53f --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.properties @@ -0,0 +1 @@ +greeting=Welcome to Tapestry 5! We hope that this project template will get you going in style. diff --git a/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.tml b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.tml new file mode 100644 index 0000000000..625a3c2fcc --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Index.tml @@ -0,0 +1,46 @@ + + + + + +
+

+ ${message:greeting} +

+

${message:greeting}

+

The current time is: ${currentTime}

+

+ This is a template for a simple marketing or informational website. It includes a large callout called + the hero unit and three supporting pieces of content. Use it as a starting point to create something + more unique. +

+

Learn more »

+
+ + +
+
+

Normal link

+

Clink the bottom link and the page refresh with event complete

+

Complete»

+
+ + + +
+

Ajax link

+

Click the bottom link to update just the middle column with Ajax call with event ajax

+

Ajax»

+
+
+ + +

Ajax updated

+

I'v been updated through AJAX call

+

The current time is: ${currentTime}

+
+ + diff --git a/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Login.tml b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Login.tml new file mode 100644 index 0000000000..ac78a55341 --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/com/baeldung/tapestry/pages/Login.tml @@ -0,0 +1,16 @@ + + +
+
+ +

Please sign in

+ + + +
+
+
+ + diff --git a/web-modules/apache-tapestry/src/main/resources/log4j.properties b/web-modules/apache-tapestry/src/main/resources/log4j.properties new file mode 100644 index 0000000000..bd90a762ca --- /dev/null +++ b/web-modules/apache-tapestry/src/main/resources/log4j.properties @@ -0,0 +1,44 @@ +# Default to info level output; this is very handy if you eventually use Hibernate as well. +log4j.rootCategory=info, A1 + +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=[%p] %c{2} %m%n + +# Service category names are the name of the defining module class +# and then the service id. +log4j.category.com.baeldung.tapestry.services.AppModule.TimingFilter=info + +# Outputs a list of pages, components and mixins at startup. +log4j.category.org.apache.tapestry5.modules.TapestryModule.ComponentClassResolver=info + +# Outputs startup statistics; elapsed time to setup and initialize the registry, a list of +# available services, and a launch banner that includes the Tapestry version number. +log4j.category.org.apache.tapestry5.TapestryFilter=info + + +# Turning on debug mode for a page's or component's transformer logger +# will show all of the code changes that occur when the +# class is loaded. + +# log4j.category.tapestry.transformer.com.baeldung.tapestry.pages.Index=debug + +# Turning on debug mode for a component's events logger will show all the events triggered on the +# component, and which component methods are invoked as a result. + +# log4j.category.tapestry.events.com.baeldung.tapestry.pages.Index=debug + +# Turning on trace mode for a page's render logger provides extended information about every step +# in rendering (this is not generally helpful). Turning on debug mode will add a one-line +# summary that includes the elapsed render time, which can be useful in tracking down +# performance issues. + +# log4j.category.tapestry.render.com.baeldung.tapestry.pages.Index=debug + +# Turn on some verbose debugging about everything in the application. This is nice initially, +# while getting everything set up. You'll probably want to remove this once you are +# up and running, replacing it with more selective debugging output. +log4j.category.com.baeldung.tapestry=debug diff --git a/web-modules/apache-tapestry/src/main/webapp/WEB-INF/app.properties b/web-modules/apache-tapestry/src/main/webapp/WEB-INF/app.properties new file mode 100644 index 0000000000..1c299311bb --- /dev/null +++ b/web-modules/apache-tapestry/src/main/webapp/WEB-INF/app.properties @@ -0,0 +1,4 @@ +# This is where global application properties go. +# You can also have individual message catalogs for each page and each +# component that override these defaults. +# The name of this file is based on the element in web. \ No newline at end of file diff --git a/web-modules/apache-tapestry/src/main/webapp/WEB-INF/web.xml b/web-modules/apache-tapestry/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..c5bdfd415c --- /dev/null +++ b/web-modules/apache-tapestry/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,54 @@ + + + + + apache-tapestry Tapestry 5 Application + + + tapestry.app-package + com.baeldung.tapestry + + + + + tapestry.development-modules + + com.baeldung.tapestry.services.DevelopmentModule + + + + tapestry.qa-modules + + com.baeldung.tapestry.services.QaModule + + + + + + + app + org.apache.tapestry5.TapestryFilter + + + + app + /* + REQUEST + ERROR + + + + 404 + /error404 + + + \ No newline at end of file diff --git a/web-modules/apache-tapestry/src/main/webapp/favicon.ico b/web-modules/apache-tapestry/src/main/webapp/favicon.ico new file mode 100644 index 0000000000..b9715a2aed Binary files /dev/null and b/web-modules/apache-tapestry/src/main/webapp/favicon.ico differ diff --git a/web-modules/apache-tapestry/src/main/webapp/images/tapestry.png b/web-modules/apache-tapestry/src/main/webapp/images/tapestry.png new file mode 100644 index 0000000000..eba58883c6 Binary files /dev/null and b/web-modules/apache-tapestry/src/main/webapp/images/tapestry.png differ diff --git a/web-modules/apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap.css b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap.css new file mode 100644 index 0000000000..057ff46dae --- /dev/null +++ b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/css/bootstrap.css @@ -0,0 +1,6588 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; + vertical-align: baseline; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + margin: .67em 0; + font-size: 2em; +} +mark { + color: #000; + background: #ff0; +} +small { + font-size: 80%; +} +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -.5em; +} +sub { + bottom: -.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + height: 0; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + margin: 0; + font: inherit; + color: inherit; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + padding: .35em .625em .75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} +legend { + padding: 0; + border: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-spacing: 0; + border-collapse: collapse; +} +td, +th { + padding: 0; +} +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ +@media print { + *, + *:before, + *:after { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .navbar { + display: none; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +@font-face { + font-family: 'Glyphicons Halflings'; + + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\2a"; +} +.glyphicon-plus:before { + content: "\2b"; +} +.glyphicon-euro:before, +.glyphicon-eur:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e035"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +.glyphicon-cd:before { + content: "\e201"; +} +.glyphicon-save-file:before { + content: "\e202"; +} +.glyphicon-open-file:before { + content: "\e203"; +} +.glyphicon-level-up:before { + content: "\e204"; +} +.glyphicon-copy:before { + content: "\e205"; +} +.glyphicon-paste:before { + content: "\e206"; +} +.glyphicon-alert:before { + content: "\e209"; +} +.glyphicon-equalizer:before { + content: "\e210"; +} +.glyphicon-king:before { + content: "\e211"; +} +.glyphicon-queen:before { + content: "\e212"; +} +.glyphicon-pawn:before { + content: "\e213"; +} +.glyphicon-bishop:before { + content: "\e214"; +} +.glyphicon-knight:before { + content: "\e215"; +} +.glyphicon-baby-formula:before { + content: "\e216"; +} +.glyphicon-tent:before { + content: "\26fa"; +} +.glyphicon-blackboard:before { + content: "\e218"; +} +.glyphicon-bed:before { + content: "\e219"; +} +.glyphicon-apple:before { + content: "\f8ff"; +} +.glyphicon-erase:before { + content: "\e221"; +} +.glyphicon-hourglass:before { + content: "\231b"; +} +.glyphicon-lamp:before { + content: "\e223"; +} +.glyphicon-duplicate:before { + content: "\e224"; +} +.glyphicon-piggy-bank:before { + content: "\e225"; +} +.glyphicon-scissors:before { + content: "\e226"; +} +.glyphicon-bitcoin:before { + content: "\e227"; +} +.glyphicon-btc:before { + content: "\e227"; +} +.glyphicon-xbt:before { + content: "\e227"; +} +.glyphicon-yen:before { + content: "\00a5"; +} +.glyphicon-jpy:before { + content: "\00a5"; +} +.glyphicon-ruble:before { + content: "\20bd"; +} +.glyphicon-rub:before { + content: "\20bd"; +} +.glyphicon-scale:before { + content: "\e230"; +} +.glyphicon-ice-lolly:before { + content: "\e231"; +} +.glyphicon-ice-lolly-tasted:before { + content: "\e232"; +} +.glyphicon-education:before { + content: "\e233"; +} +.glyphicon-option-horizontal:before { + content: "\e234"; +} +.glyphicon-option-vertical:before { + content: "\e235"; +} +.glyphicon-menu-hamburger:before { + content: "\e236"; +} +.glyphicon-modal-window:before { + content: "\e237"; +} +.glyphicon-oil:before { + content: "\e238"; +} +.glyphicon-grain:before { + content: "\e239"; +} +.glyphicon-sunglasses:before { + content: "\e240"; +} +.glyphicon-text-size:before { + content: "\e241"; +} +.glyphicon-text-color:before { + content: "\e242"; +} +.glyphicon-text-background:before { + content: "\e243"; +} +.glyphicon-object-align-top:before { + content: "\e244"; +} +.glyphicon-object-align-bottom:before { + content: "\e245"; +} +.glyphicon-object-align-horizontal:before { + content: "\e246"; +} +.glyphicon-object-align-left:before { + content: "\e247"; +} +.glyphicon-object-align-vertical:before { + content: "\e248"; +} +.glyphicon-object-align-right:before { + content: "\e249"; +} +.glyphicon-triangle-right:before { + content: "\e250"; +} +.glyphicon-triangle-left:before { + content: "\e251"; +} +.glyphicon-triangle-bottom:before { + content: "\e252"; +} +.glyphicon-triangle-top:before { + content: "\e253"; +} +.glyphicon-console:before { + content: "\e254"; +} +.glyphicon-superscript:before { + content: "\e255"; +} +.glyphicon-subscript:before { + content: "\e256"; +} +.glyphicon-menu-left:before { + content: "\e257"; +} +.glyphicon-menu-right:before { + content: "\e258"; +} +.glyphicon-menu-down:before { + content: "\e259"; +} +.glyphicon-menu-up:before { + content: "\e260"; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 10px; + + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.42857143; + color: #333; + background-color: #fff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #337ab7; + text-decoration: none; +} +a:hover, +a:focus { + color: #23527c; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive, +.thumbnail > img, +.thumbnail a > img, +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 6px; +} +.img-thumbnail { + display: inline-block; + max-width: 100%; + height: auto; + padding: 4px; + line-height: 1.42857143; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -webkit-transition: all .2s ease-in-out; + -o-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eee; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} +[role="button"] { + cursor: pointer; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: inherit; + font-weight: 500; + line-height: 1.1; + color: inherit; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #777; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 20px; + margin-bottom: 10px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10px; + margin-bottom: 10px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 36px; +} +h2, +.h2 { + font-size: 30px; +} +h3, +.h3 { + font-size: 24px; +} +h4, +.h4 { + font-size: 18px; +} +h5, +.h5 { + font-size: 14px; +} +h6, +.h6 { + font-size: 12px; +} +p { + margin: 0 0 10px; +} +.lead { + margin-bottom: 20px; + font-size: 16px; + font-weight: 300; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} +small, +.small { + font-size: 85%; +} +mark, +.mark { + padding: .2em; + background-color: #fcf8e3; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-nowrap { + white-space: nowrap; +} +.text-lowercase { + text-transform: lowercase; +} +.text-uppercase { + text-transform: uppercase; +} +.text-capitalize { + text-transform: capitalize; +} +.text-muted { + color: #777; +} +.text-primary { + color: #337ab7; +} +a.text-primary:hover { + color: #286090; +} +.text-success { + color: #3c763d; +} +a.text-success:hover { + color: #2b542c; +} +.text-info { + color: #31708f; +} +a.text-info:hover { + color: #245269; +} +.text-warning { + color: #8a6d3b; +} +a.text-warning:hover { + color: #66512c; +} +.text-danger { + color: #a94442; +} +a.text-danger:hover { + color: #843534; +} +.bg-primary { + color: #fff; + background-color: #337ab7; +} +a.bg-primary:hover { + background-color: #286090; +} +.bg-success { + background-color: #dff0d8; +} +a.bg-success:hover { + background-color: #c1e2b3; +} +.bg-info { + background-color: #d9edf7; +} +a.bg-info:hover { + background-color: #afd9ee; +} +.bg-warning { + background-color: #fcf8e3; +} +a.bg-warning:hover { + background-color: #f7ecb5; +} +.bg-danger { + background-color: #f2dede; +} +a.bg-danger:hover { + background-color: #e4b9b9; +} +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eee; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + margin-left: -5px; + list-style: none; +} +.list-inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} +dl { + margin-top: 0; + margin-bottom: 20px; +} +dt, +dd { + line-height: 1.42857143; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #777; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + font-size: 17.5px; + border-left: 5px solid #eee; +} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.42857143; + color: #777; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + text-align: right; + border-right: 5px solid #eee; + border-left: 0; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +address { + margin-bottom: 20px; + font-style: normal; + line-height: 1.42857143; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #fff; + background-color: #333; + border-radius: 3px; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); +} +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + -webkit-box-shadow: none; + box-shadow: none; +} +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.42857143; + color: #333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #ccc; + border-radius: 4px; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +.row { + margin-right: -15px; + margin-left: -15px; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666667%; +} +.col-xs-10 { + width: 83.33333333%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666667%; +} +.col-xs-7 { + width: 58.33333333%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666667%; +} +.col-xs-4 { + width: 33.33333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.66666667%; +} +.col-xs-1 { + width: 8.33333333%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666667%; +} +.col-xs-pull-10 { + right: 83.33333333%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666667%; +} +.col-xs-pull-7 { + right: 58.33333333%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666667%; +} +.col-xs-pull-4 { + right: 33.33333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.66666667%; +} +.col-xs-pull-1 { + right: 8.33333333%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666667%; +} +.col-xs-push-10 { + left: 83.33333333%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666667%; +} +.col-xs-push-7 { + left: 58.33333333%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666667%; +} +.col-xs-push-4 { + left: 33.33333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.66666667%; +} +.col-xs-push-1 { + left: 8.33333333%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666667%; +} +.col-xs-offset-10 { + margin-left: 83.33333333%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666667%; +} +.col-xs-offset-7 { + margin-left: 58.33333333%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.66666667%; +} +.col-xs-offset-1 { + margin-left: 8.33333333%; +} +.col-xs-offset-0 { + margin-left: 0; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666667%; + } + .col-sm-10 { + width: 83.33333333%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666667%; + } + .col-sm-7 { + width: 58.33333333%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666667%; + } + .col-sm-4 { + width: 33.33333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.66666667%; + } + .col-sm-1 { + width: 8.33333333%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666667%; + } + .col-sm-pull-10 { + right: 83.33333333%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666667%; + } + .col-sm-pull-7 { + right: 58.33333333%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666667%; + } + .col-sm-pull-4 { + right: 33.33333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.66666667%; + } + .col-sm-pull-1 { + right: 8.33333333%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666667%; + } + .col-sm-push-10 { + left: 83.33333333%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666667%; + } + .col-sm-push-7 { + left: 58.33333333%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666667%; + } + .col-sm-push-4 { + left: 33.33333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.66666667%; + } + .col-sm-push-1 { + left: 8.33333333%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666667%; + } + .col-sm-offset-10 { + margin-left: 83.33333333%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666667%; + } + .col-sm-offset-7 { + margin-left: 58.33333333%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.66666667%; + } + .col-sm-offset-1 { + margin-left: 8.33333333%; + } + .col-sm-offset-0 { + margin-left: 0; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666667%; + } + .col-md-10 { + width: 83.33333333%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666667%; + } + .col-md-7 { + width: 58.33333333%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666667%; + } + .col-md-4 { + width: 33.33333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.66666667%; + } + .col-md-1 { + width: 8.33333333%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666667%; + } + .col-md-pull-10 { + right: 83.33333333%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666667%; + } + .col-md-pull-7 { + right: 58.33333333%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666667%; + } + .col-md-pull-4 { + right: 33.33333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.66666667%; + } + .col-md-pull-1 { + right: 8.33333333%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666667%; + } + .col-md-push-10 { + left: 83.33333333%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666667%; + } + .col-md-push-7 { + left: 58.33333333%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666667%; + } + .col-md-push-4 { + left: 33.33333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.66666667%; + } + .col-md-push-1 { + left: 8.33333333%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666667%; + } + .col-md-offset-10 { + margin-left: 83.33333333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666667%; + } + .col-md-offset-7 { + margin-left: 58.33333333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.66666667%; + } + .col-md-offset-1 { + margin-left: 8.33333333%; + } + .col-md-offset-0 { + margin-left: 0; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666667%; + } + .col-lg-10 { + width: 83.33333333%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666667%; + } + .col-lg-7 { + width: 58.33333333%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666667%; + } + .col-lg-4 { + width: 33.33333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.66666667%; + } + .col-lg-1 { + width: 8.33333333%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666667%; + } + .col-lg-pull-10 { + right: 83.33333333%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666667%; + } + .col-lg-pull-7 { + right: 58.33333333%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666667%; + } + .col-lg-pull-4 { + right: 33.33333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.66666667%; + } + .col-lg-pull-1 { + right: 8.33333333%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666667%; + } + .col-lg-push-10 { + left: 83.33333333%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666667%; + } + .col-lg-push-7 { + left: 58.33333333%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666667%; + } + .col-lg-push-4 { + left: 33.33333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.66666667%; + } + .col-lg-push-1 { + left: 8.33333333%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666667%; + } + .col-lg-offset-10 { + margin-left: 83.33333333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666667%; + } + .col-lg-offset-7 { + margin-left: 58.33333333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66666667%; + } + .col-lg-offset-1 { + margin-left: 8.33333333%; + } + .col-lg-offset-0 { + margin-left: 0; + } +} +table { + background-color: transparent; +} +caption { + padding-top: 8px; + padding-bottom: 8px; + color: #777; + text-align: left; +} +th { + text-align: left; +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.42857143; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #ddd; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #ddd; +} +.table .table { + background-color: #fff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + display: table-column; + float: none; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + display: table-cell; + float: none; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #e8e8e8; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #d9edf7; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #c4e3f3; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ebcccc; +} +.table-responsive { + min-height: .01%; + overflow-x: auto; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #ddd; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + max-width: 100%; + margin-bottom: 5px; + font-weight: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + line-height: normal; +} +input[type="file"] { + display: block; +} +input[type="range"] { + display: block; + width: 100%; +} +select[multiple], +select[size] { + height: auto; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +output { + display: block; + padding-top: 7px; + font-size: 14px; + line-height: 1.42857143; + color: #555; +} +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.42857143; + color: #555; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); +} +.form-control::-moz-placeholder { + color: #999; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #999; +} +.form-control::-webkit-input-placeholder { + color: #999; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + background-color: #eee; + opacity: 1; +} +.form-control[disabled], +fieldset[disabled] .form-control { + cursor: not-allowed; +} +textarea.form-control { + height: auto; +} +input[type="search"] { + -webkit-appearance: none; +} +@media screen and (-webkit-min-device-pixel-ratio: 0) { + input[type="date"], + input[type="time"], + input[type="datetime-local"], + input[type="month"] { + line-height: 34px; + } + input[type="date"].input-sm, + input[type="time"].input-sm, + input[type="datetime-local"].input-sm, + input[type="month"].input-sm, + .input-group-sm input[type="date"], + .input-group-sm input[type="time"], + .input-group-sm input[type="datetime-local"], + .input-group-sm input[type="month"] { + line-height: 30px; + } + input[type="date"].input-lg, + input[type="time"].input-lg, + input[type="datetime-local"].input-lg, + input[type="month"].input-lg, + .input-group-lg input[type="date"], + .input-group-lg input[type="time"], + .input-group-lg input[type="datetime-local"], + .input-group-lg input[type="month"] { + line-height: 46px; + } +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 4px \9; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + vertical-align: middle; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + min-height: 34px; + padding-top: 7px; + padding-bottom: 7px; + margin-bottom: 0; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-right: 0; + padding-left: 0; +} +.input-sm { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-sm { + height: 30px; + line-height: 30px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.form-group-sm .form-control { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.form-group-sm .form-control { + height: 30px; + line-height: 30px; +} +textarea.form-group-sm .form-control, +select[multiple].form-group-sm .form-control { + height: auto; +} +.form-group-sm .form-control-static { + height: 30px; + min-height: 32px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; +} +.input-lg { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +select.input-lg { + height: 46px; + line-height: 46px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.form-group-lg .form-control { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +select.form-group-lg .form-control { + height: 46px; + line-height: 46px; +} +textarea.form-group-lg .form-control, +select[multiple].form-group-lg .form-control { + height: auto; +} +.form-group-lg .form-control-static { + height: 46px; + min-height: 38px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 42.5px; +} +.form-control-feedback { + position: absolute; + top: 0; + right: 0; + z-index: 2; + display: block; + width: 34px; + height: 34px; + line-height: 34px; + text-align: center; + pointer-events: none; +} +.input-lg + .form-control-feedback { + width: 46px; + height: 46px; + line-height: 46px; +} +.input-sm + .form-control-feedback { + width: 30px; + height: 30px; + line-height: 30px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-inline label { + color: #3c763d; +} +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; +} +.has-success .input-group-addon { + color: #3c763d; + background-color: #dff0d8; + border-color: #3c763d; +} +.has-success .form-control-feedback { + color: #3c763d; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-inline label { + color: #8a6d3b; +} +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; +} +.has-warning .input-group-addon { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #8a6d3b; +} +.has-warning .form-control-feedback { + color: #8a6d3b; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-inline label { + color: #a94442; +} +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; +} +.has-error .input-group-addon { + color: #a94442; + background-color: #f2dede; + border-color: #a94442; +} +.has-error .form-control-feedback { + color: #a94442; +} +.has-feedback label ~ .form-control-feedback { + top: 25px; +} +.has-feedback label.sr-only ~ .form-control-feedback { + top: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-static { + display: inline-block; + } + .form-inline .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .input-group-btn, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 27px; +} +.form-horizontal .form-group { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + padding-top: 7px; + margin-bottom: 0; + text-align: right; + } +} +.form-horizontal .has-feedback .form-control-feedback { + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 14.333333px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 6px; + } +} +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.btn:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus, +.btn.focus { + color: #333; + text-decoration: none; +} +.btn:active, +.btn.active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + pointer-events: none; + cursor: not-allowed; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; + opacity: .65; +} +.btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; +} +.btn-default:hover, +.btn-default:focus, +.btn-default.focus, +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #333; + background-color: #e6e6e6; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #fff; + border-color: #ccc; +} +.btn-default .badge { + color: #fff; + background-color: #333; +} +.btn-primary { + color: #fff; + background-color: #337ab7; + border-color: #2e6da4; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary.focus, +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #fff; + background-color: #286090; + border-color: #204d74; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled.focus, +.btn-primary[disabled].focus, +fieldset[disabled] .btn-primary.focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #337ab7; + border-color: #2e6da4; +} +.btn-primary .badge { + color: #337ab7; + background-color: #fff; +} +.btn-success { + color: #fff; + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success:hover, +.btn-success:focus, +.btn-success.focus, +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + color: #fff; + background-color: #449d44; + border-color: #398439; +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled.focus, +.btn-success[disabled].focus, +fieldset[disabled] .btn-success.focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success .badge { + color: #5cb85c; + background-color: #fff; +} +.btn-info { + color: #fff; + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info:hover, +.btn-info:focus, +.btn-info.focus, +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + color: #fff; + background-color: #31b0d5; + border-color: #269abc; +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled.focus, +.btn-info[disabled].focus, +fieldset[disabled] .btn-info.focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info .badge { + color: #5bc0de; + background-color: #fff; +} +.btn-warning { + color: #fff; + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning.focus, +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + color: #fff; + background-color: #ec971f; + border-color: #d58512; +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled.focus, +.btn-warning[disabled].focus, +fieldset[disabled] .btn-warning.focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning .badge { + color: #f0ad4e; + background-color: #fff; +} +.btn-danger { + color: #fff; + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger.focus, +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + color: #fff; + background-color: #c9302c; + border-color: #ac2925; +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled.focus, +.btn-danger[disabled].focus, +fieldset[disabled] .btn-danger.focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger .badge { + color: #d9534f; + background-color: #fff; +} +.btn-link { + font-weight: normal; + color: #337ab7; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link.active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #23527c; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #777; + text-decoration: none; +} +.btn-lg, +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +.btn-sm, +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-xs, +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-block { + display: block; + width: 100%; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity .15s linear; + -o-transition: opacity .15s linear; + transition: opacity .15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition-timing-function: ease; + -o-transition-timing-function: ease; + transition-timing-function: ease; + -webkit-transition-duration: .35s; + -o-transition-duration: .35s; + transition-duration: .35s; + -webkit-transition-property: height, visibility; + -o-transition-property: height, visibility; + transition-property: height, visibility; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px dashed; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + font-size: 14px; + text-align: left; + list-style: none; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.42857143; + color: #333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #fff; + text-decoration: none; + background-color: #337ab7; + outline: 0; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #777; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: not-allowed; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + right: 0; + left: auto; +} +.dropdown-menu-left { + right: auto; + left: 0; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.42857143; + color: #777; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + content: ""; + border-top: 0; + border-bottom: 4px solid; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } + .navbar-right .dropdown-menu-left { + right: auto; + left: 0; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar { + margin-left: -5px; +} +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: left; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group > .btn + .dropdown-toggle { + padding-right: 8px; + padding-left: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-left-radius: 4px; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + display: table-cell; + float: none; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +.btn-group-justified > .btn-group .dropdown-menu { + left: auto; +} +[data-toggle="buttons"] > .btn input[type="radio"], +[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], +[data-toggle="buttons"] > .btn input[type="checkbox"], +[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-right: 0; + padding-left: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 46px; + line-height: 46px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 30px; + line-height: 30px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 6px 12px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #555; + text-align: center; + background-color: #eee; + border: 1px solid #ccc; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 12px; + border-radius: 3px; +} +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 18px; + border-radius: 6px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + margin-left: -1px; +} +.nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eee; +} +.nav > li.disabled > a { + color: #777; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #777; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eee; + border-color: #337ab7; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eee #eee #ddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555; + cursor: default; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #fff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #fff; + background-color: #337ab7; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #fff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + padding-right: 15px; + padding-left: 15px; + overflow-x: visible; + -webkit-overflow-scrolling: touch; + border-top: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-right: 0; + padding-left: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + height: 50px; + padding: 15px 15px; + font-size: 18px; + line-height: 20px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + padding: 9px 10px; + margin-top: 8px; + margin-right: 15px; + margin-bottom: 8px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle:focus { + outline: 0; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 7.5px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + } +} +.navbar-form { + padding: 10px 15px; + margin-top: 8px; + margin-right: -15px; + margin-bottom: 8px; + margin-left: -15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .form-control-static { + display: inline-block; + } + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .input-group-btn, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + padding-top: 0; + padding-bottom: 0; + margin-right: 0; + margin-left: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 8px; + margin-bottom: 8px; +} +.navbar-btn.btn-sm { + margin-top: 10px; + margin-bottom: 10px; +} +.navbar-btn.btn-xs { + margin-top: 14px; + margin-bottom: 14px; +} +.navbar-text { + margin-top: 15px; + margin-bottom: 15px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-right: 15px; + margin-left: 15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + margin-right: -15px; + } + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} +.navbar-default .navbar-brand { + color: #777; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #777; +} +.navbar-default .navbar-nav > li > a { + color: #777; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555; + background-color: #e7e7e7; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #ccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #ddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #ddd; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #888; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e7e7e7; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + color: #555; + background-color: #e7e7e7; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #ccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #777; +} +.navbar-default .navbar-link:hover { + color: #333; +} +.navbar-default .btn-link { + color: #777; +} +.navbar-default .btn-link:hover, +.navbar-default .btn-link:focus { + color: #333; +} +.navbar-default .btn-link[disabled]:hover, +fieldset[disabled] .navbar-default .btn-link:hover, +.navbar-default .btn-link[disabled]:focus, +fieldset[disabled] .navbar-default .btn-link:focus { + color: #ccc; +} +.navbar-inverse { + background-color: #222; + border-color: #080808; +} +.navbar-inverse .navbar-brand { + color: #9d9d9d; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #9d9d9d; +} +.navbar-inverse .navbar-nav > li > a { + color: #9d9d9d; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #fff; + background-color: #080808; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #333; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #fff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + color: #fff; + background-color: #080808; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #9d9d9d; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #fff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #9d9d9d; +} +.navbar-inverse .navbar-link:hover { + color: #fff; +} +.navbar-inverse .btn-link { + color: #9d9d9d; +} +.navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link:focus { + color: #fff; +} +.navbar-inverse .btn-link[disabled]:hover, +fieldset[disabled] .navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link[disabled]:focus, +fieldset[disabled] .navbar-inverse .btn-link:focus { + color: #444; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: #f5f5f5; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + padding: 0 5px; + color: #ccc; + content: "/\00a0"; +} +.breadcrumb > .active { + color: #777; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + margin-left: -1px; + line-height: 1.42857143; + color: #337ab7; + text-decoration: none; + background-color: #fff; + border: 1px solid #ddd; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + color: #23527c; + background-color: #eee; + border-color: #ddd; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #fff; + cursor: default; + background-color: #337ab7; + border-color: #337ab7; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #777; + cursor: not-allowed; + background-color: #fff; + border-color: #ddd; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} +.pager { + padding-left: 0; + margin: 20px 0; + text-align: center; + list-style: none; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eee; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #777; + cursor: not-allowed; + background-color: #fff; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +a.label:hover, +a.label:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #777; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #5e5e5e; +} +.label-primary { + background-color: #337ab7; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #286090; +} +.label-success { + background-color: #5cb85c; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} +.label-info { + background-color: #5bc0de; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} +.label-warning { + background-color: #f0ad4e; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + background-color: #777; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge, +.btn-group-xs > .btn .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #337ab7; + background-color: #fff; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding: 30px 15px; + margin-bottom: 30px; + color: inherit; + background-color: #eee; +} +.jumbotron h1, +.jumbotron .h1 { + color: inherit; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 21px; + font-weight: 200; +} +.jumbotron > hr { + border-top-color: #d5d5d5; +} +.container .jumbotron, +.container-fluid .jumbotron { + border-radius: 6px; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding: 48px 0; + } + .container .jumbotron, + .container-fluid .jumbotron { + padding-right: 60px; + padding-left: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 63px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 20px; + line-height: 1.42857143; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -webkit-transition: border .2s ease-in-out; + -o-transition: border .2s ease-in-out; + transition: border .2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + margin-right: auto; + margin-left: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #337ab7; +} +.thumbnail .caption { + padding: 9px; + color: #333; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #2b542c; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #245269; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #66512c; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #843534; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-o-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); +} +.progress-bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #fff; + text-align: center; + background-color: #337ab7; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + -webkit-transition: width .6s ease; + -o-transition: width .6s ease; + transition: width .6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .progress-bar, +.progress-bar.active { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #5cb85c; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #5bc0de; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #f0ad4e; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #d9534f; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media, +.media-body { + overflow: hidden; + zoom: 1; +} +.media-body { + width: 10000px; +} +.media-object { + display: block; +} +.media-right, +.media > .pull-right { + padding-left: 10px; +} +.media-left, +.media > .pull-left { + padding-right: 10px; +} +.media-left, +.media-right, +.media-body { + display: table-cell; + vertical-align: top; +} +.media-middle { + vertical-align: middle; +} +.media-bottom { + vertical-align: bottom; +} +.media-heading { + margin-top: 0; + margin-bottom: 5px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + padding-left: 0; + margin-bottom: 20px; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #fff; + border: 1px solid #ddd; +} +.list-group-item:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +a.list-group-item { + color: #555; +} +a.list-group-item .list-group-item-heading { + color: #333; +} +a.list-group-item:hover, +a.list-group-item:focus { + color: #555; + text-decoration: none; + background-color: #f5f5f5; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + color: #777; + cursor: not-allowed; + background-color: #eee; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #777; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #fff; + background-color: #337ab7; + border-color: #337ab7; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #c7ddef; +} +.list-group-item-success { + color: #3c763d; + background-color: #dff0d8; +} +a.list-group-item-success { + color: #3c763d; +} +a.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +a.list-group-item-success:focus { + color: #3c763d; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +a.list-group-item-success.active:hover, +a.list-group-item-success.active:focus { + color: #fff; + background-color: #3c763d; + border-color: #3c763d; +} +.list-group-item-info { + color: #31708f; + background-color: #d9edf7; +} +a.list-group-item-info { + color: #31708f; +} +a.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +a.list-group-item-info:focus { + color: #31708f; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +a.list-group-item-info.active:hover, +a.list-group-item-info.active:focus { + color: #fff; + background-color: #31708f; + border-color: #31708f; +} +.list-group-item-warning { + color: #8a6d3b; + background-color: #fcf8e3; +} +a.list-group-item-warning { + color: #8a6d3b; +} +a.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +a.list-group-item-warning:focus { + color: #8a6d3b; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus { + color: #fff; + background-color: #8a6d3b; + border-color: #8a6d3b; +} +.list-group-item-danger { + color: #a94442; + background-color: #f2dede; +} +a.list-group-item-danger { + color: #a94442; +} +a.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +a.list-group-item-danger:focus { + color: #a94442; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus { + color: #fff; + background-color: #a94442; + border-color: #a94442; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 20px; + background-color: #fff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: 0 1px 1px rgba(0, 0, 0, .05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.panel-title > .small > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-right: 15px; + padding-left: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #ddd; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + margin-bottom: 0; + border: 0; +} +.panel-group { + margin-bottom: 20px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #ddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #ddd; +} +.panel-default { + border-color: #ddd; +} +.panel-default > .panel-heading { + color: #333; + background-color: #f5f5f5; + border-color: #ddd; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ddd; +} +.panel-default > .panel-heading .badge { + color: #f5f5f5; + background-color: #333; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ddd; +} +.panel-primary { + border-color: #337ab7; +} +.panel-primary > .panel-heading { + color: #fff; + background-color: #337ab7; + border-color: #337ab7; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #337ab7; +} +.panel-primary > .panel-heading .badge { + color: #337ab7; + background-color: #fff; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #337ab7; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-heading .badge { + color: #dff0d8; + background-color: #3c763d; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-heading .badge { + color: #d9edf7; + background-color: #31708f; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #bce8f1; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-heading .badge { + color: #fcf8e3; + background-color: #8a6d3b; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-heading .badge { + color: #f2dede; + background-color: #a94442; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ebccd1; +} +.embed-responsive { + position: relative; + display: block; + height: 0; + padding: 0; + overflow: hidden; +} +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} +.embed-responsive-16by9 { + padding-bottom: 56.25%; +} +.embed-responsive-4by3 { + padding-bottom: 75%; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, .15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + filter: alpha(opacity=20); + opacity: .2; +} +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; + filter: alpha(opacity=50); + opacity: .5; +} +button.close { + -webkit-appearance: none; + padding: 0; + cursor: pointer; + background: transparent; + border: 0; +} +.modal-open { + overflow: hidden; +} +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + display: none; + overflow: hidden; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transition: -webkit-transform .3s ease-out; + -o-transition: -o-transform .3s ease-out; + transition: transform .3s ease-out; + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + -o-transform: translate(0, -25%); + transform: translate(0, -25%); +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 6px; + outline: 0; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); + box-shadow: 0 3px 9px rgba(0, 0, 0, .5); +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000; +} +.modal-backdrop.fade { + filter: alpha(opacity=0); + opacity: 0; +} +.modal-backdrop.in { + filter: alpha(opacity=50); + opacity: .5; +} +.modal-header { + min-height: 16.42857143px; + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.42857143; +} +.modal-body { + position: relative; + padding: 15px; +} +.modal-footer { + padding: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1070; + display: block; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 12px; + font-weight: normal; + line-height: 1.4; + filter: alpha(opacity=0); + opacity: 0; +} +.tooltip.in { + filter: alpha(opacity=90); + opacity: .9; +} +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #fff; + text-align: center; + text-decoration: none; + background-color: #000; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-left .tooltip-arrow { + right: 5px; + bottom: 0; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-right .tooltip-arrow { + bottom: 0; + left: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + right: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + left: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: none; + max-width: 276px; + padding: 1px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + font-weight: normal; + line-height: 1.42857143; + text-align: left; + white-space: normal; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); + box-shadow: 0 5px 10px rgba(0, 0, 0, .2); +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover > .arrow, +.popover > .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover > .arrow { + border-width: 11px; +} +.popover > .arrow:after { + content: ""; + border-width: 10px; +} +.popover.top > .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, .25); + border-bottom-width: 0; +} +.popover.top > .arrow:after { + bottom: 1px; + margin-left: -10px; + content: " "; + border-top-color: #fff; + border-bottom-width: 0; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, .25); + border-left-width: 0; +} +.popover.right > .arrow:after { + bottom: -10px; + left: 1px; + content: " "; + border-right-color: #fff; + border-left-width: 0; +} +.popover.bottom > .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, .25); +} +.popover.bottom > .arrow:after { + top: 1px; + margin-left: -10px; + content: " "; + border-top-width: 0; + border-bottom-color: #fff; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, .25); +} +.popover.left > .arrow:after { + right: 1px; + bottom: -10px; + content: " "; + border-right-width: 0; + border-left-color: #fff; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: .6s ease-in-out left; + -o-transition: .6s ease-in-out left; + transition: .6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + line-height: 1; +} +@media all and (transform-3d), (-webkit-transform-3d) { + .carousel-inner > .item { + -webkit-transition: -webkit-transform .6s ease-in-out; + -o-transition: -o-transform .6s ease-in-out; + transition: transform .6s ease-in-out; + + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000; + perspective: 1000; + } + .carousel-inner > .item.next, + .carousel-inner > .item.active.right { + left: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + .carousel-inner > .item.prev, + .carousel-inner > .item.active.left { + left: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + .carousel-inner > .item.next.left, + .carousel-inner > .item.prev.right, + .carousel-inner > .item.active { + left: 0; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 15%; + font-size: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); + filter: alpha(opacity=50); + opacity: .5; +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001))); + background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control.right { + right: 0; + left: auto; + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5))); + background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control:hover, +.carousel-control:focus { + color: #fff; + text-decoration: none; + filter: alpha(opacity=90); + outline: 0; + opacity: .9; +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; + margin-left: -10px; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + font-family: serif; + line-height: 1; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + padding-left: 0; + margin-left: -30%; + text-align: center; + list-style: none; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); + border: 1px solid #fff; + border-radius: 10px; +} +.carousel-indicators .active { + width: 12px; + height: 12px; + margin: 0; + background-color: #fff; +} +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicon-chevron-left, + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + font-size: 30px; + } + .carousel-control .glyphicon-chevron-left, + .carousel-control .icon-prev { + margin-left: -15px; + } + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-next { + margin-right: -15px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} +.clearfix:after, +.dl-horizontal dd:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-right: auto; + margin-left: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .visible-xs-block { + display: block !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline { + display: inline !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline-block { + display: inline-block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-block { + display: block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline { + display: inline !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline-block { + display: inline-block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-block { + display: block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline { + display: inline !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline-block { + display: inline-block !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg-block { + display: block !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline { + display: inline !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline-block { + display: inline-block !important; + } +} +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +.visible-print-block { + display: none !important; +} +@media print { + .visible-print-block { + display: block !important; + } +} +.visible-print-inline { + display: none !important; +} +@media print { + .visible-print-inline { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; +} +@media print { + .visible-print-inline-block { + display: inline-block !important; + } +} +@media print { + .hidden-print { + display: none !important; + } +} + +/* tapestry-quickstart customizations start here: */ + +body { padding-top: 70px; } + diff --git a/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.eot b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000..9879fec538 Binary files /dev/null and b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.eot differ diff --git a/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.ttf b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000..c0e841e44b Binary files /dev/null and b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.ttf differ diff --git a/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000000..59d837ee61 Binary files /dev/null and b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff differ diff --git a/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff2 b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000..006d10650b Binary files /dev/null and b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/fonts/glyphicons-halflings-regular.woff2 differ diff --git a/web-modules/apache-tapestry/src/main/webapp/mybootstrap/js/button.js b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/js/button.js new file mode 100644 index 0000000000..7c7c021f95 --- /dev/null +++ b/web-modules/apache-tapestry/src/main/webapp/mybootstrap/js/button.js @@ -0,0 +1,116 @@ +/* ======================================================================== + * Bootstrap: button.js v3.3.4 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.VERSION = '3.3.4' + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (data.resetText == null) $el.data('resetText', $el[val]()) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + $el[val](data[state] == null ? this.options[state] : data[state]) + + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } else { + this.$element.attr('aria-pressed', !this.$element.hasClass('active')) + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + var old = $.fn.button + + $.fn.button = Plugin + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document) + .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + Plugin.call($btn, 'toggle') + e.preventDefault() + }) + .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { + $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) + }) + +}(jQuery); diff --git a/web-modules/apache-tapestry/src/site/apt/index.apt b/web-modules/apache-tapestry/src/site/apt/index.apt new file mode 100644 index 0000000000..0e22d10c32 --- /dev/null +++ b/web-modules/apache-tapestry/src/site/apt/index.apt @@ -0,0 +1,9 @@ + ---- + Module com.baeldung:apache-tapestry + ---- + +com.baeldung:apache-tapestry Documentation + + This is where you can start to document your module. + + Create new files in the Maven APT format, and update the site.xml file to point to them. diff --git a/web-modules/apache-tapestry/src/site/site.xml b/web-modules/apache-tapestry/src/site/site.xml new file mode 100644 index 0000000000..774861b479 --- /dev/null +++ b/web-modules/apache-tapestry/src/site/site.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/web-modules/apache-tapestry/src/test/conf/testng.xml b/web-modules/apache-tapestry/src/test/conf/testng.xml new file mode 100644 index 0000000000..c1c01e64aa --- /dev/null +++ b/web-modules/apache-tapestry/src/test/conf/testng.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/web-modules/apache-tapestry/src/test/conf/webdefault.xml b/web-modules/apache-tapestry/src/test/conf/webdefault.xml new file mode 100644 index 0000000000..c587ac7a5d --- /dev/null +++ b/web-modules/apache-tapestry/src/test/conf/webdefault.xml @@ -0,0 +1,278 @@ + + + + + Default web.xml file. + This file is applied to a Web application before it's own WEB_INF/web.xml file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + org.mortbay.jetty.servlet.Default + + acceptRanges + true + + + dirAllowed + true + + + putAllowed + false + + + delAllowed + false + + + redirectWelcome + false + + + minGzipLength + 8192 + + 0 + + + + + default + / + + + + + 30 + + + + + + index.html + index.htm + + + + + + ar + ISO-8859-6 + + + be + ISO-8859-5 + + + bg + ISO-8859-5 + + + ca + ISO-8859-1 + + + cs + ISO-8859-2 + + + da + ISO-8859-1 + + + de + ISO-8859-1 + + + el + ISO-8859-7 + + + en + ISO-8859-1 + + + es + ISO-8859-1 + + + et + ISO-8859-1 + + + fi + ISO-8859-1 + + + fr + ISO-8859-1 + + + hr + ISO-8859-2 + + + hu + ISO-8859-2 + + + is + ISO-8859-1 + + + it + ISO-8859-1 + + + iw + ISO-8859-8 + + + ja + Shift_JIS + + + ko + EUC-KR + + + lt + ISO-8859-2 + + + lv + ISO-8859-2 + + + mk + ISO-8859-5 + + + nl + ISO-8859-1 + + + no + ISO-8859-1 + + + pl + ISO-8859-2 + + + pt + ISO-8859-1 + + + ro + ISO-8859-2 + + + ru + ISO-8859-5 + + + sh + ISO-8859-5 + + + sk + ISO-8859-2 + + + sl + ISO-8859-2 + + + sq + ISO-8859-2 + + + sr + ISO-8859-5 + + + sv + ISO-8859-1 + + + tr + ISO-8859-9 + + + uk + ISO-8859-5 + + + zh + GB2312 + + + zh_TW + Big5 + + + + + + diff --git a/web-modules/blade/pom.xml b/web-modules/blade/pom.xml new file mode 100644 index 0000000000..2748c05663 --- /dev/null +++ b/web-modules/blade/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + blade + blade + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + com.bladejava + blade-mvc + ${blade-mvc.version} + + + org.webjars + bootstrap + ${bootstrap.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + test + + + org.apache.httpcomponents + httpmime + ${httpmime.version} + test + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + test + + + + + blade + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + true + + **/*LiveTest.java + + + + + + integration-test + verify + + + + + + maven-assembly-plugin + ${assembly.plugin.version} + + ${project.build.finalName} + false + + + com.baeldung.blade.sample.App + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + + + 2.0.14.RELEASE + 4.2.1 + 4.5.6 + 4.5.6 + 4.4.10 + 0.7 + 3.1.0 + + + \ No newline at end of file diff --git a/web-modules/blade/src/main/resources/static/app.js b/web-modules/blade/src/main/resources/static/app.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/bootique/pom.xml b/web-modules/bootique/pom.xml new file mode 100644 index 0000000000..8da24ebf0a --- /dev/null +++ b/web-modules/bootique/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + com.baeldung.bootique + bootique + 1.0-SNAPSHOT + bootique + jar + http://maven.apache.org + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + + io.bootique.bom + bootique-bom + ${bootique-bom.version} + pom + import + + + + + + + io.bootique.jersey + bootique-jersey + compile + + + io.bootique.logback + bootique-logback + compile + + + io.bootique + bootique-test + test + + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin.version} + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + + + com.baeldung.bootique.App + 0.23 + 2.4.3 + + + \ No newline at end of file diff --git a/web-modules/bootique/src/main/resources/logback.xml b/web-modules/bootique/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/bootique/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/dropwizard/README.md b/web-modules/dropwizard/README.md new file mode 100644 index 0000000000..76311ebbb3 --- /dev/null +++ b/web-modules/dropwizard/README.md @@ -0,0 +1,5 @@ +# Dropwizard + +### Relevant Articles: + +- [Introduction to Dropwizard](https://www.baeldung.com/java-dropwizard) diff --git a/web-modules/dropwizard/pom.xml b/web-modules/dropwizard/pom.xml new file mode 100644 index 0000000000..03562acded --- /dev/null +++ b/web-modules/dropwizard/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + dropwizard + 0.0.1-SNAPSHOT + dropwizard + jar + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + io.dropwizard + dropwizard-core + ${dropwizard.version} + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + true + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + package + + shade + + + + + + com.baeldung.dropwizard.introduction.IntroductionApplication + + + + + + + + + + + 2.0.0 + + + \ No newline at end of file diff --git a/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/IntroductionApplication.java b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/IntroductionApplication.java new file mode 100644 index 0000000000..d9af590017 --- /dev/null +++ b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/IntroductionApplication.java @@ -0,0 +1,51 @@ +package com.baeldung.dropwizard.introduction; + +import com.baeldung.dropwizard.introduction.configuration.ApplicationHealthCheck; +import com.baeldung.dropwizard.introduction.configuration.BasicConfiguration; +import com.baeldung.dropwizard.introduction.domain.Brand; +import com.baeldung.dropwizard.introduction.repository.BrandRepository; +import com.baeldung.dropwizard.introduction.resource.BrandResource; +import io.dropwizard.Application; +import io.dropwizard.configuration.ResourceConfigurationSourceProvider; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; + +import java.util.ArrayList; +import java.util.List; + +public class IntroductionApplication extends Application { + + public static void main(final String[] args) throws Exception { + new IntroductionApplication().run("server", "introduction-config.yml"); + } + + @Override + public void run(final BasicConfiguration basicConfiguration, final Environment environment) { + final int defaultSize = basicConfiguration.getDefaultSize(); + final BrandRepository brandRepository = new BrandRepository(initBrands()); + final BrandResource brandResource = new BrandResource(defaultSize, brandRepository); + environment + .jersey() + .register(brandResource); + + final ApplicationHealthCheck healthCheck = new ApplicationHealthCheck(); + environment + .healthChecks() + .register("application", healthCheck); + } + + @Override + public void initialize(final Bootstrap bootstrap) { + bootstrap.setConfigurationSourceProvider(new ResourceConfigurationSourceProvider()); + super.initialize(bootstrap); + } + + private List initBrands() { + final List brands = new ArrayList<>(); + brands.add(new Brand(1L, "Brand1")); + brands.add(new Brand(2L, "Brand2")); + brands.add(new Brand(3L, "Brand3")); + + return brands; + } +} diff --git a/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/configuration/ApplicationHealthCheck.java b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/configuration/ApplicationHealthCheck.java new file mode 100644 index 0000000000..bf4b710937 --- /dev/null +++ b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/configuration/ApplicationHealthCheck.java @@ -0,0 +1,10 @@ +package com.baeldung.dropwizard.introduction.configuration; + +import com.codahale.metrics.health.HealthCheck; + +public class ApplicationHealthCheck extends HealthCheck { + @Override + protected Result check() throws Exception { + return Result.healthy(); + } +} diff --git a/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/configuration/BasicConfiguration.java b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/configuration/BasicConfiguration.java new file mode 100644 index 0000000000..5098f89d62 --- /dev/null +++ b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/configuration/BasicConfiguration.java @@ -0,0 +1,20 @@ +package com.baeldung.dropwizard.introduction.configuration; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.dropwizard.Configuration; + +import javax.validation.constraints.NotNull; + +public class BasicConfiguration extends Configuration { + @NotNull private final int defaultSize; + + @JsonCreator + public BasicConfiguration(@JsonProperty("defaultSize") final int defaultSize) { + this.defaultSize = defaultSize; + } + + public int getDefaultSize() { + return defaultSize; + } +} diff --git a/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/domain/Brand.java b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/domain/Brand.java new file mode 100644 index 0000000000..c83f67bb6e --- /dev/null +++ b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/domain/Brand.java @@ -0,0 +1,19 @@ +package com.baeldung.dropwizard.introduction.domain; + +public class Brand { + private final Long id; + private final String name; + + public Brand(final Long id, final String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/repository/BrandRepository.java b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/repository/BrandRepository.java new file mode 100644 index 0000000000..3f187df3de --- /dev/null +++ b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/repository/BrandRepository.java @@ -0,0 +1,32 @@ +package com.baeldung.dropwizard.introduction.repository; + +import com.baeldung.dropwizard.introduction.domain.Brand; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class BrandRepository { + private final List brands; + + public BrandRepository(final List brands) { + this.brands = ImmutableList.copyOf(brands); + } + + public List findAll(final int size) { + return brands + .stream() + .limit(size) + .collect(Collectors.toList()); + } + + public Optional findById(final Long id) { + return brands + .stream() + .filter(brand -> brand + .getId() + .equals(id)) + .findFirst(); + } +} diff --git a/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/resource/BrandResource.java b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/resource/BrandResource.java new file mode 100644 index 0000000000..5f97e26faf --- /dev/null +++ b/web-modules/dropwizard/src/main/java/com/baeldung/dropwizard/introduction/resource/BrandResource.java @@ -0,0 +1,35 @@ +package com.baeldung.dropwizard.introduction.resource; + +import com.baeldung.dropwizard.introduction.domain.Brand; +import com.baeldung.dropwizard.introduction.repository.BrandRepository; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.List; +import java.util.Optional; + +@Path("/brands") +@Produces(MediaType.APPLICATION_JSON) +public class BrandResource { + private final int defaultSize; + private final BrandRepository brandRepository; + + public BrandResource(final int defaultSize, final BrandRepository brandRepository) { + this.defaultSize = defaultSize; + this.brandRepository = brandRepository; + + } + + @GET + public List getBrands(@QueryParam("size") final Optional size) { + return brandRepository.findAll(size.orElse(defaultSize)); + } + + @GET + @Path("/{id}") + public Brand getById(@PathParam("id") final Long id) { + return brandRepository + .findById(id) + .orElseThrow(RuntimeException::new); + } +} diff --git a/web-modules/dropwizard/src/main/resources/introduction-config.yml b/web-modules/dropwizard/src/main/resources/introduction-config.yml new file mode 100644 index 0000000000..02ff36de05 --- /dev/null +++ b/web-modules/dropwizard/src/main/resources/introduction-config.yml @@ -0,0 +1 @@ +defaultSize: 5 \ No newline at end of file diff --git a/web-modules/dropwizard/src/test/java/com/baeldung/dropwizard/introduction/repository/BrandRepositoryUnitTest.java b/web-modules/dropwizard/src/test/java/com/baeldung/dropwizard/introduction/repository/BrandRepositoryUnitTest.java new file mode 100644 index 0000000000..b996883ee5 --- /dev/null +++ b/web-modules/dropwizard/src/test/java/com/baeldung/dropwizard/introduction/repository/BrandRepositoryUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.dropwizard.introduction.repository; + +import com.baeldung.dropwizard.introduction.domain.Brand; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BrandRepositoryUnitTest { + + private static final Brand BRAND_1 = new Brand(1L, "Brand1"); + + private final BrandRepository brandRepository = new BrandRepository(getBrands()); + + @Test + void givenSize_whenFindingAll_thenReturnList() { + final int size = 2; + + final List result = brandRepository.findAll(size); + + assertEquals(size, result.size()); + } + + @Test + void givenId_whenFindingById_thenReturnFoundBrand() { + final Long id = BRAND_1.getId(); + + final Optional result = brandRepository.findById(id); + + Assertions.assertTrue(result.isPresent()); + assertEquals(BRAND_1, result.get()); + } + + + private List getBrands() { + final List brands = new ArrayList<>(); + brands.add(BRAND_1); + brands.add(new Brand(2L, "Brand2")); + brands.add(new Brand(3L, "Brand3")); + + return brands; + } +} \ No newline at end of file diff --git a/web-modules/google-web-toolkit/pom.xml b/web-modules/google-web-toolkit/pom.xml new file mode 100644 index 0000000000..1fdb38f0a1 --- /dev/null +++ b/web-modules/google-web-toolkit/pom.xml @@ -0,0 +1,109 @@ + + + + 4.0.0 + google-web-toolkit + 1.0-SNAPSHOT + google-web-toolkit + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + + + com.google.gwt + gwt + ${gwt.version} + pom + import + + + + + + + com.google.gwt + gwt-servlet + runtime + + + com.google.gwt + gwt-user + provided + + + com.google.gwt + gwt-dev + provided + + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + + net.ltgt.gwt.maven + gwt-maven-plugin + ${gwt.plugin.version} + + + + compile + test + + + + + com.baeldung.Google_web_toolkit + Google_web_toolkit + true + + + ${maven.compiler.source} + + + + -compileReport + -XcompilerMetrics + + + ${project.build.directory}/${project.build.finalName} + compile+runtime + + + Google_web_toolkit.html + + + + + + maven-surefire-plugin + + true + + + + + + + + + + 1.8 + 1.8 + 2.8.2 + 1.0-rc-8 + + + \ No newline at end of file diff --git a/web-modules/google-web-toolkit/src/main/resources/logback.xml b/web-modules/google-web-toolkit/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/google-web-toolkit/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/jakarta-ee/README.md b/web-modules/jakarta-ee/README.md new file mode 100644 index 0000000000..54f372f736 --- /dev/null +++ b/web-modules/jakarta-ee/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Introduction to Jakarta EE MVC / Eclipse Krazo](https://www.baeldung.com/java-ee-mvc-eclipse-krazo) diff --git a/web-modules/jakarta-ee/pom.xml b/web-modules/jakarta-ee/pom.xml new file mode 100644 index 0000000000..066bc14766 --- /dev/null +++ b/web-modules/jakarta-ee/pom.xml @@ -0,0 +1,109 @@ + + 4.0.0 + com.baeldung + jakarta-ee + 1.0-SNAPSHOT + jakarta-ee + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + jakarta.platform + jakarta.jakartaee-web-api + ${jakartaee-api.version} + provided + + + jakarta.mvc + jakarta.mvc-api + ${jakarta.mvc-api.version} + + + org.eclipse.krazo + krazo-jersey + ${krazo.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + org.mockito + mockito-all + ${mockito.version} + test + + + + + mvc-2.0 + + + org.glassfish.maven.plugin + maven-glassfish-plugin + 2.1 + + ${local.glassfish.home} + admin + + password + + ${local.glassfish.domain} + 8080 + 4848 + + + + ${project.artifactId} + target/${project.build.finalName}.war + + + true + false + true + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + 11 + + + + org.apache.maven.plugins + maven-war-plugin + + false + + + + + + + 9.0.0 + 2.0.0 + 2.0.0 + 5.8.2 + C:/glassfish6 + admin + mvn-domain + 1.10.19 + + ${local.glassfish.home}\\domains\\${local.glassfish.domain}\\config\\domain-passwords + + + + \ No newline at end of file diff --git a/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/User.java b/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/User.java new file mode 100644 index 0000000000..a2253b6aa6 --- /dev/null +++ b/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/User.java @@ -0,0 +1,84 @@ +package com.baeldung.eclipse.krazo; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Named; +import jakarta.mvc.RedirectScoped; +import jakarta.mvc.binding.MvcBinding; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Size; +import jakarta.ws.rs.FormParam; + +import java.io.Serializable; + +@Named("user") +@RedirectScoped +public class User implements Serializable { + @MvcBinding + @Null + private String id; + + @MvcBinding + @NotNull + @Size(min = 1, message = "Name cannot be blank") + @FormParam("name") + private String name; + + @MvcBinding + @Min(value = 18, message = "The minimum age of the user should be 18 years") + @FormParam("age") + private int age; + + @MvcBinding + @Email(message = "The email cannot be blank and should be in a valid format") + @Size(min=3, message = "Email cannot be empty") + @FormParam("email") + private String email; + + @MvcBinding + @Null + @FormParam("phone") + private String phone; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } +} diff --git a/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserApplication.java b/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserApplication.java new file mode 100644 index 0000000000..5a272806cb --- /dev/null +++ b/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.eclipse.krazo; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +/** + * Default JAX-RS application listening on /app + */ +@ApplicationPath("/app") +public class UserApplication extends Application { +} diff --git a/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserController.java b/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserController.java new file mode 100644 index 0000000000..92ddf73571 --- /dev/null +++ b/web-modules/jakarta-ee/src/main/java/com/baeldung/eclipse/krazo/UserController.java @@ -0,0 +1,85 @@ +package com.baeldung.eclipse.krazo; + +import jakarta.inject.Inject; +import jakarta.mvc.Controller; +import jakarta.mvc.Models; +import jakarta.mvc.binding.BindingResult; +import jakarta.mvc.security.CsrfProtected; +import jakarta.validation.Valid; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * The class contains two controllers and a REST API + */ +@Path("users") +public class UserController { + @Inject + private BindingResult bindingResult; + + private static final List users = new ArrayList<>(); + + @Inject + private Models models; + + /** + * This is a controller. It displays a initial form to the user. + * @return The view name + */ + @GET + @Controller + public String showForm() { + return "user.jsp"; + } + + /** + * The method handles the form submits + * Handles HTTP POST and is CSRF protected. The client invoking this controller should provide a CSRF token. + * @param user The user details that has to be stored + * @return Returns a view name + */ + @POST + @Controller + @CsrfProtected + public String saveUser(@Valid @BeanParam User user) { + if (bindingResult.isFailed()) { + models.put("errors", bindingResult.getAllErrors()); + return "user.jsp"; + } + String id = UUID.randomUUID().toString(); + user.setId(id); + users.add(user); + return "redirect:users/success"; + } + + /** + * Handles a redirect view + * @return The view name + */ + @GET + @Controller + @Path("success") + public String saveUserSuccess() { + return "success.jsp"; + } + + /** + * The REST API that returns all the user details in the JSON format + * @return The list of users that are saved. The List is converted into Json Array. + * If no user is present a empty array is returned + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public List getUsers() { + return users; + } + +} diff --git a/web-modules/jakarta-ee/src/main/webapp/WEB-INF/beans.xml b/web-modules/jakarta-ee/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000000..d068fbd3e4 --- /dev/null +++ b/web-modules/jakarta-ee/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/web-modules/jakarta-ee/src/main/webapp/WEB-INF/views/success.jsp b/web-modules/jakarta-ee/src/main/webapp/WEB-INF/views/success.jsp new file mode 100644 index 0000000000..19d45e46ba --- /dev/null +++ b/web-modules/jakarta-ee/src/main/webapp/WEB-INF/views/success.jsp @@ -0,0 +1,47 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + + + + MVC 2.0 + + + + + + + + + + +
+
+
+
+ +
+

User created successfully!

+
+
+ +
+ +
+
+ + + + + + \ No newline at end of file diff --git a/web-modules/jakarta-ee/src/main/webapp/WEB-INF/views/user.jsp b/web-modules/jakarta-ee/src/main/webapp/WEB-INF/views/user.jsp new file mode 100644 index 0000000000..a36655950d --- /dev/null +++ b/web-modules/jakarta-ee/src/main/webapp/WEB-INF/views/user.jsp @@ -0,0 +1,89 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + + + + MVC 2.0 + + + + + + + + + + +
+
+
+

+ User Details +

+
+ + + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ +
+
+ + + + + + \ No newline at end of file diff --git a/web-modules/jakarta-ee/src/main/webapp/styles.css b/web-modules/jakarta-ee/src/main/webapp/styles.css new file mode 100644 index 0000000000..9cc9e62f12 --- /dev/null +++ b/web-modules/jakarta-ee/src/main/webapp/styles.css @@ -0,0 +1,28 @@ +body, html { + font-family: Raleway, serif; + font-weight: 300; +} + +.bg-dark { + background-color: #63b175 !important; + font-weight: 600 !important; +} + +body { + padding-top: 80px; +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } +} + +label { + font-weight: bold; +} + +.hr-dark { + border-top: 2px solid #000; + margin-bottom: 20px; +} \ No newline at end of file diff --git a/web-modules/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/AppUnitTest.java b/web-modules/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/AppUnitTest.java new file mode 100644 index 0000000000..8c77a75318 --- /dev/null +++ b/web-modules/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/AppUnitTest.java @@ -0,0 +1,16 @@ +package com.baeldung.eclipse.krazo; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Dummy Test + */ +public class AppUnitTest { + + @Test + public void test() { + assertTrue(true); + } +} diff --git a/web-modules/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/UserControllerUnitTest.java b/web-modules/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/UserControllerUnitTest.java new file mode 100644 index 0000000000..5e79924ed7 --- /dev/null +++ b/web-modules/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/UserControllerUnitTest.java @@ -0,0 +1,116 @@ +package com.baeldung.eclipse.krazo; + +import com.baeldung.eclipse.krazo.User; +import com.baeldung.eclipse.krazo.UserController; +import jakarta.mvc.Models; +import jakarta.mvc.binding.BindingResult; +import org.eclipse.krazo.core.ModelsImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; + +/** + * The class contains unit tests. We do only unit tests. Most of the classes are mocked + */ +@DisplayName("Eclipse Krazo MVC 2.0 Test Suite") +class UserControllerUnitTest { + + @InjectMocks + UserController userController = new UserController(); + + @Mock + Models models; + + @Mock + BindingResult bindingResult; + + @BeforeEach + public void setUpClass() { + MockitoAnnotations.initMocks(this); + } + + @Test + @DisplayName("Test Show Form") + void whenShowForm_thenReturnViewName() { + assertNotNull(userController.showForm()); + assertEquals("user.jsp", userController.showForm()); + } + + @Test + @DisplayName("Test Save User Success") + void whenSaveUser_thenReturnSuccess() { + when(bindingResult.isFailed()).thenReturn(false); + + User user = new User(); + + assertNotNull(userController.saveUser(user)); + assertDoesNotThrow(() -> userController.saveUser(user)); + assertEquals("redirect:users/success", userController.saveUser(user)); + } + + @Test + @DisplayName("Test Save User Binding Errors") + void whenSaveUser_thenReturnError() { + when(bindingResult.isFailed()).thenReturn(true); + Models testModels = new ModelsImpl(); + when(models.put(anyString(), any())).thenReturn(testModels); + User user = getUser(); + assertNotNull(userController.saveUser(user)); + assertDoesNotThrow(() -> userController.saveUser(user)); + assertEquals("user.jsp", userController.saveUser(user)); + } + + @Test + @DisplayName("Test Save User Success View") + void whenSaveUserSuccess_thenRedirectSuccess() { + assertNotNull(userController.saveUserSuccess()); + assertDoesNotThrow(() -> userController.saveUserSuccess()); + assertEquals("success.jsp", userController.saveUserSuccess()); + } + + @Test + @DisplayName("Test Get Users API") + void whenGetUser_thenReturnUsers() { + when(bindingResult.isFailed()).thenReturn(false); + + User user= getUser(); + + assertNotNull(user); + assertEquals(30, user.getAge()); + assertEquals("john doe", user.getName()); + assertEquals("anymail", user.getEmail()); + assertEquals("99887766554433", user.getPhone()); + assertEquals("1", user.getId()); + + userController.saveUser(user); + userController.saveUser(user); + userController.saveUser(user); + + assertNotNull(userController.getUsers()); + assertDoesNotThrow(() -> userController.getUsers()); + assertEquals(3, userController.getUsers().size()); + + } + + private User getUser() { + User user = new User(); + user.setId("1"); + user.setName("john doe"); + user.setAge(30); + user.setEmail("anymail"); + user.setPhone("99887766554433"); + return user; + } + +} diff --git a/web-modules/java-lite/pom.xml b/web-modules/java-lite/pom.xml new file mode 100644 index 0000000000..7f1c9182f7 --- /dev/null +++ b/web-modules/java-lite/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + org.baeldung + java-lite + 1.0-SNAPSHOT + java-lite + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + org.javalite + activeweb + ${activeweb.version} + + + mysql + mysql-connector-java + ${mysql.connector.java.version} + + + com.sun + tools + ${sun.tools.version} + system + ${java.home}/../lib/tools.jar + + + org.javalite + activeweb-testing + ${activeweb-testing.version} + test + + + + + + + src/main/webapp/WEB-INF + + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty.maven.plugin.version} + + + + activejdbc.log + + + active_reload + true + + + activeweb.log.request + true + + + + + + org.javalite + activejdbc-instrumentation + ${activejdbc.version} + + + process-classes + + instrument + + + + + + + + + 9.4.8.v20171121 + 1.4.13 + 1.15 + 5.1.45 + 1.7.0 + 1.15 + + + \ No newline at end of file diff --git a/web-modules/java-lite/src/main/resources/logback.xml b/web-modules/java-lite/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/java-lite/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/README.md b/web-modules/javax-servlets-2/README.md new file mode 100644 index 0000000000..179264f90a --- /dev/null +++ b/web-modules/javax-servlets-2/README.md @@ -0,0 +1,8 @@ +## Servlets + +This module contains articles about Servlets. + +### Relevant Articles: +- [Check if a User Is Logged-in With Servlets and JSP](https://www.baeldung.com/servlets-jsp-check-user-login) +- [How to Mock HttpServletRequest](https://www.baeldung.com/java-httpservletrequest-mock) +- [Set a Parameter in an HttpServletRequest in Java](https://www.baeldung.com/java-servlet-request-set-parameter) diff --git a/web-modules/javax-servlets-2/pom.xml b/web-modules/javax-servlets-2/pom.xml new file mode 100644 index 0000000000..9ba12352fd --- /dev/null +++ b/web-modules/javax-servlets-2/pom.xml @@ -0,0 +1,106 @@ + + + 4.0.0 + com.baeldung.javax-servlets + javax-servlets-2 + 1.0-SNAPSHOT + javax-servlets-2 + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + + commons-fileupload + commons-fileupload + ${commons-fileupload.version} + + + org.apache.commons + commons-text + ${commons-text.version} + + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + + + javax.servlet.jsp + javax.servlet.jsp-api + ${javax.servlet.jsp-api.version} + provided + + + javax.servlet + jstl + ${jstl.version} + + + org.jmockit + jmockit + ${jmockit.version} + test + + + org.springframework + spring-test + ${spring-test.version} + test + + + org.apache.httpcomponents + httpclient + ${org.apache.httpcomponents.version} + test + + + commons-logging + commons-logging + + + + + + + + + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + -javaagent:"${settings.localRepository}"/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar + + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty-maven-plugin.version} + + + / + + + + + + + + 4.5.13 + 1.49 + 5.3.20 + 2.22.2 + 10.0.4 + 1.10.0 + + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/servlets/UserServlet.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/servlets/UserServlet.java new file mode 100644 index 0000000000..a71a4da8e4 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/servlets/UserServlet.java @@ -0,0 +1,24 @@ +package com.baeldung.servlets; + +import java.io.IOException; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet(name = "UserServlet", urlPatterns = "/user") +public class UserServlet extends HttpServlet { + + private static final long serialVersionUID = 2923732283720972121L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + String firstName = request.getParameter("firstName"); + String lastName = request.getParameter("lastName"); + + response.getWriter() + .append("Full Name: " + firstName + " " + lastName); + } + +} diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java new file mode 100644 index 0000000000..983066ec51 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/LanguageServlet.java @@ -0,0 +1,21 @@ +package com.baeldung.setparam; + +import java.io.IOException; +import java.util.Locale; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.*; + +@WebServlet(name = "LanguageServlet", urlPatterns = "/setparam/lang") +public class LanguageServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + + SetParameterRequestWrapper requestWrapper = new SetParameterRequestWrapper(request); + requestWrapper.setParameter("locale", Locale.getDefault().getLanguage()); + request.getRequestDispatcher("/setparam/3rd_party_module.jsp").forward(requestWrapper, response); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java new file mode 100644 index 0000000000..3f93591bd9 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersFilter.java @@ -0,0 +1,17 @@ +package com.baeldung.setparam; + +import java.io.IOException; +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; + +@WebFilter(urlPatterns = { "/setparam/with-sanitize.jsp" }) +public class SanitizeParametersFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpReq = (HttpServletRequest) request; + chain.doFilter(new SanitizeParametersRequestWrapper(httpReq), response); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java new file mode 100644 index 0000000000..e4c2870ca6 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SanitizeParametersRequestWrapper.java @@ -0,0 +1,46 @@ +package com.baeldung.setparam; + +import java.util.*; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.apache.commons.text.StringEscapeUtils; + +public class SanitizeParametersRequestWrapper extends HttpServletRequestWrapper { + + private final Map sanitizedMap; + + public SanitizeParametersRequestWrapper(HttpServletRequest request) { + super(request); + sanitizedMap = Collections.unmodifiableMap( + request.getParameterMap().entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> Arrays.stream(entry.getValue()) + .map(StringEscapeUtils::escapeHtml4) + .toArray(String[]::new) + ))); + } + + @Override + public Map getParameterMap() { + return sanitizedMap; + } + + @Override + public String[] getParameterValues(String name) { + return Optional.ofNullable(getParameterMap().get(name)) + .map(values -> Arrays.copyOf(values, values.length)) + .orElse(null); + } + + @Override + public String getParameter(String name) { + return Optional.ofNullable(getParameterValues(name)) + .map(values -> values[0]) + .orElse(null); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java new file mode 100644 index 0000000000..7b2ab4597c --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/setparam/SetParameterRequestWrapper.java @@ -0,0 +1,40 @@ +package com.baeldung.setparam; + +import java.util.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +public class SetParameterRequestWrapper extends HttpServletRequestWrapper { + + private final Map paramMap; + + public SetParameterRequestWrapper(HttpServletRequest request) { + super(request); + paramMap = new HashMap<>(request.getParameterMap()); + } + + @Override + public Map getParameterMap() { + return Collections.unmodifiableMap(paramMap); + } + + @Override + public String[] getParameterValues(String name) { + return Optional.ofNullable(getParameterMap().get(name)) + .map(values -> Arrays.copyOf(values, values.length)) + .orElse(null); + } + + @Override + public String getParameter(String name) { + return Optional.ofNullable(getParameterValues(name)) + .map(values -> values[0]) + .orElse(null); + } + + public void setParameter(String name, String value) { + paramMap.put(name, new String[] {value}); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/User.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/User.java new file mode 100644 index 0000000000..f61c0490bc --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/User.java @@ -0,0 +1,80 @@ +package com.baeldung.user.check; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +/** + * @since 6 de fev de 2022 + * @author ulisses + */ +public class User implements Serializable { + private static final long serialVersionUID = 1L; + + protected static final HashMap DB = new HashMap<>(); + static { + DB.put("admin", new User("admin", "password")); + DB.put("user", new User("user", "pass")); + } + + private String name; + private String password; + + private List logins = new ArrayList(); + + public User(String name, String password) { + this.name = name; + this.password = password; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getLogins() { + return logins; + } + + public void setLogins(List logins) { + this.logins = logins; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + User other = (User) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } +} diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckFilter.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckFilter.java new file mode 100644 index 0000000000..835275c255 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckFilter.java @@ -0,0 +1,50 @@ +package com.baeldung.user.check; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebFilter("/user-check/*") +public class UserCheckFilter implements Filter { + public static void forward(HttpServletRequest request, HttpServletResponse response, String page) throws ServletException, IOException { + request.getRequestDispatcher("/WEB-INF/user.check" + page) + .forward(request, response); + } + + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { + if (!(req instanceof HttpServletRequest)) { + throw new ServletException("Can only process HttpServletRequest"); + } + + if (!(res instanceof HttpServletResponse)) { + throw new ServletException("Can only process HttpServletResponse"); + } + + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + + request.setAttribute("origin", request.getRequestURI()); + + if (!request.getRequestURI() + .contains("login") && request.getSession(false) == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + forward(request, response, "/login.jsp"); + // we return here so the original servlet is not processed + return; + } + + chain.doFilter(request, response); + } + + public void init(FilterConfig arg) throws ServletException { + } +} diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckLoginServlet.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckLoginServlet.java new file mode 100644 index 0000000000..e1a38fc7b8 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckLoginServlet.java @@ -0,0 +1,56 @@ +package com.baeldung.user.check; + +import java.io.IOException; +import java.util.Date; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +@WebServlet("/user-check/login") +public class UserCheckLoginServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + if (request.getSession(false) != null) { + response.sendRedirect(request.getContextPath() + "/user-check/home"); + return; + } + + String referer = (String) request.getAttribute("origin"); + request.setAttribute("origin", referer); + UserCheckFilter.forward(request, response, "/login.jsp"); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String key = request.getParameter("name"); + String pass = request.getParameter("password"); + + User user = User.DB.get(key); + if (user == null || !user.getPassword() + .equals(pass)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + request.setAttribute("origin", request.getParameter("origin")); + request.setAttribute("error", "invalid login"); + UserCheckFilter.forward(request, response, "/login.jsp"); + return; + } + + user.getLogins() + .add(new Date()); + + HttpSession session = request.getSession(); + session.setAttribute("user", user); + + String origin = request.getParameter("origin"); + if (origin == null || origin.contains("login")) + origin = "./"; + + response.sendRedirect(origin); + } +} diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckLogoutServlet.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckLogoutServlet.java new file mode 100644 index 0000000000..42c0bb87ab --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckLogoutServlet.java @@ -0,0 +1,26 @@ +package com.baeldung.user.check; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +@WebServlet("/user-check/logout") +public class UserCheckLogoutServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + HttpSession session = request.getSession(false); + if (session != null) { + session.invalidate(); + } + + request.setAttribute("loggedOut", true); + response.sendRedirect("./"); + } +} diff --git a/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckServlet.java b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckServlet.java new file mode 100644 index 0000000000..d7d5d1e762 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/java/com/baeldung/user/check/UserCheckServlet.java @@ -0,0 +1,28 @@ +package com.baeldung.user.check; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +@WebServlet(name = "home", urlPatterns = { "/user-check/", "/user-check", "/user-check/home" }) +public class UserCheckServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + HttpSession session = request.getSession(false); + if (session == null || session.getAttribute("user") == null) { + throw new IllegalStateException("user not logged in"); + } + + User user = (User) session.getAttribute("user"); + request.setAttribute("user", user); + + UserCheckFilter.forward(request, response, "/home.jsp"); + } +} diff --git a/web-modules/javax-servlets-2/src/main/resources/logback.xml b/web-modules/javax-servlets-2/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/webapp/WEB-INF/user.check/home.jsp b/web-modules/javax-servlets-2/src/main/webapp/WEB-INF/user.check/home.jsp new file mode 100644 index 0000000000..4e17763552 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/webapp/WEB-INF/user.check/home.jsp @@ -0,0 +1,31 @@ +<%@ page contentType="text/html;charset=UTF-8" session="false"%> +<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> + + + + login success - current session info + + +
+

user info

+
+ name: ${user.name} +
+ +
+ logins: +
    + +
  • ${login}
  • +
    +
+
+ + +
+ + diff --git a/web-modules/javax-servlets-2/src/main/webapp/WEB-INF/user.check/login.jsp b/web-modules/javax-servlets-2/src/main/webapp/WEB-INF/user.check/login.jsp new file mode 100644 index 0000000000..19a857585d --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/webapp/WEB-INF/user.check/login.jsp @@ -0,0 +1,33 @@ +<%@ page contentType="text/html;charset=UTF-8" session="false"%> +<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> + + + + login + + +
+ + +
* redirected to login from: ${origin}
+
+ + +
* error: ${error}
+
+ +
+ credentials + + + + + + + + +
+
+ + diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp new file mode 100644 index 0000000000..9ab4fd2c00 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/3rd_party_module.jsp @@ -0,0 +1,13 @@ +<%@ page import="java.util.*"%> + + + 3rd party Module + + + <% + String localeStr = request.getParameter("locale"); + Locale currentLocale = (localeStr != null ? new Locale(localeStr) : null); + %> + The language you have selected: <%=currentLocale != null ? currentLocale.getDisplayLanguage(currentLocale) : " None"%> + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp new file mode 100644 index 0000000000..68704d6133 --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/with-sanitize.jsp @@ -0,0 +1,10 @@ + + + Sanitized request parameter + + + The text below comes from request parameter "input": +
+ <%=request.getParameter("input")%> + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp b/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp new file mode 100644 index 0000000000..f5437164ef --- /dev/null +++ b/web-modules/javax-servlets-2/src/main/webapp/setparam/without-sanitize.jsp @@ -0,0 +1,10 @@ + + + Non sanitized request parameter + + + The text below comes from request parameter "input": +
+ <%=request.getParameter("input")%> + + \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/servlets/TestUtil.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/servlets/TestUtil.java new file mode 100644 index 0000000000..e010de3a55 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/servlets/TestUtil.java @@ -0,0 +1,678 @@ +package com.baeldung.servlets; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; + +public class TestUtil { + + public static HttpServletRequest getRequest(Map params) { + return new HttpServletRequest() { + + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { + // TODO Auto-generated method stub + return null; + } + + @Override + public AsyncContext startAsync() throws IllegalStateException { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + // TODO Auto-generated method stub + + } + + @Override + public void setAttribute(String name, Object o) { + // TODO Auto-generated method stub + + } + + @Override + public void removeAttribute(String name) { + // TODO Auto-generated method stub + + } + + @Override + public boolean isSecure() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isAsyncSupported() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isAsyncStarted() { + // TODO Auto-generated method stub + return false; + } + + @Override + public ServletContext getServletContext() { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getServerPort() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getServerName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getScheme() { + // TODO Auto-generated method stub + return null; + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getRemotePort() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getRemoteHost() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getRemoteAddr() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getRealPath(String path) { + // TODO Auto-generated method stub + return null; + } + + @Override + public BufferedReader getReader() throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getProtocol() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String[] getParameterValues(String name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Enumeration getParameterNames() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getParameterMap() { + return params; + } + + @Override + public String getParameter(String name) { + String[] values = params.get(name); + if (values == null || values.length == 0) + return null; + return values[0]; + } + + @Override + public Enumeration getLocales() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Locale getLocale() { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getLocalPort() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getLocalName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getLocalAddr() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public DispatcherType getDispatcherType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getContentType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public long getContentLengthLong() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public int getContentLength() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getCharacterEncoding() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Enumeration getAttributeNames() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object getAttribute(String name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public AsyncContext getAsyncContext() { + // TODO Auto-generated method stub + return null; + } + + @Override + public T upgrade(Class handlerClass) throws IOException, ServletException { + // TODO Auto-generated method stub + return null; + } + + @Override + public void logout() throws ServletException { + // TODO Auto-generated method stub + + } + + @Override + public void login(String username, String password) throws ServletException { + // TODO Auto-generated method stub + + } + + @Override + public boolean isUserInRole(String role) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isRequestedSessionIdValid() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isRequestedSessionIdFromUrl() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isRequestedSessionIdFromURL() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + // TODO Auto-generated method stub + return false; + } + + @Override + public Principal getUserPrincipal() { + // TODO Auto-generated method stub + return null; + } + + @Override + public HttpSession getSession(boolean create) { + // TODO Auto-generated method stub + return null; + } + + @Override + public HttpSession getSession() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getServletPath() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getRequestedSessionId() { + // TODO Auto-generated method stub + return null; + } + + @Override + public StringBuffer getRequestURL() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getRequestURI() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getRemoteUser() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getQueryString() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getPathTranslated() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getPathInfo() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Collection getParts() throws IOException, ServletException { + // TODO Auto-generated method stub + return null; + } + + @Override + public Part getPart(String name) throws IOException, ServletException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMethod() { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getIntHeader(String name) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Enumeration getHeaders(String name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Enumeration getHeaderNames() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getHeader(String name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public long getDateHeader(String name) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Cookie[] getCookies() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getContextPath() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getAuthType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String changeSessionId() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { + // TODO Auto-generated method stub + return false; + } + }; + } + + public static HttpServletResponse getResponse(StringWriter writer) { + + return new HttpServletResponse() { + + @Override + public void setLocale(Locale loc) { + // TODO Auto-generated method stub + + } + + @Override + public void setContentType(String type) { + // TODO Auto-generated method stub + + } + + @Override + public void setContentLengthLong(long len) { + // TODO Auto-generated method stub + + } + + @Override + public void setContentLength(int len) { + // TODO Auto-generated method stub + + } + + @Override + public void setCharacterEncoding(String charset) { + // TODO Auto-generated method stub + + } + + @Override + public void setBufferSize(int size) { + // TODO Auto-generated method stub + + } + + @Override + public void resetBuffer() { + // TODO Auto-generated method stub + + } + + @Override + public void reset() { + // TODO Auto-generated method stub + + } + + @Override + public boolean isCommitted() { + return true; + } + + @Override + public PrintWriter getWriter() throws IOException { + return new PrintWriter(writer, isCommitted()); + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public Locale getLocale() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getContentType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getCharacterEncoding() { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getBufferSize() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void flushBuffer() throws IOException { + // TODO Auto-generated method stub + + } + + @Override + public void setStatus(int sc, String sm) { + // TODO Auto-generated method stub + + } + + @Override + public void setStatus(int sc) { + // TODO Auto-generated method stub + + } + + @Override + public void setIntHeader(String name, int value) { + // TODO Auto-generated method stub + + } + + @Override + public void setHeader(String name, String value) { + // TODO Auto-generated method stub + + } + + @Override + public void setDateHeader(String name, long date) { + // TODO Auto-generated method stub + + } + + @Override + public void sendRedirect(String location) throws IOException { + // TODO Auto-generated method stub + + } + + @Override + public void sendError(int sc, String msg) throws IOException { + // TODO Auto-generated method stub + + } + + @Override + public void sendError(int sc) throws IOException { + // TODO Auto-generated method stub + + } + + @Override + public int getStatus() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Collection getHeaders(String name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Collection getHeaderNames() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getHeader(String name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String encodeUrl(String url) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String encodeURL(String url) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String encodeRedirectUrl(String url) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String encodeRedirectURL(String url) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean containsHeader(String name) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void addIntHeader(String name, int value) { + // TODO Auto-generated method stub + + } + + @Override + public void addHeader(String name, String value) { + // TODO Auto-generated method stub + + } + + @Override + public void addDateHeader(String name, long date) { + // TODO Auto-generated method stub + + } + + @Override + public void addCookie(Cookie cookie) { + // TODO Auto-generated method stub + + } + }; + + } +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/servlets/UserServletUnitTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/servlets/UserServletUnitTest.java new file mode 100644 index 0000000000..7c207d5be3 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/servlets/UserServletUnitTest.java @@ -0,0 +1,93 @@ +package com.baeldung.servlets; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import mockit.Expectations; +import mockit.Mocked; + +class UserServletUnitTest { + + private UserServlet servlet; + private StringWriter writer; + + @Mocked + HttpServletRequest mockRequest; + @Mocked + HttpServletResponse mockResponse; + + @BeforeEach + public void setUp() throws IOException { + servlet = new UserServlet(); + writer = new StringWriter(); + } + + @Test + void givenHttpServletRequest_whenUsingAnonymousClass_thenReturnsParameterValues() throws IOException { + final Map params = new HashMap<>(); + params.put("firstName", new String[] { "Anonymous Class" }); + params.put("lastName", new String[] { "Test" }); + + servlet.doGet(TestUtil.getRequest(params), TestUtil.getResponse(writer)); + + assertThat(writer.toString()).isEqualTo("Full Name: Anonymous Class Test"); + } + + @Test + void givenHttpServletRequest_whenMockedWithMockito_thenReturnsParameterValues() throws IOException { + // mock HttpServletRequest & HttpServletResponse + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + + // mock the returned value of request.getParameterMap() + when(request.getParameter("firstName")).thenReturn("Mockito"); + when(request.getParameter("lastName")).thenReturn("Test"); + when(response.getWriter()).thenReturn(new PrintWriter(writer)); + + servlet.doGet(request, response); + + assertThat(writer.toString()).isEqualTo("Full Name: Mockito Test"); + } + + @Test + void givenHttpServletRequest_whenMockedWithJMockit_thenReturnsParameterValues() throws IOException { + + new Expectations() {{ + mockRequest.getParameter("firstName"); result = "JMockit"; + mockRequest.getParameter("lastName"); result = "Test"; + mockResponse.getWriter(); result = new PrintWriter(writer); + }}; + + servlet.doGet(mockRequest, mockResponse); + + assertThat(writer.toString()).isEqualTo("Full Name: JMockit Test"); + } + + @Test + void givenHttpServletRequest_whenUsingMockHttpServletRequest_thenReturnsParameterValues() throws IOException { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setParameter("firstName", "Spring"); + request.setParameter("lastName", "Test"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + servlet.doGet(request, response); + + assertThat(response.getContentAsString()).isEqualTo("Full Name: Spring Test"); + } + +} diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletLiveTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletLiveTest.java new file mode 100644 index 0000000000..c539ce63b9 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/LanguageServletLiveTest.java @@ -0,0 +1,34 @@ +package com.baeldung.setparam; + +import static org.junit.Assert.assertTrue; + +import java.util.Locale; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; + +public class LanguageServletLiveTest { + + @Test + public void whenGetRequestUsingHttpClient_thenResponseBodyContainsDefaultLanguage() throws Exception { + + // When + HttpClient client = HttpClientBuilder.create().build(); + HttpGet method = new HttpGet("http://localhost:8080/setparam/lang"); + HttpResponse httpResponse = client.execute(method); + + // Then + Locale defaultLocale = Locale.getDefault(); + String expectedLanguage = defaultLocale.getDisplayLanguage(defaultLocale); + + HttpEntity entity = httpResponse.getEntity(); + String responseBody = EntityUtils.toString(entity, "UTF-8"); + assertTrue(responseBody.contains("The language you have selected: " + expectedLanguage)); + } + +} diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestLiveTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestLiveTest.java new file mode 100644 index 0000000000..5fffea1824 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestLiveTest.java @@ -0,0 +1,40 @@ +package com.baeldung.setparam; + +import static org.junit.Assert.assertTrue; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.BeforeClass; +import org.junit.Test; + +public class SanitizeParametersRequestLiveTest { + + private static String PARAM_INPUT; + + @BeforeClass + public static void init() throws UnsupportedEncodingException { + PARAM_INPUT = URLEncoder.encode("", "UTF-8"); + } + + @Test + public void whenInputParameterContainsXss_thenResponseBodyContainsSanitizedValue() throws Exception { + + // When + HttpClient client = HttpClientBuilder.create().build(); + HttpGet method = new HttpGet(String.format("http://localhost:8080/setparam/with-sanitize.jsp?input=%s", PARAM_INPUT)); + HttpResponse httpResponse = client.execute(method); + + // Then + HttpEntity entity = httpResponse.getEntity(); + String responseBody = EntityUtils.toString(entity, "UTF-8"); + assertTrue(responseBody.contains("<script>alert('Hello');</script>")); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java new file mode 100644 index 0000000000..029cf41d1c --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SanitizeParametersRequestWrapperUnitTest.java @@ -0,0 +1,60 @@ +package com.baeldung.setparam; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SanitizeParametersRequestWrapperUnitTest { + + private static final String NEW_VALUE = "NEW VALUE"; + + private Map parameterMap; + + @Mock + private HttpServletRequest request; + + @Before + public void initBeforeEachTest() { + parameterMap = new HashMap<>(); + parameterMap.put("input", new String[] {""}); + when(request.getParameterMap()).thenReturn(parameterMap); + } + + @Test + public void whenGetParameterViaWrapper_thenParameterReturnedIsSanitized() { + SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request); + String actualValue = wrapper.getParameter("input"); + + assertEquals("<script>alert('Hello');</script>", actualValue); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenPutValueToWrapperParameterMap_thenThrowsUnsupportedOperationException() { + SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request); + Map wrapperParamMap = wrapper.getParameterMap(); + wrapperParamMap.put("input", new String[] {NEW_VALUE}); + } + + @Test + public void whenSetValueToWrapperParametersStringArray_thenThe2ndCallShouldNotEqualToNewValue() { + SanitizeParametersRequestWrapper wrapper = new SanitizeParametersRequestWrapper(request); + String[] firstCallValues = wrapper.getParameterValues("input"); + + firstCallValues[0] = NEW_VALUE; + String[] secondCallValues = wrapper.getParameterValues("input"); + assertThat(secondCallValues).doesNotContain(NEW_VALUE); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java new file mode 100644 index 0000000000..8ef5307d44 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/SetParameterRequestWrapperUnitTest.java @@ -0,0 +1,61 @@ +package com.baeldung.setparam; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SetParameterRequestWrapperUnitTest { + + private static final String NEW_VALUE = "NEW VALUE"; + + private Map parameterMap; + + @Mock + private HttpServletRequest request; + + @Before + public void initBeforeEachTest() { + parameterMap = new HashMap<>(); + parameterMap.put("input", new String[] {"inputValue"}); + when(request.getParameterMap()).thenReturn(parameterMap); + } + + @Test + public void whenSetParameterViaWrapper_thenGetParameterShouldReturnTheSameValue() { + SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request); + wrapper.setParameter("newInput", "newInputValue"); + String actualValue = wrapper.getParameter("newInput"); + + assertEquals("newInputValue", actualValue); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenPutValueToWrapperParameterMap_thenThrowsUnsupportedOperationException() { + SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request); + Map wrapperParamMap = wrapper.getParameterMap(); + wrapperParamMap.put("input", new String[] {NEW_VALUE}); + } + + @Test + public void whenSetValueToWrapperParametersStringArray_thenThe2ndCallShouldNotEqualToNewValue() { + SetParameterRequestWrapper wrapper = new SetParameterRequestWrapper(request); + String[] firstCallValues = wrapper.getParameterValues("input"); + + firstCallValues[0] = NEW_VALUE; + String[] secondCallValues = wrapper.getParameterValues("input"); + assertThat(secondCallValues).doesNotContain(NEW_VALUE); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestLiveTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestLiveTest.java new file mode 100644 index 0000000000..f6cc566bfc --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/setparam/UnsanitizedParametersRequestLiveTest.java @@ -0,0 +1,42 @@ +package com.baeldung.setparam; + +import static org.junit.Assert.assertTrue; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.BeforeClass; +import org.junit.Test; + +public class UnsanitizedParametersRequestLiveTest { + + private static final String TAG_SCRIPT = ""; + + private static String PARAM_INPUT; + + @BeforeClass + public static void init() throws UnsupportedEncodingException { + PARAM_INPUT = URLEncoder.encode(TAG_SCRIPT, "UTF-8"); + } + + @Test + public void whenInputParameterContainsXss_thenResponseBodyContainsUnsanitizedValue() throws Exception { + + // When + HttpClient client = HttpClientBuilder.create().build(); + HttpGet method = new HttpGet(String.format("http://localhost:8080/setparam/without-sanitize.jsp?input=%s", PARAM_INPUT)); + HttpResponse httpResponse = client.execute(method); + + // Then + HttpEntity entity = httpResponse.getEntity(); + String responseBody = EntityUtils.toString(entity, "UTF-8"); + assertTrue(responseBody.contains(TAG_SCRIPT)); + } + +} \ No newline at end of file diff --git a/web-modules/javax-servlets-2/src/test/java/com/baeldung/user/check/UserCheckServletLiveTest.java b/web-modules/javax-servlets-2/src/test/java/com/baeldung/user/check/UserCheckServletLiveTest.java new file mode 100644 index 0000000000..42858d61e7 --- /dev/null +++ b/web-modules/javax-servlets-2/src/test/java/com/baeldung/user/check/UserCheckServletLiveTest.java @@ -0,0 +1,98 @@ +package com.baeldung.user.check; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.LaxRedirectStrategy; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class UserCheckServletLiveTest { + private static final String BASE_URL = "http://localhost:8080/javax-servlets-2/user-check"; + + @Mock + HttpServletRequest request; + + @Mock + HttpServletResponse response; + + private CloseableHttpClient buildClient() { + return HttpClientBuilder.create() + .setRedirectStrategy(new LaxRedirectStrategy()) + .build(); + } + + @Test + public void whenCorrectCredentials_thenLoginSucceeds() throws Exception { + try (CloseableHttpClient client = buildClient()) { + HttpPost post = new HttpPost(BASE_URL + "/login"); + + List form = new ArrayList<>(); + form.add(new BasicNameValuePair("name", "admin")); + form.add(new BasicNameValuePair("password", "password")); + + post.setEntity(new UrlEncodedFormEntity(form)); + try (CloseableHttpResponse response = client.execute(post)) { + String body = EntityUtils.toString(response.getEntity()); + + assertTrue(response.getStatusLine() + .getStatusCode() == 200); + + assertTrue(body.contains("login success")); + } + } + } + + @Test + public void whenIncorrectCredentials_thenLoginFails() throws Exception { + try (CloseableHttpClient client = buildClient()) { + HttpPost post = new HttpPost(BASE_URL + "/login"); + + List form = new ArrayList<>(); + form.add(new BasicNameValuePair("name", "admin")); + form.add(new BasicNameValuePair("password", "invalid")); + + post.setEntity(new UrlEncodedFormEntity(form)); + try (CloseableHttpResponse response = client.execute(post)) { + String body = EntityUtils.toString(response.getEntity()); + + assertTrue(response.getStatusLine() + .getStatusCode() == 401); + + assertTrue(body.contains("invalid login")); + } + } + } + + @Test + public void whenNotLoggedIn_thenRedirectedToLoginPage() throws Exception { + try (CloseableHttpClient client = buildClient()) { + HttpGet get = new HttpGet(BASE_URL + "/home"); + + try (CloseableHttpResponse response = client.execute(get)) { + String body = EntityUtils.toString(response.getEntity()); + + assertTrue(response.getStatusLine() + .getStatusCode() == 401); + + assertTrue(body.contains("redirected to login")); + } + } + } +} diff --git a/web-modules/javax-servlets/README.md b/web-modules/javax-servlets/README.md new file mode 100644 index 0000000000..bda7cd19e3 --- /dev/null +++ b/web-modules/javax-servlets/README.md @@ -0,0 +1,15 @@ +## Servlets + +This module contains articles about Servlets. + +### Relevant Articles: +- [Introduction to Java Servlets](https://www.baeldung.com/intro-to-servlets) +- [An MVC Example with Servlets and JSP](https://www.baeldung.com/mvc-servlet-jsp) +- [Handling Cookies and a Session in a Java Servlet](https://www.baeldung.com/java-servlet-cookies-session) +- [Uploading Files with Servlets and JSP](https://www.baeldung.com/upload-file-servlet) +- [Example of Downloading File in a Servlet](https://www.baeldung.com/servlet-download-file) +- [Returning a JSON Response from a Servlet](https://www.baeldung.com/servlet-json-response) +- [Jakarta EE Servlet Exception Handling](https://www.baeldung.com/servlet-exceptions) +- [Context and Servlet Initialization Parameters](https://www.baeldung.com/context-servlet-initialization-param) +- [The Difference between getRequestURI and getPathInfo in HttpServletRequest](https://www.baeldung.com/http-servlet-request-requesturi-pathinfo) +- [Difference Between request.getSession() and request.getSession(true)](https://www.baeldung.com/java-request-getsession) diff --git a/web-modules/javax-servlets/pom.xml b/web-modules/javax-servlets/pom.xml new file mode 100644 index 0000000000..80a1e3af9f --- /dev/null +++ b/web-modules/javax-servlets/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + com.baeldung.javax-servlets + javax-servlets + 1.0-SNAPSHOT + javax-servlets + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + + commons-fileupload + commons-fileupload + ${commons-fileupload.version} + + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + + + org.apache.httpcomponents + httpclient + ${org.apache.httpcomponents.version} + test + + + commons-logging + commons-logging + + + + + com.google.code.gson + gson + ${gson.version} + + + + + 4.5.3 + 2.8.2 + + + \ No newline at end of file diff --git a/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/FormServlet.java b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/FormServlet.java new file mode 100644 index 0000000000..72a2b39a67 --- /dev/null +++ b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/FormServlet.java @@ -0,0 +1,39 @@ +package com.baeldung.servlets; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@WebServlet(name = "FormServlet", urlPatterns = "/calculateServlet") +public class FormServlet extends HttpServlet { + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + + String height = request.getParameter("height"); + String weight = request.getParameter("weight"); + try { + double bmi = calculateBMI(Double.parseDouble(weight), Double.parseDouble(height)); + request.setAttribute("bmi", bmi); + response.setHeader("Test", "Success"); + response.setHeader("BMI", String.valueOf(bmi)); + request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response); + } catch (Exception e) { + request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response); + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/jsp/index.jsp"); + dispatcher.forward(request, response); + } + + private Double calculateBMI(Double weight, Double height) { + return weight / (height * height); + } +} \ No newline at end of file diff --git a/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/MainServlet.java b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/MainServlet.java new file mode 100644 index 0000000000..198920cb23 --- /dev/null +++ b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/MainServlet.java @@ -0,0 +1,21 @@ +package com.baeldung.servlets; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/main") +public class MainServlet extends HttpServlet { + + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.getRequestDispatcher("/WEB-INF/jsp/main.jsp").forward(request, response); + } + + + + +} diff --git a/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UpdateServlet.java b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UpdateServlet.java new file mode 100644 index 0000000000..8582a1ccef --- /dev/null +++ b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UpdateServlet.java @@ -0,0 +1,31 @@ +package com.baeldung.servlets; + +import java.io.IOException; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +@WebServlet("/update") +public class UpdateServlet extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + HttpSession session = request.getSession(false); + + if (session != null) { + + session.setAttribute("userName", request.getParameter("userName")); + session.setAttribute("age", request.getParameter("age")); + + request.setAttribute("sessionData", session); + } + + request.getRequestDispatcher("/WEB-INF/jsp/update.jsp").forward(request, response); + } + +} diff --git a/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UserLoginServlet.java b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UserLoginServlet.java new file mode 100644 index 0000000000..25ec6a8f59 --- /dev/null +++ b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UserLoginServlet.java @@ -0,0 +1,28 @@ +package com.baeldung.servlets; + + +import java.io.IOException; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +@WebServlet("/u_login") +public class UserLoginServlet extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + HttpSession session = request.getSession(); + + session.setAttribute("userId", request.getParameter("userId")); + + request.setAttribute("id", session.getAttribute("userId")); + + request.getRequestDispatcher("/WEB-INF/jsp/userlogin.jsp").forward(request, response); + + } + +} diff --git a/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UserServlet.java b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UserServlet.java new file mode 100644 index 0000000000..75977b0660 --- /dev/null +++ b/web-modules/javax-servlets/src/main/java/com/baeldung/servlets/UserServlet.java @@ -0,0 +1,49 @@ +package com.baeldung.servlets; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebInitParam; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet(name = "UserServlet", urlPatterns = "/userServlet", initParams={ + @WebInitParam(name="name", value="Not provided"), + @WebInitParam(name="email", value="Not provided")}) +public class UserServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + processRequest(request, response); + forwardRequest(request, response, "/WEB-INF/jsp/result.jsp"); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + } + + protected void processRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + request.setAttribute("name", getRequestParameter(request, "name")); + request.setAttribute("email", getRequestParameter(request, "email")); + request.setAttribute("province", getContextParameter("province")); + request.setAttribute("country", getContextParameter("country")); + } + + protected String getRequestParameter(HttpServletRequest request, String name) { + String param = request.getParameter(name); + return !param.isEmpty() ? param : getInitParameter(name); + } + + protected String getContextParameter(String name) { + return getServletContext().getInitParameter(name); + } + + protected void forwardRequest(HttpServletRequest request, HttpServletResponse response, String path) + throws ServletException, IOException { + request.getRequestDispatcher(path).forward(request, response); + } +} \ No newline at end of file diff --git a/web-modules/javax-servlets/src/main/resources/logback.xml b/web-modules/javax-servlets/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/javax-servlets/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/main.jsp b/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/main.jsp new file mode 100644 index 0000000000..313310a2a9 --- /dev/null +++ b/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/main.jsp @@ -0,0 +1,15 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + + + +
+

Enter your User Id and Password

+ User ID:
+ Password:
+
+ + \ No newline at end of file diff --git a/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/result.jsp b/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/result.jsp new file mode 100644 index 0000000000..7259b96ed0 --- /dev/null +++ b/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/result.jsp @@ -0,0 +1,15 @@ +<%@ page contentType="text/html" pageEncoding="UTF-8"%> + + + + + User Data + + +

User Information

+

Name: ${name}

+

Email: ${email}

+

Province: ${province}

+

Country: ${country}

+ + diff --git a/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/update.jsp b/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/update.jsp new file mode 100644 index 0000000000..fae5ea2ac2 --- /dev/null +++ b/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/update.jsp @@ -0,0 +1,17 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + + + + + Hi, User : ${sessionData.getAttribute("userId")} + +
Your User Data has been updated as below : +
User Name: ${sessionData.getAttribute("userName")} +
Age : ${sessionData.getAttribute("age")} + + + \ No newline at end of file diff --git a/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/userlogin.jsp b/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/userlogin.jsp new file mode 100644 index 0000000000..b2a550b811 --- /dev/null +++ b/web-modules/javax-servlets/src/main/webapp/WEB-INF/jsp/userlogin.jsp @@ -0,0 +1,18 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + + + +

Update your User Details:

+ +
+ User ID:
User Name: + Age:
+
+ + \ No newline at end of file diff --git a/web-modules/javax-servlets/src/main/webapp/user.jsp b/web-modules/javax-servlets/src/main/webapp/user.jsp new file mode 100644 index 0000000000..2139052a3a --- /dev/null +++ b/web-modules/javax-servlets/src/main/webapp/user.jsp @@ -0,0 +1,18 @@ +<%@ page contentType="text/html" pageEncoding="UTF-8"%> + + + + Context and Servlet Initialization Parameters + + + +

Please fill the form below:

+
+ + + + + +
+ + diff --git a/web-modules/javax-servlets/src/test/java/com/baeldung/test/UserServletUnitTest.java b/web-modules/javax-servlets/src/test/java/com/baeldung/test/UserServletUnitTest.java new file mode 100644 index 0000000000..ef3d877dd7 --- /dev/null +++ b/web-modules/javax-servlets/src/test/java/com/baeldung/test/UserServletUnitTest.java @@ -0,0 +1,52 @@ +package com.baeldung.test; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class UserServletUnitTest { + + private static HttpServletRequest request; + private static HttpServletResponse response; + + + @BeforeClass + public static void setUpHttpServletRequestMockInstance() { + request = mock(HttpServletRequest.class); + } + + @BeforeClass + public static void setUpHttpServletResponsetMockInstance() { + response = mock(HttpServletResponse.class); + } + + @Test + public void givenHttpServletRequestMockInstance_whenCalledgetParameter_thenCalledAtLeastOnce() { + request.getParameter("name"); + verify(request, atLeast(1)).getParameter("name"); + } + + @Test + public void givenHttpServletRequestMockInstance_whenCalledgetParameter_thenOneAssertion() { + when(request.getParameter("name")).thenReturn("username"); + assertThat(request.getParameter("name")).isEqualTo("username"); + } + + @Test + public void givenHttpServletResponseMockInstance_whenCalledgetContentType_thenCalledAtLeastOnce() { + response.getContentType(); + verify(response, atLeast(1)).getContentType(); + } + + @Test + public void givenHttpServletResponseMockInstance_whenCalledgetContentType_thenOneAssertion() { + when(response.getContentType()).thenReturn("text/html"); + assertThat(response.getContentType()).isEqualTo("text/html"); + } +} \ No newline at end of file diff --git a/web-modules/jee-7/README.md b/web-modules/jee-7/README.md new file mode 100644 index 0000000000..88359a81ec --- /dev/null +++ b/web-modules/jee-7/README.md @@ -0,0 +1,14 @@ +## JEE 7 + +This module contains articles about JEE 7. + +### Relevant Articles: +- [Scheduling in Jakarta EE](https://www.baeldung.com/scheduling-in-java-enterprise-edition) +- [JSON Processing in Java EE 7](https://www.baeldung.com/jee7-json) +- [Converters, Listeners and Validators in Java EE 7](https://www.baeldung.com/java-ee7-converter-listener-validator) +- [Introduction to JAX-WS](https://www.baeldung.com/jax-ws) +- [A Guide to Java EE Web-Related Annotations](https://www.baeldung.com/javaee-web-annotations) +- [Introduction to Testing with Arquillian](https://www.baeldung.com/arquillian) +- [Java EE 7 Batch Processing](https://www.baeldung.com/java-ee-7-batch-processing) +- [The Difference Between CDI and EJB Singleton](https://www.baeldung.com/jee-cdi-vs-ejb-singleton) +- [Invoking a SOAP Web Service in Java](https://www.baeldung.com/java-soap-web-service) diff --git a/web-modules/jee-7/pom.xml b/web-modules/jee-7/pom.xml new file mode 100644 index 0000000000..b26027d9bf --- /dev/null +++ b/web-modules/jee-7/pom.xml @@ -0,0 +1,542 @@ + + + 4.0.0 + com.baeldung.jee-7 + jee-7 + 1.0-SNAPSHOT + jee-7 + war + JavaEE 7 Arquillian Archetype Sample + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + + org.jboss.arquillian + arquillian-bom + ${arquillian_core.version} + import + pom + + + org.jboss.arquillian.extension + arquillian-drone-bom + ${arquillian-drone-bom.version} + pom + import + + + + + + + javax + javaee-api + ${javaee_api.version} + provided + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + org.jboss.arquillian.graphene + graphene-webdriver + ${graphene-webdriver.version} + pom + test + + + com.jayway.awaitility + awaitility + ${awaitility.version} + test + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-impl-maven + test + jar + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-impl-maven-archive + test + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + commons-io + commons-io + ${commons-io.version} + + + com.sun.faces + jsf-api + ${com.sun.faces.jsf.version} + + + com.sun.faces + jsf-impl + ${com.sun.faces.jsf.version} + + + javax.servlet + jstl + ${jstl.version} + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + + + javax.servlet.jsp + jsp-api + ${jsp-api.version} + provided + + + taglibs + standard + ${taglibs.standard.version} + + + javax.mvc + javax.mvc-api + ${mvc.api.version} + + + org.glassfish.ozark + ozark + ${ozark.version} + + + org.springframework.security + spring-security-web + ${org.springframework.security.version} + + + org.springframework.security + spring-security-config + ${org.springframework.security.version} + + + org.springframework.security + spring-security-taglibs + ${org.springframework.security.version} + + + + org.jboss.spec.javax.batch + jboss-batch-api_1.0_spec + ${jboss-batch-api.version} + + + org.jberet + jberet-core + ${jberet.version} + + + org.jberet + jberet-support + ${jberet.version} + + + org.jboss.spec.javax.transaction + jboss-transaction-api_1.2_spec + ${jboss-transaction-api.version} + + + org.jboss.marshalling + jboss-marshalling + ${jboss-marshalling.version} + + + org.jboss.weld + weld-core + ${weld.version} + + + org.jboss.weld.se + weld-se + ${weld.version} + + + org.jberet + jberet-se + ${jberet.version} + + + com.h2database + h2 + ${h2.version} + + + org.glassfish.jersey.containers + jersey-container-jetty-servlet + ${jersey-container-jetty-servlet.version} + + + + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + src/main/webapp + false + + + + + + + + + org.eclipse.m2e + lifecycle-mapping + ${lifecycle.mapping.version} + + + + + + + org.apache.maven.plugins + + + maven-pmd-plugin + + + [3.8,) + + + check + + + + + + + + + + + + + org.codehaus.mojo + jaxws-maven-plugin + 2.6 + + + wsimport-from-jdk + + wsimport + + + + + + http://localhost:8888/ws/country?wsdl + + true + com.baeldung.soap.ws.client.generated + src/main/java + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens=java.base/java.lang.reflect=ALL-UNNAMED + --add-opens java.base/java.io=ALL-UNNAMED + + + + + + + + + + wildfly-managed-arquillian + + true + + + + io.undertow + undertow-websockets-jsr + ${undertow-websockets-jsr.version} + test + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + test + + + org.jboss.resteasy + resteasy-jaxb-provider + ${resteasy.version} + test + + + org.jboss.resteasy + resteasy-json-p-provider + ${resteasy.version} + test + + + org.wildfly + wildfly-arquillian-container-managed + ${wildfly.version} + test + + + sun.jdk + jconsole + + + + + + + + + maven-dependency-plugin + ${maven-dependency-plugin.version} + + ${maven.test.skip} + + + + unpack + process-test-classes + + unpack + + + + + org.wildfly + wildfly-dist + ${wildfly.version} + zip + false + ${project.build.directory} + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + + + wildfly-remote-arquillian + + + io.undertow + undertow-websockets-jsr + ${undertow-websockets-jsr.version} + test + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + test + + + org.jboss.resteasy + resteasy-jaxb-provider + ${resteasy.version} + test + + + org.jboss.resteasy + resteasy-json-p-provider + ${resteasy.version} + test + + + org.wildfly + wildfly-arquillian-container-remote + ${wildfly.version} + test + + + sun.jdk + jconsole + + + + + + + glassfish-embedded-arquillian + + + org.glassfish.main.extras + glassfish-embedded-all + ${glassfish-embedded-all.version} + test + + + org.glassfish + javax.json + ${javax.json.version} + test + + + org.glassfish.tyrus + tyrus-client + ${tyrus.version} + test + + + org.glassfish.tyrus + tyrus-container-grizzly-client + ${tyrus.version} + test + + + org.glassfish.jersey.core + jersey-client + ${jersey.version} + test + + + org.jboss.arquillian.container + arquillian-glassfish-embedded-3.1 + ${arquillian-glassfish.version} + test + + + + + glassfish-remote-arquillian + + + org.glassfish + javax.json + ${javax.json.version} + test + + + org.glassfish.tyrus + tyrus-client + ${tyrus.version} + test + + + org.glassfish.tyrus + tyrus-container-grizzly-client + ${tyrus.version} + test + + + org.glassfish.jersey.core + jersey-client + ${jersey.version} + test + + + org.glassfish.jersey.media + jersey-media-json-jackson + ${jersey.version} + test + + + org.glassfish.jersey.media + jersey-media-json-processing + ${jersey.version} + test + + + org.jboss.arquillian.container + arquillian-glassfish-remote-3.1 + ${arquillian-glassfish.version} + test + + + + + webdriver-chrome + + true + + + chrome + + + + webdriver-firefox + + firefox + + + + + + 1.0.0 + 1.0-edr2 + 1.8 + 3.0.0 + 7.0 + 1.1.11.Final + 8.2.1.Final + 1.7.0 + 1.4.6.Final + 3.0.19.Final + 4.1.1 + 1.0.4 + 1.13 + 2.25 + 1.0.0.Final + 4.2.3.RELEASE + 1.1.2 + 2.2.14 + 4.5 + 2.0.1.Final + 2.1.0.Final + 2.8 + 2.2 + 1.0.0-m02 + 1.0.0.Final + 1.0.2.Final + 1.0.0.Final + 2.1.1.Final + 2.1.1.Final + 2.22.1 + + + \ No newline at end of file diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/Country.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/Country.java new file mode 100644 index 0000000000..6a810b9afa --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/Country.java @@ -0,0 +1,129 @@ + +package com.baeldung.soap.ws.client.generated; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +/** + *

Java class for country complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="country">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="capital" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="currency" type="{http://server.ws.soap.baeldung.com/}currency" minOccurs="0"/>
+ *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="population" type="{http://www.w3.org/2001/XMLSchema}int"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "country", propOrder = { "capital", "currency", "name", "population" }) +public class Country { + + protected String capital; + @XmlSchemaType(name = "string") + protected Currency currency; + protected String name; + protected int population; + + /** + * Gets the value of the capital property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCapital() { + return capital; + } + + /** + * Sets the value of the capital property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCapital(String value) { + this.capital = value; + } + + /** + * Gets the value of the currency property. + * + * @return + * possible object is + * {@link Currency } + * + */ + public Currency getCurrency() { + return currency; + } + + /** + * Sets the value of the currency property. + * + * @param value + * allowed object is + * {@link Currency } + * + */ + public void setCurrency(Currency value) { + this.currency = value; + } + + /** + * Gets the value of the name property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setName(String value) { + this.name = value; + } + + /** + * Gets the value of the population property. + * + */ + public int getPopulation() { + return population; + } + + /** + * Sets the value of the population property. + * + */ + public void setPopulation(int value) { + this.population = value; + } + +} diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryService.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryService.java new file mode 100644 index 0000000000..bda4a305a5 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryService.java @@ -0,0 +1,34 @@ + +package com.baeldung.soap.ws.client.generated; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebResult; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.ws.Action; + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.3.2 + * Generated source version: 2.2 + * + */ +@WebService(name = "CountryService", targetNamespace = "http://server.ws.soap.baeldung.com/") +@SOAPBinding(style = SOAPBinding.Style.RPC) +@XmlSeeAlso({ ObjectFactory.class }) +public interface CountryService { + + /** + * + * @param arg0 + * @return + * returns com.baeldung.soap.ws.client.generated.Country + */ + @WebMethod + @WebResult(partName = "return") + @Action(input = "http://server.ws.soap.baeldung.com/CountryService/findByNameRequest", output = "http://server.ws.soap.baeldung.com/CountryService/findByNameResponse") + public Country findByName(@WebParam(name = "arg0", partName = "arg0") String arg0); + +} diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java new file mode 100644 index 0000000000..a6983938f5 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java @@ -0,0 +1,91 @@ + +package com.baeldung.soap.ws.client.generated; + +import java.net.MalformedURLException; +import java.net.URL; +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.WebServiceFeature; + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b130926.1035 + * Generated source version: 2.2 + * + */ +@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "http://server.ws.soap.baeldung.com/", wsdlLocation = "http://localhost:8888/ws/country?wsdl") +public class CountryServiceImplService extends Service { + + private final static URL COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION; + private final static WebServiceException COUNTRYSERVICEIMPLSERVICE_EXCEPTION; + private final static QName COUNTRYSERVICEIMPLSERVICE_QNAME = new QName("http://server.ws.soap.baeldung.com/", "CountryServiceImplService"); + + static { + URL url = null; + WebServiceException e = null; + try { + url = new URL("http://localhost:8888/ws/country?wsdl"); + } catch (MalformedURLException ex) { + e = new WebServiceException(ex); + } + COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION = url; + COUNTRYSERVICEIMPLSERVICE_EXCEPTION = e; + } + + public CountryServiceImplService() { + super(__getWsdlLocation(), COUNTRYSERVICEIMPLSERVICE_QNAME); + } + + public CountryServiceImplService(WebServiceFeature... features) { + super(__getWsdlLocation(), COUNTRYSERVICEIMPLSERVICE_QNAME, features); + } + + public CountryServiceImplService(URL wsdlLocation) { + super(wsdlLocation, COUNTRYSERVICEIMPLSERVICE_QNAME); + } + + public CountryServiceImplService(URL wsdlLocation, WebServiceFeature... features) { + super(wsdlLocation, COUNTRYSERVICEIMPLSERVICE_QNAME, features); + } + + public CountryServiceImplService(URL wsdlLocation, QName serviceName) { + super(wsdlLocation, serviceName); + } + + public CountryServiceImplService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { + super(wsdlLocation, serviceName, features); + } + + /** + * + * @return + * returns CountryService + */ + @WebEndpoint(name = "CountryServiceImplPort") + public CountryService getCountryServiceImplPort() { + return super.getPort(new QName("http://server.ws.soap.baeldung.com/", "CountryServiceImplPort"), CountryService.class); + } + + /** + * + * @param features + * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the features parameter will have their default values. + * @return + * returns CountryService + */ + @WebEndpoint(name = "CountryServiceImplPort") + public CountryService getCountryServiceImplPort(WebServiceFeature... features) { + return super.getPort(new QName("http://server.ws.soap.baeldung.com/", "CountryServiceImplPort"), CountryService.class, features); + } + + private static URL __getWsdlLocation() { + if (COUNTRYSERVICEIMPLSERVICE_EXCEPTION != null) { + throw COUNTRYSERVICEIMPLSERVICE_EXCEPTION; + } + return COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION; + } + +} diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/Currency.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/Currency.java new file mode 100644 index 0000000000..8b9355edc5 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/Currency.java @@ -0,0 +1,37 @@ + +package com.baeldung.soap.ws.client.generated; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + +/** + *

Java class for currency. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+ * <simpleType name="currency">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="EUR"/>
+ *     <enumeration value="INR"/>
+ *     <enumeration value="USD"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "currency") +@XmlEnum +public enum Currency { + + EUR, INR, USD; + + public String value() { + return name(); + } + + public static Currency fromValue(String v) { + return valueOf(v); + } + +} diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/ObjectFactory.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/ObjectFactory.java new file mode 100644 index 0000000000..241debe758 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/ObjectFactory.java @@ -0,0 +1,38 @@ + +package com.baeldung.soap.ws.client.generated; + +import javax.xml.bind.annotation.XmlRegistry; + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the com.baeldung.soap.ws.client.generated package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.baeldung.soap.ws.client.generated + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link Country } + * + */ + public Country createCountry() { + return new Country(); + } + +} diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/package-info.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/package-info.java new file mode 100644 index 0000000000..6df70b70f1 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/package-info.java @@ -0,0 +1,2 @@ +@javax.xml.bind.annotation.XmlSchema(namespace = "http://server.ws.soap.baeldung.com/", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) +package com.baeldung.soap.ws.client.generated; diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/Country.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/Country.java new file mode 100644 index 0000000000..62ea4a22ed --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/Country.java @@ -0,0 +1,41 @@ +package com.baeldung.soap.ws.server; + +public class Country { + protected String name; + protected int population; + protected String capital; + protected Currency currency; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPopulation() { + return population; + } + + public void setPopulation(int population) { + this.population = population; + } + + public String getCapital() { + return capital; + } + + public void setCapital(String capital) { + this.capital = capital; + } + + public Currency getCurrency() { + return currency; + } + + public void setCurrency(Currency currency) { + this.currency = currency; + } + +} \ No newline at end of file diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryRepository.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryRepository.java new file mode 100644 index 0000000000..558f7c1293 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryRepository.java @@ -0,0 +1,43 @@ +package com.baeldung.soap.ws.server; + +import java.util.HashMap; +import java.util.Map; + +public class CountryRepository { + + private static final Map countries = new HashMap<>(); + + { + initData(); + } + + private final static void initData() { + Country usa = new Country(); + usa.setName("USA"); + usa.setCapital("Washington D.C."); + usa.setCurrency(Currency.USD); + usa.setPopulation(323947000); + + countries.put(usa.getName(), usa); + + Country india = new Country(); + india.setName("India"); + india.setCapital("New Delhi"); + india.setCurrency(Currency.INR); + india.setPopulation(1295210000); + + countries.put(india.getName(), india); + + Country france = new Country(); + france.setName("France"); + france.setCapital("Paris"); + france.setCurrency(Currency.EUR); + france.setPopulation(66710000); + + countries.put(france.getName(), france); + } + + public Country findCountry(String name) { + return countries.get(name); + } +} diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryService.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryService.java new file mode 100644 index 0000000000..e3f68a4e59 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryService.java @@ -0,0 +1,15 @@ +package com.baeldung.soap.ws.server; + +import javax.jws.WebMethod; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; +import javax.jws.soap.SOAPBinding.Style; + +@WebService +@SOAPBinding(style=Style.RPC) +public interface CountryService { + + @WebMethod + Country findByName(String name); + +} diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryServiceImpl.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryServiceImpl.java new file mode 100644 index 0000000000..a8c6250354 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryServiceImpl.java @@ -0,0 +1,15 @@ +package com.baeldung.soap.ws.server; + +import javax.jws.WebService; + +@WebService(endpointInterface = "com.baeldung.soap.ws.server.CountryService") +public class CountryServiceImpl implements CountryService { + + private CountryRepository countryRepository = new CountryRepository(); + + @Override + public Country findByName(String name) { + return countryRepository.findCountry(name); + } + +} diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryServicePublisher.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryServicePublisher.java new file mode 100644 index 0000000000..e7c1c480f4 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/CountryServicePublisher.java @@ -0,0 +1,19 @@ +package com.baeldung.soap.ws.server; + +import javax.xml.ws.Endpoint; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class CountryServicePublisher { + + private static final Logger logger = LoggerFactory.getLogger(CountryServicePublisher.class); + + public static void main(String[] args) { + Endpoint endpoint = Endpoint.create(new CountryServiceImpl()); + endpoint.publish("http://localhost:8888/ws/country"); + + logger.info("Country web service ready to consume requests!"); + } +} \ No newline at end of file diff --git a/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/Currency.java b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/Currency.java new file mode 100644 index 0000000000..d1b25a26c6 --- /dev/null +++ b/web-modules/jee-7/src/main/java/com/baeldung/soap/ws/server/Currency.java @@ -0,0 +1,15 @@ +package com.baeldung.soap.ws.server; + +public enum Currency { + + EUR, INR, USD; + + public String value() { + return name(); + } + + public static Currency fromValue(String v) { + return valueOf(v); + } + +} diff --git a/web-modules/jee-7/src/main/resources/country.xsd b/web-modules/jee-7/src/main/resources/country.xsd new file mode 100644 index 0000000000..c94b6047f9 --- /dev/null +++ b/web-modules/jee-7/src/main/resources/country.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-modules/jee-7/src/main/resources/logback.xml b/web-modules/jee-7/src/main/resources/logback.xml new file mode 100644 index 0000000000..5c1b7ec771 --- /dev/null +++ b/web-modules/jee-7/src/main/resources/logback.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/web-modules/jee-7/src/main/webapp/WEB-INF/beans.xml b/web-modules/jee-7/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/CustomCheckPointIntegrationTest.java b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/CustomCheckPointIntegrationTest.java new file mode 100644 index 0000000000..8190ae5afb --- /dev/null +++ b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/CustomCheckPointIntegrationTest.java @@ -0,0 +1,33 @@ +package com.baeldung.batch.understanding; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Properties; + +import javax.batch.operations.JobOperator; +import javax.batch.runtime.BatchRuntime; +import javax.batch.runtime.BatchStatus; +import javax.batch.runtime.JobExecution; +import javax.batch.runtime.StepExecution; + +import org.junit.jupiter.api.Test; + +class CustomCheckPointIntegrationTest { + @Test + public void givenChunk_whenCustomCheckPoint_thenCommitCountIsThree() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("customCheckPoint", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + for (StepExecution stepExecution : jobOperator.getStepExecutions(executionId)) { + if (stepExecution.getStepName() + .equals("firstChunkStep")) { + jobOperator.getStepExecutions(executionId) + .stream() + .map(BatchTestHelper::getCommitCount) + .forEach(count -> assertEquals(3L, count.longValue())); + } + } + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } +} diff --git a/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/JobSequenceIntegrationTest.java b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/JobSequenceIntegrationTest.java new file mode 100644 index 0000000000..7dda13a752 --- /dev/null +++ b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/JobSequenceIntegrationTest.java @@ -0,0 +1,76 @@ +package com.baeldung.batch.understanding; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import javax.batch.operations.JobOperator; +import javax.batch.runtime.BatchRuntime; +import javax.batch.runtime.BatchStatus; +import javax.batch.runtime.JobExecution; +import javax.batch.runtime.StepExecution; + +import org.junit.jupiter.api.Test; + +class JobSequenceIntegrationTest { + @Test + public void givenTwoSteps_thenBatch_CompleteWithSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("simpleJobSequence", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + assertEquals(2 , jobOperator.getStepExecutions(executionId).size()); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } + + @Test + public void givenFlow_thenBatch_CompleteWithSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("flowJobSequence", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + assertEquals(3 , jobOperator.getStepExecutions(executionId).size()); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } + + @Test + public void givenDecider_thenBatch_CompleteWithSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("decideJobSequence", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + List stepExecutions = jobOperator.getStepExecutions(executionId); + List executedSteps = new ArrayList<>(); + for (StepExecution stepExecution : stepExecutions) { + executedSteps.add(stepExecution.getStepName()); + } + assertEquals(2, jobOperator.getStepExecutions(executionId).size()); + assertArrayEquals(new String[] { "firstBatchStepStep1", "firstBatchStepStep3" }, executedSteps.toArray()); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } + + @Test + public void givenSplit_thenBatch_CompletesWithSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("splitJobSequence", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + List stepExecutions = jobOperator.getStepExecutions(executionId); + List executedSteps = new ArrayList<>(); + for (StepExecution stepExecution : stepExecutions) { + executedSteps.add(stepExecution.getStepName()); + } + assertEquals(3, stepExecutions.size()); + assertTrue(executedSteps.contains("splitJobSequenceStep1")); + assertTrue(executedSteps.contains("splitJobSequenceStep2")); + assertTrue(executedSteps.contains("splitJobSequenceStep3")); + assertTrue(executedSteps.get(0).equals("splitJobSequenceStep1") || executedSteps.get(0).equals("splitJobSequenceStep2")); + assertTrue(executedSteps.get(1).equals("splitJobSequenceStep1") || executedSteps.get(1).equals("splitJobSequenceStep2")); + assertTrue(executedSteps.get(2).equals("splitJobSequenceStep3")); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } +} diff --git a/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleBatchLetIntegrationTest.java b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleBatchLetIntegrationTest.java new file mode 100644 index 0000000000..dc91f747d3 --- /dev/null +++ b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleBatchLetIntegrationTest.java @@ -0,0 +1,64 @@ +package com.baeldung.batch.understanding; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Properties; + +import javax.batch.operations.JobOperator; +import javax.batch.runtime.BatchRuntime; +import javax.batch.runtime.BatchStatus; +import javax.batch.runtime.JobExecution; + +import org.junit.jupiter.api.Test; + +class SimpleBatchLetIntegrationTest { + @Test + public void givenBatchLet_thenBatch_CompleteWithSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("simpleBatchLet", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } + + @Test + public void givenBatchLetProperty_thenBatch_CompleteWithSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("injectionSimpleBatchLet", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } + + @Test + public void givenBatchLetPartition_thenBatch_CompleteWithSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("partitionSimpleBatchLet", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } + + @Test + public void givenBatchLetStarted_whenStopped_thenBatchStopped() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("simpleBatchLet", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobOperator.stop(executionId); + jobExecution = BatchTestHelper.keepTestStopped(jobExecution); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.STOPPED); + } + + @Test + public void givenBatchLetStopped_whenRestarted_thenBatchCompletesSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("simpleBatchLet", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobOperator.stop(executionId); + jobExecution = BatchTestHelper.keepTestStopped(jobExecution); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.STOPPED); + executionId = jobOperator.restart(jobExecution.getExecutionId(), new Properties()); + jobExecution = BatchTestHelper.keepTestAlive(jobOperator.getJobExecution(executionId)); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } +} diff --git a/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleChunkIntegrationTest.java b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleChunkIntegrationTest.java new file mode 100644 index 0000000000..a7884dbb32 --- /dev/null +++ b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleChunkIntegrationTest.java @@ -0,0 +1,68 @@ +package com.baeldung.batch.understanding; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.batch.operations.JobOperator; +import javax.batch.runtime.BatchRuntime; +import javax.batch.runtime.BatchStatus; +import javax.batch.runtime.JobExecution; +import javax.batch.runtime.Metric; +import javax.batch.runtime.StepExecution; + +import org.junit.jupiter.api.Test; + +class SimpleChunkIntegrationTest { + @Test + public void givenChunk_thenBatch_CompletesWithSucess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("simpleChunk", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + List stepExecutions = jobOperator.getStepExecutions(executionId); + for (StepExecution stepExecution : stepExecutions) { + if (stepExecution.getStepName() + .equals("firstChunkStep")) { + Map metricsMap = BatchTestHelper.getMetricsMap(stepExecution.getMetrics()); + assertEquals(10L, metricsMap.get(Metric.MetricType.READ_COUNT) + .longValue()); + assertEquals(10L / 2L, metricsMap.get(Metric.MetricType.WRITE_COUNT) + .longValue()); + assertEquals(10L / 3 + (10L % 3 > 0 ? 1 : 0), metricsMap.get(Metric.MetricType.COMMIT_COUNT) + .longValue()); + } + } + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } + + @Test + public void givenChunk__thenBatch_fetchInformation() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("simpleChunk", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + // job name contains simpleBatchLet which is the name of the file + assertTrue(jobOperator.getJobNames().contains("simpleChunk")); + // job parameters are empty + assertTrue(jobOperator.getParameters(executionId).isEmpty()); + // step execution information + List stepExecutions = jobOperator.getStepExecutions(executionId); + assertEquals("firstChunkStep", stepExecutions.get(0).getStepName()); + // finding out batch status + assertEquals(BatchStatus.COMPLETED, stepExecutions.get(0).getBatchStatus()); + Map metricTest = BatchTestHelper.getMetricsMap(stepExecutions.get(0).getMetrics()); + assertEquals(10L, metricTest.get(Metric.MetricType.READ_COUNT).longValue()); + assertEquals(5L, metricTest.get(Metric.MetricType.FILTER_COUNT).longValue()); + assertEquals(4L, metricTest.get(Metric.MetricType.COMMIT_COUNT).longValue()); + assertEquals(5L, metricTest.get(Metric.MetricType.WRITE_COUNT).longValue()); + assertEquals(0L, metricTest.get(Metric.MetricType.READ_SKIP_COUNT).longValue()); + assertEquals(0L, metricTest.get(Metric.MetricType.WRITE_SKIP_COUNT).longValue()); + assertEquals(0L, metricTest.get(Metric.MetricType.PROCESS_SKIP_COUNT).longValue()); + assertEquals(0L, metricTest.get(Metric.MetricType.ROLLBACK_COUNT).longValue()); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } +} diff --git a/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleErrorChunkIntegrationTest.java b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleErrorChunkIntegrationTest.java new file mode 100644 index 0000000000..8c3beeb2f3 --- /dev/null +++ b/web-modules/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleErrorChunkIntegrationTest.java @@ -0,0 +1,45 @@ +package com.baeldung.batch.understanding; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.Properties; + +import javax.batch.operations.JobOperator; +import javax.batch.runtime.BatchRuntime; +import javax.batch.runtime.BatchStatus; +import javax.batch.runtime.JobExecution; +import javax.batch.runtime.StepExecution; + +import org.junit.jupiter.api.Test; + +class SimpleErrorChunkIntegrationTest { + + @Test + public void givenChunkError_thenBatch_CompletesWithFailed() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("simpleErrorChunk", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestFailed(jobExecution); + assertEquals(jobExecution.getBatchStatus(), BatchStatus.FAILED); + } + + @Test + public void givenChunkError_thenErrorSkipped_CompletesWithSuccess() throws Exception { + JobOperator jobOperator = BatchRuntime.getJobOperator(); + Long executionId = jobOperator.start("simpleErrorSkipChunk", new Properties()); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + jobExecution = BatchTestHelper.keepTestAlive(jobExecution); + List stepExecutions = jobOperator.getStepExecutions(executionId); + for (StepExecution stepExecution : stepExecutions) { + if (stepExecution.getStepName() + .equals("errorStep")) { + jobOperator.getStepExecutions(executionId) + .stream() + .map(BatchTestHelper::getProcessSkipCount) + .forEach(skipCount -> assertEquals(1L, skipCount.longValue())); + } + } + assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED); + } +} diff --git a/web-modules/jee-7/src/test/java/com/baeldung/singleton/CarServiceLiveTest.java b/web-modules/jee-7/src/test/java/com/baeldung/singleton/CarServiceLiveTest.java new file mode 100644 index 0000000000..c054f9c2db --- /dev/null +++ b/web-modules/jee-7/src/test/java/com/baeldung/singleton/CarServiceLiveTest.java @@ -0,0 +1,109 @@ +package com.baeldung.singleton; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.ejb.EJB; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.CDI; +import javax.inject.Inject; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(Arquillian.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class CarServiceLiveTest { + + public static final Logger LOG = LoggerFactory.getLogger(CarServiceLiveTest.class); + + @Deployment + public static JavaArchive createDeployment() { + return ShrinkWrap.create(JavaArchive.class) + .addClasses(CarServiceBean.class, CarServiceSingleton.class, CarServiceEjbSingleton.class, Car.class) + .addAsResource("META-INF/persistence.xml") + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Inject + private CarServiceBean carServiceBean; + + @Inject + private CarServiceSingleton carServiceSingleton; + + @EJB + private CarServiceEjbSingleton carServiceEjbSingleton; + + @Test + public void givenASingleton_whenGetBeanIsCalledTwice_thenTheSameInstanceIsReturned() { + CarServiceSingleton one = getBean(CarServiceSingleton.class); + CarServiceSingleton two = getBean(CarServiceSingleton.class); + assertTrue(one == two); + } + + @Test + public void givenAPojo_whenGetBeanIsCalledTwice_thenDifferentInstancesAreReturned() { + CarServiceBean one = getBean(CarServiceBean.class); + CarServiceBean two = getBean(CarServiceBean.class); + assertTrue(one != two); + } + + @SuppressWarnings("unchecked") + private T getBean(Class beanClass) { + BeanManager bm = CDI.current().getBeanManager(); + Bean bean = (Bean) bm.getBeans(beanClass).iterator().next(); + CreationalContext ctx = bm.createCreationalContext(bean); + return (T) bm.getReference(bean, beanClass, ctx); + } + + @Test + public void givenCDI_whenConcurrentAccess_thenLockingIsNotProvided() { + for (int i = 0; i < 10; i++) { + new Thread(new Runnable() { + @Override + public void run() { + String model = Double.toString(Math.round(Math.random() * 100)); + Car car = new Car("Speedster", model); + int serviceQueue = carServiceSingleton.service(car); + assertTrue(serviceQueue < 10); + } + }).start(); + } + return; + } + + @Test + public void givenEJB_whenConcurrentAccess_thenLockingIsProvided() { + for (int i = 0; i < 10; i++) { + new Thread(new Runnable() { + @Override + public void run() { + String model = Double.toString(Math.round(Math.random() * 100)); + Car car = new Car("Speedster", model); + int serviceQueue = carServiceEjbSingleton.service(car); + assertEquals(0, serviceQueue); + } + }).start(); + } + return; + } + +} \ No newline at end of file diff --git a/web-modules/jee-7/src/test/java/com/baeldung/soap/ws/client/CountryClientLiveTest.java b/web-modules/jee-7/src/test/java/com/baeldung/soap/ws/client/CountryClientLiveTest.java new file mode 100644 index 0000000000..ae423f9bdd --- /dev/null +++ b/web-modules/jee-7/src/test/java/com/baeldung/soap/ws/client/CountryClientLiveTest.java @@ -0,0 +1,39 @@ +package com.baeldung.soap.ws.client; + +import static org.junit.Assert.assertEquals; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.baeldung.soap.ws.client.generated.CountryService; +import com.baeldung.soap.ws.client.generated.CountryServiceImplService; +import com.baeldung.soap.ws.client.generated.Currency; + +//Ensure that com.baeldung.soap.ws.server.CountryServicePublisher is running before executing this test +public class CountryClientLiveTest { + + private static CountryService countryService; + + @BeforeClass + public static void setup() { + CountryServiceImplService service = new CountryServiceImplService(); + countryService = service.getCountryServiceImplPort(); + } + + @Test + public void givenCountryService_whenCountryIndia_thenCapitalIsNewDelhi() { + assertEquals("New Delhi", countryService.findByName("India").getCapital()); + } + + @Test + public void givenCountryService_whenCountryFrance_thenPopulationCorrect() { + assertEquals(66710000, countryService.findByName("France").getPopulation()); + } + + @Test + public void givenCountryService_whenCountryUSA_thenCurrencyUSD() { + assertEquals(Currency.USD, countryService.findByName("USA").getCurrency()); + } + + +} diff --git a/web-modules/jee-7/src/test/resources/arquillian.xml b/web-modules/jee-7/src/test/resources/arquillian.xml new file mode 100644 index 0000000000..f4274877fd --- /dev/null +++ b/web-modules/jee-7/src/test/resources/arquillian.xml @@ -0,0 +1,23 @@ + + + + + target/wildfly-8.2.1.Final + standalone.xml + true + 9990 + -Djboss.http.port=8639 + + + + + + 127.0.0.1 + 9990 + admin + pass + true + + + + \ No newline at end of file diff --git a/web-modules/jee-7/src/test/resources/jberet.properties b/web-modules/jee-7/src/test/resources/jberet.properties new file mode 100644 index 0000000000..e8b9907de5 --- /dev/null +++ b/web-modules/jee-7/src/test/resources/jberet.properties @@ -0,0 +1 @@ +db-url=jdbc:h2:mem:jberet-repo;DB_CLOSE_DELAY=-1 \ No newline at end of file diff --git a/web-modules/jooby/conf/application.conf b/web-modules/jooby/conf/application.conf new file mode 100644 index 0000000000..7da56eef6b --- /dev/null +++ b/web-modules/jooby/conf/application.conf @@ -0,0 +1,4 @@ +#application.secret = 2o128940921eo298e21 +#db = /url/to/the/datastore + +#redis = "redis://localhost:6379" \ No newline at end of file diff --git a/web-modules/jooby/pom.xml b/web-modules/jooby/pom.xml new file mode 100644 index 0000000000..238f17571f --- /dev/null +++ b/web-modules/jooby/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + com.baeldung.jooby + jooby + 1.0 + jooby + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + io.jooby + jooby + ${jooby.version} + + + io.jooby + jooby-test + ${jooby.version} + + + io.jooby + jooby-jetty + ${jooby.version} + + + io.jooby + jooby-redis + ${jooby.version} + + + io.rest-assured + rest-assured + test + ${rest-assured.version} + + + com.squareup.okhttp3 + okhttp + ${squareup.okhttp.version} + + + + + + + maven-shade-plugin + ${maven-shade-plugin.version} + + + io.jooby + jooby-maven-plugin + ${jooby.version} + + + maven-compiler-plugin + ${maven-compiler.version} + + + -parameters + + + + + + + + 2.16.1 + 3.1.1 + com.baeldung.jooby.App + 3.2.4 + 3.8.1 + 4.9.1 + + + \ No newline at end of file diff --git a/web-modules/jooby/public/form.html b/web-modules/jooby/public/form.html new file mode 100644 index 0000000000..bb9a705b9a --- /dev/null +++ b/web-modules/jooby/public/form.html @@ -0,0 +1,18 @@ + + + + + Insert title here + + +

+
+
+
+
+
+

+ +
+ + \ No newline at end of file diff --git a/web-modules/jooby/src/main/java/com/baeldung/jooby/App.java b/web-modules/jooby/src/main/java/com/baeldung/jooby/App.java new file mode 100644 index 0000000000..1bfaf6de5d --- /dev/null +++ b/web-modules/jooby/src/main/java/com/baeldung/jooby/App.java @@ -0,0 +1,123 @@ +package com.baeldung.jooby; + +import com.baeldung.jooby.bean.Employee; + +import io.jooby.Jooby; +import io.jooby.ServerOptions; +import io.jooby.Session; +import io.jooby.SessionStore; + +public class App extends Jooby { + { + setServerOptions(new ServerOptions().setPort(8080) + .setSecurePort(8433)); + } + + { + get("/", ctx -> "Hello World!"); + } + + { + get("/user/{id}", ctx -> "Hello user : " + ctx.path("id") + .value()); + get("/user/:id", ctx -> "Hello user: " + ctx.path("id") + .value()); + get("/uid:{id}", ctx -> "Hello User with id : uid = " + ctx.path("id") + .value()); + } + + { + onStarting(() -> System.out.println("starting app")); + + onStop(() -> System.out.println("stopping app")); + + onStarted(() -> System.out.println("app started")); + } + + { + get("/login", ctx -> "Hello from Baeldung"); + } + + { + post("/save", ctx -> { + String userId = ctx.query("id") + .value(); + return userId; + }); + } + + { + { + assets("/employee", "public/form.html"); + } + + post("/submitForm", ctx -> { + Employee employee = ctx.path(Employee.class); + // ... + return "employee data saved successfully"; + }); + + } + + { + decorator(next -> ctx -> { + System.out.println("first"); + // Moves execution to next handler: second + return next.apply(ctx); + }); + decorator(next -> ctx -> { + System.out.println("second"); + // Moves execution to next handler: third + return next.apply(ctx); + }); + + get("/handler", ctx -> "third"); + } + + { + get("/sessionInMemory", ctx -> { + Session session = ctx.session(); + session.put("token", "value"); + return session.get("token") + .value(); + }); + } + + { + String secret = "super secret token"; + + setSessionStore(SessionStore.signed(secret)); + + get("/signedSession", ctx -> { + Session session = ctx.session(); + session.put("token", "value"); + return session.get("token") + .value(); + }); + } + + { + get("/sessionInMemoryRedis", ctx -> { + Session session = ctx.session(); + session.put("token", "value"); + return session.get("token") + .value(); + }); + } + + /* This will work once redis is installed locally + { + install(new RedisModule("redis")); + setSessionStore(new RedisSessionStore(require(RedisClient.class))); + get("/redisSession", ctx -> { + Session session = ctx.session(); + session.put("token", "value"); + return session.get("token"); + }); + }*/ + + public static void main(final String[] args) { + runApp(args, App::new); + } + +} diff --git a/web-modules/jooby/src/main/java/com/baeldung/jooby/mvc/GetController.java b/web-modules/jooby/src/main/java/com/baeldung/jooby/mvc/GetController.java new file mode 100644 index 0000000000..bd43fb1717 --- /dev/null +++ b/web-modules/jooby/src/main/java/com/baeldung/jooby/mvc/GetController.java @@ -0,0 +1,23 @@ +package com.baeldung.jooby.mvc; + +import java.util.HashMap; + +import io.jooby.ModelAndView; +import io.jooby.annotations.GET; +import io.jooby.annotations.Path; + +@Path("/hello") +public class GetController { + + @GET + public String hello() { + return "Hello Baeldung"; + } + + @GET + @Path("/home") + public ModelAndView home() { + return new ModelAndView("welcome.html", new HashMap<>()); + } + +} diff --git a/web-modules/jooby/src/main/java/com/baeldung/jooby/mvc/PostController.java b/web-modules/jooby/src/main/java/com/baeldung/jooby/mvc/PostController.java new file mode 100644 index 0000000000..0f014580f9 --- /dev/null +++ b/web-modules/jooby/src/main/java/com/baeldung/jooby/mvc/PostController.java @@ -0,0 +1,13 @@ +package com.baeldung.jooby.mvc; + +import io.jooby.annotations.POST; +import io.jooby.annotations.Path; + +@Path("/submit") +public class PostController { + + @POST + public String hello() { + return "Submit Baeldung"; + } +} diff --git a/web-modules/jooby/src/main/resources/logback.xml b/web-modules/jooby/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/jooby/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/jooby/src/test/java/com/baeldung/jooby/AppLiveTest.java b/web-modules/jooby/src/test/java/com/baeldung/jooby/AppLiveTest.java new file mode 100644 index 0000000000..e55e0e04a4 --- /dev/null +++ b/web-modules/jooby/src/test/java/com/baeldung/jooby/AppLiveTest.java @@ -0,0 +1,32 @@ +package com.baeldung.jooby; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import io.jooby.JoobyTest; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +@JoobyTest(value = App.class, port = 8080) +class AppLiveTest { + + static OkHttpClient client = new OkHttpClient(); + + @Test + void given_defaultUrl_expect_fixedString() { + Request request = new Request.Builder().url("http://localhost:8080") + .build(); + try (Response response = client.newCall(request) + .execute()) { + assertEquals("Hello World!", response.body() + .string()); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/web-modules/jooby/src/test/java/com/baeldung/jooby/AppUnitTest.java b/web-modules/jooby/src/test/java/com/baeldung/jooby/AppUnitTest.java new file mode 100644 index 0000000000..98184e11f3 --- /dev/null +++ b/web-modules/jooby/src/test/java/com/baeldung/jooby/AppUnitTest.java @@ -0,0 +1,17 @@ +package com.baeldung.jooby; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.jooby.MockRouter; + +public class AppUnitTest { + + @Test + public void given_defaultUrl_with_mockrouter_expect_fixedString() { + MockRouter router = new MockRouter(new App()); + assertEquals("Hello World!", router.get("/") + .value()); + } +} diff --git a/web-modules/linkrest/pom.xml b/web-modules/linkrest/pom.xml new file mode 100644 index 0000000000..f43add6910 --- /dev/null +++ b/web-modules/linkrest/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + linkrest + 0.0.1-SNAPSHOT + linkrest + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + com.nhl.link.rest + link-rest + ${linkrest.version} + + + org.glassfish.jersey.containers + jersey-container-servlet + ${jersey.version} + + + + + + + maven-war-plugin + ${maven-war-plugin.version} + + WebContent + false + + + + org.apache.cayenne.plugins + cayenne-maven-plugin + ${cayenne.version} + + + ${project.basedir}/src/main/resources/linkrest.map.xml + + + + + cgen + + + + + + org.apache.cayenne.plugins + cayenne-modeler-maven-plugin + ${cayenne.version} + + + + + + 2.9 + 4.0.B1 + 2.25.1 + + + \ No newline at end of file diff --git a/web-modules/linkrest/src/main/resources/logback.xml b/web-modules/linkrest/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/linkrest/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/ninja/README.md b/web-modules/ninja/README.md new file mode 100644 index 0000000000..554d088c1b --- /dev/null +++ b/web-modules/ninja/README.md @@ -0,0 +1,3 @@ +### Relevant Articles + +- [Introduction to Ninja Framework](https://www.baeldung.com/ninja-framework-intro) diff --git a/web-modules/ninja/pom.xml b/web-modules/ninja/pom.xml new file mode 100644 index 0000000000..cb3e234172 --- /dev/null +++ b/web-modules/ninja/pom.xml @@ -0,0 +1,226 @@ + + + 4.0.0 + ninja + 1.0.0 + jar + http://www.ninjaframework.org + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + org.webjars + bootstrap + ${bootstrap.version} + + + org.webjars + jquery + ${jquery.version} + + + com.h2database + h2 + ${h2.version} + + + org.ninjaframework + ninja-standalone + ${ninja.version} + + + org.ninjaframework + ninja-test-utilities + ${ninja.version} + test + + + + junit + junit + + + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler.plugin.version} + + ${source.version} + ${target.version} + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${enforcer.plugin.version} + + + enforce-banned-dependencies + + enforce + + + + + + commons-logging + + + + true + + + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty.version} + + + / + + stop + 8889 + 1 + automatic + + + target/classes + + **/* + + + **/*.ftl.html + assets/** + + + + + + ninja.mode + dev + + + + + + + + + org.ninjaframework + ninja-maven-plugin + ${ninja.version} + + + org.apache.maven.plugins + maven-deploy-plugin + ${deploy.plugin.version} + + true + + + + org.apache.maven.plugins + maven-shade-plugin + ${shade.plugin.version} + + true + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + package + + shade + + + + + + ninja.standalone.NinjaJetty + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + + src/main/java + + **/* + + + **/*.java + + + + src/main/resources + + **/* + + + + + + + 6.5.0 + 9.4.18.v20190429 + 3.3.4 + 2.1.3 + 3.2 + 17 + 17 + 1.3.1 + 2.8.2 + 2.2 + 5.8.1 + + + \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/META-INF/persistence.xml b/web-modules/ninja/src/main/java/META-INF/persistence.xml new file mode 100644 index 0000000000..e57cd5ecc0 --- /dev/null +++ b/web-modules/ninja/src/main/java/META-INF/persistence.xml @@ -0,0 +1,29 @@ + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/assets/css/custom.css b/web-modules/ninja/src/main/java/assets/css/custom.css new file mode 100644 index 0000000000..41d249d3cb --- /dev/null +++ b/web-modules/ninja/src/main/java/assets/css/custom.css @@ -0,0 +1,3 @@ +/* Add additional stylesheets below +-------------------------------------------------- */ + diff --git a/web-modules/ninja/src/main/java/conf/Filters.java b/web-modules/ninja/src/main/java/conf/Filters.java new file mode 100644 index 0000000000..b201780fa1 --- /dev/null +++ b/web-modules/ninja/src/main/java/conf/Filters.java @@ -0,0 +1,13 @@ +package conf; + +import java.util.List; +import ninja.Filter; + +public class Filters implements ninja.application.ApplicationFilters { + + @Override + public void addFilters(List> filters) { + // Add your application - wide filters here + // filters.add(MyFilter.class); + } +} diff --git a/web-modules/ninja/src/main/java/conf/Module.java b/web-modules/ninja/src/main/java/conf/Module.java new file mode 100644 index 0000000000..f7c03a4b26 --- /dev/null +++ b/web-modules/ninja/src/main/java/conf/Module.java @@ -0,0 +1,18 @@ +package conf; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; + +import services.UserService; +import services.UserServiceImpl; + +@Singleton +public class Module extends AbstractModule { + + protected void configure() { + + bind(UserService.class).to(UserServiceImpl.class); + + } + +} diff --git a/web-modules/ninja/src/main/java/conf/Routes.java b/web-modules/ninja/src/main/java/conf/Routes.java new file mode 100644 index 0000000000..a1727d55b0 --- /dev/null +++ b/web-modules/ninja/src/main/java/conf/Routes.java @@ -0,0 +1,32 @@ +package conf; + +import ninja.AssetsController; +import ninja.Router; +import ninja.application.ApplicationRoutes; +import controllers.ApplicationController; + +public class Routes implements ApplicationRoutes { + + @Override + public void init(Router router) { + + router.GET().route("/index").with(ApplicationController::index); + router.GET().route("/home").with(ApplicationController::home); + router.GET().route("/hello").with(ApplicationController::helloWorld); + router.GET().route("/userJson").with(ApplicationController::userJson); + router.GET().route("/createUser").with(ApplicationController::createUser); + router.GET().route("/flash").with(ApplicationController::showFlashMsg); + + router.GET().route("/users").with(ApplicationController::fetchUsers); + router.POST().route("/users").with(ApplicationController::insertUser); + + //Assets + router.GET().route("/assets/webjars/{fileName: .*}").with(AssetsController::serveWebJars); + router.GET().route("/assets/{fileName: .*}").with(AssetsController::serveStatic); + + //Index + router.GET().route("/.*").with(ApplicationController::index); + + } + +} diff --git a/web-modules/ninja/src/main/java/conf/application.conf b/web-modules/ninja/src/main/java/conf/application.conf new file mode 100644 index 0000000000..0ae4c7ec40 --- /dev/null +++ b/web-modules/ninja/src/main/java/conf/application.conf @@ -0,0 +1,21 @@ +application.name=baeldung ninja dev application +%test.application.name=baeldung ninja test application +%prod.application.name=baeldung ninja application + +application.cookie.prefix=NINJA + +application.languages=fr,en + +application.session.expire_time_in_seconds=3600 +application.session.send_only_if_changed=true +application.session.transferred_over_https_only=false + +ninja.port=8000 +ninja.ssl.port=8001 +application.secret = fxSjSL9Q017BSL7gBnkyo2Prln7uXaXIT35gotXRIED8c46OSa8s4QdoIQdTsEtj + +# h2 jpa configuration +ninja.jpa.persistence_unit_name=dev_unit +db.connection.url=jdbc:h2:./devDb +db.connection.username=sa +db.connection.password= diff --git a/web-modules/ninja/src/main/java/conf/messages.properties b/web-modules/ninja/src/main/java/conf/messages.properties new file mode 100644 index 0000000000..3bddfcd8c7 --- /dev/null +++ b/web-modules/ninja/src/main/java/conf/messages.properties @@ -0,0 +1,2 @@ +header.home=Home! +helloMsg=Hello, welcome to Ninja Framework! \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/conf/messages_fr.properties b/web-modules/ninja/src/main/java/conf/messages_fr.properties new file mode 100644 index 0000000000..89264e0cb9 --- /dev/null +++ b/web-modules/ninja/src/main/java/conf/messages_fr.properties @@ -0,0 +1,2 @@ +header.home=Accueil! +helloMsg=Bonjour, bienvenue dans Ninja Framework! \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/controllers/ApplicationController.java b/web-modules/ninja/src/main/java/controllers/ApplicationController.java new file mode 100644 index 0000000000..38dd598694 --- /dev/null +++ b/web-modules/ninja/src/main/java/controllers/ApplicationController.java @@ -0,0 +1,102 @@ +package controllers; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.inject.persist.Transactional; + +import models.User; +import ninja.Context; +import ninja.Result; +import ninja.Results; +import ninja.i18n.Lang; +import ninja.i18n.Messages; +import ninja.jpa.UnitOfWork; +import ninja.session.FlashScope; +import ninja.validation.JSR303Validation; +import ninja.validation.Validation; +import services.UserService; + +@Singleton +public class ApplicationController { + + @Inject + Lang lang; + + @Inject + Messages msg; + + private static Log logger = LogFactory.getLog(ApplicationController.class); + + @Inject + Provider entityManagerProvider; + + @Inject + UserService userService; + + public Result index() { + return Results.html(); + } + + public Result userJson() { + HashMap userMap = userService.getUserMap(); + logger.info(userMap); + return Results.json().render(userMap); + } + + public Result helloWorld(Context context) { + Optional language = Optional.of("fr"); + String helloMsg = msg.get("helloMsg", language).get(); + return Results.text().render(helloMsg); + } + + public Result showFlashMsg(FlashScope flashScope) { + flashScope.success("Success message"); + flashScope.error("Error message"); + return Results.redirect("/home"); + } + + public Result home() { + return Results.html(); + } + + public Result createUser() { + return Results.html(); + } + + @UnitOfWork + public Result fetchUsers() { + EntityManager entityManager = entityManagerProvider.get(); + Query q = entityManager.createQuery("SELECT x FROM User x"); + List users = (List) q.getResultList(); + return Results.json().render(users); + } + + @Transactional + public Result insertUser(FlashScope flashScope, @JSR303Validation User user, Validation validation) { + logger.info("Inserting User : " +user); + + if (validation.getViolations().size() > 0) { + flashScope.error("Validation Error: User can't be created"); + } else { + EntityManager entityManager = entityManagerProvider.get(); + entityManager.persist(user); + entityManager.flush(); + flashScope.success("User '" + user + "' is created successfully"); + } + + return Results.redirect("/home"); + } + +} diff --git a/web-modules/ninja/src/main/java/ehcache.xml b/web-modules/ninja/src/main/java/ehcache.xml new file mode 100644 index 0000000000..b401b61a36 --- /dev/null +++ b/web-modules/ninja/src/main/java/ehcache.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/web-modules/ninja/src/main/java/logback.xml b/web-modules/ninja/src/main/java/logback.xml new file mode 100644 index 0000000000..ebdcf56f76 --- /dev/null +++ b/web-modules/ninja/src/main/java/logback.xml @@ -0,0 +1,33 @@ + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/web-modules/ninja/src/main/java/models/User.java b/web-modules/ninja/src/main/java/models/User.java new file mode 100644 index 0000000000..e021567bca --- /dev/null +++ b/web-modules/ninja/src/main/java/models/User.java @@ -0,0 +1,25 @@ +package models; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.validation.constraints.NotNull; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + Long id; + + @NotNull + public String firstName; + + public String email; + + public String toString() { + return firstName + " : " + email; + } + +} diff --git a/web-modules/ninja/src/main/java/services/UserService.java b/web-modules/ninja/src/main/java/services/UserService.java new file mode 100644 index 0000000000..10d625c66f --- /dev/null +++ b/web-modules/ninja/src/main/java/services/UserService.java @@ -0,0 +1,9 @@ +package services; + +import java.util.HashMap; + +public interface UserService { + + HashMap getUserMap(); + +} diff --git a/web-modules/ninja/src/main/java/services/UserServiceImpl.java b/web-modules/ninja/src/main/java/services/UserServiceImpl.java new file mode 100644 index 0000000000..0f8c2214cf --- /dev/null +++ b/web-modules/ninja/src/main/java/services/UserServiceImpl.java @@ -0,0 +1,15 @@ +package services; + +import java.util.HashMap; + +public class UserServiceImpl implements UserService { + + @Override + public HashMap getUserMap() { + HashMap userMap = new HashMap<>(); + userMap.put("name", "Norman Lewis"); + userMap.put("email", "norman@email.com"); + return userMap; + } + +} diff --git a/web-modules/ninja/src/main/java/views/ApplicationController/createUser.ftl.html b/web-modules/ninja/src/main/java/views/ApplicationController/createUser.ftl.html new file mode 100644 index 0000000000..9156f7dbf2 --- /dev/null +++ b/web-modules/ninja/src/main/java/views/ApplicationController/createUser.ftl.html @@ -0,0 +1,12 @@ +<#import "../layout/defaultLayout.ftl.html" as layout> +<@layout.myLayout "Create User"> + +
+ + First Name : +
+ Email : +
+ + + \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/views/ApplicationController/home.ftl.html b/web-modules/ninja/src/main/java/views/ApplicationController/home.ftl.html new file mode 100644 index 0000000000..10f6612d54 --- /dev/null +++ b/web-modules/ninja/src/main/java/views/ApplicationController/home.ftl.html @@ -0,0 +1,9 @@ +<#import "../layout/defaultLayout.ftl.html" as layout> +<@layout.myLayout "Home page"> + + +

${i18n("helloMsg")}

+ +User Json + + \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/views/ApplicationController/index.ftl.html b/web-modules/ninja/src/main/java/views/ApplicationController/index.ftl.html new file mode 100644 index 0000000000..25d0a31229 --- /dev/null +++ b/web-modules/ninja/src/main/java/views/ApplicationController/index.ftl.html @@ -0,0 +1,9 @@ + + + Ninja: Index + + +

${i18n("helloMsg")}

+ User Json + + \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/views/layout/defaultLayout.ftl.html b/web-modules/ninja/src/main/java/views/layout/defaultLayout.ftl.html new file mode 100644 index 0000000000..a61edd19e6 --- /dev/null +++ b/web-modules/ninja/src/main/java/views/layout/defaultLayout.ftl.html @@ -0,0 +1,58 @@ +<#macro myLayout title="Layout example"> + + + + + ${title} + + + + + + + + + + + + + + + + + + +
+ + <#include "header.ftl.html"/> + + <#if (flash.error)??> +
+ ${flash.error} +
+ + + <#if (flash.success)??> +
+ ${flash.success} +
+ + + <#nested/> + + <#include "footer.ftl.html"/> + +
+ + + + + \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/views/layout/footer.ftl.html b/web-modules/ninja/src/main/java/views/layout/footer.ftl.html new file mode 100644 index 0000000000..0a2cb2721e --- /dev/null +++ b/web-modules/ninja/src/main/java/views/layout/footer.ftl.html @@ -0,0 +1,5 @@ +
+ + diff --git a/web-modules/ninja/src/main/java/views/layout/header.ftl.html b/web-modules/ninja/src/main/java/views/layout/header.ftl.html new file mode 100644 index 0000000000..af79449bf2 --- /dev/null +++ b/web-modules/ninja/src/main/java/views/layout/header.ftl.html @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/views/system/403forbidden.ftl.html b/web-modules/ninja/src/main/java/views/system/403forbidden.ftl.html new file mode 100644 index 0000000000..0f4efd160a --- /dev/null +++ b/web-modules/ninja/src/main/java/views/system/403forbidden.ftl.html @@ -0,0 +1,18 @@ +<#import "../layout/defaultLayout.ftl.html" as layout> +<@layout.myLayout "Error. Forbidden."> +
+
+
+
+

+ Oops!

+

+ 403 Forbidden

+
+ Sorry, an error has occured. Requested page is forbidden! +
+
+
+
+
+ \ No newline at end of file diff --git a/web-modules/ninja/src/main/java/views/system/404notFound.ftl.html b/web-modules/ninja/src/main/java/views/system/404notFound.ftl.html new file mode 100644 index 0000000000..c10e7c3949 --- /dev/null +++ b/web-modules/ninja/src/main/java/views/system/404notFound.ftl.html @@ -0,0 +1,18 @@ +<#import "../layout/defaultLayout.ftl.html" as layout> +<@layout.myLayout "Error. Not found."> +
+
+
+
+

+ Oops!

+

+ 404 Not Found

+
+ Sorry, an error has occured. Requested page not found! +
+
+
+
+
+ \ No newline at end of file diff --git a/web-modules/ninja/src/main/webapp/WEB-INF/web.xml b/web-modules/ninja/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..fe4b2c95bf --- /dev/null +++ b/web-modules/ninja/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,41 @@ + + + + + + ninja + + + ninja.servlet.NinjaServletListener + + + + guiceFilter + com.google.inject.servlet.GuiceFilter + + + guiceFilter + /* + + + diff --git a/web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterUnitTest.java b/web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterUnitTest.java new file mode 100644 index 0000000000..64812f6935 --- /dev/null +++ b/web-modules/ninja/src/test/java/controllers/ApiControllerDocTesterUnitTest.java @@ -0,0 +1,27 @@ +package controllers; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertThat; +import org.doctester.testbrowser.Request; +import org.doctester.testbrowser.Response; +import org.junit.Test; +import ninja.NinjaDocTester; + +public class ApiControllerDocTesterUnitTest extends NinjaDocTester { + + String URL_INDEX = "/"; + String URL_HELLO = "/hello"; + + @Test + public void testGetIndex() { + Response response = makeRequest(Request.GET().url(testServerUrl().path(URL_INDEX))); + assertThat(response.payload, containsString("Hello, welcome to Ninja Framework!")); + } + + @Test + public void testGetHello() { + Response response = makeRequest(Request.GET().url(testServerUrl().path(URL_HELLO))); + assertThat(response.payload, containsString("Bonjour, bienvenue dans Ninja Framework!")); + } + +} diff --git a/web-modules/ninja/src/test/java/controllers/ApiControllerMockUnitTest.java b/web-modules/ninja/src/test/java/controllers/ApiControllerMockUnitTest.java new file mode 100644 index 0000000000..8534fa0b0f --- /dev/null +++ b/web-modules/ninja/src/test/java/controllers/ApiControllerMockUnitTest.java @@ -0,0 +1,32 @@ +package controllers; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import ninja.NinjaTest; +import ninja.Result; +import services.UserService; + +public class ApiControllerMockUnitTest extends NinjaTest { + + private UserService userService; + + private ApplicationController applicationController; + + @Before + public void setupTest() { + userService = this.ninjaTestServer.getInjector().getInstance(UserService.class); + applicationController = new ApplicationController(); + applicationController.userService = userService; + } + + @Test + public void testThatGetUserJson() { + Result result = applicationController.userJson(); + System.out.println(result.getRenderable()); + assertEquals(userService.getUserMap().toString(), result.getRenderable().toString()); + } + +} diff --git a/web-modules/play-modules/README.md b/web-modules/play-modules/README.md new file mode 100644 index 0000000000..d1ac7eb2d4 --- /dev/null +++ b/web-modules/play-modules/README.md @@ -0,0 +1,8 @@ +## Play Framework + +This module contains articles about the Play Framework. + +### Relevant Articles: +- [REST API with Play Framework in Java](https://www.baeldung.com/rest-api-with-play) +- [Routing in Play Applications in Java](https://www.baeldung.com/routing-in-play) +- [Introduction to Play in Java](https://www.baeldung.com/java-intro-to-the-play-framework) diff --git a/web-modules/play-modules/async-http/.g8/form/app/controllers/$model__Camel$Controller.java b/web-modules/play-modules/async-http/.g8/form/app/controllers/$model__Camel$Controller.java new file mode 100644 index 0000000000..1ac4fe547d --- /dev/null +++ b/web-modules/play-modules/async-http/.g8/form/app/controllers/$model__Camel$Controller.java @@ -0,0 +1,43 @@ +package controllers; + +import play.data.Form; +import play.data.FormFactory; +import play.mvc.Controller; +import play.mvc.Result; + +import javax.inject.Inject; + +// Add the following to conf/routes +/* +GET /$model;format="camel"$ controllers.$model;format="Camel"$Controller.$model;format="camel"$Get +POST /$model;format="camel"$ controllers.$model;format="Camel"$Controller.$model;format="camel"$Post +*/ + +/** + * $model;format="Camel"$ form controller for Play Java + */ +public class $model;format="Camel"$Controller extends Controller { + + private final Form<$model;format="Camel"$Data> $model;format="camel"$Form; + + @Inject + public $model;format="Camel"$Controller(FormFactory formFactory) { + this.$model;format="camel"$Form = formFactory.form($model;format="Camel"$Data.class); + } + + public Result $model;format="camel"$Get() { + return ok(views.html.$model;format="camel"$.form.render($model;format="camel"$Form)); + } + + public Result $model;format="camel"$Post() { + Form<$model;format="Camel"$Data> boundForm = $model;format="camel"$Form.bindFromRequest(); + if (boundForm.hasErrors()) { + return badRequest(views.html.$model;format="camel"$.form.render(boundForm)); + } else { + $model;format="Camel"$Data $model;format="camel"$ = boundForm.get(); + flash("success", "$model;format="Camel"$ " + $model;format="camel"$); + return redirect(routes.$model;format="Camel"$Controller.$model;format="camel"$Get()); + } + } + +} diff --git a/web-modules/play-modules/async-http/.g8/form/app/controllers/$model__Camel$Data.java b/web-modules/play-modules/async-http/.g8/form/app/controllers/$model__Camel$Data.java new file mode 100644 index 0000000000..50dc06f478 --- /dev/null +++ b/web-modules/play-modules/async-http/.g8/form/app/controllers/$model__Camel$Data.java @@ -0,0 +1,37 @@ +package controllers; + +import play.data.validation.Constraints; + +public class $model;format="Camel"$Data { + + @Constraints.Required + private String name; + + @Constraints.Required + private Integer age; + + public $model;format="Camel"$Data() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + @Override + public String toString() { + return String.format("$model;format="Camel"$Data(%s, %s)", name, age); + } + +} diff --git a/web-modules/play-modules/async-http/.g8/form/app/views/$model__camel$/form.scala.html b/web-modules/play-modules/async-http/.g8/form/app/views/$model__camel$/form.scala.html new file mode 100644 index 0000000000..7bf9fd5427 --- /dev/null +++ b/web-modules/play-modules/async-http/.g8/form/app/views/$model__camel$/form.scala.html @@ -0,0 +1,12 @@ +@($model;format="camel"$Form: Form[$model;format="Camel"$Data]) + +

$model;format="camel"$ form

+ +@flash.getOrDefault("success", "") + +@helper.form(action = routes.$model;format="Camel"$Controller.$model;format="camel"$Post()) { + @helper.CSRF.formField + @helper.inputText($model;format="camel"$Form("name")) + @helper.inputText($model;format="camel"$Form("age")) + +} diff --git a/web-modules/play-modules/async-http/.g8/form/default.properties b/web-modules/play-modules/async-http/.g8/form/default.properties new file mode 100644 index 0000000000..32090f30cb --- /dev/null +++ b/web-modules/play-modules/async-http/.g8/form/default.properties @@ -0,0 +1,2 @@ +description = Generates a Controller with form handling +model = user diff --git a/web-modules/play-modules/async-http/.g8/form/generated-test/README.md b/web-modules/play-modules/async-http/.g8/form/generated-test/README.md new file mode 100644 index 0000000000..db01c87f30 --- /dev/null +++ b/web-modules/play-modules/async-http/.g8/form/generated-test/README.md @@ -0,0 +1 @@ +Temporary file until g8-scaffold will generate "test" directory diff --git a/web-modules/play-modules/async-http/.g8/form/generated-test/controllers/$model__Camel$ControllerTest.java b/web-modules/play-modules/async-http/.g8/form/generated-test/controllers/$model__Camel$ControllerTest.java new file mode 100644 index 0000000000..7cdb87068b --- /dev/null +++ b/web-modules/play-modules/async-http/.g8/form/generated-test/controllers/$model__Camel$ControllerTest.java @@ -0,0 +1,50 @@ +package controllers; + +import org.junit.Test; +import play.Application; +import play.filters.csrf.*; +import play.inject.guice.GuiceApplicationBuilder; +import play.mvc.*; +import play.test.WithApplication; + +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static play.mvc.Http.RequestBuilder; +import static play.mvc.Http.Status.OK; +import static play.test.Helpers.*; +import static play.api.test.CSRFTokenHelper.*; + +public class $model;format="Camel"$ControllerTest extends WithApplication { + + @Override + protected Application provideApplication() { + return new GuiceApplicationBuilder().build(); + } + + @Test + public void test$model;format="Camel"$Get() { + RequestBuilder request = new RequestBuilder() + .method(GET) + .uri("/$model;format="camel"$"); + + Result result = route(app, request); + assertEquals(OK, result.status()); + } + + @Test + public void test$model;format="Camel"$Post() { + HashMap formData = new HashMap<>(); + formData.put("name", "play"); + formData.put("age", "4"); + RequestBuilder request = addCSRFToken(new RequestBuilder() + .header(Http.HeaderNames.HOST, "localhost") + .method(POST) + .bodyForm(formData) + .uri("/$model;format="camel"$")); + + Result result = route(app, request); + assertEquals(SEE_OTHER, result.status()); + } + +} diff --git a/web-modules/play-modules/async-http/.gitignore b/web-modules/play-modules/async-http/.gitignore new file mode 100644 index 0000000000..eb372fc719 --- /dev/null +++ b/web-modules/play-modules/async-http/.gitignore @@ -0,0 +1,8 @@ +logs +target +/.idea +/.idea_modules +/.classpath +/.project +/.settings +/RUNNING_PID diff --git a/web-modules/play-modules/async-http/README.md b/web-modules/play-modules/async-http/README.md new file mode 100644 index 0000000000..c42b86ad4e --- /dev/null +++ b/web-modules/play-modules/async-http/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [Asynchronous HTTP Programming with Play Framework](https://www.baeldung.com/java-play-asynchronous-http-programming) diff --git a/web-modules/play-modules/async-http/app/controllers/HomeController.java b/web-modules/play-modules/async-http/app/controllers/HomeController.java new file mode 100644 index 0000000000..5c791dcd22 --- /dev/null +++ b/web-modules/play-modules/async-http/app/controllers/HomeController.java @@ -0,0 +1,38 @@ +package controllers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import java.util.Map; +import play.mvc.Controller; +import play.mvc.Http; +import play.mvc.Result; + +/** + * This controller contains an action to handle HTTP requests to the application's home page. + */ +public class HomeController extends Controller { + + /** + * An action that renders an HTML page with a welcome message. The configuration in the + * routes file means that this method will be called when the application receives + * a + * GET request with a path of /. + */ + public Result index(Http.Request request) throws JsonProcessingException { + return ok(printStats(request)); + } + + private String printStats(Http.Request request) throws JsonProcessingException { + Map stringMap = request.body() + .asFormUrlEncoded(); + Map map = ImmutableMap.of( + "Result", "ok", + "GetParams", request.queryString(), + "PostParams", stringMap == null ? Collections.emptyMap() : stringMap, + "Headers", request.getHeaders().toMap() + ); + return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(map); + } +} diff --git a/web-modules/play-modules/async-http/build.sbt b/web-modules/play-modules/async-http/build.sbt new file mode 100644 index 0000000000..eea47ffe88 --- /dev/null +++ b/web-modules/play-modules/async-http/build.sbt @@ -0,0 +1,12 @@ +name := """async""" +organization := "com.example" + +version := "1.0-SNAPSHOT" + +lazy val root = (project in file(".")).enablePlugins(PlayJava) + +scalaVersion := "2.13.1" + +// comment out the original line +libraryDependencies += guice +libraryDependencies += javaWs diff --git a/web-modules/play-modules/async-http/conf/application.conf b/web-modules/play-modules/async-http/conf/application.conf new file mode 100644 index 0000000000..492f37fed7 --- /dev/null +++ b/web-modules/play-modules/async-http/conf/application.conf @@ -0,0 +1,11 @@ +# This is the main configuration file for the application. +# https://www.playframework.com/documentation/latest/ConfigFile +play.ws.followRedirects=false +play.ws.useragent=MyPlayApplication +play.ws.compressionEnabled=true +# time to wait for the connection to be established +play.ws.timeout.connection=30.seconds +# time to wait for data after the connection is open +play.ws.timeout.idle=30.seconds +# max time available to complete the request +play.ws.timeout.request=300.seconds diff --git a/web-modules/play-modules/async-http/conf/logback.xml b/web-modules/play-modules/async-http/conf/logback.xml new file mode 100644 index 0000000000..55441d39e2 --- /dev/null +++ b/web-modules/play-modules/async-http/conf/logback.xml @@ -0,0 +1,36 @@ + + + + + + + ${application.home:-.}/logs/application.log + + %date [%level] from %logger in %thread - %message%n%xException + + + + + + %coloredLevel %logger{15} - %message%n%xException{10} + + + + + + + + + + + + + + + + + + + + + diff --git a/web-modules/play-modules/async-http/conf/routes b/web-modules/play-modules/async-http/conf/routes new file mode 100644 index 0000000000..4f5162a8e7 --- /dev/null +++ b/web-modules/play-modules/async-http/conf/routes @@ -0,0 +1,10 @@ +# Routes +# This file defines all application routes (Higher priority routes first) +# ~~~~ + +# An example controller showing a sample home page +GET / controllers.HomeController.index(request: Request) +POST / controllers.HomeController.index(request: Request) + +# Map static resources from the /public folder to the /assets URL path +GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) diff --git a/web-modules/play-modules/async-http/project/build.properties b/web-modules/play-modules/async-http/project/build.properties new file mode 100644 index 0000000000..6adcdc753f --- /dev/null +++ b/web-modules/play-modules/async-http/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.3.3 diff --git a/web-modules/play-modules/async-http/public/javascripts/main.js b/web-modules/play-modules/async-http/public/javascripts/main.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/play-modules/async-http/public/stylesheets/main.css b/web-modules/play-modules/async-http/public/stylesheets/main.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/play-modules/async-http/test/controllers/HomeControllerTest.java b/web-modules/play-modules/async-http/test/controllers/HomeControllerTest.java new file mode 100644 index 0000000000..a232dbfde0 --- /dev/null +++ b/web-modules/play-modules/async-http/test/controllers/HomeControllerTest.java @@ -0,0 +1,232 @@ +package controllers; + +import static java.time.temporal.ChronoUnit.SECONDS; +import static org.junit.Assert.assertEquals; +import static play.mvc.Http.Status.SERVICE_UNAVAILABLE; + +import akka.Done; +import akka.actor.ActorSystem; +import akka.stream.ActorMaterializer; +import akka.stream.javadsl.Sink; +import akka.util.ByteString; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.util.OptionalInt; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; +import org.apache.http.HttpStatus; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import play.Application; +import play.inject.guice.GuiceApplicationBuilder; +import play.libs.concurrent.Futures; +import play.libs.ws.WSClient; +import play.libs.ws.WSResponse; +import play.libs.ws.ahc.AhcCurlRequestLogger; +import play.mvc.Result; +import play.mvc.Results; +import play.test.WithServer; + +public class HomeControllerTest extends WithServer { + + private final Logger log = LoggerFactory.getLogger(HomeControllerTest.class); + private String url; + private int port; + + @Override + protected Application provideApplication() { + return new GuiceApplicationBuilder().build(); + } + + @Before + public void setup() { + OptionalInt optHttpsPort = testServer.getRunningHttpsPort(); + if (optHttpsPort.isPresent()) { + port = optHttpsPort.getAsInt(); + url = "https://localhost:" + port; + } else { + port = testServer.getRunningHttpPort() + .getAsInt(); + url = "http://localhost:" + port; + } + } + + @Test + public void givenASingleGetRequestWhenResponseThenBlockWithCompletableAndLog() + throws Exception { + WSClient ws = play.test.WSTestClient.newClient(port); + WSResponse wsResponse = ws.url(url) + .setRequestFilter(new AhcCurlRequestLogger()) + .addHeader("key", "value") + .addQueryParameter("num", "" + 1) + .get() + .toCompletableFuture() + .get(); + + log.debug("Thread#" + Thread.currentThread() + .getId() + " Request complete: Response code = " + + wsResponse.getStatus() + + " | Response: " + wsResponse.getBody() + " | Current Time:" + + System.currentTimeMillis()); + assert (HttpStatus.SC_OK == wsResponse.getStatus()); + } + + @Test + public void givenASingleGetRequestWhenResponseThenLog() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + WSClient ws = play.test.WSTestClient.newClient(port); + ws.url(url) + .setRequestFilter(new AhcCurlRequestLogger()) + .addHeader("key", "value") + .addQueryParameter("num", "" + 1) + .get() + .thenAccept(r -> { + log.debug("Thread#" + Thread.currentThread() + .getId() + " Request complete: Response code = " + + r.getStatus() + + " | Response: " + r.getBody() + " | Current Time:" + System.currentTimeMillis()); + latch.countDown(); + }); + + log.debug( + "Waiting for requests to be completed. Current Time: " + System.currentTimeMillis()); + latch.await(5, TimeUnit.SECONDS ); + assertEquals(0, latch.getCount()); + log.debug("All requests have been completed. Exiting test."); + } + + @Test + public void givenASinglePostRequestWhenResponseThenLog() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + WSClient ws = play.test.WSTestClient.newClient(port); + ws.url(url) + .setContentType("application/x-www-form-urlencoded") + .post("key1=value1&key2=value2") + .thenAccept(r -> { + log.debug("Thread#" + Thread.currentThread() + .getId() + " Request complete: Response code = " + + r.getStatus() + + " | Response: " + r.getBody() + " | Current Time:" + System.currentTimeMillis()); + latch.countDown(); + }); + + log.debug( + "Waiting for requests to be completed. Current Time: " + System.currentTimeMillis()); + latch.await(5, TimeUnit.SECONDS ); + assertEquals(0, latch.getCount()); + log.debug("All requests have been completed. Exiting test."); + } + + @Test + public void givenMultipleRequestsWhenResponseThenLog() throws Exception { + CountDownLatch latch = new CountDownLatch(100); + WSClient ws = play.test.WSTestClient.newClient(port); + IntStream.range(0, 100) + .parallel() + .forEach(num -> + ws.url(url) + .setRequestFilter(new AhcCurlRequestLogger()) + .addHeader("key", "value") + .addQueryParameter("num", "" + num) + .get() + .thenAccept(r -> { + log.debug( + "Thread#" + num + " Request complete: Response code = " + r.getStatus() + + " | Response: " + r.getBody() + " | Current Time:" + + System.currentTimeMillis()); + latch.countDown(); + }) + ); + + log.debug( + "Waiting for requests to be completed. Current Time: " + System.currentTimeMillis()); + latch.await(5, TimeUnit.SECONDS ); + assertEquals(0, latch.getCount()); + log.debug("All requests have been completed. Exiting test."); + } + + @Test + public void givenLongResponseWhenTimeoutThenHandle() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + WSClient ws = play.test.WSTestClient.newClient(port); + Futures futures = app.injector() + .instanceOf(Futures.class); + CompletionStage f = futures.timeout( + ws.url(url) + .setRequestTimeout(Duration.of(1, SECONDS)) + .get() + .thenApply(result -> { + try { + Thread.sleep(2000L); + return Results.ok(); + } catch (InterruptedException e) { + return Results.status( + SERVICE_UNAVAILABLE); + } + }), 1L, TimeUnit.SECONDS + ); + CompletionStage res = f.handleAsync((result, e) -> { + if (e != null) { + log.error("Exception thrown", e); + latch.countDown(); + return e.getCause(); + } else { + return result; + } + }); + res.thenAccept(result -> assertEquals(TimeoutException.class, result)); + + log.debug( + "Waiting for requests to be completed. Current Time: " + System.currentTimeMillis()); + latch.await(5, TimeUnit.SECONDS ); + assertEquals(0, latch.getCount()); + log.debug("All requests have been completed. Exiting test."); + } + + @Test + public void givenMultigigabyteResponseConsumeWithStreams() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + final ActorSystem system = ActorSystem.create(); + final ActorMaterializer materializer = ActorMaterializer.create(system); + final Path path = Files.createTempFile("tmp_", ".out"); + + WSClient ws = play.test.WSTestClient.newClient(port); + log.info("Starting test server on url: " + url); + ws.url(url) + .stream() + .thenAccept( + response -> { + try { + OutputStream outputStream = java.nio.file.Files.newOutputStream(path); + Sink> outputWriter = + Sink.foreach(bytes -> { + log.info("Reponse: " + bytes.utf8String()); + outputStream.write(bytes.toArray()); + }); + + response.getBodyAsSource() + .runWith(outputWriter, materializer); + + } catch (IOException e) { + log.error("An error happened while opening the output stream", e); + } + }) + .whenComplete((value, error) -> latch.countDown()); + + log.debug( + "Waiting for requests to be completed. Current Time: " + System.currentTimeMillis()); + latch.await(5, TimeUnit.SECONDS ); + assertEquals(0, latch.getCount()); + log.debug("All requests have been completed. Exiting test."); + } +} diff --git a/web-modules/play-modules/introduction/public/javascripts/main.js b/web-modules/play-modules/introduction/public/javascripts/main.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/play-modules/introduction/public/stylesheets/main.css b/web-modules/play-modules/introduction/public/stylesheets/main.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/play-modules/routing-in-play/app/views/index.scala.html b/web-modules/play-modules/routing-in-play/app/views/index.scala.html new file mode 100644 index 0000000000..68d37fb1d4 --- /dev/null +++ b/web-modules/play-modules/routing-in-play/app/views/index.scala.html @@ -0,0 +1,5 @@ +@() + +@main("Welcome to Play") { +

Welcome to Play!

+} diff --git a/web-modules/play-modules/routing-in-play/app/views/main.scala.html b/web-modules/play-modules/routing-in-play/app/views/main.scala.html new file mode 100644 index 0000000000..c5f755f236 --- /dev/null +++ b/web-modules/play-modules/routing-in-play/app/views/main.scala.html @@ -0,0 +1,24 @@ +@* + * This template is called from the `index` template. This template + * handles the rendering of the page header and body tags. It takes + * two arguments, a `String` for the title of the page and an `Html` + * object to insert into the body of the page. + *@ +@(title: String)(content: Html) + + + + + @* Here's where we render the page title `String`. *@ + @title + + + + + @* And here's where we render the `Html` object containing + * the page content. *@ + @content + + + + diff --git a/web-modules/play-modules/routing-in-play/public/images/favicon.png b/web-modules/play-modules/routing-in-play/public/images/favicon.png new file mode 100644 index 0000000000..c7d92d2ae4 Binary files /dev/null and b/web-modules/play-modules/routing-in-play/public/images/favicon.png differ diff --git a/web-modules/play-modules/routing-in-play/public/javascripts/main.js b/web-modules/play-modules/routing-in-play/public/javascripts/main.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/play-modules/routing-in-play/public/stylesheets/main.css b/web-modules/play-modules/routing-in-play/public/stylesheets/main.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/play-modules/student-api/project/plugins.sbt b/web-modules/play-modules/student-api/project/plugins.sbt new file mode 100644 index 0000000000..1c8c62a0d5 --- /dev/null +++ b/web-modules/play-modules/student-api/project/plugins.sbt @@ -0,0 +1,7 @@ +// The Play plugin +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3") + +// Defines scaffolding (found under .g8 folder) +// http://www.foundweekends.org/giter8/scaffolding.html +// sbt "g8Scaffold form" +addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0") diff --git a/web-modules/play-modules/websockets/README.md b/web-modules/play-modules/websockets/README.md new file mode 100644 index 0000000000..d056b8f059 --- /dev/null +++ b/web-modules/play-modules/websockets/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: + +- [WebSockets with the Play Framework and Akka](https://www.baeldung.com/akka-play-websockets) diff --git a/web-modules/play-modules/websockets/app/actors/Messenger.java b/web-modules/play-modules/websockets/app/actors/Messenger.java new file mode 100644 index 0000000000..1c9335b82e --- /dev/null +++ b/web-modules/play-modules/websockets/app/actors/Messenger.java @@ -0,0 +1,111 @@ +package actors; + +import akka.actor.AbstractActor; +import akka.actor.ActorRef; +import akka.actor.PoisonPill; +import akka.actor.Props; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import akka.http.javadsl.Http; +import akka.http.javadsl.marshallers.jackson.Jackson; +import akka.http.javadsl.model.HttpMessage; +import akka.http.javadsl.model.HttpRequest; +import akka.http.javadsl.model.HttpResponse; +import akka.stream.Materializer; +import com.fasterxml.jackson.databind.JsonNode; +import dto.MessageDTO; +import dto.RequestDTO; +import utils.MessageConverter; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ThreadLocalRandom; + +public class Messenger extends AbstractActor { + private LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this); + + private ActorRef out; + + public Messenger(ActorRef out) { + this.out = out; + } + + public static Props props(ActorRef out) { + return Props.create(Messenger.class, () -> new Messenger(out)); + } + + @Override + public void preStart() throws Exception { + log.info("Messenger actor started at {}", + OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + } + + @Override + public void postStop() throws Exception { + log.info("Messenger actor stopped at {}", + OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + } + + private void onSendMessage(JsonNode jsonNode) { + RequestDTO requestDTO = MessageConverter.jsonNodeToRequest(jsonNode); + String message = requestDTO.getMessage().toLowerCase(); + if("stop".equals(message)) { + MessageDTO messageDTO = createMessageDTO("1", "1", "Stop", "Stopping actor"); + out.tell(MessageConverter.messageToJsonNode(messageDTO), getSelf()); + self().tell(PoisonPill.getInstance(), getSelf()); + } else { + log.info("Actor received. {}", requestDTO); + processMessage(requestDTO); + } + } + + private MessageDTO createMessageDTO(String userId, String id, String title, String message) { + MessageDTO messageDTO = new MessageDTO(); + messageDTO.setUserId(UUID.randomUUID().toString()); + messageDTO.setId(UUID.randomUUID().toString()); + messageDTO.setTitle("Self Kill"); + messageDTO.setBody("Stopping actor"); + return messageDTO; + } + + private void processMessage(RequestDTO requestDTO) { + CompletionStage responseFuture = getRandomMessage(); + responseFuture.thenCompose(this::consumeHttpResponse) + .thenAccept(messageDTO -> + out.tell(MessageConverter.messageToJsonNode(messageDTO), getSelf())); + } + + private CompletionStage getRandomMessage() { + int postId = ThreadLocalRandom.current().nextInt(0, 100); + return Http.get(getContext().getSystem()).singleRequest( + HttpRequest.create("https://jsonplaceholder.typicode.com/posts/" + postId) + ); + } + + private void discardEntity(HttpResponse httpResponse, Materializer materializer) { + httpResponse.discardEntityBytes(materializer) + .completionStage() + .whenComplete((done, ex) -> log.info("Entity discarded completely!")); + } + + private CompletionStage consumeHttpResponse(HttpResponse httpResponse) { + Materializer materializer = Materializer.matFromSystem(getContext().getSystem()); + return Jackson.unmarshaller(MessageDTO.class) + .unmarshal(httpResponse.entity(), materializer) + .thenApply(messageDTO -> { + log.info("Received message: {}", messageDTO); + discardEntity(httpResponse, materializer); + return messageDTO; + }); + } + + @Override + public Receive createReceive() { + return receiveBuilder() + .match(JsonNode.class, this::onSendMessage) + .matchAny(o -> log.error("Received unknown message: {}", o.getClass())) + .build(); + } +} diff --git a/web-modules/play-modules/websockets/app/controllers/HomeController.java b/web-modules/play-modules/websockets/app/controllers/HomeController.java new file mode 100644 index 0000000000..39c670fe59 --- /dev/null +++ b/web-modules/play-modules/websockets/app/controllers/HomeController.java @@ -0,0 +1,79 @@ +package controllers; + +import actors.Messenger; +import akka.actor.ActorSystem; +import akka.stream.Materializer; +import akka.stream.javadsl.Flow; +import akka.stream.javadsl.Sink; +import akka.stream.javadsl.Source; +import com.fasterxml.jackson.databind.JsonNode; +import dto.MessageDTO; +import lombok.extern.slf4j.Slf4j; +import play.libs.F; +import play.libs.streams.ActorFlow; +import play.mvc.*; +import utils.MessageConverter; + +import javax.inject.Inject; + +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +@Slf4j +public class HomeController extends Controller { + private ActorSystem actorSystem; + private Materializer materializer; + + @Inject + public HomeController(ActorSystem actorSystem, Materializer materializer) { + this.actorSystem = actorSystem; + this.materializer = materializer; + } + + public Result index(Http.Request request) { + String url = routes.HomeController.socket().webSocketURL(request); + //To test WebSockets with akka streams, uncomment the next line and comment out the previous + //String url = routes.HomeController.akkaStreamsSocket().webSocketURL(request); + return ok(views.html.index.render(url)); + } + + + public WebSocket socket() { + return WebSocket.Json.acceptOrResult(this::createActorFlow); + } + + private CompletionStage>> createActorFlow( + Http.RequestHeader request) { + return CompletableFuture.completedFuture(F.Either.Right(createFlowForActor())); + } + + private CompletionStage>> + createActorFlow2(Http.RequestHeader request) { + return CompletableFuture.completedFuture( + request.session() + .getOptional("username") + .map(username -> + F.Either.>Right( + createFlowForActor())) + .orElseGet(() -> F.Either.Left(forbidden()))); + } + + private Flow createFlowForActor() { + return ActorFlow.actorRef(out -> Messenger.props(out), actorSystem, materializer); + } + + public WebSocket akkaStreamsSocket() { + return WebSocket.Json.accept( + request -> { + Sink in = Sink.foreach(System.out::println); + MessageDTO messageDTO = new MessageDTO("1", "1", "Title", "Test Body"); + Source out = Source.tick( + Duration.ofSeconds(2), + Duration.ofSeconds(2), + MessageConverter.messageToJsonNode(messageDTO) + ); + return Flow.fromSinkAndSource(in, out); + }); + } +} diff --git a/web-modules/play-modules/websockets/app/dto/MessageDTO.java b/web-modules/play-modules/websockets/app/dto/MessageDTO.java new file mode 100644 index 0000000000..e6b2bac1af --- /dev/null +++ b/web-modules/play-modules/websockets/app/dto/MessageDTO.java @@ -0,0 +1,60 @@ +package dto; + +public class MessageDTO { + private String userId; + private String id; + private String title; + private String body; + + public MessageDTO() { + } + + public MessageDTO(String userId, String id, String title, String body) { + this.userId = userId; + this.id = id; + this.title = title; + this.body = body; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + @Override + public String toString() { + return "MessageDTO{" + + "userId='" + userId + '\'' + + ", id='" + id + '\'' + + ", title='" + title + '\'' + + ", body='" + body + '\'' + + '}'; + } +} diff --git a/web-modules/play-modules/websockets/app/dto/RequestDTO.java b/web-modules/play-modules/websockets/app/dto/RequestDTO.java new file mode 100644 index 0000000000..a85d3770a4 --- /dev/null +++ b/web-modules/play-modules/websockets/app/dto/RequestDTO.java @@ -0,0 +1,27 @@ +package dto; + +public class RequestDTO { + private String message; + + public RequestDTO() { + } + + public RequestDTO(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "RequestDTO{" + + "message='" + message + '\'' + + '}'; + } +} diff --git a/web-modules/play-modules/websockets/app/utils/MessageConverter.java b/web-modules/play-modules/websockets/app/utils/MessageConverter.java new file mode 100644 index 0000000000..85729cd1da --- /dev/null +++ b/web-modules/play-modules/websockets/app/utils/MessageConverter.java @@ -0,0 +1,24 @@ +package utils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import dto.MessageDTO; +import dto.RequestDTO; + +public class MessageConverter { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + public static MessageDTO jsonNodeToMessage(JsonNode jsonNode) { + return OBJECT_MAPPER.convertValue(jsonNode, MessageDTO.class); + } + + public static JsonNode messageToJsonNode(MessageDTO messageDTO) { + return OBJECT_MAPPER.convertValue(messageDTO, JsonNode.class); + } + public static RequestDTO jsonNodeToRequest(JsonNode jsonNode) { + return OBJECT_MAPPER.convertValue(jsonNode, RequestDTO.class); + } + + public static JsonNode requestToJsonNode(RequestDTO requestDTO) { + return OBJECT_MAPPER.convertValue(requestDTO, JsonNode.class); + } +} diff --git a/web-modules/play-modules/websockets/app/views/index.scala.html b/web-modules/play-modules/websockets/app/views/index.scala.html new file mode 100644 index 0000000000..b837fc6f74 --- /dev/null +++ b/web-modules/play-modules/websockets/app/views/index.scala.html @@ -0,0 +1,97 @@ +@(url: String) +@main("Welcome to Play") { +

Welcome to Play WebSockets!

+
+ + + + + + + + +} diff --git a/web-modules/play-modules/websockets/app/views/main.scala.html b/web-modules/play-modules/websockets/app/views/main.scala.html new file mode 100644 index 0000000000..be5dd8f09d --- /dev/null +++ b/web-modules/play-modules/websockets/app/views/main.scala.html @@ -0,0 +1,14 @@ +@(title: String)(content: Html) + + + + + @title + + + + + @content + + + diff --git a/web-modules/play-modules/websockets/build.sbt b/web-modules/play-modules/websockets/build.sbt new file mode 100644 index 0000000000..a076daa4f0 --- /dev/null +++ b/web-modules/play-modules/websockets/build.sbt @@ -0,0 +1,22 @@ +name := """websockets""" +organization := "com.baeldung" + +version := "1.0-SNAPSHOT" + +lazy val root = (project in file(".")).enablePlugins(PlayJava) + +scalaVersion := "2.13.0" + +lazy val akkaVersion = "2.6.0-M8" +lazy val akkaHttpVersion = "10.1.10" + +libraryDependencies += guice +libraryDependencies += "com.typesafe.akka" %% "akka-actor" % akkaVersion +libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % akkaVersion +libraryDependencies += "com.typesafe.akka" %% "akka-stream" % akkaVersion +libraryDependencies += "com.typesafe.akka" %% "akka-http-jackson" % akkaHttpVersion +libraryDependencies += "com.typesafe.akka" %% "akka-http" % akkaHttpVersion +libraryDependencies += "org.projectlombok" % "lombok" % "1.18.8" % "provided" +libraryDependencies += "junit" % "junit" % "4.12" + +PlayKeys.devSettings += "play.server.http.idleTimeout" -> "infinite" diff --git a/web-modules/play-modules/websockets/conf/application.conf b/web-modules/play-modules/websockets/conf/application.conf new file mode 100644 index 0000000000..87cb978051 --- /dev/null +++ b/web-modules/play-modules/websockets/conf/application.conf @@ -0,0 +1,7 @@ +# This is the main configuration file for the application. +# https://www.playframework.com/documentation/latest/ConfigFile +######################################## +# akka-http-core Reference Config File # +######################################## + +play.server.http.idleTimeout = "infinite" \ No newline at end of file diff --git a/web-modules/play-modules/websockets/conf/logback.xml b/web-modules/play-modules/websockets/conf/logback.xml new file mode 100644 index 0000000000..8efb66cda3 --- /dev/null +++ b/web-modules/play-modules/websockets/conf/logback.xml @@ -0,0 +1,37 @@ + + + + + + + ${application.home:-.}/logs/application.log + + %date [%level] from %logger in %thread - %message%n%xException + + + + + + %coloredLevel %logger{15} - %message%n%xException{10} + + + + + + + + + + + + + + + + + + + + + + diff --git a/web-modules/play-modules/websockets/conf/routes b/web-modules/play-modules/websockets/conf/routes new file mode 100644 index 0000000000..674aba00bd --- /dev/null +++ b/web-modules/play-modules/websockets/conf/routes @@ -0,0 +1,11 @@ +# Routes +# This file defines all application routes (Higher priority routes first) +# ~~~~ + +# An example controller showing a sample home page +GET / controllers.HomeController.index(request: Request) +GET /chat controllers.HomeController.socket +GET /chat/with/streams controllers.HomeController.akkaStreamsSocket + +# Map static resources from the /public folder to the /assets URL path +GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) diff --git a/web-modules/play-modules/websockets/project/build.properties b/web-modules/play-modules/websockets/project/build.properties new file mode 100644 index 0000000000..c0bab04941 --- /dev/null +++ b/web-modules/play-modules/websockets/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.2.8 diff --git a/web-modules/play-modules/websockets/project/plugins.sbt b/web-modules/play-modules/websockets/project/plugins.sbt new file mode 100644 index 0000000000..1c8c62a0d5 --- /dev/null +++ b/web-modules/play-modules/websockets/project/plugins.sbt @@ -0,0 +1,7 @@ +// The Play plugin +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3") + +// Defines scaffolding (found under .g8 folder) +// http://www.foundweekends.org/giter8/scaffolding.html +// sbt "g8Scaffold form" +addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0") diff --git a/web-modules/play-modules/websockets/public/images/favicon.png b/web-modules/play-modules/websockets/public/images/favicon.png new file mode 100644 index 0000000000..c7d92d2ae4 Binary files /dev/null and b/web-modules/play-modules/websockets/public/images/favicon.png differ diff --git a/web-modules/play-modules/websockets/public/javascripts/main.js b/web-modules/play-modules/websockets/public/javascripts/main.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/play-modules/websockets/public/stylesheets/main.css b/web-modules/play-modules/websockets/public/stylesheets/main.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web-modules/play-modules/websockets/test/controllers/HomeControllerTest.java b/web-modules/play-modules/websockets/test/controllers/HomeControllerTest.java new file mode 100644 index 0000000000..b006feab8c --- /dev/null +++ b/web-modules/play-modules/websockets/test/controllers/HomeControllerTest.java @@ -0,0 +1,32 @@ +package controllers; + +import org.junit.Test; +import play.Application; +import play.inject.guice.GuiceApplicationBuilder; +import play.mvc.Http; +import play.mvc.Result; +import play.test.WithApplication; + +import static org.junit.Assert.assertEquals; +import static play.mvc.Http.Status.OK; +import static play.test.Helpers.GET; +import static play.test.Helpers.route; + +public class HomeControllerTest extends WithApplication { + + @Override + protected Application provideApplication() { + return new GuiceApplicationBuilder().build(); + } + + @Test + public void giveRequest_whenRootPath_ThenStatusOkay() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/"); + + Result result = route(app, request); + assertEquals(OK, result.status()); + } + +} diff --git a/web-modules/pom.xml b/web-modules/pom.xml new file mode 100644 index 0000000000..2dcec681ad --- /dev/null +++ b/web-modules/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + web-modules + web-modules + pom + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + + + apache-tapestry + blade + bootique + dropwizard + google-web-toolkit + jakarta-ee + + javax-servlets + javax-servlets-2 + jee-7 + jooby + linkrest + + + + ratpack + resteasy + + spark-java + struts-2 + vraptor + wicket + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/web-modules/raml-modules/annotations/README.md b/web-modules/raml-modules/annotations/README.md new file mode 100644 index 0000000000..809a7a0ab1 --- /dev/null +++ b/web-modules/raml-modules/annotations/README.md @@ -0,0 +1,7 @@ +========= + +## Define Custom RAML + + +### Relevant Articles: +- [Define Custom RAML Properties Using Annotations](https://www.baeldung.com/raml-custom-properties-with-annotations) diff --git a/web-modules/raml-modules/modularization/README.md b/web-modules/raml-modules/modularization/README.md new file mode 100644 index 0000000000..bb7a3e889c --- /dev/null +++ b/web-modules/raml-modules/modularization/README.md @@ -0,0 +1,6 @@ +========= + +## Modular RESTful API Modeling Language + +### Relevant Articles: +- [Modular RAML Using Includes, Libraries, Overlays and Extensions](https://www.baeldung.com/modular-raml-includes-overlays-libraries-extensions) diff --git a/web-modules/raml-modules/resource-types-and-traits/README.md b/web-modules/raml-modules/resource-types-and-traits/README.md new file mode 100644 index 0000000000..973e59d7a5 --- /dev/null +++ b/web-modules/raml-modules/resource-types-and-traits/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Eliminate Redundancies in RAML with Resource Types and Traits](https://www.baeldung.com/simple-raml-with-resource-types-and-traits) diff --git a/web-modules/ratpack/README.md b/web-modules/ratpack/README.md new file mode 100644 index 0000000000..f42d4c030b --- /dev/null +++ b/web-modules/ratpack/README.md @@ -0,0 +1,14 @@ +## Ratpack + +This module contains articles about Ratpack. + +### Relevant articles + +- [Introduction to Ratpack](https://www.baeldung.com/ratpack) +- [Ratpack Google Guice Integration](https://www.baeldung.com/ratpack-google-guice) +- [Ratpack Integration with Spring Boot](http://www.baeldung.com/ratpack-spring-boot) +- [Ratpack with Hystrix](https://www.baeldung.com/ratpack-hystrix) +- [Ratpack HTTP Client](https://www.baeldung.com/ratpack-http-client) +- [Ratpack with RxJava](https://www.baeldung.com/ratpack-rxjava) +- [Ratpack with Groovy](https://www.baeldung.com/ratpack-groovy) +- [Reactive Streams API with Ratpack](https://www.baeldung.com/ratpack-reactive-streams-api) diff --git a/web-modules/ratpack/build.gradle b/web-modules/ratpack/build.gradle new file mode 100644 index 0000000000..f50c5b3800 --- /dev/null +++ b/web-modules/ratpack/build.gradle @@ -0,0 +1,37 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath "io.ratpack:ratpack-gradle:1.5.4" + classpath "com.h2database:h2:1.4.193" + } +} + +if (!JavaVersion.current().java8Compatible) { + throw new IllegalStateException("Must be built with Java 8 or higher") +} + +apply plugin: "io.ratpack.ratpack-java" +apply plugin: 'java' +apply plugin: 'groovy' +apply plugin: 'io.ratpack.ratpack-groovy' + +repositories { + jcenter() +} + +dependencies { + compile ratpack.dependency('hikari') + compile 'com.h2database:h2:1.4.193' + testCompile 'junit:junit:4.11' + runtime "org.slf4j:slf4j-simple:1.7.21" +} + +test { + testLogging { + events 'started', 'passed' + } +} + +mainClassName = "com.baeldung.Application" diff --git a/web-modules/ratpack/pom.xml b/web-modules/ratpack/pom.xml new file mode 100644 index 0000000000..1ef358cc55 --- /dev/null +++ b/web-modules/ratpack/pom.xml @@ -0,0 +1,111 @@ + + + 4.0.0 + ratpack + 1.0-SNAPSHOT + ratpack + jar + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + io.ratpack + ratpack-spring-boot-starter + ${ratpack.version} + pom + + + io.ratpack + ratpack-core + ${ratpack.version} + + + org.codehaus.groovy + groovy-sql + ${groovy.sql.version} + + + io.ratpack + ratpack-hikari + ${ratpack.version} + + + io.ratpack + ratpack-groovy-test + ${ratpack.test.latest.version} + + + io.ratpack + ratpack-hystrix + ${ratpack.version} + + + com.netflix.hystrix + hystrix-core + + + + + com.netflix.hystrix + hystrix-core + ${hystrix.version} + + + io.ratpack + ratpack-rx + ${ratpack.version} + + + io.ratpack + ratpack-test + ${ratpack.version} + test + + + com.h2database + h2 + ${h2.version} + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/java.lang=ALL-UNNAMED + + + + + + + + 1.9.0 + 4.5.3 + 4.4.6 + 1.5.12 + 2.4.15 + 1.6.1 + + + \ No newline at end of file diff --git a/web-modules/ratpack/src/main/java/com/baeldung/Application.java b/web-modules/ratpack/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..8035a1d0e3 --- /dev/null +++ b/web-modules/ratpack/src/main/java/com/baeldung/Application.java @@ -0,0 +1,82 @@ +package com.baeldung; + +import com.baeldung.filter.RequestValidatorFilter; +import com.baeldung.handler.EmployeeHandler; +import com.baeldung.handler.RedirectHandler; +import com.baeldung.model.Employee; +import com.baeldung.repository.EmployeeRepository; +import com.baeldung.repository.EmployeeRepositoryImpl; +import com.zaxxer.hikari.HikariConfig; +import io.netty.buffer.PooledByteBufAllocator; +import ratpack.exec.internal.DefaultExecController; +import ratpack.func.Action; +import ratpack.func.Function; +import ratpack.guice.BindingsSpec; +import ratpack.guice.Guice; +import ratpack.handling.Chain; +import ratpack.hikari.HikariModule; +import ratpack.http.client.HttpClient; +import ratpack.jackson.Jackson; +import ratpack.registry.Registry; +import ratpack.server.RatpackServer; +import ratpack.server.RatpackServerSpec; +import ratpack.server.ServerConfig; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; + +public class Application { + + public static void main(String[] args) throws Exception { + + final Action hikariConfigAction = hikariConfig -> { + hikariConfig.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); + hikariConfig.addDataSourceProperty("URL", "jdbc:h2:mem:baeldung;INIT=RUNSCRIPT FROM 'classpath:/DDL.sql'"); + }; + + final Action bindingsSpecAction = bindings -> bindings.module(HikariModule.class, hikariConfigAction); + final HttpClient httpClient = HttpClient.of(httpClientSpec -> { + httpClientSpec.poolSize(10) + .connectTimeout(Duration.of(60, ChronoUnit.SECONDS)) + .maxContentLength(ServerConfig.DEFAULT_MAX_CONTENT_LENGTH) + .responseMaxChunkSize(16384) + .readTimeout(Duration.of(60, ChronoUnit.SECONDS)) + .byteBufAllocator(PooledByteBufAllocator.DEFAULT).execController(new DefaultExecController(2)); + }); + final Function registryFunction = Guice.registry(bindingsSpecAction); + + final Action chainAction = chain -> chain.all(new RequestValidatorFilter()) + .get(ctx -> ctx.render("Welcome to baeldung ratpack!!!")) + .get("data/employees", ctx -> ctx.render(Jackson.json(createEmpList()))) + .get(":name", ctx -> ctx.render("Hello " + ctx.getPathTokens() + .get("name") + "!!!")) + .post(":amount", ctx -> ctx.render(" Amount $" + ctx.getPathTokens() + .get("amount") + " added successfully !!!")); + + final Action routerChainAction = routerChain -> { + routerChain.path("redirect", new RedirectHandler()) + .prefix("employee", empChain -> { + empChain.get(":id", new EmployeeHandler()); + }); + }; + final Action ratpackServerSpecAction = serverSpec -> serverSpec.registry(registryFunction) + .registryOf(registrySpec -> { + registrySpec.add(EmployeeRepository.class, new EmployeeRepositoryImpl()); + registrySpec.add(HttpClient.class, httpClient); + }) + .handlers(chain -> chain.insert(routerChainAction) + .insert(chainAction)); + + RatpackServer.start(ratpackServerSpecAction); + } + + private static List createEmpList() { + List employees = new ArrayList<>(); + employees.add(new Employee(1L, "Mr", "John Doe")); + employees.add(new Employee(2L, "Mr", "White Snow")); + return employees; + } + +} diff --git a/web-modules/ratpack/src/main/java/com/baeldung/model/Quote.java b/web-modules/ratpack/src/main/java/com/baeldung/model/Quote.java new file mode 100644 index 0000000000..009a85fa11 --- /dev/null +++ b/web-modules/ratpack/src/main/java/com/baeldung/model/Quote.java @@ -0,0 +1,107 @@ +package com.baeldung.model; + +import java.time.Instant; + +public class Quote { + + private Instant ts; + private String symbol; + private double value; + + public Quote() {} + + + public Quote(Instant ts, String symbol, double value) { + this.ts = ts; + this.symbol = symbol; + this.value = value; + } + + + /** + * @return the ts + */ + public Instant getTs() { + return ts; + } + + /** + * @param ts the ts to set + */ + public void setTs(Instant ts) { + this.ts = ts; + } + + /** + * @return the symbol + */ + public String getSymbol() { + return symbol; + } + + /** + * @param symbol the symbol to set + */ + public void setSymbol(String symbol) { + this.symbol = symbol; + } + + /** + * @return the value + */ + public double getValue() { + return value; + } + + /** + * @param value the value to set + */ + public void setValue(double value) { + this.value = value; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((symbol == null) ? 0 : symbol.hashCode()); + result = prime * result + ((ts == null) ? 0 : ts.hashCode()); + long temp; + temp = Double.doubleToLongBits(value); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Quote other = (Quote) obj; + if (symbol == null) { + if (other.symbol != null) + return false; + } else if (!symbol.equals(other.symbol)) + return false; + if (ts == null) { + if (other.ts != null) + return false; + } else if (!ts.equals(other.ts)) + return false; + if (Double.doubleToLongBits(value) != Double.doubleToLongBits(other.value)) + return false; + return true; + } + + + @Override + public String toString() { + return "Quote [ts=" + ts + ", symbol=" + symbol + ", value=" + value + "]"; + } + + +} diff --git a/web-modules/ratpack/src/main/java/com/baeldung/repository/EmployeeRepository.java b/web-modules/ratpack/src/main/java/com/baeldung/repository/EmployeeRepository.java new file mode 100644 index 0000000000..2b23f91877 --- /dev/null +++ b/web-modules/ratpack/src/main/java/com/baeldung/repository/EmployeeRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.repository; + +import com.baeldung.model.Employee; +import ratpack.exec.Promise; + +public interface EmployeeRepository { + + Promise findEmployeeById(Long id) throws Exception; + +} diff --git a/web-modules/ratpack/src/main/java/com/baeldung/rxjava/service/QuotesService.java b/web-modules/ratpack/src/main/java/com/baeldung/rxjava/service/QuotesService.java new file mode 100644 index 0000000000..7c073ee1de --- /dev/null +++ b/web-modules/ratpack/src/main/java/com/baeldung/rxjava/service/QuotesService.java @@ -0,0 +1,44 @@ +package com.baeldung.rxjava.service; + +import java.time.Duration; +import java.time.Instant; +import java.util.Random; +import java.util.concurrent.ScheduledExecutorService; + +import org.reactivestreams.Publisher; + +import com.baeldung.model.Quote; + +import ratpack.stream.Streams; + +public class QuotesService { + + private final ScheduledExecutorService executorService; + private static Random rnd = new Random(); + private static String[] symbols = new String[] { + "MSFT", + "ORCL", + "GOOG", + "AAPL", + "CSCO" + }; + + public QuotesService(ScheduledExecutorService executorService) { + this.executorService = executorService; + } + + public Publisher newTicker() { + return Streams.periodically(executorService, Duration.ofSeconds(2), (t) -> { + + return randomQuote(); + }); + } + + private static Quote randomQuote() { + return new Quote ( + Instant.now(), + symbols[rnd.nextInt(symbols.length)], + Math.round(rnd.nextDouble()*100) + ); + } +} diff --git a/web-modules/ratpack/src/main/java/com/baeldung/spring/EmbedRatpackStreamsApp.java b/web-modules/ratpack/src/main/java/com/baeldung/spring/EmbedRatpackStreamsApp.java new file mode 100644 index 0000000000..dc66efbecb --- /dev/null +++ b/web-modules/ratpack/src/main/java/com/baeldung/spring/EmbedRatpackStreamsApp.java @@ -0,0 +1,206 @@ +package com.baeldung.spring; + +import java.util.Random; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.atomic.AtomicLong; + +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import com.baeldung.model.Quote; +import com.baeldung.rxjava.service.QuotesService; + +import groovy.util.logging.Slf4j; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import ratpack.func.Action; +import ratpack.handling.Chain; +import ratpack.http.ResponseChunks; +import ratpack.http.Status; +import ratpack.server.ServerConfig; +import ratpack.spring.config.EnableRatpack; +import ratpack.sse.ServerSentEvents; +import ratpack.stream.Streams; +import ratpack.stream.TransformablePublisher; +import ratpack.websocket.WebSockets; +import rx.subscriptions.Subscriptions; + +/** + * @author psevestre + */ +@SpringBootApplication +@EnableRatpack +public class EmbedRatpackStreamsApp { + + private static final Logger log = LoggerFactory.getLogger(EmbedRatpackStreamsApp.class); + + @Autowired + private QuotesService quotesService; + + private AtomicLong idSeq = new AtomicLong(0); + + + @Bean + public ScheduledExecutorService executorService() { + return Executors.newScheduledThreadPool(1); + } + + @Bean + public QuotesService quotesService(ScheduledExecutorService executor) { + return new QuotesService(executor); + } + + @Bean + public Action quotes() { + ServerSentEvents sse = ServerSentEvents.serverSentEvents(quotesService.newTicker(), (evt) -> { + evt + .id(Long.toString(idSeq.incrementAndGet())) + .event("quote") + .data( q -> q.toString()); + }); + + return chain -> chain.get("quotes", ctx -> ctx.render(sse)); + } + + @Bean + public Action quotesWS() { + Publisher pub = Streams.transformable(quotesService.newTicker()) + .map(Quote::toString); + return chain -> chain.get("quotes-ws", ctx -> WebSockets.websocketBroadcast(ctx, pub)); + } + + @Bean + public Action uploadFile() { + + return chain -> chain.post("upload", ctx -> { + TransformablePublisher pub = ctx.getRequest().getBodyStream(); + pub.subscribe(new Subscriber() { + private Subscription sub; + @Override + public void onSubscribe(Subscription sub) { + this.sub = sub; + sub.request(1); + } + + @Override + public void onNext(ByteBuf t) { + try { + int len = t.readableBytes(); + log.info("Got {} bytes", len); + + // Do something useful with data + + // Request next chunk + sub.request(1); + } + finally { + // DO NOT FORGET to RELEASE ! + t.release(); + } + } + + @Override + public void onError(Throwable t) { + ctx.getResponse().status(500); + } + + @Override + public void onComplete() { + ctx.getResponse().status(202); + } + }); + }); + } + + @Bean + public Action download() { + return chain -> chain.get("download", ctx -> { + ctx.getResponse().sendStream(new RandomBytesPublisher(1024,512)); + }); + } + + @Bean + public Action downloadChunks() { + return chain -> chain.get("downloadChunks", ctx -> { + ctx.render(ResponseChunks.bufferChunks("application/octetstream", + new RandomBytesPublisher(1024,512))); + }); + } + + @Bean + public ServerConfig ratpackServerConfig() { + return ServerConfig + .builder() + .findBaseDir("public") + .build(); + } + + public static void main(String[] args) { + SpringApplication.run(EmbedRatpackStreamsApp.class, args); + } + + + public static class RandomBytesPublisher implements Publisher { + + private int bufCount; + private int bufSize; + private Random rnd = new Random(); + + + RandomBytesPublisher(int bufCount, int bufSize) { + this.bufCount = bufCount; + this.bufSize = bufSize; + } + + @Override + public void subscribe(Subscriber s) { + s.onSubscribe(new Subscription() { + + private boolean cancelled = false; + private boolean recurse; + private long requested = 0; + + @Override + public void request(long n) { + if ( bufCount == 0 ) { + s.onComplete(); + return; + } + + requested += n; + if ( recurse ) { + return; + } + + recurse = true; + try { + while ( requested-- > 0 && !cancelled && bufCount-- > 0 ) { + byte[] data = new byte[bufSize]; + rnd.nextBytes(data); + ByteBuf buf = Unpooled.wrappedBuffer(data); + s.onNext(buf); + } + } + finally { + recurse = false; + } + } + + @Override + public void cancel() { + cancelled = true; + } + }); + + } + } + +} diff --git a/web-modules/ratpack/src/main/resources/logback.xml b/web-modules/ratpack/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/ratpack/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/ratpack/src/test/java/com/baeldung/ratpack/CompliantPublisher.java b/web-modules/ratpack/src/test/java/com/baeldung/ratpack/CompliantPublisher.java new file mode 100644 index 0000000000..5526a630ff --- /dev/null +++ b/web-modules/ratpack/src/test/java/com/baeldung/ratpack/CompliantPublisher.java @@ -0,0 +1,63 @@ +package com.baeldung.ratpack; + +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +// Non-thread safe !!! +class CompliantPublisher implements Publisher { + String name; + + private static final Logger log = LoggerFactory.getLogger(CompliantPublisher.class); + private long available; + + + public CompliantPublisher(long available) { + this.available = available; + } + + @Override + public void subscribe(Subscriber subscriber) { + log.info("subscribe"); + subscriber.onSubscribe(new CompliantSubscription(subscriber)); + + } + + + private class CompliantSubscription implements Subscription { + + private Subscriber subscriber; + private int recurseLevel; + private long requested; + private boolean cancelled; + + public CompliantSubscription(Subscriber subscriber) { + this.subscriber = subscriber; + } + + @Override + public void request(long n) { + log.info("request: requested={}, available={}", n, available); + requested += n; + if ( recurseLevel > 0 ) { + return; + } + + recurseLevel++; + for (int i = 0 ; i < (requested) && !cancelled && available > 0 ; i++, available-- ) { + subscriber.onNext(i); + } + subscriber.onComplete(); + } + + @Override + public void cancel() { + cancelled = true; + } + + } + +} \ No newline at end of file diff --git a/web-modules/ratpack/src/test/java/com/baeldung/ratpack/LoggingSubscriber.java b/web-modules/ratpack/src/test/java/com/baeldung/ratpack/LoggingSubscriber.java new file mode 100644 index 0000000000..0d58b7c05e --- /dev/null +++ b/web-modules/ratpack/src/test/java/com/baeldung/ratpack/LoggingSubscriber.java @@ -0,0 +1,67 @@ +package com.baeldung.ratpack; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class LoggingSubscriber implements Subscriber { + private static final Logger log = LoggerFactory.getLogger(LoggingSubscriber.class); + + private Subscription subscription; + private long requested; + private long received; + private CountDownLatch finished = new CountDownLatch(1); + + @Override + public void onComplete() { + log.info("onComplete: sub={}", subscription.hashCode()); + finished.countDown(); + } + + @Override + public void onError(Throwable t) { + log.error("Error: sub={}, message={}", subscription.hashCode(), t.getMessage(),t); + finished.countDown(); + } + + @Override + public void onNext(T value) { + log.info("onNext: sub={}, value={}", subscription.hashCode(), value); + this.received++; + this.requested++; + subscription.request(1); + } + + @Override + public void onSubscribe(Subscription sub) { + log.info("onSubscribe: sub={}", sub.hashCode()); + this.subscription = sub; + this.received = 0; + this.requested = 1; + sub.request(1); + } + + + public long getRequested() { + return requested; + } + + public long getReceived() { + return received; + } + + public void block() { + try { + finished.await(10, TimeUnit.SECONDS); + } + catch(InterruptedException iex) { + throw new RuntimeException(iex); + } + } + +} diff --git a/web-modules/ratpack/src/test/java/com/baeldung/ratpack/NonCompliantPublisher.java b/web-modules/ratpack/src/test/java/com/baeldung/ratpack/NonCompliantPublisher.java new file mode 100644 index 0000000000..03b94d429d --- /dev/null +++ b/web-modules/ratpack/src/test/java/com/baeldung/ratpack/NonCompliantPublisher.java @@ -0,0 +1,46 @@ +package com.baeldung.ratpack; + +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class NonCompliantPublisher implements Publisher { + + private static final Logger log = LoggerFactory.getLogger(NonCompliantPublisher.class); + + @Override + public void subscribe(Subscriber subscriber) { + log.info("subscribe"); + subscriber.onSubscribe(new NonCompliantSubscription(subscriber)); + } + + private class NonCompliantSubscription implements Subscription { + private Subscriber subscriber; + private int recurseLevel = 0; + + public NonCompliantSubscription(Subscriber subscriber) { + this.subscriber = subscriber; + } + + @Override + public void request(long n) { + log.info("request: n={}", n); + if ( recurseLevel > 0 ) { + return; + } + + recurseLevel++; + for (int i = 0 ; i < (n + 5) ; i ++ ) { + subscriber.onNext(i); + } + subscriber.onComplete(); + } + + @Override + public void cancel() { + } + } +} \ No newline at end of file diff --git a/web-modules/ratpack/src/test/java/com/baeldung/ratpack/RatpackStreamsUnitTest.java b/web-modules/ratpack/src/test/java/com/baeldung/ratpack/RatpackStreamsUnitTest.java new file mode 100644 index 0000000000..54cc71c328 --- /dev/null +++ b/web-modules/ratpack/src/test/java/com/baeldung/ratpack/RatpackStreamsUnitTest.java @@ -0,0 +1,140 @@ +package com.baeldung.ratpack; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import org.junit.jupiter.api.Test; +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ratpack.exec.ExecResult; +import ratpack.func.Action; +import ratpack.stream.StreamEvent; +import ratpack.stream.Streams; +import ratpack.stream.TransformablePublisher; +import ratpack.test.exec.ExecHarness; + +public class RatpackStreamsUnitTest { + + private static Logger log = LoggerFactory.getLogger(RatpackStreamsUnitTest.class); + + @Test + public void whenPublish_thenSuccess() { + + Publisher pub = Streams.publish(Arrays.asList("hello", "hello again")); + LoggingSubscriber sub = new LoggingSubscriber(); + pub.subscribe(sub); + sub.block(); + } + + + @Test + public void whenYield_thenSuccess() { + + Publisher pub = Streams.yield((t) -> { + return t.getRequestNum() < 5 ? "hello" : null; + }); + + LoggingSubscriber sub = new LoggingSubscriber(); + pub.subscribe(sub); + sub.block(); + assertEquals(5, sub.getReceived()); + } + + @Test + public void whenPeriodic_thenSuccess() { + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + Publisher pub = Streams.periodically(executor, Duration.ofSeconds(1), (t) -> { + return t < 5 ? String.format("hello %d",t): null; + }); + + LoggingSubscriber sub = new LoggingSubscriber(); + pub.subscribe(sub); + sub.block(); + assertEquals(5, sub.getReceived()); + } + + @Test + public void whenMap_thenSuccess() throws Exception { + + TransformablePublisher pub = Streams.yield( t -> { + return t.getRequestNum() < 5 ? t.getRequestNum() : null; + }) + .map(v -> String.format("item %d", v)); + + ExecResult> result = ExecHarness.yieldSingle((c) -> pub.toList() ); + assertTrue("should succeed", result.isSuccess()); + assertEquals("should have 5 items",5,result.getValue().size()); + } + + @Test + public void whenNonCompliantPublisherWithBuffer_thenSuccess() throws Exception { + + TransformablePublisher pub = Streams.transformable(new NonCompliantPublisher()) + .wiretap(new LoggingAction("before buffer")) + .buffer() + .wiretap(new LoggingAction("after buffer")) + .take(1); + + LoggingSubscriber sub = new LoggingSubscriber<>(); + pub.subscribe(sub); + sub.block(); + } + + @Test + public void whenNonCompliantPublisherWithoutBuffer_thenSuccess() throws Exception { + TransformablePublisher pub = Streams.transformable(new NonCompliantPublisher()) + .wiretap(new LoggingAction("")) + .take(1); + + LoggingSubscriber sub = new LoggingSubscriber<>(); + pub.subscribe(sub); + sub.block(); + } + +@Test +public void whenCompliantPublisherWithoutBatch_thenSuccess() throws Exception { + + TransformablePublisher pub = Streams.transformable(new CompliantPublisher(10)) + .wiretap(new LoggingAction("")); + + LoggingSubscriber sub = new LoggingSubscriber<>(); + pub.subscribe(sub); + sub.block(); +} + +@Test +public void whenCompliantPublisherWithBatch_thenSuccess() throws Exception { + + TransformablePublisher pub = Streams.transformable(new CompliantPublisher(10)) + .wiretap(new LoggingAction("before batch")) + .batch(5, Action.noop()) + .wiretap(new LoggingAction("after batch")); + + LoggingSubscriber sub = new LoggingSubscriber<>(); + pub.subscribe(sub); + sub.block(); +} + + private static class LoggingAction implements Action>{ + private final String label; + + public LoggingAction(String label) { + this.label = label; + } + + @Override + public void execute(StreamEvent e) throws Exception { + log.info("{}: event={}", label,e); + } + + } + +} diff --git a/web-modules/resteasy/pom.xml b/web-modules/resteasy/pom.xml new file mode 100644 index 0000000000..355dcdb9b5 --- /dev/null +++ b/web-modules/resteasy/pom.xml @@ -0,0 +1,135 @@ + + + 4.0.0 + resteasy + 1.0 + resteasy + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + + org.jboss.resteasy + resteasy-servlet-initializer + ${resteasy.version} + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + + + + org.jboss.resteasy + resteasy-jaxb-provider + ${resteasy.version} + + + org.jboss.resteasy + resteasy-jackson2-provider + ${resteasy.version} + + + javax.servlet + javax.servlet-api + 4.0.1 + + + + + resteasy + + + org.codehaus.cargo + cargo-maven2-plugin + ${cargo-maven2-plugin.version} + + true + + jetty8x + embedded + + + + 8082 + + + + + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*IntegrationTest.java + **/*IntTest.java + + + **/*LiveTest.java + + + + + + + json + + + + + org.codehaus.cargo + cargo-maven2-plugin + ${cargo-maven2-plugin.version} + + false + + + + start-server + pre-integration-test + + start + + + + stop-server + post-integration-test + + stop + + + + + + + + + + + 4.7.2.Final + 1.6.1 + + + \ No newline at end of file diff --git a/web-modules/resteasy/src/main/resources/logback.xml b/web-modules/resteasy/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/resteasy/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/resteasy/src/main/webapp/WEB-INF/classes/logback.xml b/web-modules/resteasy/src/main/webapp/WEB-INF/classes/logback.xml new file mode 100644 index 0000000000..ec0dc2469a --- /dev/null +++ b/web-modules/resteasy/src/main/webapp/WEB-INF/classes/logback.xml @@ -0,0 +1,19 @@ + + + + + web - %date [%thread] %-5level %logger{36} - %message%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-modules/restx/pom.xml b/web-modules/restx/pom.xml new file mode 100644 index 0000000000..0e6cb3fa78 --- /dev/null +++ b/web-modules/restx/pom.xml @@ -0,0 +1,144 @@ + + + 4.0.0 + restx + 0.1-SNAPSHOT + restx + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + io.restx + restx-core + ${restx.version} + + + io.restx + restx-security-basic + ${restx.version} + + + io.restx + restx-core-annotation-processor + ${restx.version} + + + io.restx + restx-factory + ${restx.version} + + + io.restx + restx-factory-admin + ${restx.version} + + + io.restx + restx-validation + ${restx.version} + + + io.restx + restx-monitor-codahale + ${restx.version} + + + io.restx + restx-monitor-admin + ${restx.version} + + + io.restx + restx-log-admin + ${restx.version} + + + io.restx + restx-i18n-admin + ${restx.version} + + + io.restx + restx-stats-admin + ${restx.version} + + + io.restx + restx-servlet + ${restx.version} + + + io.restx + restx-server-jetty8 + ${restx.version} + true + + + io.restx + restx-apidocs + ${restx.version} + + + io.restx + restx-specs-admin + ${restx.version} + + + io.restx + restx-admin + ${restx.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + io.restx + restx-specs-tests + ${restx.version} + test + + + junit + junit + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-docs + + + + prepare-package + + jar + + + + + + + + + 0.35-rc4 + 1.6.0 + + + \ No newline at end of file diff --git a/web-modules/restx/src/main/resources/restx/demo/settings.properties b/web-modules/restx/src/main/resources/restx/demo/settings.properties new file mode 100644 index 0000000000..3b2b591922 --- /dev/null +++ b/web-modules/restx/src/main/resources/restx/demo/settings.properties @@ -0,0 +1,2 @@ +app.name=restx-demo +restx.stats.share.enable=false \ No newline at end of file diff --git a/web-modules/restx/src/test/java/restx/demo/rest/HelloResourceSpecIntegrationTest.java b/web-modules/restx/src/test/java/restx/demo/rest/HelloResourceSpecIntegrationTest.java new file mode 100644 index 0000000000..6ff1a7aad4 --- /dev/null +++ b/web-modules/restx/src/test/java/restx/demo/rest/HelloResourceSpecIntegrationTest.java @@ -0,0 +1,23 @@ +package restx.demo.rest; + +import org.junit.runner.RunWith; + +import restx.tests.FindSpecsIn; +import restx.tests.RestxSpecTestsRunner; + +@RunWith(RestxSpecTestsRunner.class) +@FindSpecsIn("specs/hello") +public class HelloResourceSpecIntegrationTest { + + /** + * Useless, thanks to both @RunWith(RestxSpecTestsRunner.class) & @FindSpecsIn() + * + * @Rule + * public RestxSpecRule rule = new RestxSpecRule(); + * + * @Test + * public void test_spec() throws Exception { + * rule.runTest(specTestPath); + * } + */ +} diff --git a/web-modules/spark-java/pom.xml b/web-modules/spark-java/pom.xml new file mode 100644 index 0000000000..da09467212 --- /dev/null +++ b/web-modules/spark-java/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + spark-java + 0.1.0-SNAPSHOT + spark-java + http://maven.apache.org + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + com.sparkjava + spark-core + ${sparkjava.spark-core.version} + + + + com.google.code.gson + gson + ${google.code.gson.version} + + + + + 2.5.4 + 2.8.0 + + + \ No newline at end of file diff --git a/web-modules/spark-java/src/main/resources/logback.xml b/web-modules/spark-java/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/spark-java/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/struts-2/WebContent/result.jsp b/web-modules/struts-2/WebContent/result.jsp new file mode 100644 index 0000000000..d095a493ec --- /dev/null +++ b/web-modules/struts-2/WebContent/result.jsp @@ -0,0 +1,11 @@ +<%@ page contentType="text/html; charset=UTF-8" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + +Hello World + + +

Hello Baeldung User

+

You are a

+ + diff --git a/web-modules/struts-2/pom.xml b/web-modules/struts-2/pom.xml new file mode 100644 index 0000000000..8b19bd530f --- /dev/null +++ b/web-modules/struts-2/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + struts-2 + struts-2 + pom + + + com.baeldung + parent-spring-4 + 0.0.1-SNAPSHOT + ../../parent-spring-4 + + + + + org.apache.struts + struts2-core + ${struts2.version} + + + org.apache.struts + struts2-junit-plugin + ${struts2.version} + + + org.apache.struts + struts2-convention-plugin + ${struts2-convention-plugin.version} + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + + + org.springframework + spring-core + ${spring.version} + + + commons-logging + commons-logging + + + + + + + src/main/java + + + src/main/resources + + + + + maven-war-plugin + ${maven-war-plugin.version} + + WebContent + + + + + + + 2.5.5 + 2.5.8 + 4.3.6.RELEASE + + + \ No newline at end of file diff --git a/web-modules/struts-2/src/main/resources/logback.xml b/web-modules/struts-2/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/struts-2/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/web-modules/vraptor/pom.xml b/web-modules/vraptor/pom.xml new file mode 100644 index 0000000000..ecc6fe3313 --- /dev/null +++ b/web-modules/vraptor/pom.xml @@ -0,0 +1,127 @@ + + + 4.0.0 + vraptor + vraptor + war + A demo project to start using VRaptor 4 + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + br.com.caelum + vraptor + ${vraptor.version} + + + org.jboss.weld.servlet + weld-servlet-core + ${weld.version} + + + org.jboss.spec.javax.el + jboss-el-api_3.0_spec + + + + + org.jboss.weld + weld-core-impl + ${weld.version} + + + org.jboss.spec.javax.el + jboss-el-api_3.0_spec + + + + + javax.el + el-api + ${el.version} + provided + + + org.hibernate + hibernate-validator-cdi + ${hibernate-validator.version} + + + javax.servlet + jstl + ${jstl.version} + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + provided + + + org.slf4j + slf4j-log4j12 + ${org.slf4j.version} + + + br.com.caelum.vraptor + vraptor-freemarker + ${vraptor-freemarker.version} + + + br.com.caelum.vraptor + vraptor-hibernate + ${vraptor-hibernate.version} + + + mysql + mysql-connector-java + ${mysql-connector.version} + + + org.mindrot + jbcrypt + ${jbcrypt.version} + + + org.freemarker + freemarker + ${freemarker.version} + + + + + vraptor + src/main/webapp/WEB-INF/classes + + + org.apache.tomcat.maven + tomcat7-maven-plugin + ${tomcat7-maven-plugin.version} + + / + + + + + + + 4.2.0.Final + 2.1.2.Final + 2.2 + 5.1.1.Final + 4.1.0-RC3 + 4.0.4 + 8.0.8-dmr + 0.4 + 2.3.27-incubating + 2.1 + + + \ No newline at end of file diff --git a/web-modules/vraptor/src/main/java/com/baeldung/daos/UserDao.java b/web-modules/vraptor/src/main/java/com/baeldung/daos/UserDao.java new file mode 100644 index 0000000000..f5d5a46de9 --- /dev/null +++ b/web-modules/vraptor/src/main/java/com/baeldung/daos/UserDao.java @@ -0,0 +1,47 @@ +package com.baeldung.daos; + +import com.baeldung.models.User; +import org.hibernate.Criteria; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.criterion.Restrictions; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; + +@RequestScoped +public class UserDao { + + SessionFactory sessionFactory; + + public UserDao() { + this(null); + } + + @Inject + public UserDao(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + + public Object add(User user) { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + Object Id = session.save(user); + session.getTransaction().commit(); + return Id; + } + + public User findByEmail(String email) { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + Criteria criteria = session.createCriteria(User.class); + criteria.add(Restrictions.eq("email", email)); + criteria.setMaxResults(1); + User u = (User) criteria.uniqueResult(); + session.getTransaction().commit(); + session.close(); + return u; + } + +} diff --git a/web-modules/wicket/pom.xml b/web-modules/wicket/pom.xml new file mode 100644 index 0000000000..244d176e25 --- /dev/null +++ b/web-modules/wicket/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + com.baeldung.wicket.examples + wicket + 1.0-SNAPSHOT + wicket + war + + + com.baeldung + web-modules + 1.0.0-SNAPSHOT + + + + + + org.apache.wicket + wicket-core + ${wicket.version} + + + + org.eclipse.jetty.aggregate + jetty-all + ${jetty9.version} + test + + + + + + + false + src/main/resources + + + false + src/main/java + + ** + + + **/*.java + + + + + + false + src/test/resources + + + false + src/test/java + + ** + + + **/*.java + + + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty9.version} + + + + + + 7.5.0 + 9.2.13.v20150730 + + + \ No newline at end of file diff --git a/web-modules/wicket/src/main/resources/logback.xml b/web-modules/wicket/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/web-modules/wicket/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file