Jersey with Spring AOP - jersey

I would like my AOP advice to have a handle to the currently executing Jersey resource's HttpContext. The spring-annotations sample mentions that the user could get hold of the request and authenticate etc.,, but how does one get hold of any of the values in the Context in the advice?
Currently my resource definition looks like this:
#Singleton
#Path("/persist")
public class ContentResource {
#PUT
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Auth
public Content save(Content content){
//Do some thing with the data
}
}
And the aspect is defined so:
#Aspect
public class AuthorizeProcessor {
#Around(value="#annotation(package.Auth) and #annotation(auth)", argNames = "auth")
public Object authorize(ProceedingJoinPoint pjp, Auth auth) throws Throwable{
//How do I get the HttpContext here?
return pjp.proceed();
}
}

Granted this is most likely too late, but I did what you are doing by implementing a Servlet Filter in front of the service that does the authorization. This avoids the need for AOP entirely, and it gives you the actual ServletRequest directly without working around the system to get it.
Ironically, the question that you helped me to answer would likely help you here, if you really wanted AOP.
You can supply the Spring RequestContextFilter to the request, and then access the HttpServletRequest (as opposed to the HttpContext):
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/path/to/services/*</url-pattern>
</filter-mapping>
Access code down the filter chain:
/**
* Get the current {#link HttpServletRequest} [hopefully] being made
* containing the {#link HttpServletRequest#getAttribute(String) attribute}.
* #return Never {#code null}.
* #throws NullPointerException if the Servlet Filter for the {#link
* RequestContextHolder} is not setup
* appropriately.
* #see org.springframework.web.filter.RequestContextFilter
*/
protected HttpServletRequest getRequest()
{
// get the request from the Spring Context Holder (this is done for
// every request by a filter)
ServletRequestAttributes attributes =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}

Related

How to get the DispatcherServlet from spring WebApplicationContext?

How to get the DispatcherServlet instance from a spring WebApplicationContext object?
I want to perform a direct request to the the front controller servlet (avoiding the network interface) and check the response from a spring application, e.g. WebApplicationContext instance.
Notice, we are not able to use MockMvc to check the HTML rendered by JSP because: "if you use JSPs, you can verify the JSP page to which the request was forwarded, but no HTML is rendered"(according to MockMvc vs End-to-End Tests)
So maybe if we get the DispatcherServlet instance we could perform the request through its doDispatch method and check the content from response.
When you look at
DispatcherServlet.java, there is a constructor with WebApplicationContext as parameter, but the super constructor from FrameworkServlet.java does only hold the field itself, without any callbacks - so the given web application context will not know the dispatcher servlet.
So I don't think you can resolve the dispatcher servlet by the WebApplicationContext. Of course you could try to inject/autowire the DispatcherServlet - maybe this is also possible inside tests, but I am not sure.
I think the most easiest way to check for JSP outputs would be to test those parts with a real server as described at Testing with a running server . This should give you the complete output and web application behaviour inside your test without any workarounds.
Dispatcher Servlet : It acts as front controller for Spring based web applications. It provides a mechanism for request processing where actual work is performed by configurable, delegate components. It is inherited from HttpServlet, HttpServletBean and FrameworkServlet. It also implements ApplicationContextAware hence it is able to set ApplicationContext.
WebApplicationContext : It is an extension of a plain ApplicationContext. It is web aware ApplicationContext i.e it has Servlet Context information. When DispatcherServlet is loaded, it looks for the bean configuration file of WebApplicationContext and initializes it.
So you can set and get the instance of any ApplicationContext from DispatcherServlet but not vice-versa.
dispatcherServlet.getWebApplicationContext();
Although, you can get an instance of DispatcherServlet but I doubt it will serve your purpose as it's scope is protected.
#Autowired
DispatcherServlet dispatcherServlet;
Code inside DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
It is possible to create your own DispatcherServlet and perform actions. You can override the default one created by Spring boot app.
Sample:
public class SampleDispatcherServlet extends DispatcherServlet {
private final Log logger = LogFactory.getLog(getClass());
#Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// You can use other implementations of HttpServletRequest and
// HttpServletResponse as per your requirement
// e.g. FormContentRequestWrapper , ResourceUrlEncodingResponseWrapper many more
if (!(request instanceof ContentCachingRequestWrapper)) {
request = new ContentCachingRequestWrapper(request);
}
if (!(response instanceof ContentCachingResponseWrapper)) {
response = new ContentCachingResponseWrapper(response);
}
HandlerExecutionChain handler = getHandler(request);
try {
// Any task to be done
super.doDispatch(request, response);
} finally {
// Some task to be done
}
}
}
HandlerExecutionChain- Handler mapper is used to match current request to appropriated controller. Interceptors are the objects invoked before and after some of dispatching actions
Then we have to register the DispatcherServlet:
#Bean
public ServletRegistrationBean dispatcherRegistration() {
return new ServletRegistrationBean(dispatcherServlet());
}
//The bean name for a DispatcherServlet that will be mapped to the root URL "/"
#Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
return new SampleDispatcherServlet();
}

