<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>java rants &#187; yahoo</title>
	<atom:link href="http://www.javarants.com/tag/yahoo/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.javarants.com</link>
	<description>Rants about Java and other internet technologies by Sam Pullara</description>
	<lastBuildDate>Thu, 11 Mar 2010 23:26:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>YQL opens up 3rd-party web service table definitions to developers</title>
		<link>http://www.javarants.com/2009/02/05/yql-opens-up-3rd-party-web-service-table-definitions-to-developers/</link>
		<comments>http://www.javarants.com/2009/02/05/yql-opens-up-3rd-party-web-service-table-definitions-to-developers/#comments</comments>
		<pubDate>Thu, 05 Feb 2009 20:55:51 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[yahoo]]></category>
		<category><![CDATA[yql]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=1153</guid>
		<description><![CDATA[The Yahoo! Query Language aspires to be the last web service API that the normal developer will ever have to learn.  By default we implement 50+ tables that grab data both from Yahoo! web services, some 3rd party web services and then the web at large using our dynamic tables that allow you specify [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://developer.yahoo.com/yql/">Yahoo! Query Language</a> aspires to be the last web service API that the normal developer will ever have to learn.  By default we implement 50+ tables that grab data both from Yahoo! web services, some 3rd party web services and then the web at large using our dynamic tables that allow you specify a data type and a url.  However, those dynamic APIs limit the YQL user to a very flexible but ultimately hard to work with API without the benefit of the structure found in the other tables that we offer.</p>
<p>Today <a href="http://www.yqlblog.net/blog/2009/02/05/open-data-tables-added-to-yql/">YQL introduced</a> a new feature that allows 3rd parties to define new tables and then share those table definitions with whomever they like for them to use.  For example, let&#8217;s say you are the New York Times or you are a developer that likes the New York Times APIs and would like to make them more accessible to someone using YQL.  Yesterday, they released the article search API, so I will use that one among others as an example, to get an api-key to execute these examples go to their <a href="http://developer.nytimes.com">developer site</a>.  This is a pretty sophisticated API that allows you to search using a variety of parameters.  If you were to use YQL without modification, you would simply use the dynamic JSON endpoint to parse out the results from their service.  The big issue with this though is that you would be unable to easily construct the URLs required and would have to write that code that collected all the parameters and created the URL.  If you had a YQL table, those parameters would be defined and how they are expressed in the URL codified and you would be able to individually address the keys.<br />
<span id="more-1153"></span><br />
So without this ability you would use something like this:</p>
<p><code>select * from json where url='http://api.nytimes.com/svc/search/v1/article?api-key=...<br />
&amp;query=yahoo&amp;begin_date=19990112&amp;end_date=19993112' and<br />
itemPath='json.results'</code></p>
<p>If we instead defined the API using the <a href="http://developer.yahoo.com/yql/guide/yql-opentables-chapter.html">YQL open data tables specification</a> you would be able to do this (by the way, don&#8217;t read the headlines, you&#8217;ll just be depressed):</p>
<p><code>use 'http://www.javarants.com/nyt/nyt.article.search.xml' as articles;<br />
select * from articles where apikey='...' and query='yahoo' and begin_date='19990112' and<br />
end_date='19993112'</code></p>
<p>Why is this superior?  For a number of reasons.  In the second case not only does it make it easier for anyone to use it, it also brings those keys from the query into columns which allows you to do joins that you cannot do with the first abstraction.  Here is an example join:</p>
<p><code>select * from bs where apikey='...' and query in ('yahoo', 'google', 'microsoft') and begin_date='19990112' and end_date='20000101'</code></p>
<p>This will actually do 3 searches for you in parallel and then return the combined result.  By creating a YQL open table we can really off-load processing that you would normally do on your client or server to the YQL engine.  You&#8217;ll note with that query that the user-time spent is actually about half or less than the actual service-time thus drastically decreasing the latency through asynchronous processing.</p>
<p>One of the really nice APIs out there is <a href="http://friendfeed.com/api/">FriendFeed&#8217;s API</a>.  It really is very well designed and easily works with straight-forward table definitions.  Here is an example of how to get the public feed:</p>
<p><code>use 'http://www.javarants.com/friendfeed/friendfeed.feeds.xml' as ff;<br />
select * from ff</code><a href="http://developer.yahoo.com/yql/console/?q=use%20'http%3A%2F%2Fwww.javarants.com%2Ffriendfeed%2Ffriendfeed.feeds.xml'%20as%20ff%3B%0Aselect%20*%20from%20ff"><small>console</small></a></p>
<p>By defining different endpoints with the same table definition we will automatically select the correct API based on the keys included in the query.  Using that same table we can also get my public entries from twitter:</p>
<p><code>select * from ff where nickname='spullara' and service='twitter'</code><a href="http://developer.yahoo.com/yql/console/?q=use%20'http%3A%2F%2Fwww.javarants.com%2Ffriendfeed%2Ffriendfeed.feeds.xml'%20as%20ff%3B%0Aselect%20*%20from%20ff%20where%20nickname%3D'spullara'%20and%20service%3D'twitter'"><small>console</small></a></p>
<p>This won&#8217;t include my private entries though.  However, if you had my remotekey you could generate and pass YQL the authorization header required and it would pass it on to authenticate the API call.  Another popular example that has been on the forums is the ability to use <a href="http://weather.com">weather.com</a>&#8217;s API to tease out international locations.  That is actually really easy and you can even use that data to join with their weather forecasts.  Here is an example where we pull the weather for all the Moscow&#8217;s of the world:</p>
<p><code>use 'http://www.javarants.com/weather/weather.search.xml' as ws;use 'http://www.javarants.com/weather/weather.local.xml' as wl;<br />
select * from wl where location in (select id from ws where query='moscow')</code><a href="http://developer.yahoo.com/yql/console/?q=use%20'http%3A%2F%2Fwww.javarants.com%2Fweather%2Fweather.search.xml'%20as%20ws%3Buse%20'http%3A%2F%2Fwww.javarants.com%2Fweather%2Fweather.local.xml'%20as%20wl%3B%0Aselect%20*%20from%20wl%20where%20location%20in%20(select%20id%20from%20ws%20where%20query%3D'moscow')"><small>console</small></a></p>
<p>I&#8217;ve actually started up a project on <a href="http://github.com">github</a> called <a href="http://github.com/spullara/yql-tables/tree/master">yql-tables</a> to store useful table definitions and will be taking submissions from the community. You can try them out by &#8216;use&#8217;ing them directly from the git repository or by pulling them onto your own server accessible from the YQL servers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2009/02/05/yql-opens-up-3rd-party-web-service-table-definitions-to-developers/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Build your own mail analyzer for Mac Mail.app</title>
		<link>http://www.javarants.com/2008/12/26/build-your-own-mail-analyzer-for-mac-mailapp/</link>
		<comments>http://www.javarants.com/2008/12/26/build-your-own-mail-analyzer-for-mac-mailapp/#comments</comments>
		<pubDate>Sat, 27 Dec 2008 03:46:49 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[yahoo]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=943</guid>
		<description><![CDATA[You&#8217;ve probably read about things like Xoopit and Xobni for analyzing both online mail and your outlook mail.  As it turns out, Apple has done something great in this regard that I think has been mostly overlooked.  Mail.app stores all of the meta-data for you email in a file called ~/Library/Mail/Envelope Index.  [...]]]></description>
			<content:encoded><![CDATA[<p>You&#8217;ve probably read about things like Xoopit and Xobni for analyzing both online mail and your outlook mail.  As it turns out, Apple has done something great in this regard that I think has been mostly overlooked.  Mail.app stores all of the meta-data for you email in a file called <i>~/Library/Mail/Envelope Index</i>.  You might wonder what the format of this file is&#8230; well it is a SQLite3 database.  The contents are pretty easy to see, go to the terminal and type:</p>
<p><code>macpro:~ sam$ sqlite3 ~/Library/Mail/Envelope\ Index<br />
SQLite version 3.6.3<br />
Enter ".help" for instructions<br />
Enter SQL statements terminated with a ";"<br />
sqlite><br />
</code><br />
<span id="more-943"></span><br />
Everything about your mailboxes is stored within this database and the structure of the database is normalized so its very easy to navigate.  The tables of most interest for mail analysis are:</p>
<pre>
sqlite> .tables
<strong>addresses</strong>              <strong>mailboxes</strong>              todo_notes
alarms                 <strong>messages</strong>               todos
associations           properties             todos_deleted_log
<strong>attachments</strong>            <strong>recipients</strong>             todos_server_snapshot
calendars              <strong>subjects</strong>
feeds                  <strong>threads</strong>
</pre>
<p>Fortunately, accessing a SQLite database is quite easy from just about any language that you decide to use. I&#8217;m just going to do all the queries in straight sqlite3 rather than a language, but they could be embedded in your application.  First things first, copy your <em>Envelope Index</em> to another directory:</p>
<pre>macpro:tmp sam$ cp ~/Library/Mail/Envelope\ Index .</pre>
<p>Now you can use that database without worrying about messing up the locking or corrupting data while Mail.app is using it.  Since we might as well do an example that  is interesting rather than merely educational, how about we answer the question: &#8220;Who are my coworkers with whom that I collaborated?&#8221;.  This is going to be a multi-query process to extract the information &#8212; there may be more efficient ways to do it &#8212; but think of this as instructive rather than prescriptive.  First I need to limit the query to only those mailboxes which contain work email:</p>
<pre>
<span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">DROP</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">TABLE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkermailboxes;
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">CREATE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">TABLE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkermailboxes(id);
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">CREATE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> INDEX coworkermailboxes_index </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">ON</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkermailboxes(id);
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INSERT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INTO</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkermailboxes </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> rowid </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> mailboxes
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">WHERE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
url </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">like</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,128,0); font-weight: bold; font-style: normal; ">&apos;imap://samp@snv-webmail.corp.yahoo.com/%&apos;</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">OR</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
url </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">like</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,128,0); font-weight: bold; font-style: normal; ">&apos;imap://sam@mail.sampullara.com/Yahoo%20Inc%20Archive&apos;</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">;
</span>
</pre>
<p>That gives us a table with several mailboxes that I have in Mail.app including Sent Messages.  I would peruse the list of mailboxes to ensure that you are grabbing all the correct information. For me I had to also search my archives.  Now I am going to take a series of steps to get to the final out put by iteratively processing successive tables of information.  The first table, is a list of those people that you have both sent and received an email with directly (they were the sender and you were a receiver or you were the sender and they were the receiver):</p>
<pre>
<span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">DROP</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">TABLE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers;
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">CREATE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">TABLE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers(id);
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">CREATE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> INDEX coworkers_index </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">ON</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers(id);
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INSERT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INTO</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> a.rowid </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> addresses a, messages m, recipients r
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">WHERE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
m.sender = a.rowid </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
m.mailbox </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">IN</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> (</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkermailboxes) </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
r.message_id = m.rowid </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> r.address_id = </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">4</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INTERSECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> a.rowid </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> addresses a, messages m, recipients r
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">WHERE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
m.sender = </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">4</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
m.mailbox </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">IN</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> (</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkermailboxes) </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
r.message_id = m.rowid </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> r.address_id = a.rowid
;
</span>
</pre>
<p>Note I have directly inserted my addresses rowid into this query for the sender on the one hand and the receiver on the other.  The next step will be to count the actual number of emails you have received from each of those on the list:</p>
<pre>
<span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">DROP</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">TABLE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers2;
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">CREATE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">TABLE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers2(id, recv);
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">CREATE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> INDEX coworkers2_index </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">ON</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers2(id);
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> &quot;Get the received mail&quot;;
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INSERT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INTO</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers2 </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> w.id, </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">COUNT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">(*) </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> messages m, recipients r, coworkers w
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">WHERE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> m.sender = </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">4</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
m.mailbox </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">IN</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> (</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkermailboxes) </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
r.message_id = m.rowid </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> r.address_id = w.id
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">GROUP</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">BY</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> w.id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">ORDER</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">BY</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">COUNT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">(*)
;</span>
</pre>
<p>Finally, we count the number of sent emails and also derive a ratio of sent/received so we can judge how collaborative the exchanges have been:</p>
<pre>
<span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">DROP</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">TABLE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers3;
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">CREATE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">TABLE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers3(id, sent </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">float</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">, recv </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">float</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">, ratio </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">float</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">);
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">CREATE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> INDEX coworkers3_index </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">ON</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers3(id);
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> &quot;Get the sent mail&quot;;
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INSERT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">INTO</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkers3 </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> w.id, </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">COUNT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">(*), w.recv, </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">COUNT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">(*)*</span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">1.0</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">/w.recv </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> messages m, recipients r, coworkers2 w
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">WHERE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
m.sender = w.id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
m.mailbox </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">IN</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> (</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> coworkermailboxes) </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
r.message_id = m.rowid </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> r.address_id = </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">4</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">GROUP</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">BY</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> w.id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">ORDER</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">BY</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">COUNT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">(*)
;</span>
</pre>
<p>You will now have a table named <em>coworkers3</em> that can be mined for information about your level of correspondence with them. For example, here is way to find relatively equal sends and receives:</p>
<pre>
<span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> a.comment </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> addresses a, coworkers3 w
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">WHERE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
a.rowid = w.id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
ratio &gt;= </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">.5</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
ratio &lt;=</span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">2</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
sent &gt; </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">10</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">ORDER</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">BY</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> sent
LIMIT </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">20</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">;</span>
</pre>
<p>When I do this I see the people that either I use to find information or that use me to find information.  Every interaction is usually a request and then a response.  On the other hand, this query will find those that typically made announcements out to the groups that I also worked with:</p>
<pre>
<span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">SELECT</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> a.comment </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">FROM</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> addresses a, coworkers3 w
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">WHERE</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
a.rowid = w.id </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
ratio &lt;= </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">1</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">AND</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
sent &gt; </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">10</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">
</span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">ORDER</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> </span><span style="color: rgb(0,0,128); font-weight: bold; font-style: normal; ">BY</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; "> ratio
LIMIT </span><span style="color: rgb(0,0,255); font-weight: normal; font-style: normal; ">20</span><span style="color: rgb(0,0,0); font-weight: normal; font-style: normal; ">;</span>
</pre>
<p>And so on.  Adding more filters on top of this you could easily derive your team at work for a particular time period and other insights.  With the wealth of information contained in this meta-data store you could figure out all kinds of things:</p>
<ul>
<li>Who sent you an email that you didn&#8217;t reply to yet?</li>
<li>Who do you respond to the most quickly?</li>
<li>Who responds to you most quickly?</li>
<li>What are you and your coworkers approximate working hours?</li>
<li>What groups of CCs could be made into aliases?</li>
</ul>
<p>There really is no limit to how far the analysis could go.  Ideally, it would be possible to setup a dashboard in Mail.app that let you cut and slice the data in a far more precise way than smart folders currently allow today.  Maybe they should come out with super-sql-smart folders!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2008/12/26/build-your-own-mail-analyzer-for-mac-mailapp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yahoo! Application Platform (YAP) and Yahoo! Query Language (YQL) launch today</title>
		<link>http://www.javarants.com/2008/10/28/yahoo-application-platform-yap-and-yahoo-query-language-yql-launch-today/</link>
		<comments>http://www.javarants.com/2008/10/28/yahoo-application-platform-yap-and-yahoo-query-language-yql-launch-today/#comments</comments>
		<pubDate>Tue, 28 Oct 2008 22:40:32 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[yahoo]]></category>
		<category><![CDATA[yap]]></category>
		<category><![CDATA[yos]]></category>
		<category><![CDATA[yql]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=909</guid>
		<description><![CDATA[Since I moved into the platform group at the beginning of the year I had worked with the YAP and YQL teams to help them define their strategy and direction but without being part of the day-to-day operations.  In August, the head of the Y!OS project asked me to step in to take them [...]]]></description>
			<content:encoded><![CDATA[<p>Since I moved into the platform group at the beginning of the year I had worked with the <a href="http://developers.yahoo.com/yap">YAP</a> and <a href="http://developers.yahoo.com/yql">YQL</a> teams to help them define their strategy and direction but without being part of the day-to-day operations.  In August, the head of the Y!OS project asked me to step in to take them through their final run to launch.  It has been a great couple of months working with the teams.  They both had an amazing showing at Hack Day and now today we are launching the platforms worldwide.<br />
<span id="more-909"></span><br />
Over the next few months and into 2009 YAP will be rolling across Yahoo!.  Developers will be able to embed their applications in places like My Yahoo, Frontpage, Media properties and Mail. YQL will continue to be extended to other services by Yahoo! and through a plugin API in the future.  Please check out the announcements at the <a href="http://ycorpblog.com/2008/10/28/were-open-have-at-it/">Yodel</a>, <a href="http://developer.yahoo.net/blog/archives/2008/10/yos_10_launch.html">YDN</a> and <a href="http://opensocialapis.blogspot.com/2008/10/launched-yahoos-first-implementation-of.html">OpenSocial blog.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2008/10/28/yahoo-application-platform-yap-and-yahoo-query-language-yql-launch-today/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>2008 Olympic Medal Counts by Population</title>
		<link>http://www.javarants.com/2008/08/24/2008-olympic-medal-counts-by-population/</link>
		<comments>http://www.javarants.com/2008/08/24/2008-olympic-medal-counts-by-population/#comments</comments>
		<pubDate>Sun, 24 Aug 2008 19:25:18 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[yahoo]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=882</guid>
		<description><![CDATA[There are obviously a lot of ways to measure how well a country did at the Olympics. This post takes a view that we should look at how many people the country had to draw on in order to send the athletes to China to compete.  There are a lot of problems with this [...]]]></description>
			<content:encoded><![CDATA[<p>There are obviously a lot of ways to measure how well a country did at the Olympics. This post takes a view that we should look at how many people the country had to draw on in order to send the athletes to China to compete.  There are a lot of problems with this including: ex-pats competing for their home country, vast disparity in wealth between countries and the relative interest in the Olympic games of the cultures.  One of the things that jumps out immediately is that island nations that draw on a larger related population do very well in the games.  They likely have inherited not only the interest in the competition but are also wealthy enough to train and compete in the games.<br />
<span id="more-882"></span><br />
One of the things that was interesting in putting this together was that I eventually settled on <a href="http://www.powerset.com">PowerSet</a><noscript><a href="http://www.sibresource.ru/">&#1083;&#1072;&#1085;&#1076;&#1096;&#1072;&#1092;&#1090;</a></noscript> as the easiest way to lookup the population of a country.  Both Yahoo and Google will give shortcuts to many of them, they don&#8217;t do it for all of them.  Though PowerSet gets this population data through <a href="http://www.freebase.com">Freebase</a>, Freebase itself doesn&#8217;t have a great search interface.</p>
<p>If I was going to declare an overall country winner for the games I would likely choose Australia.  I&#8217;ve highlighted the top-10 total medal winners in the table in blue and they are far ahead of anyone else in the top-10 on a people / medal basis.</p>
<p> <iframe src='http://sheet.zoho.com/publishrange.do?id=05289758aef52c400f4972263d64beb1' frameborder='0' style='height:600px;width:600px' scrolling='auto' marginwidth='0' marginheight='0'>&nbsp;</iframe></p>
<p> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2008/08/24/2008-olympic-medal-counts-by-population/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Yuil is dead! 4hoursearch is now online.</title>
		<link>http://www.javarants.com/2008/08/01/yuil-is-dead-4hoursearch-is-now-online/</link>
		<comments>http://www.javarants.com/2008/08/01/yuil-is-dead-4hoursearch-is-now-online/#comments</comments>
		<pubDate>Fri, 01 Aug 2008 22:22:07 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[4hoursearch]]></category>
		<category><![CDATA[boss]]></category>
		<category><![CDATA[cuil]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[yahoo]]></category>
		<category><![CDATA[yui]]></category>
		<category><![CDATA[yuil]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=880</guid>
		<description><![CDATA[As this was really just a demonstration of the power of Yahoo! BOSS, I have brought the site back as a demonstration site. Additionally, Yahoo! is making the source code to the new site available so anyone with a knack for Python, HTML and CSS can take a swipe at making a better search experience. [...]]]></description>
			<content:encoded><![CDATA[<p>As this was really just a demonstration of the power of <a href="http://developer.yahoo.com/search/boss/">Yahoo! BOSS,</a> I have brought the site back as a demonstration site. Additionally, <a href="http://www.yahoo.com">Yahoo!</a> is making the source code to the new site available so anyone with a knack for Python, HTML and CSS can take a swipe at making a better search experience.  In order to make a nice UI I teamed up with another Sam, <a href="http://sam.besigner.com">Sam Lind</a>.  I put together the skeleton using Yahoo!&#8217;s amazing <a href="http://developer.yahoo.com/yui/">YUI</a> tools and he created the look and feel.  Please try it out and take advantage of Yahoo!&#8217;s open search API:<br />
<span id="more-880"></span><br />
 </p>
<p style="text-align: center;"><a title="4hoursearch" href="http://www.4hoursearch.com"><img class="aligncenter" src="http://buildandtest.com/files/4hoursearch.png" alt="" width="435" height="220" /></a></p>
<p> </p>
<p>Why <a href="http://www.4hoursearch.com">4hoursearch</a>?  It took 4 hours to write the initial code, 4 hours for it to go from unknown to 20 hits / second, 4 hours looking for a domain name and 4 hours to build the brand new UI.  Fortunately, it won&#8217;t take 4 hours to find something with it <img src='http://www.javarants.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>If you want the classic list of links, now enhanced with <a href="http://developer.yahoo.com/searchmonkey/">SearchMonkey</a> results, you can always start <a href="http://search.yahoo.com">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2008/08/01/yuil-is-dead-4hoursearch-is-now-online/feed/</wfw:commentRss>
		<slash:comments>67</slash:comments>
		</item>
		<item>
		<title>Yahoo! BOSS is easy &#8212; meet Yuil</title>
		<link>http://www.javarants.com/2008/07/30/yahoo-boss-is-easy-meet-yuil/</link>
		<comments>http://www.javarants.com/2008/07/30/yahoo-boss-is-easy-meet-yuil/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 09:01:40 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[4hoursearch]]></category>
		<category><![CDATA[boss]]></category>
		<category><![CDATA[cuil]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[yahoo]]></category>
		<category><![CDATA[yui]]></category>
		<category><![CDATA[yuil]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=879</guid>
		<description><![CDATA[Updated Yet Again: Relaunched as 4hoursearch including the source code. See this blog entry.
Updated Again: Yuil is dead. However, you can always get the same great search results here.
Updated: Using Glue I was able to add some simple category functionality.
I&#8217;m sure everyone saw the recent announcement of a new search engine, Cuil.  I thought [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left;"><strong>Updated Yet Again: Relaunched as </strong><a href="http://www.4hoursearch.com"><strong>4hoursearch</strong></a><strong> including the source code. See this </strong><a href="http://www.javarants.com/2008/08/01/yuil-is-dead-4hoursearch-is-now-online/"><strong>blog entry</strong></a>.</p>
<p><strong>Updated Again: Yuil is dead. However, you can always get the same great search results </strong><a href="http://search.yahoo.com"><strong>here</strong></a><strong>.</strong></p>
<p><strong>Updated: Using Glue I was able to add some </strong><a href="http://sampullara.appspot.com/search?q=friend&amp;sl=long"><strong>simple category functionality</strong></a><strong>.</strong></p>
<p>I&#8217;m sure everyone saw the recent announcement of a new search engine, <a href="http://www.cuil.com">Cuil</a>.  I thought I would have a little fun with it and put together a quick parody of it by mashing up their UI and Yahoo!&#8217;s search results.  As usual, the biggest problems I had were related to my pathetic Python skills.  I&#8217;d love to add the category stuff in (Yahoo! has that info as you can see in <a href="http://tools.search.yahoo.com/newsearch/searchassist">search assist</a>) but BOSS doesn&#8217;t yet have that in the API.  But it does have web and image search and even search suggestions.  Here is the one, the only, the amazing:<br />
<span id="more-879"></span><br />
It was great fun to hack together.  Check out the <a href="http://developer.yahoo.com/search/boss/">BOSS APIs</a>.   Maybe I should have converted the UI to YUI as well&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2008/07/30/yahoo-boss-is-easy-meet-yuil/feed/</wfw:commentRss>
		<slash:comments>87</slash:comments>
		</item>
		<item>
		<title>Better Javadoc results using SearchMonkey</title>
		<link>http://www.javarants.com/2008/05/19/better-javadoc-results-using-searchmonkey/</link>
		<comments>http://www.javarants.com/2008/05/19/better-javadoc-results-using-searchmonkey/#comments</comments>
		<pubDate>Mon, 19 May 2008 19:00:13 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[custom search]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[searchmonkey]]></category>
		<category><![CDATA[yahoo]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=874</guid>
		<description><![CDATA[When you are searching for things like java.util.HashMap one of the issues that you run into is that it will give you the result with the highest rank which more often than not is the 1.4.2 version of the documentation. &#160;I&#8217;ve moved on from that version of Java and would much rather see results for [...]]]></description>
			<content:encoded><![CDATA[<p>When you are searching for things like <a title="Search for java.util.HashMap" href="http://search.yahoo.com/search?p=java.util.HashMap">java.util.HashMap</a> one of the issues that you run into is that it will give you the result with the highest rank which more often than not is the 1.4.2 version of the documentation. &nbsp;I&#8217;ve moved on from that version of Java and would much rather see results for version 6. &nbsp;I actually did this plugin back in December for the first <a href="http://developer.yahoo.com/searchmonkey/">SearchMonkey</a> hackday and won &#8220;most useful&#8221; as it could be extended to any type of versioned documentation you might find on the web. &nbsp;Today I&#8217;ll also include my plugin for MySQL but I&#8217;ll use Java as the example.<br />
<span id="more-874"></span><br />
Here is the normal search result that you get on Yahoo:</p>
<p><img style="border: 1px solid black;" src="http://buildandtest.com/files/javautilhashmapnormal.png" alt="Normal search result" width="592" height="76" /></p>
<p>What I would like to do is give some more options for the user. &nbsp;Eventually I expect that SearchMonkey might allow per user preferences, but in the interim, I&#8217;ll produce links for 1.4.2, 1.5, 1.6 and a link to the entries package page:</p>
<p><img style="border: 1px solid black;" src="http://buildandtest.com/files/javautilhashmapenhanced.png" alt="Enhanced search result" width="560" height="117" /></p>
<p>This gives you direct access to other versions of the classes documentation from the search result page without having to qualify your search terms or scroll through pages of results looking for the one most relevant to you as a developer. &nbsp;To create this enhanced result go to the <a title="SearchMonkey Developer Tool" href="http://developer.search.yahoo.com/wizard/index">SearchMonkey Developer Tool</a> and create a new application. &nbsp;Choose Enhanced Result rather than Infobar. &nbsp;The URL pattern that I used was &#8220;*.java.sun.com/*&#8221;. &nbsp;Obviously the real work is done in the PHP code for the appearance of the enhanced result:</p>
<pre>public static function getOutput() {
&nbsp;&nbsp;&nbsp; $ret = array();&nbsp;&nbsp;&nbsp;

$classname = Data::get('yahoo:index/dc:identifier');
&nbsp;&nbsp;&nbsp; $pattern = "/.*\/docs\/api\/(.*\/[A-Z].*).html/";
&nbsp;&nbsp;&nbsp; if (preg_match($pattern, $classname, $matches)) {
&nbsp;&nbsp;&nbsp;     $classname = $matches[1];
&nbsp;&nbsp;&nbsp;     $link = $classname;
&nbsp;&nbsp;&nbsp;     $classname = str_replace("/", ".", $classname);
&nbsp;&nbsp;&nbsp; } else {
&nbsp;&nbsp;&nbsp;     return $ret;
&nbsp;&nbsp;&nbsp; }

/* pull the package reference out */
&nbsp;&nbsp;&nbsp; if (preg_match("/(.*)\.([^.]+)/", $classname, $matches)) {
&nbsp;&nbsp;&nbsp;     $packagename = $matches[1];
&nbsp;&nbsp;&nbsp; }

/* change the title to the name of the class */
&nbsp;&nbsp;&nbsp; $ret['title'] = $classname;

// Deep links - up to 4
&nbsp;&nbsp;&nbsp; $ret['links'][0]['text'] = "1.6.0";
&nbsp;&nbsp;&nbsp; $ret['links'][0]['href'] = "http://java.sun.com/javase/6/docs/api/" . $link . ".html";
&nbsp;&nbsp;&nbsp; $ret['links'][1]['text'] = "1.5.0";
&nbsp;&nbsp;&nbsp; $ret['links'][1]['href'] = "http://java.sun.com/j2se/1.5.0/docs/api/" . $link . ".html";;
&nbsp;&nbsp;&nbsp; $ret['links'][2]['text'] = "1.4.2";
&nbsp;&nbsp;&nbsp; $ret['links'][2]['href'] = "http://java.sun.com/j2se/1.4.2/docs/api/" . $link . ".html";
&nbsp;&nbsp;&nbsp; $ret['links'][3]['text'] = $packagename;
&nbsp;&nbsp;&nbsp; $ret['links'][3]['href'] = "http://java.sun.com/javase/6/docs/api/" . str_replace(".", "/", $packagename) . "/package-summary.html";

return $ret;
}</pre>
<p>Once that is done you confirm that you are finished and you will then see these enhanced result when you use <a title="Alpha Search" href="http://alpha.search.yahoo.com">alpha.search.yahoo.com</a>. &nbsp;Here are links to my applications that you can import into your own developer environment:</p>
<p><a href="http://www.javarants.com/wp-content/uploads/2008/05/javadoc-smapp.txt">javadoc-smapp</a></p>
<p><a href="http://www.javarants.com/wp-content/uploads/2008/05/mysql-smapp.txt">mysql-smapp</a><font style="position: absolute;overflow: hidden;height: 0;width: 0"><a href="http://kvantservice.com/">компютри</a></font></p>
<p> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2008/05/19/better-javadoc-results-using-searchmonkey/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Using Google App Engine to Extend Yahoo! Pipes</title>
		<link>http://www.javarants.com/2008/04/13/using-google-app-engine-to-extend-yahoo-pipes/</link>
		<comments>http://www.javarants.com/2008/04/13/using-google-app-engine-to-extend-yahoo-pipes/#comments</comments>
		<pubDate>Mon, 14 Apr 2008 02:59:45 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[google app engine]]></category>
		<category><![CDATA[googleappengine]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[pipes]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web service]]></category>
		<category><![CDATA[yahoo]]></category>
		<category><![CDATA[yahoo pipes]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=871</guid>
		<description><![CDATA[Update: A commenter pointed out that you can
from django.utils import simplejson
 instead of including it.  Makes this even easier.
Yahoo! Pipes has always been a great tool for manipulating data but often you have to go to great contortions to get it to do what you want because of its very simple data flow programming [...]]]></description>
			<content:encoded><![CDATA[<p>Update: A commenter pointed out that you can
<pre>from django.utils import simplejson</pre>
<p> instead of including it.  Makes this even easier.</p>
<p><a href="http://pipes.yahoo.com">Yahoo! Pipes</a> has always been a great tool for manipulating data but often you have to go to great contortions to get it to do what you want because of its very simple data flow programming model.  <a href="http://appengine.google.com">Google&#8217;s App Engine </a>opens up the possibility of extending Yahoo! Pipes in very interesting ways through Pipes&#8217; Web Service operator.  Currently this operator sees little use as it requires you to be running an external server somewhere on the internet that is always available for the Pipe execution which is quite a high barrier to entry for the typical Pipes developer. Here is what a Pipe that is using web service looks like and our example pipe:</p>
<p><a title="Web Services Example Pipe" href="http://pipes.yahoo.com/spullara/mirror"><img src="http://buildandtest.com/files/pipeusingwebservice.png" alt="Web Service Pipes Example" width="676" height="585" /></a> </p>
<p>With the launch of Google App Engine there is now a very simple way to get code up on the internet quickly in order to include arbitrary processing in the interior of your Pipes.</p>
<p>To demonstrate how this works, let&#8217;s first build a very simple web service that simply mirrors the data that it receives from Pipes.   If you don&#8217;t have a Google App Engine account you can still follow along by download the <a href="http://code.google.com/appengine/">SDK</a> and executing all the stuff locally though it will have to be accessible from the public internet if you want Pipes to send you requests.</p>
<p>First create a new application directory:</p>
<pre>mkdir pipes-mirror
cd pipes-mirror </pre>
<p>Now create an application descriptor called app.yaml:</p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">application: javarants
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
  script: pipes.py</span></pre>
<p>This application descriptor basically tells Google how to deploy your application.  Your application name should match an application name that you create within the GAE administration tool:</p>
<p><img src="http://buildandtest.com/files/applicationname.png" alt="Application Name" width="495" height="161" /></p>
<p>Now we need to process the data coming from pipes.  Pipes is going to pass this web service some data in JSON format and we need to parse it.  GAE doesn&#8217;t include &#8216;<code>simplejson</code>&#8216; in the Python container so you are going to have to include it with your application.  I downloaded <a href="http://pypi.python.org/pypi/simplejson">simplejson-1.8.1</a> and symbolically linked its <code>simplejson</code> directory into my application directory.  When the request comes in the JSON data will be in the &#8216;<code>data</code>&#8216; parameter so we are going to pull it out, parse it, grab the <code>items</code> array and write it back over the wire in pipes.py:</p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="color:#000080;background-color:#ffffff;font-weight:bold;">import</span><span style="background-color:#ffffff;"> simplejson
</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">import</span><span style="background-color:#ffffff;"> wsgiref.handlers

</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">from</span><span style="background-color:#ffffff;"> google.appengine.ext </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">import</span><span style="background-color:#ffffff;"> webapp

</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">class</span><span style="background-color:#ffffff;"> MirrorPipesWebService (webapp.RequestHandler):
	</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">def</span><span style="background-color:#ffffff;"> post(self):
		data = self.request.get(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"data"</span><span style="background-color:#ffffff;">)
		obj = simplejson.loads(data)
		obj = obj[</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"items"</span><span style="background-color:#ffffff;">]
		self.response.content_type = </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"application/json"
</span><span style="background-color:#ffffff;">		simplejson.dump(obj, self.response.out)

</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">def</span><span style="background-color:#ffffff;"> main():
  application = webapp.WSGIApplication([(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">'/mirror'</span><span style="background-color:#ffffff;">, MirrorPipesWebService)],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)

</span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">if</span><span style="background-color:#ffffff;"> __name__ == </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"__main__"</span><span style="background-color:#ffffff;">:
  main()</span></pre>
<p>Now you should have a directory structure that looks a lot like this:</p>
<pre>-rw-r--r--@ 1 sam  sam  106 Apr 13 18:55 app.yaml
-rw-r--r--  1 sam  sam  559 Apr 13 19:28 pipes.py
lrwxr-xr-x  1 sam  sam   47 Apr 13 17:40 simplejson -&gt; /Users/sam/Software/simplejson-1.8.1/simplejson</pre>
<p>Now that we have all the pieces we can deploy the application to GAE with a simple command from the GAE SDK:</p>
<pre>appcfg.py update .</pre>
<p>At this point you should be able to replace my <a href="http://javarants.appspot.com/mirror">web service URL</a> that you find in my example Pipe with your application URL which will be
<pre>http://[application name].appspot.com/mirror</pre>
<p> and get the same results as mine.</p>
<p>What kind of uses can you put this great power?  I currently have a web service that I run that combines RSS entries from the same day into a single entry and have it deployed on my own server.  I will likely port that to GAE as it doesn&#8217;t require a lot of CPU and it is a pain having to administer it.  In fact, most of the functionality that you see in a service like <a href="http://feedburner.com">FeedBurner</a> would be easy to build on top of this framework.  More exotic use cases can be found on Y! Pipes itself where at least one person uses web services to pass in <a href="http://pipes.yahoo.com/pipes/pipe.info?_id=qKDcUk1r3BGBg4HtODY80A">photo URLs and return the coordinates of human faces</a> in the images.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2008/04/13/using-google-app-engine-to-extend-yahoo-pipes/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Using the Yahoo! Mail SOAP API 1.1 from Java&#8217;s JAX-WS 2.1</title>
		<link>http://www.javarants.com/2007/08/31/using-the-yahoo-mail-soap-api-1-1-from-java-s-jax-ws-2-1/</link>
		<comments>http://www.javarants.com/2007/08/31/using-the-yahoo-mail-soap-api-1-1-from-java-s-jax-ws-2-1/#comments</comments>
		<pubDate>Fri, 31 Aug 2007 13:22:39 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[yahoo]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=966</guid>
		<description><![CDATA[Using the Yahoo! Mail SOAP API 1.1 from Java's JAX-WS 2.1 ]]></description>
			<content:encoded><![CDATA[<div><span style="font-family: Helvetica;">On <a href="http://developer.yahoo.com/">YDN</a> they have samples and documentation on how to use the <a href="http://developer.yahoo.com/mail/docs/html/index.html">Yahoo! Mail SOAP API</a> from <a href="http://ws.apache.org/axis2/">Axis2</a>.  I&#8217;m not a big fan of that method so I went ahead and used <a href="https://jax-ws.dev.java.net/">JAX-WS</a> to do my dirty work.  As an example, I will build an <a href="http://javarants.com/rssmail/">RSS feed of the users unread messages</a>.</span></div>
<div><span style="font-family: Helvetica;">First get <a href="https://jax-ws.dev.java.net/2.1.2rc1/">JAX-WS 2.1.x</a> or possibly just JDK 1.6 (though I did all my testing with the former and JDK 1.5). Since its easiest to work with typed APIs we are first going to generate the classes needed to talk to the the Yahoo! Mail web service.  From their site, we find that the latest <a href="http://mail.yahooapis.com/ws/mail/v1.1/wsdl">WSDL</a> URL.  To generate the API from the WSDL we use the &#8216;wsimport&#8217; command from JAX-WS like this:</span></p>
<p><span style="font-family: CourierNewPSMT;">wsimport.sh -extension -s src -p com.yahoo.mail http://mail.yahooapis.com/ws/mail/v1.1/wsdl</span></p>
<p><span style="font-family: Helvetica;">The key command line option there is the &#8216;-extension&#8217; option as the Yahoo! Mail WSDL has a few things that by default would get named the same thing by the schema compiler.  By using Sun&#8217;s extensions we can automatically rename them rather than making our own binding.  This will generate 120+ classes representing each part of the complex API along with some special classes like </span><span style="font-family: CourierNewPSMT;">ObjectFactory</span><span style="font-family: Helvetica;">.  This gives us the foundation for accessing Y! Mail but there are still a few quirks that we need to understand.  Normally when you use JAX-WS you would simply access the web service using the main </span><span style="font-family: CourierNewPSMT;">Ymws</span><span style="font-family: Helvetica;"> class that was generated like this:</span></p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">             </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Instantiate the SOAP proxy
 </span><span style="background-color:#ffffff;">            Ymws service = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> Ymws();
             YmwsPortType stub = service.getYmws();</span></pre>
<p><span style="font-family: Helvetica;">Then you would be able to make calls on that stub directly like this:</span></p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">            UserData userData = stub.getUserData();</span></pre>
<p><span style="font-family: Helvetica;">You&#8217;d find though if you tried to do this that you would not be authenticated with the service nor would there be anyway to select what user for which you are making this call.  Yahoo! Mail&#8217;s web services have their own authentication scheme that is built on Yahoo&#8217;s <a href="http://developer.yahoo.com/auth/">BBAuth</a> &#8212; a 3rd party authentication system.  In order to make use of BBAuth you will need to <a href="https://developer.yahoo.com/wsregapp/index.php">register your application</a> with Yahoo. Make sure that you use a publicly available URL for your application and also select the third option at the bottom: &#8220;Yahoo! Mail (via BBAuth) with Read/Write access&#8221; so that you will be able to use this application ID to access the Y! Mail API.  Once you have registered you will be asked to authenticate your URL by placing a special file at the root of the domain of your URL.  This means you needs write access to the root of the web server so don&#8217;t attempt this on a domain that you don&#8217;t control in that way.  After this is complete you continue to the success page where it provides you with your </span><span style="font-family: Helvetica-Bold;"><strong>application ID</strong></span><span style="font-family: Helvetica;"> (</span><span style="font-family: Helvetica-Bold;"><strong>appid</strong></span><span style="font-family: Helvetica;">) and your </span><span style="font-family: Helvetica-Bold;"><strong>shared secret</strong></span><span style="font-family: Helvetica;"> (</span><span style="font-family: Helvetica-Bold;"><strong>secret</strong></span><span style="font-family: Helvetica;">). These will be required for you to access the Y! Mail APIs on behalf of Y! users.</span></p>
<p><span style="font-family: Helvetica;">The core of the way BBAuth works is for you to redirect to their server when you want to authenticate a user and then they send back the token that is required to access Y! as that user to the registered application URL.  Here is the code that we can use to generate the URL required to get authenticated:</span></p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">             </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">long</span><span style="background-color:#ffffff;"> ts = date.getTime() / </span><span style="color:#0000ff;background-color:#ffffff;">1000</span><span style="background-color:#ffffff;">;
             String uri;
             uri = </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"/WSLogin/V1/wslogin?send_userhash=1&amp;appid="</span><span style="background-color:#ffffff;"> + URLEncoder.</span><span style="background-color:#ffffff;font-style:italic;">encode(</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">appid,</span><span style="background-color:#ffffff;"> </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"UTF-8"</span><span style="background-color:#ffffff;">) + </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"&amp;ts="</span><span style="background-color:#ffffff;"> + ts;
             MessageDigest md;
             md = MessageDigest.</span><span style="background-color:#ffffff;font-style:italic;">getInstance(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"md5"</span><span style="background-color:#ffffff;">);
             String sig = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> BigInteger(</span><span style="color:#0000ff;background-color:#ffffff;">1</span><span style="background-color:#ffffff;">, md.digest((uri + </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">secret)</span><span style="background-color:#ffffff;">.getBytes())).toString(</span><span style="color:#0000ff;background-color:#ffffff;">16</span><span style="background-color:#ffffff;">);</span>
             <span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">LOGIN_URL </span><span style="background-color:#ffffff;">+ uri + </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"&amp;sig="</span><span style="background-color:#ffffff;"> + sig;</span></pre>
<p><span style="font-family: Helvetica;">Essentially this code creates a URI with our </span><span style="font-family: Helvetica-Bold;"><strong>appid</strong></span><span style="font-family: Helvetica;"> and signs it with the </span><span style="font-family: Helvetica-Bold;"><strong>secret</strong></span><span style="font-family: Helvetica;"> which is then used to create a URL that includes the signature.  This ensures that only someone with the </span><span style="font-family: Helvetica-Bold;"><strong>secret</strong></span><span style="font-family: Helvetica;"> can work on behalf of the application that we registered.  Once the user is authenticated you will receive a callback at the registered URL that includes the information passed here plus a </span><span style="font-family: Helvetica-Bold;"><strong>token</strong></span><span style="font-family: Helvetica;"> that can be used to retrieve a WSSID and cookie that can then be used to construct authenticated web service requests.  There is an additional login URL parameter that you can pass called </span><span style="font-family: Helvetica-Bold;"><strong>appdata </strong></span><span style="font-family: Helvetica;">that will be returned to you when Y! redirects the user back to your application.  The </span><span style="font-family: Helvetica-Bold;"><strong>token</strong></span><span style="font-family: Helvetica;"> that is returned is generally good for 2 weeks of authenticated access.  The </span><span style="font-family: Helvetica-Bold;"><strong>send_userhash=1</strong></span><span style="font-family: Helvetica;"> option tells Yahoo to return to us a unique identifier tied to your application id that will always be the same so you can use it to tie back to a particular user in your application.</span></p>
<p><span style="font-family: Helvetica;">Now that we have gotten the token back from Yahoo we can get our WSSID and Cookie.  Included with the Yahoo! Mail sample code they have an inner class called BrowserBasedAuthManager.  We&#8217;ll just use that rather than rewrite it but basically it does  something similar to the code above and retrieves the two values from an XML document returned from a URL:</span></p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">             </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Instantiate the auth manager and set it up with the date, application ID,
 </span><span style="background-color:#ffffff;">            </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// shared secret and the user token.
 </span><span style="background-color:#ffffff;">            BrowserBasedAuthManager authManager = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> BrowserBasedAuthManager(date, </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">appid,</span><span style="background-color:#ffffff;"> </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">secret,</span><span style="background-color:#ffffff;"> token);</span></pre>
<p><span style="font-family: Helvetica;">These two values, </span><span style="font-family: Helvetica-Bold;"><strong>wssid</strong></span><span style="font-family: Helvetica;"> and </span><span style="font-family: Helvetica-Bold;"><strong>cookie</strong></span><span style="font-family: Helvetica;">, are then needed to construct our web service requests.  JAX-WS doesn&#8217;t expose this functionality directly in the API but instead allows you to set various properties on the request context:</span></p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">         Map&lt;String, Object&gt; requestContext = ((BindingProvider) stub).getRequestContext();
         requestContext.put(BindingProvider.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">ENDPOINT_ADDRESS_PROPERTY,
 </span><span style="background-color:#ffffff;">                </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"http://mail.yahooapis.com/ws/mail/v1.1/soap?appid="</span><span style="background-color:#ffffff;"> +
                         URLEncoder.</span><span style="background-color:#ffffff;font-style:italic;">encode(</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">appid,</span><span style="background-color:#ffffff;"> </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"UTF-8"</span><span style="background-color:#ffffff;">) + </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"&amp;wssid="</span><span style="background-color:#ffffff;"> +
                         URLEncoder.</span><span style="background-color:#ffffff;font-style:italic;">encode(</span><span style="background-color:#ffffff;">authManager.getWssid(), </span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"UTF-8"</span><span style="background-color:#ffffff;">));
         Map&lt;String, List&lt;String&gt;&gt; cookies = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> HashMap&lt;String, List&lt;String&gt;&gt;();
         cookies.put(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"Cookie"</span><span style="background-color:#ffffff;">, Arrays.</span><span style="background-color:#ffffff;font-style:italic;">asList(</span><span style="background-color:#ffffff;">authManager.getCookie()));
         requestContext.put(MessageContext.</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">HTTP_REQUEST_HEADERS,</span><span style="background-color:#ffffff;"> cookies);</span></pre>
<p><span style="font-family: Helvetica;">The first property allows us to change the actual endpoint of the web service call to include the WSSID that we got from our authentication request.  The second call allows us to set cookies on the HTTP request that is used to make the specific call.  Together these will give us the access we need in order to use the stub securely.  Actually making use of the API is quite easy now that we are authenticated.  For instance, we can trivially discover whether or not the user is a <a href="http://www.jdoqocy.com/nt83uoxuowBEHKJJLIBDCGILJLG">Y! Mail Plus subscriber</a> and has access to the <a href="http://developer.yahoo.com/mail/account_types.html">full API functionality</a> (non-premium users can&#8217;t get the contents of messages for instance):</span></p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">         UserData userData = stub.getUserData();
         </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">boolean</span><span style="background-color:#ffffff;"> isPremium = userData.getUserFeaturePref().isIsPremium() </span></pre>
<p><span style="font-family: Helvetica;">Here is the code to pull all the unread messages from a folder:</span></p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">         </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// List out up to 100 new messages in the folder
</span><span style="background-color:#ffffff;">         ListMessages lm = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> ListMessages();
         Flag flag = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> Flag();
         flag.setIsRead(</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">FALSE)</span><span style="background-color:#ffffff;">;
         lm.setFilterBy(</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">of.</span><span style="background-color:#ffffff;">createListMessagesFilterBy(flag));
         lm.setFid(folder.getFid());
         lm.setNumInfo(BigInteger.</span><span style="background-color:#ffffff;font-style:italic;">valueOf(</span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;font-style:italic;">NUM_MESSAGES)</span><span style="background-color:#ffffff;">);
         ListMessagesResponse lmResp = stub.listMessages(lm);
         </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">return</span><span style="background-color:#ffffff;"> lmResp.getMessageInfo();</span></pre>
<p><span style="font-family: Helvetica;">Notice how we use the </span><span style="font-family: CourierNewPSMT;">ObjectFactory</span><span style="font-family: Helvetica;"> to create the </span><span style="font-family: CourierNewPSMT;">filterBy</span><span style="font-family: Helvetica;"> element.  Whenever you see a reference like </span><span style="font-family: CourierNewPSMT;">JAXBElement&lt;Flag&gt;</span><span style="font-family: Helvetica;"> in the API you will likely want to use one of the convenience APIs within </span><span style="font-family: CourierNewPSMT;">ObjectFactory</span><span style="font-family: Helvetica;"> to create the argument.</span></p>
<p><span style="font-family: Helvetica;">Now lets get to our RSS feed of unread messages example. To create our RSS feeds we could have just written out the feed directly but instead I&#8217;m going to use <a href="https://rome.dev.java.net/">ROME</a> as we might want to extend the example to a real application later.  ROME has one dependency, <a href="http://www.jdom.org/">JDOM-1.0</a> so we will have to get that as well.  We can encapsulate the application into a single servlet that serves both the authentication feed and the mail feed.  Here is the core servlet method:</span></p>
<pre style="line-height: 100%;font-family:monospace;background-color:#ffffff; border-width:0.01mm; border-color:#000000; border-style:solid; padding:4px;"><span style="background-color:#ffffff;">        </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">try</span><span style="background-color:#ffffff;"> {
             String token = httpServletRequest.getParameter(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"token"</span><span style="background-color:#ffffff;">);</span>
             <span style="color:#000080;background-color:#ffffff;font-weight:bold;">if</span><span style="background-color:#ffffff;"> (token == </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">) {
                 </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// If there is no token we are not authenticated
 </span><span style="background-color:#ffffff;">                </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">throw</span><span style="background-color:#ffffff;"> </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> AuthException(</span><span style="color:#008000;background-color:#ffffff;font-weight:bold;">"No token"</span><span style="background-color:#ffffff;">);
             }
             </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Current date, needed for many API calls
 </span><span style="background-color:#ffffff;">            Date date = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> Date();
             </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Instantiate the SOAP proxy
 </span><span style="background-color:#ffffff;">            Ymws service = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> Ymws();
             YmwsPortType stub = service.getYmws();
             </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Instantiate the auth manager and set it up with the date, application ID,
 </span><span style="background-color:#ffffff;">            </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// shared secret and the user token.
 </span><span style="background-color:#ffffff;">            BrowserBasedAuthManager authManager = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> BrowserBasedAuthManager(date, </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">appid,</span><span style="background-color:#ffffff;"> </span><span style="color:#660e7a;background-color:#ffffff;font-weight:bold;">secret,</span><span style="background-color:#ffffff;"> token);
             </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Set up the web service call
 </span><span style="background-color:#ffffff;">            setupWebServiceCall(authManager, stub);
              </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Create the feed
 </span><span style="background-color:#ffffff;">            SyndFeed sf = createFeed(date);
             </span><span style="color:#808080;background-color:#ffffff;font-style:italic;">// Go and get the list of folders and pull out the inbox
 </span><span style="background-color:#ffffff;">            Fid inbox = getInbox(stub);</span>
             <span style="color:#000080;background-color:#ffffff;font-weight:bold;">if</span><span style="background-color:#ffffff;"> (inbox != </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">null</span><span style="background-color:#ffffff;">) {
                 List&lt;MessageInfo&gt; messages = listUnreadMessagesInFolder(stub, inbox);
                 List&lt;SyndEntry&gt; entries = </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">new</span><span style="background-color:#ffffff;"> ArrayList&lt;SyndEntry&gt;();
                 </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">for</span><span style="background-color:#ffffff;"> (MessageInfo message : messages) {
                     SyndEntry se = createEntry(message);
                     entries.add(se);
                 }
                 sf.setEntries(entries);
             }
             writeFeed(httpServletResponse, sf);
         } </span><span style="color:#000080;background-color:#ffffff;font-weight:bold;">catch</span><span style="background-color:#ffffff;"> (AuthException e) {
             unauthorizedFeedResponse(httpServletResponse);
         } </span></pre>
<p><span style="font-family: Helvetica;">This code should be fairly self-explantory and it builds on all the work that we have done so far.  The only new things are the actual calls into the Y! Mail API that retrieve the messages from Y! Mail, converts them into an RSS 2.0 feed, and writes that feed to the wire. There are a couple of issues with this code that we don&#8217;t address, like generating a permanent URL for the user to use.  Right now whenever their authentication is reset (at least every 2 weeks) they will have to get a new feed URL from the application.</span></p>
<p><span style="font-family: Helvetica;">Throughout these simple examples there are opportunities for optimization.  Many of the pieces of data can be cached for some amount of time and regenerated later like the token, the wssid and the cookie when the user fails to authenticate.  The user hash can, of course, be used forever as a unique identifier for the user.  Other opportunities for optimization include the ability to multiply dispatch requests to the API using </span><span style="font-family: CourierNewPSMT;">batchExecute</span><span style="font-family: Helvetica;">.  Our example is an unoptimized version so that you can see how everything works before its made more complicated through the optimization process. </span></p>
<p><span style="font-family: Helvetica;">Here is a link to the <a href="http://buildandtest.com/files/rssmail.war">full application</a>, the source code is under WEB-INF/src.  You will need to configure the web.xml with your own </span><span style="font-family: Helvetica-Bold;"><strong>appid</strong></span><span style="font-family: Helvetica;"> and </span><span style="font-family: Helvetica-Bold;"><strong>secret</strong></span><span style="font-family: Helvetica;"> but otherwise it should run in a standard JEE Servlet 2.4 container out of the box.</span></div>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2007/08/31/using-the-yahoo-mail-soap-api-1-1-from-java-s-jax-ws-2-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Versus: Argue why Foo is better than Bar</title>
		<link>http://www.javarants.com/2007/08/17/versus-argue-why-foo-is-better-than-bar/</link>
		<comments>http://www.javarants.com/2007/08/17/versus-argue-why-foo-is-better-than-bar/#comments</comments>
		<pubDate>Fri, 17 Aug 2007 11:37:53 +0000</pubDate>
		<dc:creator>Sam Pullara</dc:creator>
				<category><![CDATA[yahoo]]></category>

		<guid isPermaLink="false">http://www.javarants.com/?p=967</guid>
		<description><![CDATA[Versus: Argue why Foo is better than Bar ]]></description>
			<content:encoded><![CDATA[<div><font face="Helvetica"><a href="http://versus.bix.yahoo.com">Versus</a> is a research project by some <a href="http://bix.yahoo.com">Bix</a> developers (my friend <a href="http://johndbeatty.com/">John Beatty</a>  is one of them) at <a href="http://yahoo.com">Yahoo</a> that is trying to aggregate the arguments for choosing between two or more competitive offerings.</font></div>
<p> 
<div><font face="Helvetica">It was just released near the beginning of the month and is building momentum but there are already very good comparisons with many arguments on both sides:</font></p>
<p><font face="Helvetica"><a href="http://versus.bix.yahoo.com/vs/MySQL-vs-PostgreSQL">MySQL vs PostgreSQL</a></font><br /><font face="Helvetica"><a href="http://versus.bix.yahoo.com/vs/Static_typing-vs-Duck_typing">Static typing vs Duck typing</a> </font><br /><font face="Helvetica"><a href="http://versus.bix.yahoo.com/vs/Squeezebox-vs-AirTunes">Squeezebox vs AirTunes</a></font><br /><font face="Helvetica"><a href="http://versus.bix.yahoo.com/vs/Yelp-vs-Zagat">Yelp vs Zagat</a></font></p>
<p><font face="Helvetica">The other cool thing about it is that anyone can add new arguments, people can vote for arguments on both sides, there are comments associated with each argument, and anyone can introduce a new competition.  With luck Versus will become the place to settle arguments of all kinds!</font></div>
]]></content:encoded>
			<wfw:commentRss>http://www.javarants.com/2007/08/17/versus-argue-why-foo-is-better-than-bar/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
