I'm implementing web application based on Spring MVC and organized around DDD concepts. Currently I try to implement ticket reservation functionality. The customer can see number of tickets available for the particular event. Then, he can enter number of tickets to be reserved and submit form. Request is received by controller which calls application service responsible for registration. Application service logic is as follows:
Validate incoming parameters:
1A. Check if event with the given ID exists
1B. Check if number of tickets available allows for reservation
If validation passed, proceed with registration; otherwise, report an error.
I have some doubts about the proper way for reporting validation errors - especially for point 1B. Situation when number of tickets does not allow for reservation is not something very unusual. Customer can see number of tickets that is not fully synchronized with current number of tickets in database (eventual consistency) - some other person could reserve some tickets in the meantime.
Initially I was thinking about reporting this problems by throwing some specific exceptions. However, I can think of couple of other problematic situations and having one exception for each on of them doesn't sound very well.
The other option I was considering was throwing one type of exception containing error code. However, I don't know how to handle this situation in Spring MVC properly.
What are the best practices for such problems? How do you deal with them in your MVC applications? Any advices greatly appreciated.
I think these are business constraint brokens that cannot be recovered.
My current solution is Exception hierachy.
public abstract class UncheckedApplicationException extends RuntimeException {
//omitted factory methods and constructors
public abstract String getStatusCode();
public abstract String getI18nCode();//ignore this if you don't need i18n
public abstract String[] getI18nArgs();//ignore this if you don't need i18n
}
Any custom exception extends this one. I think this could avoid code like this:
try {
//invoke your application service
} catch (InsufficientInventoryException e) {
statusCode = INSUFFICIENT_INVENTORY;
} catch (ExpriedPriceException e) {
statusCode = EXPIRED_PRICE;
} catch (NoSuchProductException e) {
statusCode = NO_SUCH_PRODUCT;
} catch (Exception e) {
statusCode = UNKNOWN;
}
Controller code snippet:
try {
//invoke your application service here
statusCode = SUCCESS;
message = messageSource.getSuccess(locale));
} catch (UncheckedApplicationException e) {
statusCode = e.getStatusCode();
message = messageSource.getMessage(e, locale));
} catch (Exception e) {
statusCode = UNKNOWN;
message = messageSource.getUnknownError(e, locale));
}
//add statusCode & message to modelAttribute
You can use #ExceptionHandler to reduce boilerplate try-catch code if your Controller is well organized(but pretty difficult).
The other reason to use Excepton is that application service is often used to delimit transaction boundary. An exception has to be thrown if you want to rollback.
Related
A few examples for implementing HealthIndicator needs a KafkaTemplate. I don't actually manually create a KafkaTemplate but the HealthIndicator requires one. Is there a way to automatically grab the created KafkaTemplate (that uses the application.yml configurations)? This is versus manually creating duplicated configurations that already exist in the application.yml in a newly created consumerFactory.
See this answer.
(S)he wanted to get access to the template's ProducerFactory but you can use the same technique to just get a reference to the template.
That said, the binder comes with its own health indicator.
https://github.com/spring-cloud/spring-cloud-stream-binder-kafka/blob/a7299df63f495af3a798637551c2179c947af9cf/spring-cloud-stream-binder-kafka/src/main/java/org/springframework/cloud/stream/binder/kafka/KafkaBinderHealthIndicator.java#L52
We also had the same requirement of creating a custom health checker Spring Cloud stream. We leveraged the inbuild health checker(KafkaBinderHealthIndicator). But while injecting the KafkaBinderHealthIndicator bean facing lot of issue. So instead of that we inject the health checker holder HealthContributorRegistry, and got the KafkaBinderHealthIndicator bean from it.
Example:
#Component
#Slf4j
#RequiredArgsConstructor
public class KafkaHealthChecker implements ComponentHealthChecker {
private final HealthContributorRegistry registry;
public String checkHealth() {
String status;
try {
BindersHealthContributor bindersHealthContributor = (BindersHealthContributor)
registry.getContributor("binders");
KafkaBinderHealthIndicator kafkaBinderHealthIndicator = (KafkaBinderHealthIndicator)
bindersHealthContributor.getContributor("kafka");
Health health = kafkaBinderHealthIndicator.health();
status = UP.equals(health.getStatus()) ? "OK" : "FAIL";
} catch (Exception e) {
log.error("Error occurred while checking the kafka health ", e);
status = "DEGRADED";
}
return status;
}
}
I have developed an application with spring mvc for high user traffic. Suppose there is least 20,000 concurrent user. I have implemented spring security custom authentication provider in two ways.
1st one is :
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
CustomUser user = _userDetailService.loadUserByUsername(username);
if (user == null || !user.getUsername().equalsIgnoreCase(username)) {
throw new BadCredentialsException("Username not found.");
}
if (!BCrypt.checkpw(password, user.getPassword())) {
throw new BadCredentialsException("Wrong password.");
}
Collection < ? extends GrantedAuthority > authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}
2nd one is:
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
try {
Authentication auth = super.authenticate(authentication);
//if reach here, means login success, else an exception will be thrown
//reset the user_attempts
return auth;
} catch (BadCredentialsException e) {
//invalid login, update to user_attempts
throw e;
}
}
Now my question is whice implementation will give me the faster output?
As already pointed out by Afridi, your 1st version is exactly what DaoAuthenticationProvider is supposed to do. I would strongly discourage from re-implementing its functionality, since you might for example introduce new security relevant errors.
If you really need a custom authentication method, there is no way around a custom authentication method of course. In order to measure the performance of this implementation in general or versus the standard implementation, you should simply define a test scenario (e.g. 20000 dummy authentications as homlis83 suggested) and run the program in a profiler. This will how you exactly how much time is spent in you authentication method and even which part takes the most time.
I think the most popular Java profiler is VisualVM and depending on your IDE there might be a plugin that further simplifies its use. There are also a lot of tutorials for Java profiling out there, but this is definitvely the way to go for you to get reliable data for the performance.
Is there any way in ASP.NET Web API to mark an exception as handled in an ExceptionFilterAttribute?
I want to handle the exception at the method level with an exception filter and stop the propagation to a globally registered exception filter.
Filter used on a controller action:
public class MethodExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
// here in MVC you could set context.ExceptionHandled = true;
}
}
}
The globally registered filter:
public class GlobalExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is SomeOtherException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.SomethingElse)
{
Content = new StringContent(context.Exception.Message)
};
}
}
}
Try throwing an HttpResponseException at the end of your local handling. By design, they are not caught by exception filters.
throw new HttpResponseException(context.Response);
Web API 2 is designed with inversion of control in mind. You consider the possibility for the exception to already be handled, rather than interrupting the filter execution after you handle it.
In this sense, attributes deriving from ExceptionFilterAttribute should check if the exception is already handled, which your code already does since is operator returns false for null values. In addition, after you handle the exception, you set context.Exception to null in order to avoid further handling.
To achieve this in your code, you need to replace your comment from MethodExceptionFilterAttribute with context.Exception = null to clear the exception.
It is important to note that it is not a good idea to register more than one global exception filter, due to ordering issues. For information about the execution order of attribute filters in Web API, see the following thread Order of execution with multiple filters in web api.
I'm migrating some servlets over to the Spring framework, using Spring MVC. Currently in each servlet we authenticate the user and if the authentication fails we do this:
if (authfailed)
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"You are not authorized.");
return;
}
On the front end is a YUI-based application, and when an error status is returned the "failure" callback displays a dialog with the error message given above.
I know in my controller I can get the response object and call sendError, but is that the best way to handle this? sendError also throws an IOException so I'd have to catch that - a bit of annoying code to insert in every method of every controller.
I have the same problem handling exceptions - the servlets have try-catch blocks that call sendError in the catch method. I know I can mark my exception handlers with
#ExceptionHandler
#ResponseStatus(value = HttpStatus.NOT_FOUND)
but doesn't the exception handling class need to be in each controller class?
Finally, if the exception happens in a service called from a controller, does the exception bubble up to the controller or should I handle the exception in the service (thus pushing these exception handling issues into the service layer)?
This seems more difficult than it should be, but as with many things in Spring it's likely I don't understand what's going on. All I want to do is to send an error status and message back in the response!
Thanks,
Paul
It looks like you have the most of the answers in your question itself :)
To reiterate,
Have the controller like this
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request) throws NotFoundException {
String id = request.getParameter("id");
if (id == null)
throw new NotFoundException("Id not found in the request");
return "success";
}
Declare the exception class in NotFoundException.java,
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Id Not Found")
public class NotFoundException extends Exception {
public NotFoundException(String msg) {
super(msg);
}
}
This exception class need not be every controller class. Declare it as public class and import it in every required controller.
This is one way of doing it. If you like the non-spring style, declare HttpServletResponse in every controller arguments and do
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request, HttpServletResponse response) {
...
try {
response.sendError(..)
catch(..) {}
}
Or you can use views to show error message,
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request, Map<String, Object> map){
String id = request.getParameter("id");
if (id == null) {
map.put("status", HttpStatus.NOTFOUND);
map.put("reason", "Id Not Found");
return "error"
}
return "success";
}
Make sure your viewResolver is configured correctly and in the error.jsp to get the error string, you could say.
<body>
${status} ${reason}
</body>
Define error.jsp with nice css for all kind of errors you would expect.
These are not the only ways. With spring you have freedom to do anything. I have seen few ppl rendering json object for error message.
To answer your another question of if the error happens in the service called by the controller is depend on your scenario. For example you are trying to read the user store, if the user store not available error happens, I would handle there itself to read from another replica user store if one available and If I found user does not exist I would leave the exception to the controller to throw.
The default behavior of a [WebMethod] attributed static method on an aspx page is to return the error to the caller. We are accessing these methods using json, and the only way we have found of capturing exceptions is either a try/catch in every webmethod on the site or using a javascript callback with the error (which has the unacceptable downside of exposing the error to the client).
Is there any way to globally handle these exceptions using the HealthMonitoring setup in ASP.NET?
I don't know about health monitoring, but I normally have a generic wrapper that executes the endpoint code inside. This records the real exception but always throws a generic exception across the boundry.
public static T wrapAjaxRequestsToCatchException<T>(Func<T> wrappedDelegate) where T : JsonBase, new()
{
try
{
return wrappedDelegate();
}
catch (Exception ex)
{
var errResponse = new T()
{
Success = false,
Message = getErrorMessage(ex)
};
// Log the exception
ErrorLog.LogAjaxEvent(string.Format("AJAX EXCEPTION : {0}", ex.ToString()), System.Diagnostics.EventLogEntryType.Error);
return errResponse;
}
}