Spring simultaneous calls - java

I think my problems is architecture-based, but not so sure so I'll try to explain the reality of it.
The software I'm working on is monolithic oriented but fully exposed with SOAP. The architecture is as followed :
The fondamental concept is what we called "Transaction", which is defined by its request and response (used for SOAP). It structures configurable business logic as well (editing documents, workflows, etc)
We have 1 bean configured in application-context.xml for each Transaction (PersonViewTransaction, PersonSelectTransaction, PersonEditTransaction for example)
All of them inherit
from the same abstract class AbstractTransaction which implements controls on the request provided
that AbstractTransaction implements an interface ITransaction
We build a TransactionFactory which, on any call with beanId and request, calls static methods calling every ITransaction's methods for the Transaction identified by beanId.
When a call is made through Webservices, a Servlet will call this factory, and execute the same logic, as a call from the web project (maven) would do calling directly the factory.
In other words :
Definition of ITransaction
/**
* The main interface defining what a transaction is.
*/
public interface ITransaction <Q extends GenericRequest, P extends GenericResponse> {
P businessLogic(Q req);
void executeControls(String transactionId, Q params, PerimetreAppel environnement)
default void controleLicence() throws NassurCoreException
{
//TODO : contrôles de la licence à effectuer.
}
/**
* Log before transaction
*/
default void logEntree() throws NassurCoreException
{
//TODO to be implemented
}
/**
* Log after transaction
*/
default void logSortie() throws NassurCoreException
{
//TODO to be implemented
}
/**
* Checks that the user can call transaction
*/
default void controleDroits() throws NassurCoreException
{
//TODO to be implemented
}
//...
//Some other method not necessarily implemented in each transaction
}
/**
* The abstract defining the default behaviour of a transaction
*/
public abstract class AbstractTransaction<Q extends GenericRequest, P extends GenericResponse> implements ITransaction<Q, P>{
#Autowired
private ControlService controlService;
//.... some other autowired fields
#Autowired
protected UserDetailsService userDetailsService;
protected String idTransaction;
//Every transaction must implement its own logic
P businessLogic(Q params);
#Override
public void initialisation(String trId)
{
this.idTransaction = trId;
}
#Override
#Transactional
public void executeControls(String transactionId, Q params, PerimetreAppel environnement)
{
//Some controls found from database, and executed
// A control consists of a combination between java checks and some Jruby executed from the Service
List<SomeEntity> list = someEntityRepository.findByTransactionId(transactionId);
for(SomeEntity e : list){
controlService.executeUnitControl(e, params);
}
}
}
Transactions
//Example Transaction
public class PersonViewTransaction extends AbstractTransaction<PersonViewRequest, PersonViewResponse>{
#Override
#Transactional
public PersonViewResponse businessLogic(PersonViewRequest req){
//...
}
}
//Example Transaction
public class PersonEditTransaction extends AbstractTransaction<PersonEditRequest, PersonEditResponse> {
#Override
#Transactional
public PersonEditResponse businessLogic(PersonEditRequest req){
//...
}
}
//Example Transaction
public class PersonSearchTransaction extends AbstractTransaction<PersonSearchRequest, PersonSearchResponse> {
#Override
#Transactional
public PersonSearchResponse businessLogic(PersonSearchRequest req){
//...
}
}
Those Beans are declared in application-context.xml.
Factory
public class TransactionFactory
{
public static GenericResponse executeTransaction(String id, GenericRequest req, HttpServletRequest request)
throws SomeExceptions
{
ServletContext servletCtx = request.getSession().getServletContext();
ApplicationContext actualCtx = WebApplicationContextUtils.getWebApplicationContext(servletCtx);
ITransaction tr = (ITransaction<GenericRequest, GenericResponse>) actualCtx.getBean(id.name());
if (tr == null)
{
throw new Exception("internal Error", null);
}
return executeStack(id, tr, req, request);
}
private static GenericResponse executeStack(String id, ITransaction tr, GenericRequest req, HttpServletRequest request)
throws SomeExceptions
{
try
{
tr.initialisation(id);
tr.controleLicence();
tr.logEntree();
tr.controleDroits();
//...Several operations calling ITransaction
tr.executeControls(id, req, provenance);
//Calling transaction logic
GenericResponse resp = tr.businessLogic(req);
//...Many "after-business" other calls
return resp;
}
catch (SomeExceptions e)
{
logger.error(e);
throw e;
}
}
}
By some mystery, when two calls are made simultaneously on the same transactionId, the executeControls throws some weird returns, as if both executions where mixed in the same bean (to me it appears thread-safe but not that sure...) :
List<SomeEntity> list = someEntityRepository.findByTransactionId(transactionId);
for(SomeEntity e : list){
controlService.executeUnitControl(e, params);
}
executeUnitControl checks if the control must apply, and throws an error if needed. To be more into detail, this is based on a JRuby script that takes params as parameter to build configurable and non-Java based business logic.
Thanks a lots for your help, and if there are french people, I'd love to chat with them any time to explain more details if needed !

