Lead Developer of the Jetty Open Source Servlet Server
Greg is the lead developer of the Jetty open source servlet server and a member of the experts group for the servlet specification from the Java Community Process. Greg has contributed to Geronimo, JBoss, activemq, DWR and other open source projects. Born in Sydney in 1964, Greg graduated from Sydney University with an honours degree in Computer Science in 1986. Since then he has worked as developer, designer, team leader and architect on varied problem domains including telecoms and WWW. Greg is the founder of Mort Bay Consulting and the CEO of Webtide.gregw
Greg's Blog
Wednesday, October 29, 2008
Valery Silaev has pointed me to an article on flex.sys-con.com that demonstrates how the asynchronous features of Jetty have been used by Farata Systems to achieve some excellent scalability results with BlazeDS.
BlazeDS is an open source server side that provides comet style streaming events to a flex/flash client side (but not strictly comet as it is not strictly ajax).
Good work!
Monday, October 13, 2008
Open source business plans are tough. It's hard to come up with a clear and comprehendable revenue model when you give so much of your work away for free.
But those of us who work in open source, must not forget that freedom is the at core of our model and that we must grant those freedoms on a non-discrimanatory basis. Recently I've seen several postings that make me concerned that some core principals are being forgotten.
Firstly LWN reported on the Linux Plumbers Conference, where the key-note from Greg Kroah-Hartman tried to shame Canonical for not contributing enough kernel patches back from their work on ubuntu:
"there is the matter of redistributors who base their products on another distributor's work; these are distributors like Ubuntu or CentOS. There are no contributions back to the community from that kind of distributor at all. They are not functioning as a part of the Linux ecosystem."
Then Rod Johnson blog on springsofts maintenance describes the ideal open source business model as:
"If you are an organization deriving tremendous value from Spring by using it in large production environments, please send SpringSource a check for 1% of the value you are receiving by using Spring. We will use this money to pay salaries, grow our investment in open source and return a profit."
Another example of this thinking comes from the blog of Jack Slocum from Ext.js:
"Ext JS 1.0 is released under the LGPL, minus the Assets license as mentioned above. Shortly thereafter 2 major publicly traded corporations (names withheld) embedded Ext JS into their development frameworks. With no mention of Ext JS except in credits files that no one ever saw. No support for all the work that had been put into the framework. Neither one of them even contacted us. How can that be possible? Can they do that?"
While I have some sympathy with Rod's and Greg's positions, I do believe they are forgetting something fundamental. The users of our Free and Open Source Software (FOSS) are free from any obligation to contribute back patches or cash. FOSS licenses don't say "you are free to use this unless you are making money" and they don't say "legally speaking your not obligated to contribute cash or code, but morally you really should".
What Greg Kroah-Hartman needs to remember, is that contributions are not just code or cash. Growing market share, educating users, finding new uses are all great contributions to an open source project.
What Rod is forgetting, is that spring software is now a free commodity, to be used without cost. The expensive valuable resource that Springsoft should focus their marketing on is the clever people that created spring.
What Jack needs to realize is that major publicly traded corporations are unlikely to integrate closed source, proprietary licensed software into their core infrastructure if it it comes from a small operation without major support infrastructure. My mother frequently asks: "why don't you just charge $1 per month to all those hundreds of thousands of Jetty users?" and I realize that my mother has never tried to obtain a purchase order from a major publicly traded corporation.
At Webtide, we sell developer advice, custom development and production support for jetty and dojo cometd. We don't expect our clients to buy our services because of some sort of guilt trip from the value they obtain from those projects. We expect our clients to pay for the value add that we give. The software is free under the terms of the apache 2.0 license and we expect no charity or moral obligation in return. But our developers are highly skilled, and if you want their advice, effort and/or experience directly applied to your commercial concerns, then you have to pay for that valuable resource.
I consider it a confirmation of the quality and value of the project when large corporations make it part of their infrastructure or ship product that contains it. I'm glad that many users can often succeed on their own without questions, or producing bug reports and/or fixes. It indicates that the project is doing a good job of well designing, implementing and documenting our software for those users. When Jetty users are profitable, we don't see that as a lost revenue opportunity, but as a potential client who already should appreciate the value of the skills we have on offer.
You can't be half free. For those struggling with open source business models, my (free) advice is to embrace the freedom that is fundamental to the success of your project and don't resent the success of others who use the freedoms that you have granted. If you want to sell software, then don't open it or get a job at Microsoft, IBM or Oracle.
Friday, August 29, 2008
Thursday, August 14, 2008

