JavaEE Globally Catch Runtime exception - java

I want to "globally" catch a Runtime exception, now this sounds silly right but let me explain.
I have created a interceptor that I use on all my ejbs which require authorization to use, this interceptor is called every time a method is called.
See here the code:
#Secure
#Interceptor
public class SecurityInterceptor {
#EJB
private SessionManager sessionManager;
#AroundInvoke
private Object securityCheck(InvocationContext ctx) throws Exception {
System.out.println("hello");
List<UserGroup> allowedRoles = (List<UserGroup>) ctx.getContextData().get("rolesAllowed");
sessionManager.isAuthorized(allowedRoles);
return ctx.proceed();
}
}
Now I don't want in my Named Bean to surround the body of every method that uses one of these secured beans with a try and catch block, like this:
public List<Contracts> getContracts() {
List<Contracts> contracts = new ArrayList<>();
try {
contracts = contractEntityManager.getAll();
} catch (EJBTransactionRolledbackException e) {
Throwable throwable = ExceptionUtils.getRootCause(e);
if (throwable instanceof NotAuthenticatedException) {
System.out.println("Not Authenticated");
}
else if (throwable instanceof UnAuthorizedException) {
System.out.println("Not Authorized");
}
}
return contracts;
}
So is there some way to globally catch a runtime exception and the redirect the user to the login page if he is unauthenticated and to a error page when he is unauthorized.
Maybe my design is just generally bad and I would need to complety rethink this idea.
Please let me know.
Thank you

So, in the end, it is the in the web tier that you want to catch the exceptions. This is easy:
If you are only on servlets, specify the error-page element in web.xml for each exception you wish to handle, e.g. as follows:
<error-page>
<exception-type>fully.quallified.NotAuthenticatedException</exception-type>
<location>/where/to/redirect/eg/login</location>
</error-page>
You declare the exception you want to handle globally and the URL you want to handle it, it may be a servlet, a JSP or any other resource.
JAX-RS offers a similar mechanism with the javax.ws.rs.ext.ExceptionMapper:
#Provider
public class NotAuthenticatedExceptionMapper implements ExceptionMapper<NotAuthenticatedException> {
...
}

Related

#ControllerAdvice doesn't handle more specific exception

There's a piece of code that throws a exception:
java.lang.RuntimeException: cn.dev33.satoken.exception.NotLoginException: Invalid Token:ldxutBDDKBEDa9LjWNTKLFbW7g7B86qU.
And then it goes into handleRuntimeException rather than returnNotLoginException method.
#Component
#Slf4j
#Primary
public class MyLockKeyBuilder extends DefaultLockKeyBuilder {
#Override
public String buildKey(MethodInvocation invocation, String[] definitionKeys) {
String key = super.buildKey(invocation, definitionKeys);
Object loginId = StpUtil.getLoginId(); // throw a exception
key = loginId.toString();
return key;
}
}
#ControllerAdvice(basePackages = "com.test")
#Slf4j
public class GraceExceptionHandlerApp {
#ResponseStatus(HttpStatus.UNAUTHORIZED)
#ExceptionHandler(value = NotLoginException.class)
#ResponseBody
public JSONObject returnNotLoginException(NotLoginException e) {
e.printStackTrace();
String message = e.getMessage();
ResponseStatusEnum failed = ResponseStatusEnum.UNAUTHORIZED;
failed.setMsg(message);
return ZheliResult.exception(failed);
}
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(RuntimeException.class)
#ResponseBody
public JSONObject handleRuntimeException(RuntimeException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
return ZheliResult.errorCustom(ResponseStatusEnum.FAILED);
}
...
}
I want it goes into the returnNotLoginException method, could anyone tell me how to do it?
UPDATE
I've made a mistake, really, for I didn't offer enough info.
Missed Info:
My application was a distributed system and services to invoke another via rpc communication. MyLockKeyBuilder was on the provider service, and GraceExceptionHandlerApp was on the comsumer service.
When the provider service throw a exception and before it being passed to the comsumer sevice, it would be filter by a Filter called ExceptionFilter, which wrap the exception that the comsumer side doesn't recognize to RuntimeException, to avoid serialization issue.
Finally I solved this problem by rewritting the ExceptionFilter class to allow original NotLoginException to be passed to the consumer side.
NotLoginException is the inner exception of your RuntimeException. If you want your controller advice to handle it, catch the RuntimeException buildKey and throw its inner exception.
Based on your question,
java.lang.RuntimeException: cn.dev33.satoken.exception.NotLoginException: Invalid Token:
Your exception type is java.lang.RuntimeException & cause of exception is NotLoginException.
Controller advice will invoke respective method when type of exception matches & not cause of exception.
So if you really want to invoke returnNotLoginException, then you need to throw NotLoginException in your logic instead of throwing RuntimeException.
Something like:
..
throw new NotLoginException("exception"); //in your StpUtil.getLoginId();
..

how to trigger ExceptionMapper in jersey 2?

I have a problem with my ExceptionMapper:
#Provider
#Component
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
public GenericExceptionMapper() {
logger.debug("hej hopp");
}
#Override
public Response toResponse(Throwable exception) {
ErrorMessage errorMessage = new ErrorMessage("Technical error",
"An unknown technical error occured.");
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(errorMessage).build();
}
}
It doesn't catch any exceptions from my resources. I have placed a debug point in the constructor and see that it is created. I have debuged the request and it doesn't seem to look for any exception handlers.
This is part of my configuration:
#ComponentScan("com.companywhereiwork.application")
And another part:
jerseyServlet.setInitParameter("jersey.config.server.provider.packages",
"com.companywhereiwork.application");
When I throw an exception from inside one of my resources:
if (Math.random() < 1f) {
throw new RuntimeException("Blä");
}
It is returned to the client as a tomcat errorpage. It doesn't enter my errorhandler.
The solution was to remove the #Component annotation. For some reason, the ExceptionMapperFactory didn't pick up my class when it had double annotations like this. I didn't think it would be a problem, but it was. It now works (and I know a little more about the ExceptionMapperFactory).