Spring retry - can #Recover be in standalone class?

I have a Spring Integration app with multiple endpoint that process the same data in different ways.
They all have identical '#Recover' methods which has become boilerplate and seems fragile.
Can you you centralize the #Recover method (e.g. in a standalone class) and/or can you specify how to find this #Recover annotated method?
It's not clear why would one use a #Retryable in Spring Integration when there is that RequestHandlerRetryAdvice: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#message-handler-advice-chain...
Anyway see this option on the #Retryable:
/**
* Retry interceptor bean name to be applied for retryable method. Is mutually
* exclusive with other attributes.
* #return the retry interceptor bean name
*/
String interceptor() default "";
So, instead of #Recover method you provide your own:
#Bean
public MethodInterceptor retryInterceptor() {
return RetryInterceptorBuilder.stateless()
.maxAttempts(...)
.recoverer(...)
.build();
}
...
#Retryable(interceptor = "retryInterceptor")
public void service() {

spring: where does `#autowired` look for beans?

I'm having a spring mvc application with two contexts (as declared in my AbstractAnnotationConfigDispatcherServletInitializer subclass)
the root context contains models, repositories, etc
the mvc context contains the controllers
Now, I can inject a repository into a controller, but why?
Does the web context also include the beans from the root context (something like #Import??). The documentation implies they have a parent-child relationship, but by inspecting the web context I don't the repository beans inside it.
Or, does #Autowired work across multiple contexts? And, if so, how??
Both contexts are stored in the same servlet context.
If you notice, AbstractDispatcherServletInitializer,the parent class of AbstractAnnotationConfigDispatcherServletInitializer, does the registration on the onStartup method
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
registerDispatcherServlet(servletContext);
}
To do that, first calls its parent onStartup method where it first adds the rootApplicationContext which is created by the createRootApplicationContext method of the AbstractAnnotationConfigDispatcherServletInitializer class and finally adds it to the ServletContext received on the onStartup method:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
/**
* Register a {#link ContextLoaderListener} against the given servlet context. The
* {#code ContextLoaderListener} is initialized with the application context returned
* from the {#link #createRootApplicationContext()} template method.
* #param servletContext the servlet context to register the listener against
*/
protected void registerContextLoaderListener(ServletContext servletContext) {
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
And after that, AbstractDispatcherServletInitializer calls its registerDispatcherServlet method where it calls the abstract method createServletApplicationContext that is in the AbstractAnnotationConfigDispatcherServletInitializerclass and creates the dispatcherServlet that is then added to the same ServletContext:
/**
* Register a {#link DispatcherServlet} against the given servlet context.
* <p>This method will create a {#code DispatcherServlet} with the name returned by
* {#link #getServletName()}, initializing it with the application context returned
* from {#link #createServletApplicationContext()}, and mapping it to the patterns
* returned from {#link #getServletMappings()}.
* <p>Further customization can be achieved by overriding {#link
* #customizeRegistration(ServletRegistration.Dynamic)} or
* {#link #createDispatcherServlet(WebApplicationContext)}.
* #param servletContext the context to register the servlet against
*/
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return empty or null");
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext,
"createServletApplicationContext() did not return an application " +
"context for servlet [" + servletName + "]");
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
Assert.notNull(registration,
"Failed to register servlet with name '" + servletName + "'." +
"Check if there is another servlet registered under the same name.");
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
That's why you can inject a repository in a controller, because the 2 contexts are in the same ServletContext.
I typically return a single context from AbstractAnnotationConfigDispatcherServletInitializer.getRootConfigClasses() this class then has ComponentScan and/or Imports which finds #Configurations and #Components etc.
Unless you explicitly create parent-child contexts, all your beans, components, services ends up in a single ApplicationContext. By explicit I mean that you have to call setParent() on ApplicationContext before refresh() is called, so you typically know when you have done it.
This means that you can #AutoWire into an other spring bean from the same application context (the autowired bean may be from a parent context if you have nested contexts)
Edit
If you use AbstractAnnotationConfigDispatcherServletInitializer.getServletConfigClasses() and return two contexts from you initializer, the servletConfig context will be a child and the root context will be the parent. This means that you can autowire beans from the RootConfig context into the servletConfig context beans, but not the other way around. - This is why I typically only return a context from getRootConfigClasses() and null from getServletConfigClasses().

What does the #Secure annotation do and what package is it apart of

I'm writing an API using Java EE, JAX-RS, Jersey. In doing this I've implemented my own security context and security filter.
Looking at questions like this one (How to get MIME type of uploaded file in Jersey) I've seen the #Secure annotation but what does it do? My hope was that is was an annotation that queries the isSecure method of the security context in the same way that #RolesAllowed does for checking if a user has the right to access a particular method. If so is there such a way of doing so with annotations or am I stuck to using the #Context to get the security context and just from that.
The #Secure annotation seems to be a custom one. JAX-RS/Jersey does not support such feature out-of-the-box but it's not that hard to implement. Lets say you have your own #Secure annotation and you want to do checks whether a communication channel is secure for methods annotated with this annotation. You need to create a custom ResourceFilterFactory in which you'll assign a special filter for such methods:
public class IsSecureResourceFilterFactory implements ResourceFilterFactory {
private class IsSecureFilter implements ResourceFilter, ContainerRequestFilter {
// ResourceFilter
#Override
public ContainerRequestFilter getRequestFilter() {
return this;
}
#Override
public ContainerResponseFilter getResponseFilter() {
return null;
}
// ContainerRequestFilter
#Override
public ContainerRequest filter(final ContainerRequest request) {
// Check whether the channel is secure.
if (request.isSecure()) {
return request;
}
// Throw an exception if it's not.
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
}
#Override
public List<ResourceFilter> create(final AbstractMethod abstractMethod) {
// Add IsSecureFilter for resource methods annotated with #Secure annotation (ignore other resource methods).
return abstractMethod.isAnnotationPresent(Secure.class)
? Collections.<ResourceFilter>singletonList(new IsSecureFilter()): null;
}
}
Now you need to tell Jersey about this ResourceFilterFactory. There are 2 ways:
via web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>my.package.IsSecureResourceFilterFactory</param-value>
</init-param>
or via META-INF/services mechanism - you need to create a file called META-INF/services/com.sun.jersey.spi.container.ResourceFilterFactory which would contain a fully qualified name of your factory (in this case my.package.IsSecureResourceFilterFactory) and make sure this file is on the class-path of your application.

java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut

I'm really very new to Spring AOP. In my application, I had configured HiddenHttpMethodFilter that converts method parameters into HTTP methods and enables Spring to handle other HTTP methods like DELETE, PUT etc including GET and POST.
It is some times necessary to disable this functionality especially when handling multipart requests. In order to disable it at a specific request (regarding mulripart), I was using the following code.
package resolver;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartResolver;
/**
* Disables the spring multipart resolver for specific client requests and
* therefore keeps the request intact so that controllers can process it in
* whatever way they wish. This behaviour is triggered by a particular GET
* parameter in the client request so it is configurable.
* #see MultipartResolver
*/
#Aspect
public final class MultipartResolverDisablingAspect
{
/**
* GET parameter which, if present in request, enables advice.
*/
private static final String DISABLING_HTTP_REQUEST_PARAMETER_KEY = "_multipartResolverDisable";
private static boolean disablingParameterExists(final HttpServletRequest request)
{
Assert.notNull(request);
return request.getParameter(DISABLING_HTTP_REQUEST_PARAMETER_KEY) != null;
}
/**
* If above GET parameter exists in request then prompt the spring multipart
* resolver to always tell spring that request is not of type multipart.
* Spring then does not process the request any further.
* #param pjp
* #param request
* #return
* #throws Throwable
*/
#Around("isMultipartOperation() && args(request)")
public Object disableIsMultipartOperation(final ProceedingJoinPoint pjp, final HttpServletRequest request) throws Throwable
{
Assert.notNull(pjp);
Assert.notNull(request);
if (disablingParameterExists(request))
{
return Boolean.FALSE;
}
return pjp.proceed();
}
/**
* Applies to any implementation of {#linkplain MultipartResolver}
*/
#SuppressWarnings("unused")
#Pointcut("execution(public boolean " + "org.springframework.web.multipart.MultipartResolver." + "isMultipart(javax.servlet.http.HttpServletRequest))")
private void isMultipartOperation() {}
}
and in the application-context.xml file, the following xml is required.
<aop:aspectj-autoproxy proxy-target-class="false" />
<bean class="resolver.MultipartResolverDisablingAspect" /> <!--Registers the above bean (class)-->
This code was taken from this article under the section - MULTIPART RESOLVER DISABLING ASPECT.
It is meant to disable multipart processing by HiddenHttpMethodFilter when a GET parameter multipartResolverDisable=1 is used as a query string as specified by the code above so that one can use commons fileupload as usual (when multipartResolverDisable=1 is supplied as a query string)
The actual question is still not in the picture. This approach was earlier working correctly in the following environment (with NetBeans 6.9.1).
Spring 3.2.0
Apache Tomcat 6.0.26.6 with the Servlet API 2.5.
Recently I have upgraded NetBeans 7.2.1 with Apache Tomcat 7.0.35 which has the Servlet API 3.0. The Spring version is the same as it was before - Spring 3.2.0.
With this updates, the approach as described above caused the following exception.
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'org.springframework.transaction.config.internalTransactionAdvisor':
Cannot resolve reference to bean
'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0'
while setting bean property 'transactionAttributeSource'; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0':
Initialization of bean failed; nested exception is
**java.lang.IllegalArgumentException: error at ::0 can't find referenced
pointcut isMultipartOperation**
Where the isMultipartOperation() is the last method in the above class.
There might be a small change to the code but I know a very little about AOP and cannot figure out the cause of this exception in this nice-looking code.
What is the cause of this exception? Dose it have to do something with the Servlet API?
I think you should change your around advice to
#Around("isMultipartOperation(..) && args(request)")
your pointcut annotation to
#Pointcut("execution(* org.springframework.web.multipart.MultipartResolver.isMultipart(..)) && args(request)")
and the pointcut annotated method to
private void isMultipartOperation(HttpServletRequest request) {}
From memory, I had this issue where I was trying to wrap a pointcut with some advice, and the advice had a different number of arguments to the pointcut. In your code you appear to be using #Around to target a pointcut with args(request), but your pointcut method has no such parameter.

Resources