Related

Incorporating Guice and AOP

I'm building a package that is trying to intercept a function's return value based on a flag. My design involves some AOP. The idea is that a class FirstIntercept intercepts a call firstCall and stores parameters in a Parameters object. Then later, a second class SecondIntercept intercepts another call secondCall and does some logic based on what is populated in Parameters:
// pseudoish code
public class FirstIntercept {
private Parameters param;
#AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
public void loadParam(Joinpoint joinPoint, Object payload) {
// logic handling payload returned from firstCall()
// logic provides a Boolean flag
this.param = new Parameters(flag);
}
}
public class Parameters {
#Getter
private Boolean flag;
public Parameters(Boolean flag) {
this.flag = flag;
}
}
public class SecondIntercept {
private static Parameters params;
#Around("execution(* ...secondCall(..))")
public void handleSecondCallIntercept(ProceedingJoinPoint joinPoint) {
// want to do logic here based on what params contains
}
}
What I want to achieve is that the Parameters object is loaded once and for all when FirstIntercept.loadParam is invoked through AOP. I'm not too sure how I can go about with this persistence. I looked online and Google guice seems to be promising. I believe a first step would to use dependency injection on the Parameters, but I'm really not sure. Can someone help point me in the right direction?
edit:
So I tried this setup:
public class FirstIntercept implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("invoked!");
return invocation.proceed();
}
#AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
public void loadParam(Joinpoint joinPoint, Object payload) {
// do stuff
}
public String firstCall() {
return "hello";
}
}
public class InterceptionModule extends AbstractModule {
protected void configure() {
FirstIntercept first = new FirstIntercept();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class), first);
}
}
public class FirstIterceptTest {
#Test
public void dummy() {
Injector injector = Guice.createInjector(new InterceptionModule());
FirstIntercept intercept = injector.getInstance(FirstIntercept.class);
intercept.firstCall();
}
}
When I do .firstCall(), I can see the #AfterReturning running but the invoke is not being called.
If you expand upon the documentation for AOP https://github.com/google/guice/wiki/AOP you should get something close to:
public class FirstInterceptor implements MethodInterceptor {
#Inject Parameters parameters; // Injected with singleton Parameter
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = invocation.proceed();
// your logic based on result to set parameters.setFlag()
return result;
}
}
Then the second:
public class SecondInterceptor implements MethodInterceptor {
#Inject Parameters parameters; // Injected with singleton Parameter
public Object invoke(MethodInvocation invocation) throws Throwable {
boolean flag = parameters.getFlag();
// your logic here
return invocation.proceed(); // maybe maybe not?
}
}
Your parameters is the key, you'll need to ensure it's thread safe, which is another topic. But to inject these you need:
public class InterceptionModule extends AbstractModule {
protected void configure() {
// Ensure there is only ever one Parameter injected
bind(Parameter.class).in(Scopes.SINGLETON);
// Now inject and bind the first interceptor
FirstInterceptor firstInterceptor = new FirstInterceptor();
requestInjection(firstInterceptor );
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
firstInterceptor);
// Now inject and bind the second interceptor
SecondInterceptor SecondInterceptor = new SecondInterceptor ();
requestInjection(firstInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
SecondInterceptor);
}
}
Edit
Look at what you're doing.
You're telling Guice to wrap a method with #AfterReturn with the FirstInterceptor
Then you're calling interceptor.firstCall()
First call does not have #AfterReturn annotation, so why would it be matched against that configuration?
I'm guessing if you called:
intercept.loadParam();
you would see the invoke method. Also, this is great for a test, but in real life you want to have a Service level class have the #AfterReturn which is then Injected into another Api/Job/Etc that will call LoadParam.
edit
Oh no. Take a look at this line
bindInterceptor(Matchers.any(), // a class with this matcher
Matchers.annotatedWith(AfterReturning.class), // a method with this
firstInterceptor);
This means that the injector only fires on the loadParams. You need to annotate the method of the class youw ish to cause the interception with #AfterReturning. And you want the loadParams to be the invoke method.