How to return http status code for exceptions in rest services

In my application I have different layers like the rest layer, service layer and DB layer, according to business scenarios I am trowing different business exceptions from the service layer.
But now, I have to set different HTTP codes like 400, 403, 409, 412.. to REST responses.
How can I set different HTTP status codes based on different scenarios?
Which is the most feasible way like: aspect, exception mapper, or ....?
Since I can set HTTP status only once in rest layer (
referred this ), I am not able to map to different HTTP codes because my exception is from service layer.
My exception class looks like this:
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
public BusinessException(ErrorEnumeration error) {
}
public BusinessException(Exception e, ErrorEnumeration error) {
}
}
and the exception will be thrown from the service like this:
throw new BusinessException(ErrorEnumeration.VALIDATION_FAILED);
Please help by suggesting a solution
You can use exceptions defined in jax-rs or you can use your own exceptions. Fist catch your business exceptions and convert them to jax-rs versions. For example, for 404 you can throw javax.ws.rs.NotFoundException.
You can also write your own exceptions by extending them from javax.ws.rs.ClientErrorException
Here is an example for 409-Conflict status exception
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.core.Response;
public class ConflictException extends ClientErrorException{
public ConflictException(Response.Status status) {
super(Response.Status.CONFLICT); // 409
}
}
Update
Most simple and feasible way is catching your business exceptions and re-throw them with jax-rs exceptions.
try{
businessService.executeBusinessRule();
}catch (BusinessException e){
// It is better if your BusinessException has some child class to handle
if(e.getError() == ErrorEnumeration.VALIDATION_FAILED){
throw new BadRequestException();
}else{
throw new ConflictException();
}
}
If you are using spring you can always catch these exceptions using aop.
#Aspect
public class BusinessExceptionInterceptor{
#AfterThrowing(pointcut = "execution(* com.your.service.packge..* (..))", throwing = "e")
public void errorInterceptor(BusinessException e) {
// re-throw again...
}
Update 2
Also it is better to define a new exception instead of reusing same exception with different state. You can define a new ValidationException which extends from BusinessException like this.
public class ValidationException extends BusinessException{
public ValidationException() {
super(ErrorEnumeration.VALIDATION_FAILED);
}
}
By using this way you can still handle all the BusinessException but it is easier to identify or map them to Jax-rs exceptions.

EJBProcessor exception handling

I have a JBOSS ESB that uses a standard out of the box EJBProcessor action. How do I get hold of an exception, if the exception be thrown in the method call that was run in the EJB?
Any advice would be helpful.
You can subclass EJBProcessor and override the process method like this:
#Override
public Message process(Message pMessage) {
try {
pMessage = super.process(pMessage);
} catch (Throwable wEx) {
handleProcessError(pMessage, wEx);
}
return pMessage;
}
You will more than likely catch an instance of ActionProcessingException, and you can look at the cause to see the exception in your EJB.
Your action configuration in your jboss-esb.xml will remain exactly the same, except you will substitute the name of your subclass for org.jboss.soa.esb.actions.EJBProcessor.

JBoss JAAS custom Login Module Error messages

I have an application that makes used of a custom login module of JBoss. Authentication can fail for a wide variety of reasons and i have to display these to the user instead of the usual Inavlid username / password error.
Is there a way to get error message from the login message? I think the best would be to through an exception since authenticate returns a boolean, however i can't figure how to catch it after authentication. Any pointers welcomes.
Used valve org.jboss.web.tomcat.security.ExtendedFormAuthenticator and grabbed j_exception from the session.
Ref:
http://books.zkoss.org/wiki/Small_Talks/2009/August/Form_Based_Login_with_JAAS_on_JBoss_and_ZK
http://community.jboss.org/wiki/ExtendedFormAuthenticator
You can use the Database login module and then get the exception using
Exception e = (Exception) SecurityContextAssociation.getContextInfo("org.jboss.security.exception");
You can use this code inside managed bean function to fetch the error message ex.
public String getLoginFailureMsg(){
Exception e = (Exception) SecurityContextAssociation.
getContextInfo("org.jboss.security.exception");
if(e != null){
if(e.getMessage().contains("PB00019"))
return "invalid username";
else
return "invalid password";
}
return null;
}
for setting up JAAS with Jboss 7 see this blow:
http://amatya.net/blog/implementing-security-with-jaas-in-jboss-as-7/
I had the same problem..., but I don't like writting code tied to container for obvious reasons.
So what I did was to add the exception to the session myself.
First, build a ThreadLocal exception holder to send the exception between LoginContext and ServletContext:
public final class SecurityThreadLocal {
private static final ThreadLocal<Exception> j_exception = new ThreadLocal<Exception>();
public static void setException(Exception e) {
j_exception.set(e);
}
public static Exception getException() {
return (Exception)j_exception.get();
}
public static void clear() {
j_exception.remove();
}
}
Add LoginException to SecurityThreadLocal:
catch (Exception e) { // or just catch LoginException
log.log(Level.SEVERE, e.getMessage(), e);
SecurityThreadLocal.setException(e);
}
Add Exception to the HttpSession with a Filter:
web.xml
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
SecurityFilter.java
if (uri.endsWith("<form-error-page>") && session != null){
Exception j_exception = SecurityThreadLocal.getException();
if( j_exception != null)
session.setAttribute("j_exception", j_exception);
}
But you should know as I know this is a bad practice and a security crack.
Well.., in my case the customer won ...

Categories

Resources