Read data from Redis to Flink - redis

I have been trying to find a connector to read data from Redis to Flink. Flink's documentation contains the description for a connector to write to Redis. I need to read data from Redis in my Flink job. In Using Apache Flink for data streaming, Fabian has mentioned that it is possible to read data from Redis. What is the connector that can be used for the purpose?

We are running one in production that looks roughly like this
class RedisSource extends RichSourceFunction[SomeDataType] {
var client: RedisClient = _
override def open(parameters: Configuration) = {
client = RedisClient() // init connection etc
}
#volatile var isRunning = true
override def cancel(): Unit = {
isRunning = false
client.close()
}
override def run(ctx: SourceContext[SomeDataType]): Unit = while (isRunning) {
for {
data <- ??? // get some data from the redis client
} yield ctx.collect(SomeDataType(data))
}
}
I think it really depends on what you need to fetch from redis. The above could be used to fetch a message from a list/queue, transform/push and then delete it form the queue.
Redis also supports Pub/Sub, so it would possible to subscribe, grab the SourceConext and push messages downstream.

Currently, Flink Redis Connector is not available but it can be implemented by extending RichSinkFunction/SinkFunction class.
public class RedisSink extends RichSinkFunction<String> {
#Override
public void open(Configuration parameters) throws Exception {
//open redis connection
}
#Override
public void invoke(String map) throws Exception {
//sink data to redis
}
#Override
public void close() throws Exception {
super.close();
}
}

There's been a bit of discussion about having a streaming redis source connector for Apache Flink (see FLINK-3033), but there isn't one available. It shouldn't be difficult to implement one, however.