Spring custom request context

One of the scopes that Spring provides is request, beans in it are only valid in the context of a request.
That request is normally delegated to a controller after an HTTP request with Spring already setting up everything necessary.
But what if the request comes from a different source, like for example a Java Message Service.
Would it possible to set up a request scope for each processing of a message?
Can I annotate a method with something to mark it as the boundary of a request scope?
Under the cover , Spring just calls RequestContextHolder to set RequestAttributes to ThreadLocal at the beginning when processing the HTTP request , and remove it from ThreadLocal just before that thread finishes processing the request. The request and session scope beans are actually stored in and get from this RequestAttributes.
In the normal web situation ,this RequestAttributes implementation is backed with the HttpServletRequest. However , in the non-web context , there is no HttpServletRequest and so you cannot use the existing implementation. One of the way is to implement a RequestAttributes that is backed by an internal map :
public class InMemoryRequestAttributes extends AbstractRequestAttributes {
protected Map<String, Object> attributes = new HashMap<>();
#Override
public Object getAttribute(String name, int scope) {
return attributes.get(name);
}
#Override
public void setAttribute(String name, Object value, int scope) {
attributes.put(name, value);
}
#Override
public void removeAttribute(String name, int scope) {
attributes.remove(name);
}
#Override
public String[] getAttributeNames(int scope) {
String[] result = new String[attributes.keySet().size()];
attributes.keySet().toArray(result);
return result;
}
#Override
public void registerDestructionCallback(String name, Runnable callback, int scope) {
synchronized (this.requestDestructionCallbacks) {
this.requestDestructionCallbacks.put(name, callback);
}
}
#Override
public Object resolveReference(String key) {
return attributes;
}
#Override
public String getSessionId() {
return null;
}
#Override
public Object getSessionMutex() {
return null;
}
#Override
protected void updateAccessedSessionAttributes() {
}
}
Note: It only work with request scope bean. Modify it if you want to support session scope bean too ....
Then set it and remove it from the ThreadLocal just before and finish processing the JMS messages, something likes :
public void receive(String message){
RequestContextHolder.setRequestAttributes(new InMemoryRequestAttributes());
fooBean.processMessage(message);
RequestContextHolder.resetRequestAttributes();
}

ThreadLocal in DispatcherServlet

