Embedded Jetty Server Classpath Issue - web.xml

I'm trying to deploy a web application on an embedded Jetty Server. My application runs fine locally in a windows environment with the code below but when i deploy it as a JAR File on a Linux Server, it looks like my web.xml File is not picked up. Is there something i need to change in Descriptor or ResourceBase fields below before building a JAR?
static void startJetty() {
try {
Server server = new Server(9090);
WebAppContext context = new WebAppContext();
context.setDescriptor("/WEB-INF/web.xml");
context.setResourceBase("../DemoWithMultiChannels/src/");
context.setContextPath("/");
context.setParentLoaderPriority(true);
server.setHandler(context);
System.out.println("Starting Server!");
server.start();

I had the same problem and just found the solution:
It was working fine when I run "java -jar ..." from terminal, but when I spawned it off from another project, web.xml was not picked up.
Reason was web.xml path was wrong, it was relative to original project, what I end up doing is:
context.setDescriptor(Launch.class.getResource("/WEB-INF/web.xml").toString());
If you don't use resource you just read the regular file inside your src folder, not the one inside the .jar

Here is how to do it.
First, in your pom.xml, declare where the webapp folder is:
<build>
<resources>
<resource>
<directory>src/main</directory>
</resource>
</resources>
Here is the tree of my src/main directory:
├── java
│   └── com
│   └── myco
│   └── myapp
│   └── worker
│   ├── App.java
| ...
├── resources
│   ├── log4j.properties
│   └── version.properties
└── webapp
├── index.html
├── index.jsp
├── lib
│   ├── inc_meta.jsp
│   └── inc_navigation.jsp
├── query.html
├── scripts
│   ├── angular.min.js
│   └── bootstrap.min.css
├── showresults.jsp
├── status.jsp
└── WEB-INF
└── web.xml
Add Maven Shade plugin in your pom.xml file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>uber-${artifactId}-${version}/finalName>
</configuration>
</plugin>
Then start Jetty like this:
public static void startJetty() throws Exception {
logger.info("starting Jetty...");
Server server = new Server(8080);
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/");
/* Important: Use getResource */
String webxmlLocation = App.class.getResource("/webapp/WEB-INF/web.xml").toString();
webAppContext.setDescriptor(webxmlLocation);
/* Important: Use getResource */
String resLocation = App.class.getResource("/webapp").toString();
webAppContext.setResourceBase(resLocation);
webAppContext.setParentLoaderPriority(true);
server.setHandler(webAppContext);
server.start();
server.join();
}
The important part is to use <YourApp>.class.getResource(<your location>) that will give the path to the files inside the jar. The wrong way would be to do it like this: webContext.setDescriptor("WEB-INF/web.xml"); which gives the path on the file system.
Then create package
$mvn clean package
The uber-jar file is generated and contains the webapp directory that was declared as resource.
Move the jar anywhere or on the production server and run it like this:
$ java -jar myjettyembededwithwebxmlandhtmljspfile.jar

Deploy embedded Jetty as follows:
Main Class
public static void main(String[] args) throws Exception {
Server server = new Server(8085);
WebAppContext webContext = new WebAppContext();
webContext.setDescriptor("WEB-INF/web.xml");
webContext.setResourceBase("src/sim/ai/server/start");
webContext.setServer(server);
webContext.setParentLoaderPriority(true);
server.setHandler(webContext);
server.start();
server.join();
}
web.xml
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>sim.ai.server.start</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>sim.ai.server.start</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Create a WEB_INF folder in the same folder as the jar file; copy web.xml into WEB_INF, such as:
sim/light.jar
sim/WEB-INF/web.xml

I have replaced WebAppContext and WebXmlConfiguration with specific descendants which can find resources in classpath:
Server: https://github.com/jreznot/diy-remote/blob/master/server/src/org/strangeway/diyremote/server/RemoteServer.java
WebAppContex: https://github.com/jreznot/diy-remote/blob/master/server/src/org/strangeway/diyremote/server/sys/ClasspathWebAppContext.java
WebXmlConfiguration: https://github.com/jreznot/diy-remote/blob/master/server/src/org/strangeway/diyremote/server/sys/ClasspathWebXmlConfiguration.java
It works good for me

Related

`maven compile` can not find package when they are installed in ~/.m2

I am trying to learn how to build a maven project.
this is my ./src/main/java/Hello.java
import com.google.code.gson.*;
public class Hello{
public static void main(String[] args) {
System.out.println("Hello world");
}
}
This file does't do something actually, I just want to learn how to import a 3rd library.
this is my ./pom.xml
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
So, I try to execute mvn compile.
But there is an error:
package com.google.code.gson does not exist
But in my ~/.m2/repository
$ tree -L 3 ~/.m2/repository/com/google/code/gson
/Users/apple/.m2/repository/com/google/code/gson
├── 2.8.5
│   ├── gson-2.8.5.jar.lastUpdated
│   └── gson-2.8.5.pom.lastUpdated
├── gson
│   └── 2.8.5
│   ├── _remote.repositories
│   ├── gson-2.8.5.jar
│   ├── gson-2.8.5.jar.sha1
│   ├── gson-2.8.5.pom
│   └── gson-2.8.5.pom.sha1
I seems that mvn don't add ~/.m2/repository to my classpath, How to fix this?
$ mvn -v
Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-25T02:41:47+08:00)
Maven home: /Users/apple/Downloads/apache-maven-3.6.0
Java version: 10, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home
Default locale: en_CN, platform encoding: UTF-8
OS name: "mac os x", version: "10.12.6", arch: "x86_64", family: "mac"
According to GSON javadoc , there is no package called com.google.code.gson.*. The root package starts from com.google.gson . So change to :
import com.google.gson.*;
What you see in the <groupId> has nothing to do with the package name. Always refer to the javadoc or its source codes for the package name.

Execute custom script before integration tests

my application is using Spring Boot, with 2 main modules main and test. In another directory on same level I have folder which contains script with database triggers which I need create in database before tests.
Here is my project structure:
src/
├── main
├── scripts (this is not module, only default folder)
│   └── custom_script.sql
└── test
└── persistent
└── TestConfiguration.java
Test configuration is only interface where I set some configuration for tests, currently contains following code:
#Sql("../../scripts/custom_script.sql")
public interface TestConfiguration {
}
This code didn't work, and custom_script.sql isn't executed. Can you tell me why, or what is the better to execute it?

create new project using maven archetype how to specify custom folder name

I'm now trying to create a maven archetype which uses spring + mybatis framework. There is a mybatis xml file: src/main/resources/archetype-resources/src/main/resources/sql/myapp/DemoUser.xml, and execute below command to create new project using this archetype.
mvn archetype:generate ... -DartifactId=foo.bar -Dpackage=com.foo.bar ...
I want to replace myapp to bar, that is I want to mybatis xml file in sql/bar folder, how to implement this?
My way is in src/main/resources/META-INF/maven/archetype-metadata.xml to add this property
<requiredProperty key="appName">
<defaultValue>${appName}</defaultValue>
</requiredProperty>
Then in src/main/resources/archetype-resources/pom.xml to add
#set ($artifactId = "${artifactId}")
#set ($index = $artifactId.indexOf('.'))
#set ($index = $index + 1)
#set ($appName = $artifactId.substring($index))
and remember to change folder name to
src/main/resources/archetype-resources/src/main/resources/sql/__appName__/DemoUser.xml
So when you execute mvn archetype:generate ... -DartifactId=foo.bar ... now, you could get
│   └── resources
│   └── sql
│   └── bar
│   └── DemoUser.xml
refer doc: http://maven.apache.org/archetype/archetype-models/archetype-descriptor/archetype-descriptor.html

How to add the static resources in Spring-boot by annotation?

Besides the pre-determined folders (such as /static/), is there any way to configure Spring Boot (not by XML) to specify the locations of static resources?
For example, starting from this guide, we add another image file, test1.jpg, as our static resource.
Here is the final directory structure:
└── src
└── main
└── java
└── hello
└── Application.java
└── GreetingController.java
└── resources
└── templates
└── greeting.html
└── assets
└── img
└── test1.jpg
We did not change any java code from this guide , but only add one additional line in greeting.html :
<img src="test1.jpg" />
Nevertheless, our greeting.html still cannot find test1.jpg.
Could someone give us some suggestions?
Thanks!!
You can add a #Bean of type WebMvcConfigurerAdapter and set the paths yourself, e.g.
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/assets/img";
}
Why not just use the defaults though?

