> >>> * I'm not a big friend of abstract classes since it reduces the
> >> freedom of the provider. Why not just providing an interface for
> >> ClientFilter? I doubt that anybody is unable to write that single
> code
> >> line that keeps the "next" reference. Also, as a WebResource is only
> to
> >> be created by a builder and the builder is to be provided by a JAX-
> RS
> >> implementation, I do not see a need to provide more than the
> >> WebResource's interface as part of the spec. It should be completely
> up
> >> to the implementation how WebResource works internally and what it
> >> extends from.
> >>
> >> This is going to be redesigned as part of the task #99.
> >>
> >> As for the interface vs. abstract class, I prefer interfaces too,
> but
> >> we need to understand that there is a serious
> >> limitation: you cannot add new methods into an interface in a future
> >> release without breaking BW compatibility.
> >
> > I think this could be solved, e. g. by versioned interfaces as
> Microsoft did in the Win32 API or by additional interfaces for new
> methods. We use the latter pattern a lot as having a single interface
> for a task often is typical but actually not needed.
>
> The above works particularly well in designs where interface is
> representing some "able" or some specialization. When
> you need to fix a missing method in the original interface, the results
> tend to be clumsy. Consider e.g. JAX-RS
> core.Request - apparently the interface is missing many methods
> particularly from a filter/interceptor perspective. But
> how to add more methods? By introducing e.g. MutableRequest? Sure, you
> could do it, but it still feels more like a
> workaround (that we may want to apply eventually if we reach a
> consensus here - see task #76).
Well, I hope that a set of experts will be smart enough to not miss an essential method when they have enough time to discuss and test (as we do have). So let's just be careful enough. A Client API is no rocket science, so I do not see that *actual* risk. And introducing "Filterable" and "Interceptable" mixin interfaces is not clumsy but modular.
> > Or we accept that breaking BW compatibility is not that big issue as
> we all might think: Nobody is forced to switch to the next generation
> of Java EE. If one does, he actually has much bigger problems that the
> need to recompile...
>
> While I can personally see some benefits, that's not the common Java EE
> strategy. I would be very skeptical about
> proposing to break BW compatibility.
I do not see that anybody would stop us from doing so, as Java EE already did such cuts (think of CMR vs. JPA) in the past and is planning to drop more stuff in the future. Forcing a recompile at a Java EE version change is nothing anybody would not understand. Certainly it should be prevented in a minor release but with a major release this is ok. We should not think in too narrow rules unless they are explicitly given. I did not get told that rules. Did you?
> >>> * I'm not a mathematical expert, but WebResourceBase's .hashCode()
> >> implementation looks rather complex. I think "return
> >> this.getClass().hashCode() ^ this.uri.hashCode()" would do and would
> be
> >> much simpler? Looks like some black magic currently. ;-)
> >>>
> >>
> >> Me neither, that's why I used my IDE to generate it for me. I would
> be
> >> happy to change it if you can prove that your
> >> version provides a widely spread hash codes :)
> >
> > What mass of WebResource instances do you plan to create at runtime
> that hashCode performance will be an issue actual? Do you even plan to
> use WebResource in any kind of Collection (otherwise nobody would call
> hashCode anyways)?
>
> Not really, although one never knows. In fact I was really surprised
> that you focused at that part of the code. :)
If just came into my focus by incident when scolling down the lines. As it is part of API, I have to check it, as every implementor and user is forced to use it. So I wondered why it is so complex. I think we should provide a clear and clean code and that strange formula was everthing but clear to me, so I added it to the list of comments.
> > And: Can your IDE proof that your algorithm is better spread than
> mine? ;-)
>
> It's a common pattern described and explained by Josh Bloch in his
> Effective Java book; see e.g. here (item 8):
> http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf
>
> Just the constant numbers are different - 3/29 vs. 17/37 in the book.
> Still prime though and the book does not mandate
> the use of those particular numbers.
>
> As all I do is calling existing JVM hash code methods (which should be
> done well) and XORing them to not lose too much
> information, I expect them to be rather well spread for the target use.
> :-)
>
> Without a proof, I wouldn't expect that XORing two random ints would
> provide necessarily a good or better wide spread.
> In fact, my feeling is that opposite behavior would be more probable :)
>
> Anyway, as we both agree, this part of the code is not going to be the
> hot spot of the API, so why not to stick to
> something that is commonly accepted as a good & correct approach?
As much as I appreciate Josh's book and I totally share the idea of that chapter, I need to tell you that his actual algorithm implementation is actually not spreading so well as you might think: He just multiplies by an arbitrary number which affects the spread obviously in an arbitrary way. As you know you have to put exactly two numbers into exactly 32 Bit, the obviously best solution will be to move positions by exactly 16 Bit (just as he does to fold long -- see few lines early in that chapter) to have one at the leftmost position and one at the rightmost... Anyways, what I don't like with that code actually is not the algorithm itself, but the fact that our API is providing implementation. I think it should be up to the implementor to choose implementation, which is why I said that I like interfaces more than classes. Our job is to define an API in the end and I do not like that (for any good reason) we are providing implementation.
> >>> * Why insisting on ClientRequest being Cloneable?
> >>
> >> Since it seems we will have a fully mutable request, to be able to
> >> reuse a preconfigured request in multiple
> >> invocations, having it cloneable may come handy IMO.
> >
> > Can you give an example of ClientRequest reuse? Why not just using
> the same instance?
>
> If the request is mutable, once you pass it to the framework you can
> never be sure that your instance you hold still
> represents the same request as the one you used previously.
But if you clone the instance what difference does that make? Also, the obvious solution to clear an instance would be either a clear or reset method instead of a clone method, or a pooling factory cleaning instances under the hood. It just looks odd to be forced to call clone to clean things up. Or we could make Requests immutable, which is my favorite anyways.
> >>> * Is it essential to keep the ordering of cookies? If not, why then
> >> returning List<NewCookie> instead of just Collection<NewCookie>?
> >>
> >> Is there any signinficant advantage behind that generalization? List
> >> provides more manipulation methods compared to
> >> collection. How about Set?
> >
> > You are reducing the freedom of the user of the Collection without
> any particular need.
>
> How is that?
Sorry I was not thinking correctly. I wrote "user" but should have written "implementor". The implementor possibly is applying an algorithm that produces an unsorted result. You are now forcing him to provide a sorted result. That means, you influence the implementor's choice with no need. So we should not force that. If an implementor has an ordered result, he is free to return any kind if List. But if he has an unordered result, he should be free to use a non-List.
> > It is a default pattern of mine to use the topmost generalization
> whenever possible, to give the user the most possible freedom.
>
> To do what?
(Sorry again for "user", still mean "implementor".)
To implement in a non-sorted way.
See the domain of databases for example: The user wants to get some result. If you just write SELECT then you get unordered and even duplicate values (comparable to Collection). If you want ordering or unique values, you must specify it, as it imposes additional work.
Same applies here. When using List or Set you constraint the implementation to either order results or check for duplicates. If there is a real need to do so, I do not object. But I just do not see the need to order them. I could get convinced to use Set to prevent duplicates, as callers would not expect duplicates, but that need was not told so far.
> > Set would be better than List as it at least has a use: It expresses
> that a Cookie cannot be duplicate.
> >
> > But again, why *not* Collection?
>
> I may want to change it to Set indeed. As for the generalization, I
> feel that it is better to:
> - provide as specific interface as reasonably possible and to
> - consume as general interface as possible
No problem with that, but Set is the right choice then, not List. Having duplicates my induce problems. Unsorted results will not.
> That's why I chose List... or if we agree that Set is better, then I
> would change it to Set. Maybe we can start a
> separate thread on this particular thing? I'd like to hear what others
> have to say and I'm afraid not everyone is going
> to follow these long email exchanges. Do you want to take action and
> start the new thread?
Ok for me. Set would be ok for me if others know any good reason why duplicates could become a problem. List is not, as it imposes ordering and it is not told to what property actually to order by and there is no problem with unordered processing.
> >>> * Can you provide a use case when a user will apply the
> >> ClientResponse.bufferEntity() method?
> >>
> >> E.g. you want to execute XQuery on the returned XML stream?
> >
> > Still didn't get the point (sorry I am using XPath a lot but am not
> used to XQuery). How will that work? If I will run XPath for example, I
> would just pick the entity, surround it with JAXBSource and run JAXP.
> No need for that method so far. So what is it actually good for?
>
> Suppose you are on a very slow connection and don't want to process the
> input stream byte per byte. But I do not have
> any particularly strong feelings about this method.
Well, if even yourself do not have strong feeling, we should discart it until some knows a very good reason to add it. Every method we have forces an implementor to implement it. If there is no need, we should not force that.
Whether or not the processing happens byte by byte should be up to the choice of the implementor. Possibly he likes to measure the throughput and decide to buffer on his own, why not? It has no effect upon the user.
On one hand you propose to not add caching (which has strong effect upon the user), on the other had you propose that the user can decide about buffering (which is clearly not an application's choice but up to the transport level). This is inconsistent.
> >>> * The current proposal seems to expect that a WebResources get
> >> filtered ever or never, but it might be the case where filtering is
> >> dependend of the current session. So the question is where we need
> to
> >> support that. Currently it won't work as removing a filter while an
> >> asynchrounous request is pending might lead to unknown behaviour.
> >>
> >> Can you share the use case in particular? I am confused by the
> notion
> >> of the session - I thought we are shooting for a
> >> stateless API.
> >
> > Yes and no. First, it was a hypothetical question. Second, the
> question is whether we need to support something like sessions (client-
> side, not server-side). See, the service's is stateless, but one might
> have a need to have some kind of transaction (not in the database
> sense), or let's better call it, a business process. That process
> involves lots of GET and PUT, which in the end create what the user
> wants (like a money transfer involves many GETs and PUTs on different
> resources). Each single invocation is stateless, but the process itself
> is definitively there and must keep state on the client (it must track
> the state of both accounts whilst the transfer is running and if one
> method fails it has to decide what to do with both accounts now). To
> model that, it might be beneficial to have sessions (aka business
> processes). Now it could happen that one such session needs a filter,
> while another does not. For example, if your credit card was stolen,
> the ATM (= client) shall tr
> ack all communication with your account. Not with the bank server in
> generel, only with YOUR account. So the filter will be account
> dependent, not server or JAX-RS-Resource dependent.
>
> Such state management concept belongs naturally to the layer above the
> proposed JAX-RS client api IMO. It would be
> easier to decide if we need to add any support to the client API if we
> had more experience with particular use cases.
> This may be a good candidate for a potential future enhancement.
Yes you are right, but it is not about state management but about preventing failures. Let me give an example:
WebResource instance is used by two differen processes. The processes are managed by a higher level (agreed). One process needs filter, the other does not. Both processes are running in different threads. Process A set a filter. Process B sets "null" to prevent filtering. Now you are in a nice race condition. Depending on what thread runs faster, process B might getting filtered without actually setting a filter or process A might not getting filter but actually wants to. That's why you *need* sessions on the client even if the processes A and B itself one execute one single http command each!
That's why WebResourceBase must either cleary told to be not thread safe (a user is not allowed to share it among multiple processes) or it must be able to support different filters for different processes. But if you say it is not thread save, then the name is just misleading. Maybe the best solution would be to have other names? If WebResource is not thread safe, then it is not the reflection of a physical server side web resource anymore (which obviously IS thread safe), but it then is nothing but a Client side session instance.
So, even if our interface is stateless, as you can see, you HAVE to deal with sessions, even in other names. Not with server side sessions, but with Java sessions.
> >>> * A GUI might be heavily interested in getting updated after
> >> receivering another HTTP chunk. I didn't find a way how an
> application
> >> could register for such events. This is essential to show a progress
> >> bar with long-lasting downloads.
> >>
> >> Let me have a look at that - added new subtask #105. But it seems to
> me
> >> that this is something that should be done at
> >> the transport layer.
> >
> > Yes but the problem is that the client has no influence on the
> transport layer. A client on Java SE cannot register at the transport
> level as it is up to the JAX RS Engine to select or implement the
> transport layer. Or did I miss something, like "Client.getTransport()"
> where a client could register for such events?
>
> Seems to me that we may actually need some way to expose the transport
> (also based on the client cache discussion we are
> having).
Right. Either the transport layer is exposed, or we need methods to register status listeners (and to enable caching). Personally I would prefer no transport layer exposure, as it should be JAX RS layer's work to translate the application's wishes (process events and local caching) into the language of the transport layer:
**** APP ***
** JAX-RS ***
* TRANSPORT *
but not
********* APP ***********
** JAX-RS ** TRANSPORT **
Regards
Markus