Mapping Struts 2 Exception Handler to an Action - exception

I have Struts 2 configured to redirect any java.lang.Exception to a special Action which logs the exception. My redirection works, but my Action always gets a null exception (even when I explicitly throw an Exception). Here is my struts.xml file:
<global-results>
<result name="errHandler" type="chain">
<param name="actionName">errorProcessor</param>
</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="errHandler" />
</global-exception-mappings>
<action name="errorProcessor" class="myErrorProcessor">
<result name="error">/error.jsp</result>
</action>
<action name="throwExceptions" class="throwExceptions">
<result name="success">done.jsp</result>
</action>
In my error processor, I have the following:
public class myErrorProcessor extends ActionSupport {
private Exception exception;
public String execute() {
System.out.println("null check: " + (exception == null));
return "error";
}
public void setException(Exception exception) {
this.exception = exception;
}
public Exception getException() {
return exception;
}
}
In the throwsException class, I have the following:
public String execute() {
int x = 7 / 0;
return "success";
}
When I run my program, the Exception handler always gets a null exception. I am using the chain type to redirect to the exception handler. Do I need to implement some sort of ExceptionAware interface? Is the Struts 2 exception setter called something besides setException?
Note: I was trying to follow this tutorial when writing this program.

Using struts2 version 2.3.1.2 I do not get a null exception in my error handler everything works as advertised. Ensure you are using an unmodified defaultStack.
As far as credible sources, we can reference the interceptor documentation for ExceptionMappingInterceptor and Chaining Interceptor. The ExceptionMappingInterceptor pushes an ExceptionHolder onto the value stack which in turn exposes an exception property. The chaining interceptor copies all the properties on the value stack to the target. Since ExceptionHolder is on the stack if there is a setter for Exception it will be set.
Here are all the files which produce a working example:
struts.xml (kept quite similar to the questions):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.ui.theme" value="simple" />
<package name="kenmcwilliams" namespace="/" extends="struts-default">
<global-results>
<result name="errHandler" type="chain">
<param name="actionName">errorProcessor</param>
</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="errHandler" />
</global-exception-mappings>
<action name="errorProcessor" class="com.kenmcwilliams.test.myErrorProcessor">
<result name="error">/WEB-INF/content/error.jsp</result>
</action>
<action name="throwExceptions" class="com.kenmcwilliams.kensocketchat.action.Bomb">
<result name="success">/WEB-INF/content/bomb.jsp</result>
</action>
</package>
</struts>
MyErrorProcessor.java
package com.kenmcwilliams.test;
import com.opensymphony.xwork2.ActionSupport;
public class MyErrorProcessor extends ActionSupport {
private Exception exception;
#Override
public String execute() {
System.out.println("Is exception null: " + (exception == null));
System.out.println(""
+ exception.getMessage());
return "error";
}
public void setException(Exception exceptionHolder) {
this.exception = exceptionHolder;
}
public Exception getException() {
return exception;
}
}
Bomb (just throws RuntimeException):
package com.kenmcwilliams.kensocketchat.action;
import com.opensymphony.xwork2.ActionSupport;
public class Bomb extends ActionSupport{
#Override
public String execute() throws Exception{
throw new RuntimeException("Hello from Exception!");
}
}
View for bomb (/WEB-INF/content/bomb.jsp) [Never reachable]
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>The Bomb!</title>
</head>
<body>
<h1>The Bomb!</h1>
</body>
</html>
View for error (/WEB-INF/content/error.jsp)
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Global Error Handler</title>
</head>
<body>
<h1>Global Error Handler</h1>
<s:property value="exception.stackTrace"/>
</body>
</html>
Output:
I see error.jsp render and I see the following printed on the glassfish console:
INFO: Is exception null: false
INFO: Hello from Exception!

I was having the same issue you were having!
While it is much cleaner to have the exception field populated by Struts, it appears that this field population is not happening (as you stated). To get around this, I removed the exception field (and its getter/setter) from my Exception handler class (your myErrorProcessor class) and replaced that with a method to "manually" extract the exception from the ValueStack:
/**
* Finds exception object on the value stack
*
* #return the exception object on the value stack
*/
private Object findException() {
ActionContext ac = ActionContext.getContext();
ValueStack vs = ac.getValueStack();
Object exception = vs.findValue("exception");
return exception;
}
I can then use instanceof to make sure the exception Object is the type that I was expecting and then handle that exception accordingly (like writing messages found in a custom Exception object to a database).
Let me know how this works for you! :)

Related

primefaces graphicimage CDI bean doesn't work

