We are researching the possibility to migrate some web JSF applications from Payara 5 to Tomcat 9 (TomEE 8). We are using Java 11 and Java EE 7/8. Our applications connect to a backend server using RMI. At the moment, with Payara 5, when the code that connects us to the backend server fails (exception is thrown because server is unavailable or credentials defined in web.xml are invalid), the deployment fails.
See this piece of code:
public class MainServlet extends HttpServlet {
//constructor, variables etc.
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
//read configurations from web.xml
try {
connectToBackendServer();
catch (Exception e) {
throw new UnavailableException("Cannot connect to Backend Server");
}
}
//other methods
}
The above piece of code makes the deployment fail on Payara 5, but Tomcat 9 allows the deployment. With Tomcat we notice that the backend is not ok by checking the logs or by trying the front-end and getting the errors. See the below picture where the NullPointerException is thrown by our connectToBackendServer() method.
We are fully aware that this is not the best approach as the backend may fail later, after the successful deployment, but at least we are covering the cases when the configuration from web.xml is wrong.
Can we achieve a similar functionality with Tomcat 9(TomEE 8)?
Thank you all in advance!
..
Move your logic to a ServletContextListener and throw a runtime exception from contextInitialized(). On many servers this will fail the deployment and any requests to the application will return error 500. The spec does not require this exact behaviour though, so the outcome is slightly different between servers.
This is an example implementation using a ServletContextListener that fails the deployment:
package com.example;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
#WebListener
public class ExampleServletContextListener implements ServletContextListener{
#Override
public void contextInitialized(ServletContextEvent e) {
try {
callThatFailsAndThrowsAnException();
catch (Exception e) {
throw new UnavailableException("Something went very wrong - I'm bailing out.");
}
}
#Override
public void contextDestroyed(ServletContextEvent e) {
/* Application shutdown */
}
}
#WebListener registers the context listener with the container. If you are using an older version of JakartaEE/JavaEE and the annotation is unavailable, you can register the context listener in web.xml instead.
Related
I am trying to create a Web service using JAX-WS. I do have a very basic Java project with the following:
EmployeeService .java
import javax.jws.WebMethod;
import javax.jws.WebService;
#WebService
public class EmployeeService {
#WebMethod
public String getEmployee(String id) {
return "Vlad Danila";
}
}
Exporter.java
import javax.xml.ws.Endpoint;
import services.EmployeeService;
public class Exporter {
public static void main(String[] args) {
Endpoint.publish("http://localhost:8080/hello",
new EmployeeService());
System.out.println("Successfull!");
}
}
Running the above will throw no error and print "Successfull!".
However, accessing http://localhost:8080/hello on browser gives This page isn’t working.
What am I missing?
I did an example with your code, and it works.. you have to add this to the browser to see
http://localhost:9999/ws/hello?wsdl
This is the url on my case. Then consume it with soap ui or another ws client.
The error you see its cause you are doing a get request on that url and not a soap request.
You don't give much context about what you are doing. JAX-WS is supposed to run in container. Do you run in container which is JEE compatible. See this tutorial, especially the last part:
https://docs.oracle.com/javaee/6/tutorial/doc/bnayn.html#gjyge
If you want something simple, I would recommend to make a spring-boot app, which will work out of the box for you. Forget about heavy JEE containers and try to run a simple spring-boot app which have integrated server inside the spring-boot app.
Here is a link to follow: https://spring.io/guides/gs/rest-service/
I know this is usually an issue that happens the other way around, so I am caught a little of guard here :D
I have built a user-management backend that provides a UI with data. When this architecture is deployed on our dev-server, everything works beautifully. However, as soon as I try to run the integration tests (which we do using a maven cargo tomcat) or if I use the war file in a local tomcat, the exception handlers aren't used at all. Spring simply displays a standard 500 response with the exception transformed into the body.
Perusing SO for similar issues has only resulted in the advice that I should use #EnableWebMVC, but that is neither applicable to what my backend is trying to accomplish, nor does it change anything.
How should I go about looking for the solution to this issue? Specifically, can I somehow observe if my controlleradvice is even scanned, and is there a reason why it might not be?
EDIT: These are the relevant files:
SpringConfiguration:
#Configuration
#ComponentScan(basePackageClasses = {UserManagementSpringConfiguration.class})
#EnableWebSecurity
public class UserManagementSpringConfiguration {
#Configuration
public static class ResourceMappingConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ui/*/usermanagement").setViewName("forward:/usermanagement-ui/index.html");
// registry.addViewController("/ui/*/*/generator/").setViewName("forward:/generator-ui/index.html");
registry.addViewController("/ui/*/usermanagement/*").setViewName("forward:/usermanagement-ui/index.html");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// cache setting, otherwise fonts are not loaded in IE over https
CacheControl cacheControl = CacheControl.noCache().mustRevalidate();
registry.addResourceHandler("/ui/**/*").addResourceLocations("/usermanagement-ui/")
.setCacheControl(cacheControl);
}
}
}
ControllerAdvice:
#ControllerAdvice
public class CustomResponseEntityExceptionHandler {
public static final Logger LOG = EISLoggerFactory.getLogger(CustomResponseEntityExceptionHandler.class);
#PostConstruct
public void postConstruct() {
LOG.debug("CustomExceptionHandler loaded and ready for use");
}
#ExceptionHandler(PasswordMismatchException.class)
public final ResponseEntity<ErrorDetails> handlePasswordChangeMismatch(
PasswordMismatchException ex,
WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(
new Date(),
ex.getMessage(),
request.getDescription(false),
MessageKeys.mismatchedPassword);
return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
}
}
It turns out that one of the modules that we wrote and that my project contains defines an ExceptionHandler for Throwable.class. On my machine, this ControllerAdvice is registered before my own ControllerAdvice, which causes Spring to look there first. Since Throwable fits the bill, Spring asks no further questions and just uses that handler.
The solution to my immediate problem was to add #Order(Ordered.HIGHEST_PRECEDENCE) to my ControllerAdvice. Since the exceptions I define within are quite specific, this will not cause any issues.
I have yet to find an explanation for why the order in which the two ControllerAdvice classes are registered is so consistently different between my machine and our dev server. Will update if I find anything. For now, I consider this issue to be answered.
This SO question was essential to solving this particular problem. Perhaps it helps someone in the future to link it here: Setting Precedence of Multiple #ControllerAdvice #ExceptionHandlers
Thanks to ValentinCarnu for pointing me to it!
I have a WebApplication on Websphere 8.5.5.8, one (more or less empty) EAR Project which contains my WAR Project.
In my main Servlet, which is loaded on startup, i do some checks, if everything is alright.
If its not, I'm throwing a javax.servlet.ServletException.
My expectation is, that Websphere would recognize that there is a Problem and abort the startup of my application so its not usable at all.
What actually happens is, Websphere just logs that Exception away with only Waring level, the Exception is even in another File, not in the Log itself:
[06.04.16 07:42:27:229 CEST] 0000004c FfdcProvider W com.ibm.ws.ffdc.impl.FfdcProvider logIncident FFDC1003I: FFDC-Vorfall an C:\IBM\WAS8.5\profiles\AppSrv01\logs\ffdc\server1_bb44715_16.04.06_07.42.27.2056702894000999712166.txt com.ibm.ws.webcontainer.servlet.ServletInstance.init 259 erstellt.
Then my Application is started anyways so its available to use with a Browser. People of course then start using it and recognize later, that that there is a Problem. After digging in Log files, it comes out that the startup failed.
Question:
What can i do to make Websphere abort the Startup Process?
Is there maybe a Special kind of Exception i could throw?
I tried
javax.servlet.ServletException
javax.servlet.UnavailableException
java.lang.Error
I found this in the IBM Forums, which indicates, that my expected behavior would violate the JEE Spec, which wouldn't make much sense for me.
I tried a javax.servlet.ServletContextListener as mentioned here, one Plus is, that i'll get a error Message in the log, but the Application still starts.
As mentioned here I tried the Startup Beans. The solution posted there is not working for me, those proprietary startup beans are not allowed in a WAR, and they're are also Deprecated. I only have a EAR Project, since Websphere/RAD is forcing me to use one in my local environment. On Test/Production Systems, only the WAR is used.
If i use the startup beans defined by EJB 3.1:
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
#Singleton
#Startup
public class MyStartupBean {
public boolean start() {
System.out.println("MyStartupBean.start()");
return false;
}
public void stop(){
System.out.println("MyStartupBean.stop()");
}
#PostConstruct
public void postConstruct() {
System.out.println("MyStartupBean.postConstruct()");
}
}
The start() method doesn't get called, i only see the postConstruct() message in my log. Throwing an Exception in postConstruct() wont abort the startup process.
So far, i only came up with an Workaround (inspired by the comment of Jason Faust in https://stackoverflow.com/a/1337927/5072526):
Have a static flag, and if the initialization has completed correctly, set it to true.
Use a Filter to check that flag and output an Error if its false, so at least the Application dosen't seem usable when the Startup failed:
public class HealthCheckFilter implements Filter{
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(AppBridge.isStartupFinished()) {
chain.doFilter(request, response);
}else {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setCharacterEncoding(AppConstants.ENCODING);
httpResponse.setContentType("text/plain");
httpResponse.setStatus(500);
PrintWriter out = httpResponse.getWriter();
out.write("Startup failed");
}
}
/* Methods init(FilterConfig filterConfig) and destroy() ommitted*/
}
The last couple of days, I have been struggling with an issue. I've created a rest service hosted by a Grizzly server inside an OSGi container. Everything is working perfectly at this point.
Now, I want to add a header in every response.Not so complex or illogical right? Yet, I can't find a way to do it.
I have tried to:
1) Get the response object inside the rest functions as this question suggests (pretty textbook when you are not under OSGi).
2) Add a handler using the code above (in this case the service method is never called)
server.getServerConfiguration().addHttpHandler(
new HttpHandler() {
#Override
public void service(Request arg0, Response arg1)
throws Exception {
arg1.setHeader("Access-Control-Allow-Origin", "*");
}
});
I am using jersey-server/client/core 1.18.1 and grizzly2-server 1.18.1, hence i prefer a solution that can be applied in this version, but I am willing to update jar versions if it cannot be done in 1.18.x.
You could give a try to Jersey filters.
In a nutshell, you should create class implementing ContainerResponseFilter:
public class MyFilter implements ContainerResponseFilter {
#Override
public void filter(
ContainerRequest request,
ContainerResponse response
) throws IOException {
request.getHttpHeaders().add(<header name>, <header value>);
}
}
Then, you should register this filter in your Jersey server configuration.
Please, note, that this filter would be invoked on every response. To bind it only to specific resources, you could use annotation-binding, that is described here.
All other information you could find here.
I am trying to find a simple way to publish my RESTful web service using JAX-RS 2.0 with Java SE using Jersey and/or the Java SE build-in http server.
I want to keep my dependencies to the minimum so i wanted to avoid grizzly and also do not want to use any external application server.
Can you point me how to publish a rest service with this requirements?
Thanks in advance,
I mean to achieve somethig like this:
public static void main(String args[]) {
try {
final HttpServer server = GrizzlyHttpServerFactory.createHttpServer("http://localhost:8080/calculator/",new ResourceConfig(SumEndpoint.class));
System.in.read();
server.stop();
} catch (IOException ex) {
}
}
... but avoiding the grizzly dependency
If you just depend on
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jdk-http</artifactId>
<version>2.2</version>
</dependency>
you can then start the server
JdkHttpServerFactory.createHttpServer(URI.create("http://localhost:8090/root"),
new MyApplication());
where MyApplication extends ResourceConfig to obtain resource scanning.
#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("...");
}
#GET
#Produces("text/plain")
public Response foo() {
return Response.ok("Hey, it's working!\n").build();
}
}
There may a better way to control the server life cycle, but that eludes me for the moment.