On 23/04/2015 11:52, Sergey Beryozkin wrote:
Hi,
On 23/04/15 09:20, Francesco Chicchiriccò wrote:
On 22/04/2015 17:28, Sergey Beryozkin wrote:
Hi

I've done some basic local test and I expect it to work, can you give
me a bit more information:

- request URI example, does it end with something
like "/users;realm=a" or "/users/;realm=a"

Note an extra slash in the 2nd option - should not make a difference
but I'd like to know exactly the request URI structure

(the fact it may contain query parameters is not important)

I think you still have UserService selected - if you enable a TRACE
logging you should see it confirmed, can you please give me a favour
and confirm that ? The trace will also show what path is matched
against a given resource method's path. Can you please check ?

I have forked the Syncope repository at

https://github.com/ilgrosso/syncope

and pushed some changes there:

  1. removed QueryResourceInfoComparator and changed configuration
accordingly
  2. "squashed" all list() / search() methods into the version with more
arguments

with commit

https://github.com/ilgrosso/syncope/commit/b8de72cbbe9536093d22acd5f5f5e6981e5e7bea


At this point (still using @QueryParam instead of @MatrixParam for
realms) everything is still working - the only thing I don't like
particularly is to force client code to write something like as

         userService.list(Arrays.asList("/even/two", "/odd"), null,
null, null);

e.g. those "null, null, null": isn't there any magic trick to avoid
that? (null values are naturally managed server-side).

Right, indeed at a pure Java level have the method overloading done helps.

These 'nulls' is the downside of using proxies were some of method parameters are optional. I can think of 2 alternatives: - do not put @QueryParam in the signature, have a "@Context UriInfo ui;" field in the server code and use UriInfo.getQueryParameters - the downside there is that WADL will now show these query parameters as the method signature will be more generic. - Use CXF WebClient or JAX-RS 2.0 Client/WebTarget - it is easy to use and the code can also be type-safe and there's no need to add nulls for optional parameters. - Use JAX-RS 2.0 BeanParam bean that would have properties corresponding to some of optional query parameters (and other optional parameters), and have that in a list() signature. This should actually work for WADL too...So say we have

list(@BeanParam ListQuery query)

examples:

list(new ListQuery(Arrays.asList("/even/two", "/odd")))
list(new ListQuery(Arrays.asList("/even/two", "/odd")), "a", "b")
list(new ListQuery(Arrays.asList("/even/two", "/odd")), "a", "b", "c")

assuming ListQuery has few helper constructors

This last option seems to be the most suitable, even if it means adding few beans (and builders): are you aware of some Commons equivalent of Guava's @AutoValue?

Then I have also turned @QueryParam into @MatrixParam for UserService's
and GroupService's list() and search(), with commit

https://github.com/ilgrosso/syncope/commit/1d2be4938fcc7ec25d9bd388a3f5d6dff69a37de


At this point, when calling userService as shown above, the following
URL is generated:

http://localhost:9080/syncope/rest/users;realm=/even/two;realm=/odd


This explains it :-) A matrix value such as "/even/two" has slash characters which serve as URI path component separators but they are not percent-encoded - the server thinks you have 3 path segments in "/users;realm=/even/two;realm=/odd" - hence no match.

I think it is a CXF client runtime bug. When a path parameter is provided, a "/" is always kept by default, but there is an option to control it directly when working with UriBuilder. However when a matrix parameter is provided I guess "/" has to be encoded immediately by the client runtime. I will still need to investigate it further as it is all so sensitive around using "/" in paths...

But at least we have a workaround now: do

userService.list(Arrays.asList(replaceSlashInMatrix("/even/two"), replaceSlashInMatrix("/odd")), ...);

String replaceSlashInMatrix(String matrix) {
   return matrix.replaceAll("/", "%2F");
}

and

javax.xml.ws.WebServiceException: Remote exception with status code:
NOT_FOUND

is returned; FYI, this works for this URL

http://localhost:9080/syncope/rest/users;realm=/

but "/" is the @DefaultValue.

This works because effectively you get an empty 'realm' matrix value and there's no extra path segment behind the last "/" path segment separator - from the server point's of view.

When enabling TRACE for CXF, I read from logs:

[...]
10:08:45.885 DEBUG org.apache.cxf.jaxrs.utils.JAXRSUtils - Resource
class org.apache.syncope.core.rest.cxf.service.UserServiceImpl has been
selected, request path :
org.apache.syncope.core.rest.cxf.service.UserServiceImpl, resource class
@Path : /users;realm=/even/two;realm=/odd
[...]
10:08:45.885 DEBUG org.apache.cxf.jaxrs.utils.JAXRSUtils - Trying to
select a resource operation on the resource class
org.apache.syncope.core.rest.cxf.service.UserServiceImpl
[...]
10:08:45.896 DEBUG org.apache.cxf.jaxrs.utils.JAXRSUtils - No method
match, method name : list, request path : /even/two;realm=/odd, method
@Path : /, HTTP Method : GET, method HTTP Method : GET, ContentType :
*/*, method @Consumes : */*,, Accept : application/json,, method
@Produces : application/xml,application/json,.
[...]
10:08:45.897 WARN  org.apache.cxf.jaxrs.utils.JAXRSUtils - No operation
matching request path "/syncope/rest/users;realm=/even/two;realm=/odd"
is found, Relative Path: /even/two;realm=/odd, HTTP Method: GET,
ContentType: */*, Accept: application/json,. Please enable FINE/TRACE
log level for more details.
Yes indeed, multiple path segments there due to a "/" in matrix params being not encoded

So - thanks for the above analysis, please do the workaround for now, and I will investigate if encoding a "/" in matrix params on the client side should be done by default

Thanks Sergey, I confirm that this workaround works like a charm: I'll be waiting for the outcomes of your analysis, but I might even embed the "/" encoding into the "ListQuery" (or such) bean, isn'it?

Regards.

On 22/04/15 15:05, Francesco Chicchiriccò wrote:
On 22/04/2015 14:13, Francesco Chicchiriccò wrote:
On 22/04/2015 14:09, Sergey Beryozkin wrote:
Hi Francesco

Actually, you said two ClassResourceInfo candidates have been
checked ?
One is UserService, what is the other one (and what Path does it
have ?)

First time is SyncopeService Vs SyncopeService, second is
SyncopeService Vs UserService, the exception is thrown.

Now I see how this sentence

This all should work but I wonder if there's some subtle bug in CXF if
you have a default/empty Path as in UserService list...I'll need to
have
a look

is relevant and related to my sentence above, because SyncopeService is
annotated with Path("").

Regards.

On 22/04/15 12:37, Sergey Beryozkin wrote:
Hi
On 22/04/15 12:20, Francesco Chicchiriccò wrote:
On 22/04/2015 12:48, Sergey Beryozkin wrote:
Hi Francesco

I suppose the problem lies somewhere starting from

https://github.com/apache/syncope/blob/master/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/QueryResourceInfoComparator.java#L77





It is a custom implementation and I guess the rating becomes
problematic when both query and matrix parameters are used.
It may make sense, going forward, to strictly depend on a JAX-RS
only
matching logic (note Query and Matrix parameters can not affect the
selection process in a pure JAX-RS) but I agree it can be
sensitive to
migrate the code.

Well, the ongoing changes towards 2.0.0 are substantial, so I would
not
have problems in removing QueryResourceInfoComparator, if this means
improving our compliance with JAX-RS best practices.

Does this also mean that we need to remove all duplicate methods
(see
list() or search() with variable arguments)?

Yes, unless some of the methods are available on unique @Paths.


Can you please get a breakpoint at the above code ? We can chat and
see afterwards if a comparator can be tuned further?

I've already done this before deciding to (hopefully temporarily)
switch
back to @QueryParam: only the ClassResourceInfo's compare gets
invoked,
not OperationResourceInfo's; as a result, getMatchingRate() is not
invoked at all in this case.

So you are actually seeing 404... Sorry, you actually did say it. I
thought it was a case of multiple matching methods with the one
having a
Matrix parameter being one of them but not selected in the end :-)...

the request URI is something like
"/users;realm=a;realm=b"

?

This all should work but I wonder if there's some subtle bug in
CXF if
you have a default/empty Path as in UserService list...I'll need to
have
a look

Thanks, Sergey


Thanks for your support.
Regards.

On 22/04/15 11:36, Francesco Chicchiriccò wrote:
Hi,
I have recently experimented some troubles in matching REST
methods
using @MaxtrixParam.

If you take a look at [1], this works fine; when changing the
first
@QueryParam to @MatrixParam instead, CXF throws a "Not Found"
exception.
At first I thought that the problem might depend on the fact that
there
are many methods with same name, but the problem occurs even if I
leave
only the version with all parameters (e.g. the one at [1]).

FYI, we are using a custom OperationResourceInfoComparator [2].

Any idea?
TIA

Regards.

[1] https://github.com/apache/syncope/blob/master/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java#L146


[2] https://github.com/apache/syncope/blob/master/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/QueryResourceInfoComparator.java

--
Francesco Chicchiriccò

Tirasa - Open Source Excellence
http://www.tirasa.net/

Involved at The Apache Software Foundation:
member, Syncope PMC chair, Cocoon PMC, Olingo PMC
http://people.apache.org/~ilgrosso/


Reply via email to