I have a Spring MVC (v4.1.3) web application with javascript UI. I have implemented a custom DispatcherServlet and configured the same in web.xml
There is a unique screen code which is sent in the HTTP Header of each request made by the UI to server.
In the doService method of my custom dispatcher servlet, I capture the HTTP Header and put the value in a ThreadLocal dto variable. I access this ThreadLocal variable in the service layer for performing some audit logic which is common for all requests.
Code from CustomDispatcherServlet:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
String uiCode = request.getHeader("uiCode");
if ((uiCode != null && !uiCode.trim().isEmpty())) {
UiCodeDto uiCodeDto = new UiCodeDto(uiCode);
final ThreadLocal<UiCodeDto> threadLocalUser = new ThreadLocal<UiCodeDto>();
threadLocalUser.set(uiCodeDto);
}
...
super.doService(request, response);
}
Code from service layer:
UiCodeDto temp = ThreadLocalUtil.getUiCodeDto(Thread.currentThread());
Code of ThreadLocalUtil to retrieve the value from ThreadLocal:
public final class ThreadLocalUtil {
public static UiCodeDto getUiCodeDto(Thread currThread) {
UiCodeDto UiCodeDto = null;
try {
Field threadLocals = Thread.class.getDeclaredField("threadLocals");
threadLocals.setAccessible(true);
Object currentThread = threadLocals.get(currThread);
Field threadLocalsMap = currentThread.getClass().getDeclaredField("table");
threadLocalsMap.setAccessible(true);
threadLocalsMap.setAccessible(true);
Object[] objectKeys = (Object[]) threadLocalsMap.get(currentThread);
for (Object objectKey : objectKeys) {
if (objectKey != null) {
Field objectMap = objectKey.getClass().getDeclaredField("value");
objectMap.setAccessible(true);
Object object = objectMap.get(objectKey);
if (object instanceof UiCodeDto) {
UiCodeDto = (UiCodeDto) object;
break;
}
}
}
} catch (Exception e) {
...
}
return UiCodeDto;
}
}
The problem is as follows -
1. I am getting random values of screen code - which means the value of some http request N is coming in http request N+1.
2. There are null DTOs in ThreadLocal variable with same name - hence, sometimes when I access the ThreadLocal in service layer, I get a null
I need help in understanding the behavior of ThreadLocal in DispatcherServlet - why would it get values of another request in doService method?
Thanks in advance.
Your code is error prone and hard to understand also why would you need a custom DispatcherServlet. A filter seems more suited for this task.
public class UiCodeFilter extends OncePerRequestFilter {
protected void doFilterInternally(HttpServletRequest req, HttpServletResponse res, FilterChain chain) {
try {
String uiCode = req.getHeader("uiCode");
if ((uiCode != null && !uiCode.trim().isEmpty())) {
UiCodeDto uiCodeDto = new UiCodeDto(uiCode);
UiCodeHolder.set(uiCodeDta);
}
chain.doFilter(req, res);
} finally {
UiCodeHolder.clear(); // Always clear!
}
}
}
The UiCodeHolder has a static ThreadLocal to keep the value.
public abstract class UiCodeHolder {
static ThreadLocal<UiCodeDto> current = new ThreadLocal<>()
public void set(UiCodeDto uiCode) {
current.set(uiCode);
}
public UiCodeDta get() {
return current.get();
}
public void clear() {
current.remove(); // for older versions use current.set(null);
}
}
In your service you can now simply do UiContextHolder.get() to obtain the correct value. The UiCodeFilter takes care of setting the value and at the end of the request clears the value again to prevent leaking.
This approach doesn't require ugly reflection hooks, is quite easy to understand is is used by Spring, Hibernate and frameworks alike.
A more Spring way of doing this is to use a request-scoped bean to extract and hold the header:
#Component
#Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UiCodeDto {
private String uiCode;
#Inject
public void setCode(HttpServletRequest req) {
uiCode = req.getHeader("uiCode");
}
public String getUiCode() {
return uiCode;
}
}
And you can use it like a normal bean:
#Service
public class RandomService {
#Inject
UiCodeDto uiCodeDto;
public void handle() {
System.out.println(uiCodeDto.getUiCode());
}
}

why does interceptor not get fired on an EJB method called from servlet filter?

