I am working on a servlet (containing a Jersey REST server) which I ship in the war format. I wrote extensive unit tests to thoroughly test the code base. However, I often have the problem that the war does not start correctly.
This is mostly due to me making some kind of mistake in the web.xml file. For example, I rename some class mentioned in the xml without changing the corresponding line in the xml itself. The problem is that in my tests I create a debug Application so the xml is never considered. More to the point, lets say I have the following (Jersey) ResourceConfig:
import org.glassfish.jersey.server.ResourceConfig;
public class MyConfig extends ResourceConfig {
public MyConfig() {
register(...);
}
}
Now suppose I have an error in the web.xml:
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>MyMisspelledConfig</param-value>
</init-param>
My unit tests look like this:
public class ServerTest extends JerseyTest {
#Override
protected Application configure() {
return new MyConfig();
}
#Test
public void test() {
//...
}
}
The tests pass but the deployed servlet won't even start...
Is there a way to automatically test the default deployment (including the web.xml)?
The only way I know for testing the deployment descriptor web.xml is to deploy the war on a local server on the developper machine (tomcat or jetty are good candidates). Netbeans or Eclipse offer nice integration for that, opening a browser window to the root of the web application.
You can then manually view some pages, or if you prefere automated tests, you can use the excellent Selenium that plays some recorded scenarii controlling portions of the received pages.
Related
I have developed "hello-world" web application using Spring Boot and locally (on embedded Tomcat) it works fine.
But when I uploaded my WAR file to Tomcat7 installed on AWS EC2 I have problems with invoking my simple http get methods - I am getting GET http:/ /my_server_address:8080/ping 404 (Not Found).
All static resources works ok (html, css files).
My Controller looks like:
#RestController
public class PingController {
#RequestMapping(value = "/ping", method = RequestMethod.GET)
public String ping() {
return "Live!";
}
}
My main class looks like:
#SpringBootApplication
public class ServletInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ServletInitializer.class);
}
public static void main(String[] args) {
SpringApplication.run(ServletInitializer.class, args);
}
}
I assume that I have problem with DispatcherServlet? I don't have web.xml - only simple application.properties
Can somebody help me?
Thanks in advance!
Yes, you're right that you have an issue with DispatcherServlet. But more correctly to say, you have an issue with Spring Context.
When application is run via Spring Boot then Spring Boot cares about Spring Context and component scans.
If you want to run Spring MVC application with Tomcat you have to configure Spring Application Context manually either via XML or Java Base configuration. If you don't want to use web.xml you may use 'Full Java Base' configuration with WebApplicationInitializer (You're using Tomcat 7, so it supports Servlet API 3.0)
By the way, in any way I suggest you to create web.xml to run Java Web Application in Java Web Server like the Tomcat.
Please, loot in Spring MVC documentation to find more information.
I have a working web-application that I built, successfully deployed to Heroku, and is functioning well. However, I'm trying to tune the server/servlet config, and that's when I realized that I don't know what my application is actually doing.
For glassfish, this is the config that's needed.
However, for Jetty, this is the config that's needed.
I realized I have no idea which of the above my application is actually using, so I started digging in my code and found the following:
The main method being called by Heroku is instantiating the following Jetty server/webappcontext.
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
However, the jetty config seems to rely on a number of files (such as etc/jetty.xml, webapps folder or war files) which my project does not have at all.
In addition, my web.xml file defines the following servlet:
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
The fact that my application is defining a Jetty server but Glassfish servlet concerned me quite a bit. In an effort to standardize everything around Jetty, I tried adding the jetty servlet to my pom.xml dependencies and changed the above to:
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
However, this change caused my application to break. It still compiles successfully and all my jerset-test based integration tests still succeed locally. But when I actually run the server, none of the routes work.
Some questions:
Is it a ill-advised to use a Jetty server along with a Glassfish servlet (container)?
If yes, what servlet (container?) should I replace Glassfish with, and what do I need to do to get the new Jetty servlet working?
If no, what config should I be using for my current setup? Should I be implementing the Glassfish config or the Jersey config?
I've spent many hours trying to read through various documentations, tutorials and stack-overflow threads, but they all either assume prior knowledge about servlets, JavaEE and related topics (none of which I'm familiar with), or they are oriented towards building brand new hello-world apps from scratch (as opposed to porting an existing working app over, which is what I'm trying to do). Any explanations you could give, without assuming prior knowledge, relevant to the context described above, would be much appreciated.
Edit: I think I'm starting to understand now that a Servlet is the code that generates the response for a request, and the ServletContainer is what provides the infrastructure for the Servlet. I've never had to deal with Servlets directly in building my web-app. Here's an example of what a route looks like in my app:
#Path(Ping.REST_PREFIX)
public class Ping {
static final String REST_PREFIX = "/ping";
#GET
public static Response get(#DefaultValue("getPing") #QueryParam("param") String param) {
return Response.ok().entity(param).build();
}
#Path("/pong")
#GET
public static Response getPong(#DefaultValue("getPong") #QueryParam("param") String param) {
return Response.ok().entity(param).build();
}
}
How can I port code like the above into a Jetty ServletContainer, without rewriting vast sections of my application?
You are not using a "Glassfish Servlet Container", you are using a "Jersey Servlet Container".
Jersey is the project you are using.
Glassfish was the umbrella organization (sometimes called "a forge") that helps manage/maintain the Jersey project (along with dozens of other projects).
Difference com.sun.jersey and org.glassfish.jersey
The Jersey project can now be found at the java.net organization.
https://jersey.java.net/
I have a simple web project which changes a line of text with another at the click of a button. What I want is a core Java method which will recognise when the .war file is deployed on the Tomcat server.
I want to output the exact time when the deployment happens. I have the code ready for that, and I want it to be in core Java.
Is there any such method that will allow me to perform some activity when the deployment happens?
You can use a ServletContextListener.
Add a <listener> tag in your web.xml file as follows:
<listener>
<listener-class>classes.MyListener</listener-class>
</listener>
And make a Java class implement the ServletContextListener interface. Overriding the contextInitialized() method and writing your code in it will do the trick.
For example:
package classes;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.joda.time.DateTime;
public class MyListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Project deployed: " + new DateTime());
//or any other form of output
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Project undeployed: " + new DateTime());
//or any other form of output
}
}
Hope this helps!
Look to see if the WAR file has been unzipped (exploded) in the webapps directory. This itself can be done two different ways, by looking to see if the exploded directory is there. Or by looking at the access time of the WAR file. Please note to see the access time of a file in *nix you have to use the -u option in the ls command.
But this has a flaw in the you cannot tell when the webservice has finished initializing. For that you can create a keepAlive service that you can poll in your webservice. That way when your application is done initializing you will get a response from the keepAlive. You can set a high loadnumber on this service to allow all the other Servlets to load first.
curl "http:localhost:8080/MyWebService/keepAlive"
Furthermore, I know specifically with Tomcat you can query its JMX monitor. I do not know if it has a JMX query to list out loaded Servlets, but it might and it is extensible so you can add your own queries for finding that out.
EDIT: You can also setup your Servlet to log when it is done initializing. Then just grep "your services' log msg" in a loop till it exits with exit code 0.
I am creating a REST based web application and using the latest version of Jersey and embedded Jetty. Descriptor-less deployment for Servlet 3.0 allows the exclusion of web.xml. However, I am having trouble understanding how you can serve static content in this case (.html, .css, .js and image files)? As the application is using embedded Jetty, I am not deploying this in a standalone servlet container, so the resulting file is a shaded .jar. Perhaps, I need to use the WAR plugin to make this possible? If so, where exactly do I have to place the aforementioned files? Is it still possible with packaging into .jar only as well?
The only way I have been able to serve static content so far, was with direct filesystem access, like this (Jersey's JAX-RS part):
#GET
#Path("manager/preview/img/loader.gif")
#Produces("image/gif")
public final Response preview() throws Exception
{
final byte[] b = Files.readAllBytes(Paths.get("manager/preview/img/loader.gif"));
return Response.ok().entity(b).build();
}
This definitely does not seem like the appropriate way. I'd be thankful, if someone could point me in the right direction.
I have a java application that up until now was run as a stand alone java application (i.e. executable jar). I now need to deploy it in Tomcat as a servlet. It doesn't need to actually process any HTTP requests though, but it needs to be started using tomcat.
What are the steps required to convert the project so that it can be deployed in Tomcat? I'm using maven as a build tool and Java 1.5.
I understand that you want to run this app on server's startup. The best way would be implementing ServletContextListener and run the app in the contextInitialized() method. E.g.
public class Config implements ServletContextListener {
private YourApp yourApp;
public void contextInitialized(ServletContextEvent event) {
yourApp = new YourApp();
yourApp.start();
}
public void contextDestroyed(ServletContextEvent event) {
yourApp.shutdown();
}
}
Register this in web.xml as follows:
<listener>
<listener-class>com.example.Config</listener-class>
</listener>
That's it. No need to wrap it in flavor of a HttpServlet as you aren't going to fire HTTP requests on it.
You however need to ensure that it runs in its own thread, otherwise it would block the startup. If it doesn't, then wrap it in a Runnable and execute it using ExecutorService.
I'm assuming that your app is continuously running and you have an app/web server already (e.g. Tomcat/Jetty), such that it's making your life easy to deploy into it. Given that, you need to:
extend an AbstractHttpServlet class and in particular the init() method. This would start your app.
build a web.xml that references this and sets the load-on-startup attribute to 1 (or at least non-zero)
build a .war from this and deploy it
Step 2 ensures that the init() method is called upon deployment/server reboot, and so you don't have to respond to HTTP requests (a normal startup trigger for a servlet).
It may be simpler and more appropriate to use something like javaservicewrapper, and wrap it up to be a Windows service or similar.