Change Spring-boot static web resources location?

Base on this tutorial:
http://spring.io/guides/gs/serving-web-content/
I can use the thymeleaf to serve the view in the location
/src/main/resources/templates/
However, I have to put the static web contents (css, js) in another location:
/src/main/webapp/resources
And linking the resources in the hello.html like that:
<link href="resources/hello.css" />
<script src="resources/hello.js"></script>
The directory structure is:
└── src
└── main
└── java
└── hello.java
└──resources
└──templates
└──hello.html
└──webapp
└──resources
└──hello.js
└──hello.css
The problem is that the links of the static files are work when I run the web server. But if I open the html files in offline mode, the links are broken.
Could I move the static resource from
/src/main/webapp/resources
to:
/src/main/resources/templates/resources
The new directory structure would be like:
└── src
└── main
└── java
└── hello.java
└──resources
└──templates
└──hello.html
└──resources
└──hello.js
└──hello.css
I tried it but is doesn't work.
Try src/main/resources/static (or src/main/resources/public or src/main/resources/resources). All those are registered by Spring Boot autoconfig.
Define the mapping in your context like following -
<mvc:resources mapping="/templates/**"
location="classpath:/templates/" />
This will route everything that's hitting /template/ url to search for contents under your src/main/resources/templates/ folder.
In case you need tweaking in the url/prefix - adjust the mapping accordingly.

Resources