One of challenges in getting your Flink program to use Jedis to talk to Redis is getting the appropriate libraries into the JAR file you submit to Flink. Absent this, you will get call stacks indicating certain classes are undefined. Here is a snippet of a Maven pom.xml I created to move Redis and its dependent component, apache commons-pool2, into my JAR.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>unpack</id>
<!-- executed just before the package phase -->
<!-- https://ci.apache.org/projects/flink/flink-docs-release-1.3/dev/linking.html -->
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<includes>org/apache/commons/**</includes>
</artifactItem>
<artifactItem>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<includes>redis/clients/**</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

Related

Bean Validation on Jax-RS Resource stops working while using CDI on Apache TomEE 8.0.10

I'm having troubles getting bean validation to work with the following minimalised project consisting only of this three java files plus pom.xml. I'm using Apache TomEE 8.0.10.
LoginMessage.java
package org.example;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.validation.constraints.NotBlank;
#Getter
#Setter
#ToString
public class LoginMessage {
#NotBlank
private String username;
#NotBlank
private String password;
}
SessionService.java
package org.example;
import lombok.extern.java.Log;
import javax.enterprise.context.RequestScoped;
#Log
#RequestScoped
public class SessionService {
public void login(final LoginMessage loginMessage) {
log.info(loginMessage.toString());
}
}
SessionController.java
package org.example;
import lombok.extern.java.Log;
import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
#Log
#Path("/session")
public class SessionController {
#Inject
private SessionService sessionService;
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void postLoginMessage(#Valid final LoginMessage loginMessage) {
sessionService.login(loginMessage);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<groupId>org.example</groupId>
<artifactId>beanval</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
</project>
If you post an empty JSON object it ignores the #Valid annotation in SessionController#postLoginMessage() and directly outputs the log message containing the toString() content of the LoginMessage object through SessionService#login() method.
POST http://localhost:8080/beanval-1.0-SNAPSHOT/session
Content-Type: application/json
{
}
13-Mar-2022 01:30:39.700 INFORMATION [http-nio-8080-exec-6] SessionService.login LoginMessage(username=null, password=null)
If you remove or comment out the #RequestScoped annotation from SessionService and post the empty JSON-Object after restart of TomEE then bean validation works and logs:
13-Mar-2022 01:52:51.594 WARNUNG [http-nio-8080-exec-6] org.apache.cxf.jaxrs.validation.ValidationExceptionMapper.toResponse Value (null) of SessionController.postLoginMessage.arg0.password: must not be blank
13-Mar-2022 01:52:51.595 WARNUNG [http-nio-8080-exec-6] org.apache.cxf.jaxrs.validation.ValidationExceptionMapper.toResponse Value (null) of SessionController.postLoginMessage.arg0.username: must not be blank
I would like to use CDI in combination with Bean-Validation in JAX-RS Resource.
What am I doing wrong?
Thanks in advance.
This appears to be a bug in OpenWebBeans or TomEE. So what's happening is the first the actual instance of the bean is managed by JAX-RS, and the second, the bean is managed by the CDI container. In the second case, there needs to be some sort of interceptor the invokes the Bean Validation framework.
I would start a discussion on the mailing list and open a bug on in the JIRA. If you can create a sample project that reproduces the problem it helps the devs out tremendously.
As a workaround, you can #Inject private Validator validator and if there are any constraint violations returned, throw new ConstraintViolationException(constraintViolations);.
After all to come up to some kind of a solution I will stop using bean validation at controller layer. It works at service layer and so I can continue to work on my web app.
The solution is using the #Valid annotation in SessionService#login() method and remove it from SessionController#postLoginMessage() method.
If it is really a bug in TomEE the alternative could also be to use another application server until it is fixed.

Unable to use aspectJ interceptor in a non-spring project

I am trying to use Aspectj to execute some code after some method execution. I cannot use spring AOP as the project is a non-spring project and at this point of time I cannot change it to spring project. I have tried with a very simple implementation as below but it is not at all working:
POM of my project
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test.aspectj</groupId>
<artifactId>HelloAspectj</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.plugin.version>3.5.1</maven.compiler.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
A normal class and method after which the aspect methods will run:
package tester;
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
}
public void printHello() {
System.out.println("Spring 3 : Hello ! " + name);
}
}
Aspect class
package tester;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class TestAspect {
#Before(" call(void java.io.PrintStream.println(String)) " +
"&& !within(net.andrewewhite.aspects..*)")
public void beforePrintlnCall() {
System.out.println("About to make call to print Hello World");
}
#After(" call(void java.io.PrintStream.println(String)) " +
"&& !within(net.andrewewhite.aspects..*)")
public void afterPrintlnCall() {
System.out.println("Just made call to print Hello World");
}
}
Main class
package tester;
public class MainApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Hello World");
}
}
aop.xml
<aspectj>
<aspects>
<aspect name="tester.TestAspect"/>
</aspects>
</aspectj>
Project Structure:
Now i am expecting that it will price About to make call to print Hello World & Just made call to print Hello World BUt it is only printing Hello World
can someone help here..
If you want to use compile-time weaving, use
Mojohaus AspectJ Maven plugin until Java 8 and AspectJ 1.8.x or
Nick Wongdev's AspectJ Maven fork for Java 9+.
Javac via Maven Compiler plugin is not enough.
If you wish to use load-time weaving (LTW), it should be okay to compile your aspects with Javac via Maven Compiler plugin, as long as you only use annotation-driven #AspectJ syntax. For native AspectJ syntax you always need the AspectJ compiler Ajc via AspectJ Maven plugin, no matter what. For LTW you also need the weaving agent on the Java command line via -javaagent:/path/to/aspectjweaver.jar. There is also a hot-attachment option, but that is advanced stuff and you need to know what you are doing and the application must know that it wants to attach the weaver, so let's not talk about this here, as you are clearly a beginner.
All of this has been documented on the AspectJ website and the AspectJ Maven website. I have also answered numerous questions about AspectJ + Maven here, you should easily find some. Before asking questions, you should really search first. This website does not replace manuals and tutorials.

#MicronautTest does not start the embedded server

I am writing a Spock test for controllers in an app using Micronaut. When using #MicronautTest(application=Application), it throws exception with message #MicronautTest used on test but no bean definition for the test present..
On examining the code, I see the following 2 reasons why Micronaut throws this exception. From io.micronaut.test.extensions.spock.MicronautSpockExtension :
if (this.specDefinition == null) {
if (!this.isTestSuiteBeanPresent((Class)spec.getReflection())) {
throw new InvalidSpecException("#MicronautTest used on test but no bean definition for the test present. This error indicates a misconfigured build or IDE. Please add the 'micronaut-inject-java' annotation processor to your test processor path (for Java this is the testAnnotationProcessor scope, for Kotlin kaptTest and for Groovy testCompile). See the documentation for reference: https://micronaut-projects.github.io/micronaut-test/latest/guide/");
}
...
}
My POM configuration is:
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<goals>
<goal>addTestSources</goal>
<goal>addSources</goal>
<goal>compileTests</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-inject-java</artifactId>
<version>${micronaut.version}</version>
</path>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-validation</artifactId>
<version>${micronaut.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
<executions>
<execution>
<id>test-compile</id>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-inject-java</artifactId>
<version>${micronaut.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
</plugin>
If I do not define the annotation the test #MicronautTest, it seems that the application doesn't even start.
Below is the spec code:
#MicronautTest(application= Application)
#PropertySource(value = [
#Property(name='spec.name', value = 'EndpointSpec'),
#Property(name = 'endpoints.health.details-visible', value = 'ANONYMOUS'),
#Property(name = MongoSettings.EMBEDDED, value = 'true'),
])
class EndpointSpec extends Specification {
#Inject
EmbeddedServer embeddedServer
#Inject
ApplicationContext applicationContext
#Unroll
def "test health endpoint is working"() {
given: 'a RxHttpClient'
URL server = embeddedServer.getURL()
RxHttpClient client = new DefaultHttpClient(server, new DefaultHttpClientConfiguration(), '/management')
when: '/health is called'
HttpResponse response = client.toBlocking().exchange('/health')
then: 'response is 200 OK and contains valid headers'
response.status == HttpStatus.OK
response.headers.size() == 5
response.headers.contains('uber-trace-id')
response.headers.contains('Date')
response.headers.contains('content-type') && response.headers.get('content-type') == MediaType.APPLICATION_JSON
response.headers.contains('content-length')
response.headers.contains('connection')
//and: 'response contains valid HealthResult'
//HealthResult healthResult = response.body()
// Want to validate the health result here but nothing is present in body
}
}
How I can either defined the specDefinition value or mark the test in such a way that it is present as a bean definition and what is the reason for such a behavior. Any help would be greatly appreciated.
Micronaut-test makes the tests themselves beans. In order for a Groovy test to be a bean, you need to have micronaut-inject-groovy on the compilation path for test.
Yes, adding the micronaut-inject-groovy to your maven build will resolve the issue. Add the following.
<dependency>
<groupId>io.micronaut.test</groupId>
<artifactId>micronaut-test-spock</artifactId>
<scope>test</scope>
</dependency>

Attaching attachments in Allure reports using cucumber jvm after hooks

With Allure report framework when a step fails we can attach a screenshot or logs by calling a method with #Attachment annotation.
#Attachment(value = "Message", type = "text/plain")
public String attachLog(){
return "Hello, Test failed!";
}
But this means I have to explicitly call this method ( attachLog() ) in every step before assertions. Which seems unreasonable.
In CucumberJvm the "after" hooks are a great way to attach screenshots or logs. we do this by checking the scenario status and attach screenshots/logs based on the outcome.
I tried invoking the above method ( attachLog() ) in the cucumberJvm "after" hook. But unfortunately did not work.
Is there a solution to make this work?
Cheers
Vinod
You can override test failure method from ru.yandex.qatools.allure.cucumberjvm.AllureRunListener
public class CustomAllureListener extends AllureRunListener {
#Override
public void testFailure(Failure failure) {
super.testFailure(failure);
if (!failure.getDescription().isSuite()) { // check is needed to avoid double attaching
attachFailed();
}
}
#Attachment(value = "Message", type = "text/plain")
public String attachFailed(){
return "Test failed!";
}
}
And don't forget to change listener in pom.xml file
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<testFailureIgnore>false</testFailureIgnore>
<argLine>
-javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
</argLine>
<properties>
<property>
<name>listener</name>
<value>com.mycompany.testing.CustomAllureListener</value>
</property>
</properties>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>

Looking for Webstart Maven Plugin sample application [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 8 years ago.
Improve this question
I am looking for source code for a complete application that uses the Webstart Maven Plugin.
Any ideas?
I tried the webstart plugin in a prrof of concept involving an embedded tomcat server. The plugin is bound to the package phase and takes a longtime to execute, I would recommend to invoke it manually from the command line. It generates a zip file in the target directory containing the jnlp file and all dependencies. This file can then be extraced and put on a webserver. The url in the pom should point to this path on the server. When started, the app runs a tomcat server on localhost port 8080 with a simple servlet that just returns the requested path as a string.
Let me know if this works for you.
Here is the pom of the project, the plugin configuration was mostly copied from the documentation here
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.jhorstmann</groupId>
<artifactId>EmbeddedTomcatWebstart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>EmbeddedTomcatWebstart</name>
<url>http://localhost/jnlp/</url>
<organization>
<name>Organisation</name>
</organization>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<tomcat.version>7.0.6</tomcat.version>
</properties>
<repositories>
<repository>
<id>jboss</id>
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>sonatype</id>
<url>http://oss.sonatype.org/content/repositories/releases/</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<mainClass>net.jhorstmann.embeddedtomcat7.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo.webstart</groupId>
<artifactId>webstart-maven-plugin</artifactId>
<executions>
<execution>
<!-- bind to phase, I prefer to call it manualls -->
<phase>package</phase>
<goals>
<goal>jnlp-inline</goal> <!-- use jnlp, jnlp-inline or jnlp-single as appropriate -->
</goals>
</execution>
</executions>
<configuration>
<!--outputDirectory></outputDirectory--> <!-- not required?? -->
<!-- Set to true to exclude all transitive dependencies. Default is false. -->
<excludeTransitive>false</excludeTransitive>
<!-- The path where the libraries are stored within the jnlp structure. not required. by default the libraries are within the working directory -->
<libPath>lib</libPath>
<outputJarVersions>true</outputJarVersions>
<!-- [optional] transitive dependencies filter - if omitted, all transitive dependencies are included -->
<dependencies>
<!-- Note that only groupId and artifactId must be specified here. because of a limitation of the Include/ExcludesArtifactFilter -->
<!--
<includes>
<include>commons-logging:commons-logging</include>
<include>commons-cli:commons-cli</include>
</includes>
-->
<!--
<excludes>
<exclude></exclude>
<excludes>
-->
</dependencies>
<!--
<resourcesDirectory>${project.basedir}/src/main/jnlp/resources</resourcesDirectory>
-->
<!-- default value -->
<!-- JNLP generation -->
<jnlp>
<!-- default values -->
<!--inputTemplateResourcePath>${project.basedir}</inputTemplateResourcePath-->
<!--inputTemplate>src/main/jnlp/template.vm</inputTemplate--> <!-- relative to inputTemplateResourcePath -->
<outputFile>app.jnlp</outputFile> <!-- defaults to launch.jnlp -->
<!-- used to automatically identify the jar containing the main class. -->
<!-- this is perhaps going to change -->
<mainClass>net.jhorstmann.embeddedtomcat7.App</mainClass>
</jnlp>
<!-- SIGNING -->
<!-- defining this will automatically sign the jar and its dependencies, if necessary -->
<sign>
<keystore>${basedir}/keystore</keystore>
<keypass>password</keypass> <!-- we need to override passwords easily from the command line. ${keypass} -->
<storepass>password</storepass> <!-- ${storepass} -->
<!--storetype>fillme</storetype-->
<alias>EmbeddedTomcatWebstart</alias>
<!--validity>fillme</validity-->
<!-- only required for generating the keystore -->
<dnameCn>EmbeddedTomcatWebstart</dnameCn>
<dnameOu>Organisation Unit</dnameOu>
<dnameO>Organisation</dnameO>
<dnameL>Location</dnameL>
<dnameSt>State</dnameSt>
<dnameC>Country</dnameC>
<verify>true</verify> <!-- verify that the signing operation succeeded -->
<!-- KEYSTORE MANAGEMENT -->
<keystoreConfig>
<delete>true</delete> <!-- delete the keystore -->
<gen>true</gen> <!-- optional shortcut to generate the store. -->
</keystoreConfig>
</sign>
<!-- BUILDING PROCESS -->
<pack200>true</pack200>
<gzip>true</gzip> <!-- default force when pack200 false, true when pack200 selected ?? -->
<!-- causes a version attribute to be output in each jar resource element, optional, default is false -->
<outputJarVersions>false</outputJarVersions>
<!--install>false</install--> <!-- not yet supported -->
<verbose>true</verbose>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-coyote</artifactId>
<version>${tomcat.version}</version>
</dependency>
</dependencies>
</project>
Here is a custom template for the jnlp file placed at src/main/jnlp/template.vm, I can't remember why I needed that exactly:
<?xml version="1.0" encoding="utf-8"?>
<jnlp
spec="$jnlpspec"
codebase="$project.Url"
href="$outputFile">
<information>
<title>$project.Name</title>
<vendor>$project.Organization.Name</vendor>
<homepage href="$project.Url"/>
<description>$project.Description</description>
#if($offlineAllowed)
<offline-allowed/>
#end
</information>
#if($allPermissions)
<security>
<all-permissions/>
</security>
#end
<resources>
<j2se version="$j2seVersion"/>
$dependencies
</resources>
<application-desc main-class="$mainClass"/>
</jnlp>
This is the main class at src/main/java/net/jhorstmann/embeddedtomcat7/App.java
package net.jhorstmann.embeddedtomcat7;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Wrapper;
import org.apache.catalina.startup.Tomcat;
public class App {
public static void main(String[] args) throws LifecycleException, ServletException, IOException {
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
File webappDir = new File(tmpDir, "embeddedtomcat7");
webappDir.mkdir();
final Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.setBaseDir(tmpDir.getAbsolutePath());
tomcat.getConnector().setURIEncoding("UTF-8");
String contextPath = "/";
Context context = tomcat.addContext(contextPath, webappDir.getAbsolutePath());
Wrapper wrapper = tomcat.addServlet(contextPath, "Test", new TestServlet());
//Wrapper wrapper = tomcat.addServlet(contextPath, "Async", new AsyncServlet());
//wrapper.setAsyncSupported(true);
wrapper.addMapping("/*");
tomcat.start();
tomcat.getServer().await();
}
}
And finally a servlet at src/main/java/net/jhorstmann/embeddedtomcat7/TestServlet.java
package net.jhorstmann.embeddedtomcat7;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.println("<h1>" + req.getPathInfo() + "</h1>");
writer.close();
}
}
A few notes on this plugin (it's documentation is horrible):
It won't use the template.vm file unless you specify it, like
<templateFilename>roll-gen-template.vm</templateFilename>
For creating a war:
If you want to use the JnlpDownloadServlet (the standard one java provides) to serve up the files instead of the above code (and have the plugin generate a working version.xml file for it to use, etc.), basically you need to create a new project of type war and target the jnlp-download-servlet goal (it doesn't seem to support creating a war with classes from the current pom project) then, instead of a single <jnlp> section, you'll have the <jnlpFiles> section instead, which can list multiple jar dependencies. You may need to modify your web.xml file as well.
http://www.mojohaus.org/webstart/webstart-maven-plugin/jnlp-mojos-overview.html has an example pom for
If you have additional comments feel free to edit this, it is a community wiki.