Fixing the pointcut definition error while defining an aspect for tracing the RabbitMQ send - aspectj

The opentracing instrumentation for spring-rabbitmq doesn't have an aspect defined for tracing the org.springframework.amqp.rabbit.core.RabbitTemplate#send. Here is the link of the code: RabbitMqSendTracingAspect.java
I tried implementing it and got some serious errors while defining a pointcut.
Here is my code for the same:
#Aspect
#Configuration
public class AmqpSendTracingAspect {
private final Tracer tracer;
public AmqpSendTracingAspect(Tracer tracer) {
this.tracer = tracer;
}
#Around(value = "execution(* org.springframework.amqp.core.AmqpTemplate.send(..)) " +
"&& args(exchange,routingKey, message)",
argNames = "pjp,exchange,routingKey,message")
public Object traceAmqpSend(ProceedingJoinPoint pjp,
String exchange, String routingKey, Message message) throws Throwable {
final Object[] args = pjp.getArgs();
System.out.println("Aspect RUnning");
final MessageProperties messageProperties = message.getMessageProperties();
Scope scope = AmqpTracingUtils.buildSendSpan(tracer, messageProperties);
tracer.inject(
scope.span().context(),
Format.Builtin.TEXT_MAP,
new AmqpInjectAdapter(messageProperties));
AmqpSpanDecorator spanDecorator = new AmqpSpanDecorator();
spanDecorator.onSend(messageProperties, exchange, routingKey, scope.span());
args[2] = message;
try {
return pjp.proceed(args);
} catch (Exception ex) {
spanDecorator.onError(ex, scope.span());
throw ex;
} finally {
scope.close();
}
}
}
I am getting the following errors from CglibAopProxy framework even when I annotated with #EnableAspectJAutoProxy(proxyTargetClass = false)
Unable to proxy interface-implementing method [public final void org.springframework.amqp.rabbit.core.RabbitTemplate.start()] because it is marked as final: Consider using interface-based JDK proxies instead!
Unable to proxy interface-implementing method [public final void org.springframework.amqp.rabbit.core.RabbitTemplate.stop()] because it is marked as final: Consider using interface-based JDK proxies instead!
Please help me out!

It's not an error. the code producing that message is like this:
if (implementsInterface(method, ifcs)) {
logger.info("Unable to proxy interface-implementing method [" + method + "] because " +
"it is marked as final: Consider using interface-based JDK proxies instead!");
}
So, it is an info and it fully doesn't stop your application to work afterward. Just a pointer that RabbitTemplate.start() method is not going to be proxied, which definitely should not be. So, you are good so far.
I think since you use Spring Cloud, you are not able to override the AOP config with that #EnableAspectJAutoProxy therefore it always uses CglibAopProxy.
I would just ignore that info. Would be better do not such a logging level for framework categories.

Related

Customising Spring Boot Exception Handling to Prevent Stacktraces Being Returned in Rest Response