The screen shot above shows four iframes calling either a synchronous or the asynchronous demonstration servlet, with the following results:
- Synchronous Call, Single Keyword
- A request to lookup ebay auctions with the keyword "chair" is handled by the synchronous implementation. The call takes 660ms and the servlet thread is blocked for the entire time. A server with a 100 threads in a pool would be able to handle 151 requests per second.
- Asynchronous Call, Single Keyword
- A request to lookup ebay auctions with the keyword "chair" is handled by the asynchronous implementation. The call takes 669ms, but the servlet request is suspended so the request thread is held for only 2ms. A server with a 100 threads in a pool would be able to handle 5000 requests per second (if not constrained by other limitations)
- Synchronous Call, Three Keywords
- A request to lookup ebay auctions with keywords "mouse", "beer" and "gnomes" is handled by the synchronous implementation. Three calls are made to ebay in series, each taking approx 900ms, with a total time of 2706ms and the servlet thread is blocked for the entire time. A server with a 100 threads in a pool would be able to handle only 40 requests per second!
- Asynchronous Call, Three Keywords
- A request to lookup ebay auctions with keywords "mouse", "beer" and "gnomes" is handled by the asynchronous implementation. The three calls can be made to ebay in parallel, each taking approx 900ms, with a total time of 906ms and the servlet request is suspended, so the request thread is held for only 2ms. A server with a 100 threads in a pool would be able to handle 5000 requests per second (if not constrained by other limitations).
The code for the example asynchronous servlet is available here and works as follows:
- The servlet is passed the request, which is detected as the first dispatch, so the request is suspended and a list to accumulate results is added as a request attribute:
if (request.isInitial() || request.getAttribute(CLIENT_ATTR)==null)
The request is suspended before starting the searches in order to avoid races if the searches somehow complete before the request is suspended.
{
String[] keywords=request.getParameter(ITEMS_PARAM).split(",");
final List<Map<String, String>> results =
Collections.synchronizedList(new ArrayList<Map<String, String>>());
final AtomicInteger count=new AtomicInteger(keywords.length);
request.suspend();
request.setAttribute(CLIENT_ATTR, results);
- After suspending, the servlet creates and sends an asynchronous HTTP exchange for each keyword:
for (final String item:keywords)
The API for the Jetty Http client exchanges was inspired by the callback style of javascript XHR.
{
ContentExchange exchange = new ContentExchange()
{
protected void onResponseComplete() throws IOException
{
// see step 4 below
}
};
exchange.setMethod("GET");
exchange.setURL("http://open.api.ebay.com/shopping?MaxEntries=5&appid=" +
_appid +
"&version=573&siteid=0&callname=FindItems&responseencoding=JSON&QueryKeywords=" +
URLEncoder.encode(item,"UTF-8"));
_client.send(exchange);
}
- Once all asynchronous HTTP exchanges are sent, the servlet saves some timing information for the demo and then returns. Because the request is suspended, the response is not flushed to the browser, but the thread is returned to the thread pool so it can service other requests:
request.setAttribute(START_ATTR, start);
request.setAttribute(DURATION_ATTR, new Long(System.currentTimeMillis() - start));
return;
} - All the rest requests are handled in parallel by the eBay servers and when each of them completes, the call back on the exchange object is called. The code (omitted above, shown below)extracts auction information from the JSON response and adds it to the results list. The count of expected responses is then decremented and when it reaches 0, the suspended request is resumed:
protected void onResponseComplete() throws IOException
{
Map query = (Map) JSON.parse(this.getResponseContent());
Object[] auctions = (Object[]) query.get("Item");
if (auctions != null)
{
for (Object o : auctions)
results.add((Map) o);
}
if (count.decrementAndGet()<=0)
request.resume();
} - After being resumed, the request is re-dispatched to the servlet. This time the request is not initial and has results, so the results are retrieved from the request attribute and normal servlet style code is used to generate a response:
List<Map<String, String>> results = (List<Map<String, String>>) request.getAttribute(CLIENT_ATTR);
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html><head><style type='text/css'>img:hover {height:75px}</style></head><body><small>");
for (Map<String, String> m : results)
{
out.print("<a href=\""+m.get("ViewItemURLForNaturalSearch")+"\">");
...
Friday, August 8, 2008
The core issue, is that after an initial promising start, google appear to have backtracked on the openness bit. SDKs updates are only being distributed to select partners who are gagged with NDAs and thus can't illuminate the community as to the now unclear intentions of Google. This bad robot violates all three laws:
A committer may not, through action or inaction, violate IP cleanliness
A committer may not, through action or inaction, disenfranchise contributors
A committer may not, through action or inaction, surprise the membership
I see little reason that we should continue to put development resources towards this project. While we accept and embrace that that the vast majority of the users of our software will do so freely, we are not a charity and certainly not to the likes of Google. We give away our software and openly collaborate on it's development, but if one wants our commercial priorities to be aligned with their own commercial activities, then we expect a commercial relationship. Google have used false open pretenses to induce ourselves and many others to align our open source efforts with their closed commercial priorities.