I want to implement high level resource filtering on URLs with a servlet filter and lower level action filtering on methods with an interceptor but my interceptor does not get fired on the EJB method called from the servlet filter.
Interceptor annotation Interface:
#Inherited
#InterceptorBinding
#Retention (RUNTIME)
#Target({TYPE, METHOD})
public #interface Permit {
#Nonbinding
String[] actions() default "N/A";
}
The Interceptor:
#Permit
#Interceptor
public class PermitInterceptor {
#AroundInvoke
public Object verifyPermission(InvocationContext context) throws Exception {
Method method = context.getMethod();
if(method.isAnnotationPresent(Permit.class)) {
Permit permitAnnotation = method.getAnnotation(Permit.class);
List<String> permittedActions = Arrays.asList(permitAnnotation.actions());
List<String> userActions = SecurityContextHandler.getActiveUser().getActions();
if(!Collections.disjoint(permittedActions, userActions)){
return context.proceed();
}
}
throw new PermissionException("You do NOT have the required permissions to perform this action");
}
}
Servlet Filter:
#WebFilter(urlPatterns = {"/*"})
public class AccessFilter implements Filter {
#EJB
private RulesBean rules;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
try{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String url = request.getRequestURI();
if(rules.isAllowed(url)){
chain.doFilter(request, response);
}else{
//handle as necessary
}
}catch(Exception ex){
//handle as necessary
}
}
}
And finally here's what the EJB RulesBean that I want to use to manage routing/interception for all my servlets looks like;
Rules:
#Stateless
#LocalBean
public class RulesBean {
private static final String CUSTOMERS = "/customers"
public boolean isAllowed(String url) throws PermissionException {
switch(url){
case CUSTOMERS: return canViewAllCustomers();
default: return true;
}
}
/*This should trigger PermitInterceptor before entering method and
should throw my custom PermissionException if permission fails*/
#Permit(actions={"ViewCustomers"})
private boolean canViewAllCustomers(){
return true;
}
...
//Other tests carried out here ...
}
Unfortunately PermitInterceptor doesn't get called before entering canViewAllCustomers() method.
Amazingly however, PermitInterceptor gets triggered when canViewAllCustomers() is made public and called directly as rules.canViewAllCustomers() instead of through the helper method rules.isAllowed(String url). But this isn't helpful in my case, as it gives me no single entry point for my URL checks which essentially means I have to do all the checks in the Servlet Filter.
QUESTION: Please can anybody shed more light on the reason why things are occurring in this manner?... and suggestions about the best way to implement this scenario is highly welcome. Thanks.
NOTE: (To give more perspective)
You may be wondering why I want to do this OR more specifically why the RuleBean even exists at all... The reason is simply because a good number of my Servlets aren't doing much except route response to a view that triggers a server-side DataTables ajax call which populates the tables, hence I really need to ensure that the request for the view doesn't even get through to the if...else condition that fetches the view unless the permission checks in the interceptor is satisfied.
See sample servlet below;
#WebServlet ("/customers/*")
public class CustomerServlet extends VelocityViewServlet {
private static final String CUSTOMERS = "/customers"
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String uri = request.getRequestURI();
if(uri.equals(CUSTOMERS)){
String view = Path.getTemplate("/customers/index.vm");
request.setAttribute("headerTitle", "Customers");
request.getRequestDispatcher(view).forward(request, response);
}else if(...){
...
}
}
}
You invoke canViewAllCustomers() within isAllowed() directly, which gives the Application Server no chance to intercept the call.
Interception works with proxy classes. When you inject the EJB into your servlet, like you did with:
#EJB
private RulesBean rules;
what actually gets injected is not an EJB instance, but a proxy class, that the application server created at runtime (you can see this with the debugger). Invocations on that proxy class will be intercepted for transactions, custom interceptors, etc. and then delegated to the actual class instance.
So what you need to do is either put canViewAllCustomers() into a new EJB, that you can let the application server inject into your RulesBean class,
or you can retrieve a reference of your RulesBean class from inside isAllowed() like so:
#Stateless
#LocalBean
public class RulesBean {
private static final String CUSTOMERS = "/customers"
#Resource
SessionContext ctx;
public boolean isAllowed(String url) throws PermissionException {
switch(url){
case CUSTOMERS: return self().canViewAllCustomers();
default: return true;
}
}
private RulesBean self() {
return ctx.getBusinessObject(RulesBean.class);
}
/*This should trigger PermitInterceptor before entering method and
should throw my custom PermissionException if permission fails*/
#Permit(actions={"ViewCustomers"})
public boolean canViewAllCustomers(){
return true;
}
}