How do I configure my spring boot service so that errors such as 500 don't potentially leak implementation details such as stacktraces.
{
"timestamp": "2019/05/01 15:06:17",
"status": 500,
"error": "Internal Server Error",
"message": "Type definition error: [simple type, class net.i2p.crypto.eddsa.math.ed25519.Ed25519LittleEndianEncoding]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class net.i2p.crypto.eddsa.math.ed25519.Ed25519LittleEndianEncoding and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.Collections$UnmodifiableRandomAccessList[0]->........)",
"path": "/api/test"
}
Note: here the stacktrace is in the message and not the exception part of the json.
As you can see I am already formatting the timestamp with:
#Component
public class CustomErrorAttributes extends DefaultErrorAttributes {
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
private static final String TIMESTAMP = "timestamp";
#Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
//Let Spring handle the error first
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
//Format & update timestamp
Object timestamp = errorAttributes.get(TIMESTAMP);
if(timestamp == null) {
errorAttributes.put(TIMESTAMP, dateFormat.format(new Date()));
} else {
errorAttributes.put(TIMESTAMP, dateFormat.format((Date)timestamp));
}
return errorAttributes;
}
}
But I need to handle the message too.
If this 500 was the only error I could just do:
errorAttributes.put("message", "Server error. Contact support.");
However, all the errors go through here and that would override all the messages.
I could check if the status is 500 and only modify it then. However, there are other errors that can be generated that also might leak stacktraces.
Using #RestControllerAdvice seems to require knowing every exception that is generated and having an #ExceptionHandler for each and knowing which status code to respond with.
Is there a cleaner way to handle this?
It may not be the "cleanest" approach, but with projects I've been on we had a "standard format" for our Error Responses across projects, so we had a custom object with the fields that matched our orgs standard (HttpStatus, Reason, ect.) that extended RuntimeException. Then in our controllers, services, repos, ect we would catch exceptions and create this object accordingly and throw the custom one up instead. Based upon where it happened in the app (repo, service, controller, ect.) we could give our own custom verbage to it, but still log out the full exception in our server logs so we could investigate later
For example if we caught an error in our repository we would create our custom error object, set the Reason to DB unavailable (really all the consumer needs to know), set the status to HttpStatus.SERVICE_UNAVAILABLE (we tracked these with reasons and httpstatus with enums to keep status the same across modules), and throw the custom object up to the controller to be returned.
Sorry if this was a longwinded answer that may not give you what you want, I'm not too familiar with how you're trying to do it so figured I'd just give an example of other methods. I'll put some sample code as well
Custom Exception:
data class MyException(
val reason: String,
val httpStatus: HttpStatus? = null
) : RuntimeException(reason)
Method for creation:
fun createApiException(errorCode: ErrorCodeEnum) = MyException(
reason = errorCode.reason,
httpStatus = errorCode.httpStatus,
)
Spring-boot provides us with a standard method to handle exceptions using spring aop concept. You can use the #ControllerAdvice and #Exceptionhandled annotations to handle exceptions from a spring-boot rest endpoint so that a custom exception is always thrown from a rest endpoint with proper error code and error response.
The #ResponseStatus() annotation can be used to customize the response code being thrown.
For example consider the custom exception :
#ResponseStatus(HttpStatus.NOT_FOUND)
public class DataNotFoundException extends RuntimeException {
public DataNotFoundException(String exception) {
super(exception);
}
}
We can throw this error from a rest GET mapping when a data is not found like :
#GetMapping("/trains/{id}")
public Resource<Student> retrieveTrains(#PathVariable long id) {
Optional<Trains> trains = trainRepository.findById(id);
if (!train.isPresent())
throw new DataNotFoundException("id-" + id);
Resource<Trains> resource = new Resource<Trains>(train.get());
ControllerLinkBuilder linkTo = linkTo(methodOn(this.getClass()).retrieveAllTrains());
resource.add(linkTo.withRel("all-trains"));
return resource;
}
Default error response provided by Spring Boot contains all the details that are typically needed.
However, you might want to create a framework independent response structure for your organization. In that case, you can define a specific error response structure.
For example :
public class ErrorDetails {
private Date timestamp;
private String message;
private String details;
public ErrorDetails(Date timestamp, String message, String details) {
super();
this.timestamp = timestamp;
this.message = message;
this.details = details;
}
To use this error node we use :
#ControllerAdvice
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(DataNotFoundException.class)
public final ResponseEntity<ErrorDetails> handleUserNotFoundException(DataNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
#ExceptionHandler(DataNotFoundException.class) indicates that this
method would handle exceptions of the specific type.
new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND) - Create an
error response object and return it with a specific Http Status.
For a more generalized exception handler you can define a method that handles exception of the type Exception.class, that way you don't have to know every exception.
Like :
#ExceptionHandler(Exception.class)
public final ResponseEntity<ErrorDetails> handleAllExceptions(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
}
Reference from : https://www.javaguides.net/2019/02/spring-boot-2-angular-7-crud-example-tutorial.html

Issues with Restful Jersey and JSON

I have a strange issue and didn't find any information about it at all.
Having a simple POJO like (simplified..)
#XmlRootElement
public class Bill {
List<Position> positions
.. getter/setter
}
#XmlRootElement
public class Position {
.. some simple properties with getters/setters
}
I am unable to call a RESTful Service using instances of these classes. I'm getting real weird errors I don't really understand.
org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.util.List out of START_OBJECT token
The funny thing is, when I just test serialization/deserialization using Jackson Object mapper directly, it works as expected!
ObjectMapper mapper = new ...
mapper.writeValue(stringWriter, bill);
mapper.readValue(stringWriter.toString(), Bill.class);
This works perfectly. So I guess the POJO itself is OK and Jackson is able to handle the JSON-String.
Calling the RESTful service using the same Bill instance fails with the error mentioned above. I see it is using Jackson as well, here is part of stack trace:
at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:160)
at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:198)
at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:103)
at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:93)
at org.codehaus.jackson.map.deser.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
at org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:230)
And here is how the RESTful Application is configured:
#javax.ws.rs.ApplicationPath("rest")
public class ApplicationConfig extends Application {
public Set<Class<?>> getClasses() {
return getRestResourceClasses();
}
/**
* Do not modify this method. It is automatically generated by NetBeans REST support.
*/
private Set<Class<?>> getRestResourceClasses() {
Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
resources.add(rest.RestAPI.class);
// following code can be used to customize Jersey 1.x JSON provider:
try {
Class jacksonProvider = Class.forName("org.codehaus.jackson.jaxrs.JacksonJsonProvider");
resources.add(jacksonProvider);
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
return resources;
}
}
Do you have any idea what I'm missing?
I generated the service and the client with NetBeans. Oh and it works when I use XML instead of JSON.
Any help would be very much appreciated.
I'm sorry but after hours of testing and debugging I finally found the cause of the problem.
Still I would be very interested why this is?
Commenting out the following code did the trick:
// following code can be used to customize Jersey 1.x JSON provider:
try {
Class jacksonProvider = Class.forName("org.codehaus.jackson.jaxrs.JacksonJsonProvider");
resources.add(jacksonProvider);
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE, null, ex);
}