i had some problem showing images retrieved by my db.
View caller:
<p:graphicImage value="#{appController.image}" height="200 px" >
<f:param name="oid" value="#{item.oid}" />
</p:graphicImage>
Controller:
#Named("appController")
#ApplicationScoped
public class AppController {
#Inject
private MultimediaFacade multimediaFacade;
public StreamedContent getImage() throws IOException {
System.out.println("getting image")
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
} else {
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
String imageId = context.getExternalContext().getRequestParameterMap().get("oid");
int oid=Integer.parseInt(imageId);
System.out.println(oid);
Multimedia image = multimediaFacade.find(oid);
System.out.println(Arrays.toString(image.getFileBlob()));
return new DefaultStreamedContent(new ByteArrayInputStream(image.getFileBlob()));
}
}
}
this code shows nothing and it looks like the method is never called (never print in console)!
after days of trial changing the scope, i tried to use #ManagedBean instead of #Named, and it works!!!
can someone explain me why this work only with #ManagedBean and not with #Named?
Check that you have javax.enterprise.context.ApplicationScoped in imports.
If you have a different import for #ApplicationScoped (e.g. javax.faces.bean.ApplicationScoped), then you need to configure CDI to discover all beans instead of only those with CDI annotations (which is the default)
To tun discovery for all beans, either add empty beans.xml into WEB-INF directory, or if you already have beans.xml there, add bean-discovery-mode="all" into the <beans> element, like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="annotated">
</beans>

Apache-cxf client gets SOAPFaultException instead of custom exception

I'm having troubles with handling Exceptions in my apache-cxf client.
I'm expecting an exception that is thrown by the soap call 'Fault_Exception' but I'm always receiving the common SOAPFaultException
Generated classes:
#WebFault(name = "FaultMessage", targetNamespace = "http://a.b.c/ws/")
public class Fault_Exception extends Exception {
private a.b.c.Fault faultMessage;
....
}
and Fault is
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "fault", propOrder = {
"code",
"description",
"stack"
})
public class Fault {
...
}
soap:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>EXCEPTION</faultstring>
<detail>
<Fault xmlns:n1="http://a.b.c/ws/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://a.b.c/ws/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="n1:fault">
<code xmlns="http://a.b.c/ws/">error.code.1</code>
<description xmlns="http://a.b.c/ws/">some description of the error.</description>
<stack xmlns="http://a.b.c/ws/">....</stack>
</Fault>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Is there a mismatch between the generated classes and the response ?
Or what else can be the problem of this?
Or is it totally logic that I get a SOAPFaultException? I have no clue how to get the information (code & description) then ...
Kind regards!

Insert XmlFile (or other) from camel route to mongoDB

I've been trying to insert a XML file into mongoDB with camel and I can't manage to make it work.
I've followed this tutorial for the first steps:
http://www.pretechsol.com/2014/09/apache-camel-mongodb-component-example.html
In my route, I convert it in JSON then use 'convertBodyTo(string.class) for mongo to recognize the file.
The code works well with regular route (sending the file to another folder for example). But when I run it for mongoDB, all I get in the console is my Process message again and again with my databased never being filled.As I don't receive any error message, I don't know how to find where the problem come from.
The mongoDB name, ip, users, password have been already checked multiple times.
I would be very grateful if someone could help me on this one. Here is the files I am using. (I will spare you the process file).
camel-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="myDb" class="com.mongodb.Mongo">
<constructor-arg index="0">
<bean class="com.mongodb.MongoURI">
<constructor-arg index="0"
value="mongodb://username:password#192.168.3.29:27017/db" />
</bean>
</constructor-arg>
</bean>
<bean id="mongodb" class="org.apache.camel.component.mongodb.MongoDbComponent"></bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<routeBuilder ref="camelRoute" />
</camelContext>
<bean id="camelRoute" class="infotel.camel.project01.CamelRoute" />
Here is my RoutingFile:
#Component
public class CamelRoute extends SpringRouteBuilder {
final Processor myProcessor = new MyProcessor();
final Processor myProcessorMongo = new MyProcessorMongo();
final XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat();
#Override
public void configure() {
xmlJsonFormat.setForceTopLevelObject(true);
from("file:xml_files?noop=true").marshal(xmlJsonFormat).convertBodyTo(String.class).process(myProcessorMongo)
.to("mongodb:myDb?database=test_bignav&collection=doc&operation=insert");
}
}
And finally here is my main:
public class MyMain {
public static void main(String[] args) throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/spring/camel-context.xml");
}
}
Thanks a lot.
Edit:
Here is MyProcessorMongo edited to get the error:
public class MyProcessorMongo implements Processor{
public void process(Exchange exchange) throws Exception {
System.out.println("\n file transfered to mongo: "+ exchange.getIn().getHeader("CamelFileName"));
exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class).printStackTrace();
}
}
Enable tracing with trace="true":
<camelContext trace="true" xmlns="http://camel.apache.org/schema/spring">
Dirty but quick, to get the error you can add this to you configure() method before your from :
.onException(Exception.class).handled(true).process(new Processor() {
#Override
public void process(Exchange exchange) {
exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class).printStackTrace();
}
})
The handled(true) prevents your message from being processed again and again.
thanks for your help I have been able to get the error message.
The problem actually came from mongoDB itself and not camel or code. With the change on users the connection works and I'm able to insert document inside a collection.
Remove the ".process(myProcessorMongo)" from route configuration . Input xml-> json conversion->string conversion -> Mongodb. Above route will work. And you are passing the exchange object to myProcessorMongo but Out message is null so nothing will be inserted into MongoDB . Put exchange.getOut().getBody(); in the myProcessorMongo and print it.If its coming as null u have to get the input message from exchange Obj and set it back it in to Out message property in the exchange Object.