jersey 2: How to create custom HTTP param binding

I am trying to create a custom http param binding for my restful service. Please see the example below.
#POST
#Path("/user/{userId}/orders")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public MyResult foo(#PathParam("userId") String someString, #UserAuthHeaderParam String authString){
}
You can see that there is a UserAuthHeaderParam annotation in the function signature. What I want to do is have a custom http param binding other than the standard javax.ws.rs.*Param .
I have try to implement org.glassfish.hk2.api.InjectionResolver which basically extract the value from http header:
public class ProtoInjectionResolver implements InjectionResolver<UserAuthHeaderParam>{
...
#Override
public Object resolve(Injectee injectee, ServiceHandle< ? > root)
{
return "Hello World";
}
...
}
When I call the restful service, the server get below exceptions. It indicates that the framework fails to resolve the param in the function signature:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=MyResource,qualifiers={}),position=0,optional=false,self=false,unqualified=null,2136594195),
java.lang.IllegalArgumentException: While attempting to resolve the dependencies of rs.server.MyResource errors were found
Please help. Any advise is appreciated. I do make a lot of search on google but fails to make it work. Jersey 2.*. How to replace InjectableProvider and AbstractHttpContextInjectable of Jersey 1.* might be the similar question.
-- UPDATES:
I use AbstractBinder to bind my resolver to UserAuthHeaderParam:
public class MyApplication extends ResourceConfig
{
public MyApplication()
{
register(new AbstractBinder()
{
#Override
protected void configure()
{
// bindFactory(UrlStringFactory.class).to(String.class);
bind(UrlStringInjectResolver.class).to(new TypeLiteral<InjectionResolver<UrlInject>>()
{
}).in(Singleton.class);
}
});
packages("rs");
}
}
Thank you!
If all you want is to pass value directly from the header to the method you don't need to create custom annotations. Let's say you have a header Authorization, then you can easily access it by declaring your method like this:
#GET
public String authFromHeader(#HeaderParam("Authorization") String authorization) {
return "Header Value: " + authorization + "\n";
}
You can test it by calling curl, e.g.
$ curl --header "Authorization: 1234" http://localhost:8080/rest/resource
Header Value: 1234
Given that the answer to your question, how to create custom binding is as follows.
First you have to declare your annotation like this:
#java.lang.annotation.Target(PARAMETER)
#java.lang.annotation.Retention(RUNTIME)
#java.lang.annotation.Documented
public #interface UserAuthHeaderParam {
}
Having your annotation declared you have to define how it will be resolved. Declare the Value Factory Provider (this is where you'll have access to the header parameters - see my comment):
#Singleton
public class UserAuthHeaderParamValueFactoryProvider extends AbstractValueFactoryProvider {
#Inject
protected UserAuthHeaderParamValueFactoryProvider(MultivaluedParameterExtractorProvider mpep, ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
#Override
protected Factory<?> createValueFactory(Parameter parameter) {
Class<?> classType = parameter.getRawType();
if (classType == null || (!classType.equals(String.class))) {
return null;
}
return new AbstractHttpContextValueFactory<String>() {
#Override
protected String get(HttpContext httpContext) {
// you can get the header value here
return "testString";
}
};
}
}
Now declare an injection resolver
public class UserAuthHeaderParamResolver extends ParamInjectionResolver<UserAuthHeaderParam> {
public UserAuthHeaderParamResolver() {
super(UserAuthHeaderParamValueFactoryProvider.class);
}
}
and a Binder for your configuration
public class HeaderParamResolverBinder extends AbstractBinder {
#Override
protected void configure() {
bind(UserAuthHeaderParamValueFactoryProvider.class)
.to(ValueFactoryProvider.class)
.in(Singleton.class);
bind(UserAuthHeaderParamResolver.class)
.to(new TypeLiteral<InjectionResolver<UserAuthHeaderParam>>() {})
.in(Singleton.class);
}
}
now the last thing, in your ResourceConfig add register(new HeaderParamResolverBinder()), like this
#ApplicationPath("rest")
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new HeaderParamResolverBinder());
packages("your.packages");
}
}
Given that, you should be now able to use the value as you wanted:
#GET
public String getResult(#UserAuthHeaderParam String param) {
return "RESULT: " + param;
}
I hope this helps.
I don't know how to resolve your exception. However, may I propose you a different way to do the same thing. I hope it helps.
I've faced exactly the same problem: I need extra parameters in the http header (btw, also related to authentication). Besides, I need to send them in every call, since I want to do a "typical" rest implementation, without maintaining a session.
I'm using Jersey 2.7 - but I'd say it should work in 2.0. I've followed their documentation
https://jersey.java.net/documentation/2.0/filters-and-interceptors.html
It's quite clear there, but anyway I copy-paste my implementation below.
It works fine. True there are some other ways to secure a rest service, for example this is a good one:
http://www.objecthunter.net/tinybo/blog/articles/89
But they depend on the application server implementation and the database you use. The filter, in my opinion, is more flexible and easier to implement.
The copy-paste: I've defined a filter for authentication, which applies to every call and it is executed before the service (thanks to #PreMatching).
#PreMatching
public class AuthenticationRequestFilter implements ContainerRequestFilter {
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
if (headers == null) {
throw new...
}
// here I get parameters from the header, via headers.get("parameter_name")
// In particular, I get the profile, which I plan to use as a Jersey role
// then I authenticate
// finally, I inform the Principal and the role in the SecurityContext object, so that I can use #RolesAllowed later
requestContext.setSecurityContext(new SecurityContext() {
#Override
public boolean isUserInRole(final String arg0) {
//...
}
#Override
public boolean isSecure() {
//...
}
#Override
public Principal getUserPrincipal() {
//...
}
#Override
public String getAuthenticationScheme() {
//...
}
});
}
}
You have to include this filter class in your implementation of ResourceConfig,
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
// my init
// my packages
register(AuthenticationRequestFilter.class); // filtro de autenticación
// other register
}
}
Hope it helps!
If your need is to retrieve all the http headers binding into one object, a solution could be to use the #Context annotation to get javax.ws.rs.core.HttpHeaders; which contains the list of all request headers.
#POST
#Path("/user/{userId}/orders")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public MyResult foo(#PathParam("userId") String someString, #Context HttpHeaders headers){
// You can list all available HTTP request headers via following code :
for(String header : headers.getRequestHeaders().keySet()){
System.out.println(header);
}
}
here is my actual implementatipn of UserAuthHeaderParamValueFactoryProvider class
import javax.inject.Inject;
import javax.inject.Singleton;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;
import org.glassfish.jersey.server.model.Parameter;
#Singleton
public class UserAuthHeaderParamValueFactoryProvider extends AbstractValueFactoryProvider {
#Inject
protected UserAuthHeaderParamValueFactoryProvider(MultivaluedParameterExtractorProvider mpep, ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
#Override
protected Factory<?> createValueFactory(Parameter parameter) {
Class<?> classType = parameter.getRawType();
if (classType == null || (!classType.equals(String.class))) {
return null;
}
return new AbstractContainerRequestValueFactory<String>() {
#Override
public String provide() {
//you can use get any header value.
return getContainerRequest().getHeaderString("Authorization");
}
};
}

Categories

Resources