Re: B2B proposal
- From: Jonas Borjesson <
- Subject: Re: B2B proposal
- Date: Fri, 14 Jun 2013 16:34:17 -0700
> I will respond to this by, at first, ignoring anything to do with
> maintaining consistency with the rest of the API - but I will address that
> at the end of this comment.
> I have just had to write an app component that copies the route headers from
> one message to another. To do this, I had to get the route header using
> msg.getHeaders, which returns a ListIterator... which then has to be
> reversed to push the routes into the other message; this is where our notion
> of pushRoutes(...) (search up for this) came from. I find the ListIterator
> irritating: for example, I cannot call isEmpty and it was irritating having
> to write reversal code.
> When it comes to returning data from an API: I think that you can return the
> relevant collection type, where relevant, typically as a delegating
> read-only or snapshot view of the underlying data. I wish that the
> SipServlet API returned an immutable snapshot List view when you call
> getHeaders(). This could be efficiently implemented as a Copy-On-Write
> structure. I would like more useful header specific utilities that return
> useful collections: if I could call Set<String> getRequired(), then I could
> if (msg.getRequired().contains("100rel"))
> Collections are more useful than iterators: this seems obvious. I would
> suggest that you need a good reason to use an iterator (or iterable) over a
> Collection. Reasons to use iterator/Iterable, as Jonas has stated:
> 1) It's easier for the implementer, as the contract is less rigid.
> 2) It's easier to write a lazy-load iterator than a lazy-load collection.
> I'm not sure that (1) is a sufficiently good reason for us: our focus should
> be on the user of the API (as Jonas points out).
> I'm not sure that we need lazy-loading in most of the places that we use
> iterators in the SipServlet API.
I actually agree with you in that I like Collection better then
Iterator (and yes, Iterable is what you want to use) but I think we
should make sure that we consider all the scenarios before making a
decision. I don't know what the original reason for using Iterator was
but I do like consistency in an API, which is the main reason I
brought it up.
Note, for an implementor it is not easier to return an iterator per
say. it may in fact be more annoying if you already have stored
everything in collections. However, for streaming results, iterators
of some kind is the better choice since you cannot answer questions
such as size() anyway (or contains). But yeah Tom, I would also agree
that for the purpose of the SipServlet API, it may not really matter
because most of the methods we discuss is around manipulating some
structure you most likely have in memory anyway...
> I would also point out that, where a method returns iterator, it is usually
> better to return iterable, as that is nice to use in a for...each loop. If
> you want to look at a library that has given the whole issue of Collections
> vs Iterators/Iterables, look at Google's Guava.
> As for consistency: I think that the API should, over time, move away from
> using iterators. Which is more broadly useful of the following?
> ListIterator<Locale> getAcceptLanguages()
> Set<Locale> getAcceptLanguages() - where the iterator of Set is guaranteed
> to return items the order of the headers
The guarantee of ordering is up to the Iterator so just because you
return an Iterator doesn't mean that you won't guarantee whatever
ordering you wish...
> With the second option, I can call methods such as contains().
> Furthermore, we have used collections in some places:
> Set<Map.Entry<String,String>> Parameterable.getParameters
Yes, I would like to change many things in this API but seems like we
cannot. But to your point, if we change these methods then perhaps in
some distant future we can change the signature of the others as well.
> A SIP request is uniquely associated with a SIP dialog, which is uniquely
> associated with a SipSession. This all seems simple enough, until you
> consider forking. When downstream forking occurs, you will have more than
> one SipSession, but still only have one SipServletRequest. This is not so
> bad when you are acting as a UAC, but when you are running a B2BUA and
> acting as a UAS, what happens when you want to "fork back" to the caller?
> Alice B2BUA Proxy Bob1 Bob2
> 1. INV(a1)---------->
> 2. INV(b1)------->
> 3. INV(b1)------->
> 4. INV(b2)--------------------->
> 5. <-------180(b1)
> 6. <-------180(b1)
> 7. <----------180(a1)
> 8. <---------------------180(b2)
> 9. <-------180(b2)
> 10. <----------180(a2)
> Here we have an example of parallel downstream forking. Assume that the
> B2BUA is an app running on a SipServlet container. Everything else is a
> normal SIP actor outside of the container. At step (9), the response from
> Bob2 leads the container to realise that forking has occurred, and so it
> creates a derived SipSession from the session used to send the initial
> INVITE to Bob in step (2). When we need to send the first response to Alice
> in (7), then the existing SipSession is used, but to create the second
> response in (10) requires a new SipSession to be created. After all this
> forking: Alice has two SipSessions, but only one INVITE SipServletRequest -
> when that SipServletRequest is queried for Alice each has one INVITE. When
> you call getSession() on the INVITE SipServletRequest, it will return the
> original SipSession. All quite weird.
Ok, from an API perspective then. What happens if you pass in a
completely unrelated SipSession? Allowed?