Struts2 JSON Plugin with Hibernate

So I'm trying to create a JSON object from a List of AcaClasses.
Action Class:
public class StudentJSONAction extends ActionSupport{
//Your result List
private List<AcaClass> gridModel;
public String getJSON() {
return execute();
}
public String execute() {
//Get the first student from the Factory and get their AcaClasses
gridModel = StudentFactory.getAll().get(0).getAcaClasses();
return SUCCESS;
}
//Getters and Setters
The StudentFactory is my interface to the hibernate database.
Struts.xml
<action name="getJSON" class="StudentJSONAction">
<result type="json">
<param name="enableSMD">true</param>
<param name="ignoreInterfaces">false</param>
</result>
</action>
When I call the getJSON action, all I get is:
{"methods":[],"objectName":null,"serviceType":"JSON-RPC","serviceUrl":"\/FlowridersSP\/getJSON","version":".1"}
This problem is very similar to mine but I would like to see if there is a solution using the Struts2 JSON Plugin
Question: Why am I not getting back a list of AcaClasses in JSON form?
My end goal is to plug in this JSON in the JQuery Grid Plugin
I am not familiar with JSON plugin, but are you correctly configuring the plugin to serialize the gridModel? A quick look at the plugin documentation suggests that you might want to set the root parameter also:
<action name="getJSON" class="StudentJSONAction">
<result type="json">
<param name="enableSMD">true</param>
<param name="ignoreInterfaces">false</param>
<param name="root">gridModel</param>
</result>
</action>
Also, try to identify if the problem is with StudentFactory or with the JSON serialization. You can set up gridModel with a list of dummy AcaClass objects and see if the serialization works correctly. Also, as suggested by #Quaternion, you can log the list of AcaClass objects loaded by StudentFactory and verify that it is loading the expected instances.

Struts2 Application hides my exceptions after adding Interceptor

So I have a Struts2 application that I'm working on. On my front page I have a section that will display any exceptions my application throws. This worked well until I added a custom Interceptor.
Here is my interceptor code:
public String intercept(ActionInvocation actionInvocation) throws Exception {
String result = actionInvocation.invoke();
return result;
}
This is the code in my Action class where the exception gets generated, it occurs where AuthService.Authorize() is called:
if(AuthService.Authorize(username, password)) {
if(AuthService.AdminAuthorized()) {
return "admin";
}
return SUCCESS;
}
This is inside of AuthService.Authorize(), it throws a null point exception when acc is accessed :
try {
acc = profileRepository.WhereSingle("Username", "=", username);
} catch (Exception e) {
return false;
}
if (acc.Password.equals(password)) {
However, when the page is loaded. This is not populated:
<s:property value="%{exception.message}"/>
I have tested it and it would work if I was simply throwing an exception from the Action class. I am not calling a redirectAction or anything
Here is the top of my default package definition which all my other packages extend
<package name="default" namespace="/" extends="struts-default">
<!-- Interceptors -->
<interceptors>
<interceptor name="conversation" class="global.ConversationInterceptor"/>
<interceptor-stack name="dils-stack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="conversation"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="dils-stack"/>
<global-results>
<result name="Exception" >/index.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="Exception"/>
<exception-mapping exception="java.lang.NullPointerException" result="Exception"/>
</global-exception-mappings>
How is your interceptor stack defined for that action? The ExceptionMappingInterceptor should be defined first in the stack. Can you post the interceptor stack configuration from your struts.xml? Your custom interceptor should not be interfering (it does nothing).
Updated:
I was able to reproduce this issue, however it occurs for me with or without your custom interceptor.
The reason is that you are specifically looking for the exception message, which is not set for NullPointerExceptions that are automatically thrown (as in your case). You can confirm this by instead displaying the stack trace, such as: %{exceptionStack}
%{exception.message} is null for the NullPointerException, and so it displays nothing. If instead you were to throw an exception with a message (e.g., throw new RuntimeException("OMG!");), then you will see the message.
Also, note that you must specify more specific exception mappings before less specific mappings in your struts.xml. Because NullPointerException is more specific than Exception, you must list it first. Note that this doesn't really matter in your example, because they map to the same thing. Just know that your NPE will map to the first entry, not the second.