Hi Anthony

Sorry for a delay
On 05/07/12 15:50, Muller, Anthony wrote:
Sergey,

More particularly, could you confirm handleRequest ans handleResponse will 
still be called before and after any REST calls?

I don't like to have a lock never removed! :)

As it happens at the moment, if the exception is thrown during a call to the resource method, then the out filters (ResponseHandler) are not called so effectively a lock will stay where it is at the moment.

It appears things are not going to easy for you :-).
Few options are still available but given the fact you can not use Spring and that CXF 2.3.x has been made obsolete makes it a bit tricky to plan for a best approach.

First of all, regarding that missing path parameter. I'll write a test later on and fix if needed, but your custom approach to do with parsing the URI looks OK.

Now, using the custom invoker would be perfect in this case because the exceptions will be caught early. But the fix I will apply to get CXFNonSpringJAXRSServlet accept custom invokers won't make it to 2.3.8.

Next is the possible workaround where your resource method makes sure that no exception ever escapes it: returning Response which will have a proper status code set will be the easiest way to achieve it

Next option is to have your composite filter also implement CXF OutFaultInterceptor, example:
http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/CustomOutFaultInterceptor.java

and register it as jaxrs:outFaultInterceptors, however I can see CXFNonSpringJAXRSServlet does only recognizes in/out interceptors but not fault ones.

So I think right now the best approach, given that you can not use Spring/Blueprint, is to have the resource method which is being locked ensure that no exception escapes and use the current filter implementation.

I'll take care of fixing CXFNonSpringJaxrsServlet to recognize custom invokers and fault interceptors, and check why UriInfo.getPathParameters does not return the parameters as expected

Thanks, Sergey

Anthony


-----Original Message-----
From: Muller, Anthony
Sent: jeudi 5 juillet 2012 16:23
To: 'Sergey Beryozkin'
Cc: [email protected]
Subject: RE: JAX-RS services - Interceptor

Sergey,

What do you think about this implementation?

Anthony


public final class BookHandler implements RequestHandler, ResponseHandler {

        private static final String KEY = "/books/";

        private static final ConcurrentMap<String, Lock>  BOOK_LOCKS = new 
ConcurrentHashMap<String, Lock>();

        public BookHandler() {}

        @Context
        private UriInfo uriInfo;

        @Override
        public Response handleRequest(final Message m, final ClassResourceInfo 
resourceClass)
        {
                final String bookId = getBookId();

                if (bookId != null) {
                        BOOK_LOCKS.putIfAbsent(bookId, new ReentrantLock());
                        BOOK_LOCKS.get(bookId).lock();
                        System.out.println("lock: " + bookId);
                }

                return null;
        }

        @Override
        public Response handleResponse(final Message m, final 
OperationResourceInfo ori, final Response response)
        {
                final String bookId = getBookId();

                if(bookId != null) {
                        BOOK_LOCKS.get(bookId).unlock();
                        System.out.println("unlock: " + bookId);
                }

                return null;
        }

        private String getBookId() {
                String bookId = null;
                int startIndex = uriInfo.getPath().indexOf(KEY);
                startIndex += KEY.length();
                if (startIndex>= 0) {
                        final int lastIndex = uriInfo.getPath().indexOf("/", 
startIndex);
                        bookId = uriInfo.getPath().substring(startIndex, 
lastIndex);
                }
                return bookId;
        }
}



-----Original Message-----
From: Sergey Beryozkin [mailto:[email protected]]
Sent: jeudi 5 juillet 2012 14:17
To: Muller, Anthony
Cc: [email protected]
Subject: Re: JAX-RS services - Interceptor

Hi Anthony
On 05/07/12 12:50, Muller, Anthony wrote:
Thx Sergey, that seems fine!

I'm trying using UriInfo injection and I'm trying to detect the case where I 
must lock my resource.

I hope to get the {bookId} easily, but there is nothing into path parameters... 
Normal?

I wrote something like:

@Override
public Response handleRequest(final Message m, final ClassResourceInfo 
resourceClass) {
        System.out.println("BookHandler.handleRequest: " + uriInfo.getPath());
        
        if(uriInfo.getPath().contains("/books/")) {
                final MultivaluedMap<String, String>   pathParameters = 
uriInfo.getPathParameters();
                final Set<String>   pathParameterNames = 
pathParameters.keySet();
                for (final String pathParameterName : pathParameterNames) {
                        System.out.println(pathParameterName + " : " + 
pathParameters.getFirst(pathParameterName));
                }       
        }
        
        return null;
}


I'm looking at the CXF code and I can confirm that the operation
matching is attempted before the filters are run. So if you have a
method such as

@POST
@Path("{index}")
public void addBook(@PathParam("index") int index, Book book) {}

and a request URI ending with something like /books/123

then UriInfo should return an "index":123 pair

Can you confirm please that in your above case the request URI is
expected to match a method with @PathParam annotations ?

By the way, perhaps there's one option for this case.
Instead of doing the filters, consider creating a custom invoker which
gets the control immediately before and after the matched method is
invoked. For example:

http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/CustomJAXRSInvoker.java

Custom invokers are registered using a jaxrs:invoker extension. However,
I recall you might be using CXFNonSpringJaxrsServlet - so is not
possible to register invokers from this servlet yet unless you extend
the servlet class and set the invoker on JAXRSServerFactoryBean. I'll
get this specific issue fixed,

But using the filters should also do OK

Sergey




-----Original Message-----
From: Sergey Beryozkin [mailto:[email protected]]
Sent: jeudi 5 juillet 2012 12:49
To: [email protected]
Cc: Muller, Anthony
Subject: Re: JAX-RS services - Interceptor

Hi Anthony
On 05/07/12 11:17, Muller, Anthony wrote:
Hello,

I have a use case when I need to intercept some REST calls to lock a used 
resource (underlying code doesn't support concurrent access). I wish to use an 
CXF interceptor to implement the lock mechanism (something else can help ?)

Example of concurrent calls:
Client 1 : [POST]<baseurl>/books/1234/chapters/ -->    Book<   1234>   must be 
locked to avoid concurrent modifications
Client 2 : [POST]<baseurl>/books/1234/chapters/56/paragraph -->    Webservice must 
wait because book<   1234>   is currently locked

So, I wish to add a CXF interceptor on URL starting by<   /books/{bookId}/...>, 
but I don't see how can I do...

(In my case, I can not use Servlet API...)


I think the simplest way is to create a class implementing both
RequestHandler and ResponseHandler interfaces and have a '@Context
UriInfo' injected (which is thread safe).

You can use UriInfo.getPath() method to get values like
'books/1234/chapters', etc.  Perhaps, even simpler, is to do
RequestHandler'message.get(Message.REQUEST_URI)', where 'message' is of
type Message and is available as a method parameter.

This implementation will 'lock' by updating the concurrent cache of some
sort (Colm done few Ehcache based implementations in CXF for example) in
its handleRequest method and 'unlock' in its handleResponse if it is
'books/1234/chapters'. It can be registered as a jaxrs:provider



Hope that helps :-)

Sergey

Can you help ?

Thanks and regards,
Anthony






--
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Reply via email to