Autofac, OrchardProject and AsyncControllers

I'm working on trying to get an AsyncController to work in OrchardProject. The current version I'm using is 2.2.4.9.0.
I've had 2 people eyeball my code: http://www.pastie.org/2117952 (AsyncController) which works fine in a regular MVC3 vanilla application.
Basically, I can route to IndexCompleted, but I can't route to Index. I am going to assume i'm missing something in the Autofac configuration of the overall project.
I think the configuration is in the global.asax: http://pastie.org/2118008
What I'm looking for is some guidance on if this is the correct way to implement autofac for AsyncControllers, or if there is something/someplace else I need to implement/initialize/etc.
~Dan
Orchard appears to register its own IActionInvoker, called Orchard.Mvc.Filters.FilterResolvingActionInvoker.
This class derives from ControllerActionInvoker. At a guess, in order to support async actions, it should instead derive from AsyncControllerActionInvoker.
Hope this helps!
Nick
The Autofac setup looks ok, and as long as you can navigate to something I cannot say that your assumption makes sense. Also, the pattern you are using for initialization in global.asax is used by others too.
The AsyncController requires that async methods come in pairs, in your case IndexAsync & IndexCompleted. These together represent the Index action. When you say you can navigate to IndexCompleted, do you mean that you open a url "..../IndexCompleted"?
Also, and this I cannot confirm from any documentation, but I would guess that AsyncController requires that all actions are async. Thus, your NewMessage action causes trouble and should be converted to an async NewMessageAsync & NewMessageCompleted pair.
I did too needed to have AsyncController which I easily changed FilterResolvingActionInvoker to be based on AsyncControllerActionInvoker instead of ControllerActionInvoker.
But there was other problems because of automatic transaction disposal after completion of request. In AsyncController starting thread and the thread that completes the request can be different which throws following exception in Dispose method of TransactionManager class:
A TransactionScope must be disposed on the same thread that it was created.
This exception is suppressed without any logging and really was hard to find out. In this case session remains not-disposed and subsequent sessions will timeout.
So I made dispose method public on ITransactionManager and now in my AsyncController, whenever I need a query to database I wrap it in:
using (_services.TransactionManager) {
.....
}
new TransactionManager :
public interface ITransactionManager : IDependency, IDisposable {
void Demand();
void Cancel();
}
public class TransactionManager : ITransactionManager {
private TransactionScope _scope;
private bool _cancelled;
public TransactionManager() {
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void Demand() {
if (_scope == null) {
Logger.Debug("Creating transaction on Demand");
_scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = IsolationLevel.ReadCommitted
});
_cancelled = false;
}
}
void ITransactionManager.Cancel() {
Logger.Debug("Transaction cancelled flag set");
_cancelled = true;
}
void IDisposable.Dispose() {
if (_scope != null) {
if (!_cancelled) {
Logger.Debug("Marking transaction as complete");
_scope.Complete();
}
Logger.Debug("Final work for transaction being performed");
try {
_scope.Dispose();
}
catch {
// swallowing the exception
}
Logger.Debug("Transaction disposed");
}
_scope = null;
}
}
Please notice that I have made other small changes to TransactionManager.
I tried the AsyncControllerActionInvoker route as well to no avail. I would get intermittent errors from Orchard itself with the following errors:
Orchard.Exceptions.DefaultExceptionPolicy - An unexpected exception was caught
System.TimeoutException: The operation has timed out.
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.Async.ReflectedAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3f.<BeginInvokeAsynchronousActionMethod>b__3e(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
NHibernate.Util.ADOExceptionReporter - While preparing SELECT this_.Id as Id236_2_, this_.Number as Number236_2_,...<blah blah blah>
NHibernate.Util.ADOExceptionReporter - The connection object can not be enlisted in transaction scope.
So I don't think just wrapping your own database calls with a transaction object will help. The innards of Orchard would have to modified as well.
Go vote for this issue if you want AsyncControllers supported in Orchard:
https://orchard.codeplex.com/workitem/18012

How to trigger onFailure in GWT RPC? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
StatusCodeException Vs. RuntimeException in GWT
I want to trigger RPC callback "onFailure" if the session expires in the server.
I created a custom RPC AsyncCallback that handles the "session expired" event from the server.
I overrode RemoteServiceServlet to validate the session prior to invoking the method. So basically, it is not the declared method that throws the exception but the custom RemoteServiceServlet. It still goes to the "onFailure" in the client async but the Throwable object is still of type "StatusCodeException" without the EXPIRED_SESSION_MSG message. Any ideas?
Custom RemoteServiceServlet:
public class XRemoteServiceServlet extends RemoteServiceServlet {
private final static String EXPIRED_SESSION_MSG = "ERROR: Application has expired session.";
#Override
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) {
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
HttpSession session = httpServletRequest.getSession(false);
if (session != null) {
final String sessionIdFromRequestHeader = getSessionIdFromHeader();
if (!isNullOrEmptyString(sessionIdFromRequestHeader)) {
final String sessionId = session.getId();
if (!sessionId.equals(sessionIdFromRequestHeader)) {
throw new RuntimeException(EXPIRED_SESSION_MSG);
}
}
Custom AsyncCallback:
public class XAsyncCallback<T> implements AsyncCallback<T> {
private final static String EXPIRED_SESSION_MSG = "ERROR: Application has expired session.";
#Override
public void onFailure(Throwable caught) {
final String message = caught.getMessage();
if (!isNullOrEmptyString(message) && message.contains(EXPIRED_SESSION_MSG)) {
com.google.gwt.user.client.Window.Location.reload();
}
}
#Override
public void onSuccess(T arg0) {
}
/**
* Returns true if the string is null or equals to the empty string.
*
* #param string the string to test
* #return true if the string is empty
*/
private static boolean isNullOrEmptyString(String string) {
return string == null || "".equals(string);
}
}
See here for handling exceptions with GWT RPC.
An "expected failure" is an exception thrown by a service method that is declared in the signature of the service method. These exceptions are serialized back to the client.
"Unexpected expections" are errors that are not part of the service method's signature, or that result from SecurityExceptions, SerializationExceptions, or other failures within the RPC framework.
What you want is a checked exception, because you want to send it back to the client and do something about it. The RPC framework is in charge of catching it, serializing it and calling the onFailure method with the right exception. In order to do that, you need to follow its guidelines which are :
You need to specifiy in the service
signature that the exception can be
thrown.
The exception must be thrown
in the service implementation method.
What you're doing is throwing an unexcepted exception from some method that shouldn't even be throwing exceptions. So RPC doesn't know what really happened and sends back a generic message saying 'Hey, something unexpected happened, look at the server log'.
I understand that you want to check the session on every call. Your easiest option is to have a method to check that in your servlet implementation and call it from all your service methods.
Otherwise, you can try to override the GWT RPC framework by looking at the class
com.google.gwt.user.server.rpc.RPC
but that's pretty advanced stuff.
If you want to send exceptions via GWT-RPC you must use checked exceptions. RuntimeException is an unchecked exception so you can not use it in this case.
Create your own exception that extends Exception and implements Serializable. Also, you must indicate on methods declaration that this method might throw an exceptions:

StatusCodeException Vs. RuntimeException in GWT

In my GWT app. I overrode RemoteServiceServlet to check if the session is valid right before the service method is being called. I am trying to throw a RuntimeException("expired session") from the server and I would like the client to catch this exception from the asynccallback onFailure...
In the client I would like to:
Asynccallback:
#Override
public void onFailure(Throwable caught) {
final String message = caught.getMessage();
if (!isNullOrEmptyString(message) && message.contains("expired session")) {
com.google.gwt.user.client.Window.Location.reload();
}
}
However, in the client, the caught object is still a StatusCodeException and the message is still the default "...Exception in the server...". how can I override the exception at least the default message to compare if it was a session expired message I sent from the server?
thanks
Hi Gursel,
Here's my code:
-> Custom RemoteServiceServlet. I'm trying to "intercept" every method before it's invoked. I check the session and throw a RuntimeException if it's already expired. So basically, it is not the declared method that throws the exception but the custom RemoteServiceServlet. It still goes to the "onFailure" in the client async but the Throwable object is still of type "StatusCodeException" without the EXPIRED_SESSION_MSG message. Don;t know how to make this work. Thanks!
public class XRemoteServiceServlet extends RemoteServiceServlet {
private final static String EXPIRED_SESSION_MSG = "ERROR: Application has expired session.";
#Override
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) {
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
HttpSession session = httpServletRequest.getSession(false);
if (session != null) {
final String sessionIdFromRequestHeader = getSessionIdFromHeader();
if (!isNullOrEmptyString(sessionIdFromRequestHeader)) {
final String sessionId = session.getId();
if (!sessionId.equals(sessionIdFromRequestHeader)) {
throw new RuntimeException(EXPIRED_SESSION_MSG);
}
}
All RuntimeExceptions thrown by Server side of gwt application has been wrapped as StatusCodeException if you did not declare them at your remote method declaration.
EDIT :
After, Thomas Broyer comment, I have learned that all exceptions (checked or unchecked) that are declared at remote method declaration are propagated to gwt client. Therefore all you have to do is just declare your remote method such as :
public void myRemoteMethod() throws RuntimeException;
The post looks too old, still here is the solution I have come up with. Override processCall(String payload) of RemoveServiceServlet, if the session is invalid execute the blow code else call super.processCall(payload).
//Pass the exception to Client
RPCRequest rpcRequest = RPC.decodeRequest(payload, this.getClass(), this);
onAfterRequestDeserialized(rpcRequest);
return RPC.encodeResponseForFailure(rpcRequest.getMethod(), new CustomException("Invalid Session!"),rpcRequest.getSerializationPolicy(), rpcRequest.getFlags());
All the GWT services are servlets so GWT serializes the custom exception and sends to client as string, we follow the same :)