<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7400362863068587019</id><updated>2012-02-22T08:55:47.811Z</updated><title type='text'>Adventures in Web Development</title><subtitle type='html'>A blog about this summers adventures in web development.  This year I'll be looking more at RESTfull interfaces, MVC and the Cassandra NOSQL database.

Serverside  I'll be using JAVA and on the client jquery.   I may even venture into iPad development, but only  a little</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>31</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-5608304097563474349</id><published>2011-06-14T15:00:00.004+01:00</published><updated>2011-06-17T14:34:57.018+01:00</updated><title type='text'>Generate rails from a ERD ?</title><content type='html'>This isn't much of a blog post, it's a question ! &amp;nbsp;I love ERDs (Entity Relationship Diagrams) &amp;nbsp;for database design and have been known to produce them before the database or the code . &amp;nbsp;Recently I've been doing a lot of work in Ruby on Rails which generates the database and model code for you, hiding the database under a ORM layer. &amp;nbsp;This is all very well and good &amp;nbsp;but you can see my problem. &amp;nbsp;No longer can I build &amp;nbsp;a ERD, check it's normalisation &amp;nbsp;nd&amp;nbsp;optimise&amp;nbsp;it with a bit of de-normalisation.&lt;br /&gt;
&lt;br /&gt;
So, the question is:&lt;br /&gt;
&lt;br /&gt;
Is there a tool out there that will take a ERD and generate the rails commands to build a app from the ERD. &amp;nbsp;I mean create the models and generate the migrations at least &amp;nbsp;?&lt;br /&gt;
&lt;br /&gt;
Suppose you had an ERD like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-UoOnH2Ojp10/TftV4I6GHoI/AAAAAAAAABs/6eoZVMM8xqo/s1600/test2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="94" src="http://3.bp.blogspot.com/-UoOnH2Ojp10/TftV4I6GHoI/AAAAAAAAABs/6eoZVMM8xqo/s320/test2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;When I want to generate rails this would do something like the following&lt;br /&gt;
&lt;br /&gt;
rails generate scaffold Person name:string&lt;br /&gt;
rails generate scaffold Town name:string&amp;lt;&lt;br /&gt;
rake db:migrate&lt;br /&gt;
&lt;br /&gt;
It would then go in and alter the model for Person to set up the relationship to town.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Answers on a postcard !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-5608304097563474349?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/5608304097563474349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/06/generate-rails-from-erd.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5608304097563474349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5608304097563474349'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/06/generate-rails-from-erd.html' title='Generate rails from a ERD ?'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-UoOnH2Ojp10/TftV4I6GHoI/AAAAAAAAABs/6eoZVMM8xqo/s72-c/test2.png' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-5111051840015975687</id><published>2011-05-25T19:41:00.001+01:00</published><updated>2011-05-25T19:47:42.583+01:00</updated><title type='text'>Setting a home directory link in Rails 3</title><content type='html'>If you need to set up a path to the home directory in Rails 3 &amp;nbsp;you need to change your routes.rb &amp;nbsp;file to create a named path. &amp;nbsp;In your routes.rb file you create the following mapping&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
match '/' =&amp;gt; "home#index", :as =&amp;gt; :home&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;(&lt;/div&gt;&lt;div&gt;this assumes your rails app has been created with&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;rails generate controller home index&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;you can then create a link using linked_to&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&amp;lt;%= link_to "Home", home_path %&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The point here is we've created the named link as "home" &amp;nbsp;but the path is referred to home_path.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-5111051840015975687?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/5111051840015975687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/05/setting-home-directory-in-rails-3.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5111051840015975687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5111051840015975687'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/05/setting-home-directory-in-rails-3.html' title='Setting a home directory link in Rails 3'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-3437773227230616139</id><published>2011-04-20T11:59:00.000+01:00</published><updated>2011-04-20T11:59:36.864+01:00</updated><title type='text'>Fun with the Independent's URL's</title><content type='html'>So:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.malcolmcoles.co.uk/blog/indy-jelly-bean/"&gt;This blog&lt;/a&gt;&amp;nbsp;points out that you can alter URL's at "The Independent" to say anything you wish. &amp;nbsp;For instance @girlgeeks produced this one&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.independent.co.uk/environment/Cameron-destroys-environmental-laws-inUK-26-2270274.html"&gt;http://www.independent.co.uk/environment/Cameron-destroys-environmental-laws-inUK-26-2270274.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
And&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.independent.co.uk/news/business/news/rupert-murdochs-is-a-PROPAGANDA-peddling-bampot-2270217.html"&gt;http://www.independent.co.uk/news/business/news/rupert-murdochs-is-a-PROPAGANDA-peddling-bampot-2270217.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
The question is, will they find their way into google search engine ? Lets wait a day or to and see !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-3437773227230616139?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/3437773227230616139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/04/fun-with-independents-urls.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3437773227230616139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3437773227230616139'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/04/fun-with-independents-urls.html' title='Fun with the Independent&apos;s URL&apos;s'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-8708930836183984971</id><published>2011-04-06T15:01:00.002+01:00</published><updated>2011-04-06T16:16:20.439+01:00</updated><title type='text'>General Advice for commissioning a web service (web site)</title><content type='html'>&lt;span class="Apple-style-span" style="font-size: large;"&gt;Contract&lt;/span&gt;&lt;br /&gt;
Ensure you are clear what you are going to get for the money !  Make a tick list of what will be delivered and produce a Gantt chart to track the progress.  Ask what development methodology the programmers are going to follow, agile or waterfall.  Make sure they explain their methodology so you are clear when you are going to meet with them and how you can track progress.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Browser support&lt;/span&gt;&lt;br /&gt;
Define which Browsers should be supported.  At a very minimum this should include:&lt;br /&gt;
&lt;br /&gt;
I.E9, I.E8&lt;br /&gt;
Firefox 3.6 and 4&lt;br /&gt;
Chrome 9 and 10&lt;br /&gt;
Safari 4&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;HTML version&lt;/span&gt;&lt;br /&gt;
Define the version of HTMl you want,  make sure your website validates correctly to that version.    If you plumb for HTML 5 make sure it displays correctly on the supported browsers.  If you use HTML 5, use roles correctly.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;CSS version&lt;/span&gt;&lt;br /&gt;
Again,  check the supported browsers will support the version of CSS you choice.  If you use CSS3, use only features supported  by all browsers.&lt;br /&gt;
Interface&lt;br /&gt;
&lt;br /&gt;
Ensure the interface is restful.  Ensure return codes are meaningful.  This will help when  you want to  create a mobile verson of the site or create mobile apps that use the site as a service.&lt;br /&gt;
&lt;br /&gt;
A restful interface should help  with jQuery support as well.  Make sure your interface supports returning data as JSON at a the very least and  a RSS feed as an option&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Security&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Escape all input to avoid XSS attacks .  For PHP use htmlentities, all other languages should have something similar&lt;br /&gt;
&lt;br /&gt;
All input and queries to the database should either be Paramatised or better still stored procedures should be used. &lt;br /&gt;
&lt;br /&gt;
Any uploaded content should be limited to known file types.  The content of the file should be verified and the file should be stored outside the webserver directories.    Download should be anonymous so the file system is obscured.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Version Control&lt;/span&gt;&lt;br /&gt;
What version control system will they use.  If they use a public one are they aware of any copyright  problems that it may bring&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Testing&lt;/span&gt;&lt;br /&gt;
How are they going to test the site ?  Do they propose to use unit testing, if so will it be automated ?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-8708930836183984971?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/8708930836183984971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/04/general-advice-for-commissioning-web.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/8708930836183984971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/8708930836183984971'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/04/general-advice-for-commissioning-web.html' title='General Advice for commissioning a web service (web site)'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-3825085740546614879</id><published>2011-03-23T11:27:00.001Z</published><updated>2011-03-23T11:32:33.907Z</updated><title type='text'>Hackday at Dundee</title><content type='html'>I've started wandering around taking pictures of the students in acton as they near the start of Dundeeuhack 2011.  The demos will take place on Friday afternoon in the QMB street area.  Looking forward to seeing what everyone does.  The current list of projects is here:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://hackday.computing.dundee.ac.uk:8080/allhacks.jsp?Year=2011"&gt;http://hackday.computing.dundee.ac.uk:8080/allhacks.jsp?Year=2011&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Pictures as they arrive, &lt;br /&gt;
&lt;br /&gt;
&lt;!-- Start of Flickr Badge --&gt;&lt;br /&gt;
&lt;style type="text/css"&gt;
#flickr_badge_source_txt {padding:0; font: 11px Arial, Helvetica, Sans serif; color:#666666;}
#flickr_badge_icon {display:block !important; margin:0 !important; border: 1px solid rgb(0, 0, 0) !important;}
#flickr_icon_td {padding:0 5px 0 0 !important;}
.flickr_badge_image {text-align:center !important;}
.flickr_badge_image img {border: 1px solid black !important;}
#flickr_badge_uber_wrapper {width:150px;}
#flickr_www {display:block; text-align:center; padding:0 10px 0 10px !important; font: 11px Arial, Helvetica, Sans serif !important; color:#3993ff !important;}
#flickr_badge_uber_wrapper a:hover,
#flickr_badge_uber_wrapper a:link,
#flickr_badge_uber_wrapper a:active,
#flickr_badge_uber_wrapper a:visited {text-decoration:none !important; background:inherit !important;color:#3993ff;}
#flickr_badge_wrapper {background-color:#ffffff;border: solid 1px #000000}
#flickr_badge_source {padding:0 !important; font: 11px Arial, Helvetica, Sans serif !important; color:#666666 !important;}
&lt;/style&gt;&lt;br /&gt;
&lt;table id="flickr_badge_uber_wrapper" cellpadding="0" cellspacing="10" border="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://www.flickr.com" id="flickr_www"&gt;www.&lt;strong style="color:#3993ff"&gt;flick&lt;span style="color:#ff1c92"&gt;r&lt;/span&gt;&lt;/strong&gt;.com&lt;/a&gt;&lt;table cellpadding="0" cellspacing="10" border="0" id="flickr_badge_wrapper"&gt;&lt;script type="text/javascript" src="http://www.flickr.com/badge_code_v2.gne?show_name=1&amp;count=5&amp;display=latest&amp;size=m&amp;layout=v&amp;source=user_tag&amp;user=7507524%40N03&amp;tag=uhackdundee11"&gt;&lt;/script&gt;
&lt;tr&gt; &lt;td id="flickr_badge_source" valign="center" align="center"&gt;&lt;br /&gt;
&lt;table cellpadding="0" cellspacing="0" border="0"&gt;&lt;tr&gt; &lt;td width="10" id="flickr_icon_td"&gt;&lt;a href="http://www.flickr.com/photos/7507524@N03/tags/uhackdundee11/"&gt;&lt;img id="flickr_badge_icon" alt="acobley's items tagged with uhackdundee11" src="http://farm3.static.flickr.com/2077/buddyicons/7507524@N03.jpg?1193763253#7507524@N03" align="left" width="48" height="48"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td id="flickr_badge_source_txt"&gt;&lt;nobr&gt;More of&lt;/nobr&gt; &lt;a href="http://www.flickr.com/photos/7507524@N03/tags/uhackdundee11/"&gt;acobley's stuff tagged with uhackdundee11&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;/table&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;!-- End of Flickr Badge --&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-3825085740546614879?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/3825085740546614879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/03/hackday-at-dundee.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3825085740546614879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3825085740546614879'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/03/hackday-at-dundee.html' title='Hackday at Dundee'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-3185957791911417623</id><published>2011-03-11T08:24:00.007Z</published><updated>2011-03-15T18:06:07.328Z</updated><title type='text'>So you think you own your twitter name ?</title><content type='html'>&lt;b&gt;Update Tuesday 15th March&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
An interview with @girlgeeks with the full story is available here: &lt;a href="http://mailright.co.uk/email-marketing-articles/How-safe-is-your-Twitter-name/"&gt;How-safe-is-your-Twitter-name/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;hr&gt;&lt;br /&gt;
&lt;b&gt;Update Sunday 13th March&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I believe this matter has now been resolved and the girlgeeks name will go back to the original owner.  Thanks for all the support.&lt;br /&gt;
&lt;br /&gt;
&lt;hr&gt;&lt;br /&gt;
So you think you own your twitter name ?&lt;br /&gt;
&lt;br /&gt;
Chances are you don’t, chances are you could have it taken away from you at any moment or  have it changed  by twitter adding an underscore to it.   So what does it matter, it’s only a twiter account after all.    Wrong, your twitter account can be your main online presence, your main identity that people know you by and your main contact.  &lt;br /&gt;
&lt;br /&gt;
Suppose you’ve spent 2 years building an international reputation, have thousands of follower, some of own are leaders in their fields, some of who are close friends.  Overnight their contact books are out of date, overnight their DM messages no longer go to you but some third party, overnight any archived Follow Friday tags #FF are out of date,  overnight your on line  reputation has gone.  And worse, think how many resources you will need to update, business cards, linkedin, Skype and thats not to mention your presence in search engines.  Can’t happen here ?  It can and it has.&lt;br /&gt;
&lt;br /&gt;
It happened to a close friend of mine last night.  She spent over two years building the @girlgeeks account,  spreading  words of Girl Geek Scotland to over 26 countries.  Last night an organsation called @GIRLGEEKS contacted Twitter to say they had registered trademark for Girl Geeks  and wanted the @girlgeeks account for themselves.  This organisation only stated a couple of months ago and yet compared to the prior reputation of  @girlgeeks this meant nothing, Twitter took the account and handed it to them on a plate.   To make matters worse, twitter sent    message to the original owner to say they where going to change their twitter name, there was no chance to respond, to argue or to appeal.  They just change your name and then tell you afterwards.  Oh, and they ask you to make it clear on your that your account is not associated with the brand.  &lt;br /&gt;
&lt;br /&gt;
As the previous owner of  @girlgeeks says:&lt;br /&gt;
&lt;br /&gt;
“The message from Twitter is get an International TM for your name or they'll take it for a private ltd company”.&lt;br /&gt;
&lt;br /&gt;
Just to make the effect clear, here's what happes if you do a search for girlgeeks on google:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-WE7bVAt_9eY/TXoLRiYpN0I/AAAAAAAAABc/yPHTvlrgRM8/s1600/gg-Google.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="130" src="http://4.bp.blogspot.com/-WE7bVAt_9eY/TXoLRiYpN0I/AAAAAAAAABc/yPHTvlrgRM8/s320/gg-Google.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Clearly pointing to the old account, we'd expect to see the good work girlgeeks has been doing.  if we click on we get:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-khEnIed4bfE/TXoLcqEU6fI/AAAAAAAAABk/Jte8vtUxxz4/s1600/gg-Twitter.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="155" src="http://3.bp.blogspot.com/-khEnIed4bfE/TXoLcqEU6fI/AAAAAAAAABk/Jte8vtUxxz4/s320/gg-Twitter.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Not what expected and very damaging to the original owner to the original owner of the twitter account.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is clear case of  #copywrong, its heavy handed and I suspect that Twitter have no clear idea of the damage they have done.   The message is clear, you don’t own your twitter account, Twitter does.&lt;br /&gt;
&lt;br /&gt;
There is an official responce from the other side here &lt;a href="http://is.gd/wZZW4g"&gt;PDF&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-3185957791911417623?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/3185957791911417623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/03/so-you-think-you-own-your-twitter-name.html#comment-form' title='74 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3185957791911417623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3185957791911417623'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/03/so-you-think-you-own-your-twitter-name.html' title='So you think you own your twitter name ?'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-WE7bVAt_9eY/TXoLRiYpN0I/AAAAAAAAABc/yPHTvlrgRM8/s72-c/gg-Google.png' height='72' width='72'/><thr:total>74</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-6084859633073719170</id><published>2011-02-21T10:51:00.001Z</published><updated>2011-02-21T10:54:07.649Z</updated><title type='text'>Cassandra’s data model as records and lists</title><content type='html'>I have to admit I’ve never really been happy with Cassandra’s data model, or to be more precisely, I’ve never really been with my understanding of the model.  However I’ve realized that if we think of two use cases for column families then things may  become a bit clearer.  For me, Column families can be used in one of two ways,  either as a record or an ordered list.   &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Columns used as a record&lt;/b&gt;&lt;br /&gt;
If we place name value pairs under the column key that contain different attributes then we can consider the columns as classic database record.   So if we are wanting to store the details of a user then the columns might be:&lt;br /&gt;
&lt;br /&gt;
Name (key)&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Email: user@example.com&lt;/li&gt;
&lt;li&gt;Twiter: TwitterUser&lt;/li&gt;
&lt;li&gt;Phone: 01 000 345678&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
In this schema the order of the columns is not important because the names are not related.  However unlike a relational database, there is no definition of  the “fields” in the record, we define them at runtime in the application.    This does give us the flexibility to add new fields providing our application can handle missing “fields”. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Columns used as a List&lt;/b&gt;&lt;br /&gt;
If each of the name value pairs are the same attributes then we can consider this as an ordered list .  In this use case the ordering of the columns is important and the ordering type needs to be carefully thought out.   For example if we want to store messages from a user, and we want to be able to get the most recent, then we will store them as:&lt;br /&gt;
&lt;br /&gt;
Author (key)&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Timeuuid: Message&lt;/li&gt;
&lt;li&gt;Timeuuid: Message&lt;/li&gt;
&lt;li&gt;Timeuuid: Message&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
This ordered list can be thought of as an index of records.  The records would be stored in another column family.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Supercolumns as a list of records &lt;/b&gt;&lt;br /&gt;
Even better, we can use supercolumns to create a combination of lists and records.  Normally we would make the supercolumns the ordered list and   the columns the record.  In our messaging system, we want to get the latest messages from a user:&lt;br /&gt;
&lt;br /&gt;
Author (Key)&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Timeuuid: (Supercolumn name)&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Message: Message Text&lt;/li&gt;
&lt;li&gt;Time: Time of message&lt;/li&gt;
&lt;li&gt;Picture: Binary picture data&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;Timeuuid: (Supercolumn name)&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Message: Message Text&lt;/li&gt;
&lt;li&gt;Time: Time of message&lt;/li&gt;
&lt;li&gt;Picture: Binary picture data&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;
The supercolumns are ordered by time, the columns under it are not ordered.&lt;br /&gt;
&lt;br /&gt;
As ever I look forward to comments about this post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-6084859633073719170?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/6084859633073719170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/02/cassandras-data-model-as-records-and.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/6084859633073719170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/6084859633073719170'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/02/cassandras-data-model-as-records-and.html' title='Cassandra’s data model as records and lists'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-8592313288348567522</id><published>2011-02-16T13:32:00.004Z</published><updated>2011-03-24T10:48:15.195Z</updated><title type='text'>Dundee Hackday 2011  begins.</title><content type='html'>So yesterday we kicked off this years Dundee Hackday  with YDN and Mozilla.  The timetable for this year is:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Tuesday 15th, Video conference with Murray Rowan and Steve Marshall from YDN! and Christian Heilmann from Mozilla&lt;/li&gt;
&lt;li&gt;Wednesday 16th Start to assemble into teams and get your ideas together.&lt;/li&gt;
&lt;li&gt;Tuesday March 1st Post your groups and ideas to &lt;a href="http://hackday.computing.dundee.ac.uk:8080/allhacks.jsp?Year=2011"&gt;Entry form&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;We will will then take a look at your idea and give you feedback.&lt;/li&gt;
&lt;li&gt;Start build your Hack.&lt;/li&gt;
&lt;li&gt;March 25: Show your Hack in the QMB Street to University staff,  Yahoo! developers and Christian Heilmann&lt;/li&gt;
&lt;li&gt;March 25 The Best Hacks are announced, prizes are given. All retire to the student union for a well earned rest!&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Christian Heilmann has published his thoughts on yesterday's video conference &lt;a href="http://www.wait-till-i.com/2011/02/15/introducing-mozilla-technology-and-ideas-to-students-for-a-hack-day/"&gt;Introducing Mozilla technology and ideas to students for a hack day&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TwitterTag #uhackdundee11&lt;br /&gt;
FlickrTag uhackdundee11&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-8592313288348567522?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/8592313288348567522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/02/dundee-hackday-2010-begins.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/8592313288348567522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/8592313288348567522'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/02/dundee-hackday-2010-begins.html' title='Dundee Hackday 2011  begins.'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-4007324070268316837</id><published>2011-01-14T11:54:00.000Z</published><updated>2011-01-14T11:54:55.971Z</updated><title type='text'>IIS and Glassfish together</title><content type='html'>This is really just a note to myself.  However if you want to run IIS and glassfish on the same windows 2008 server it's not enough to config IIS to listen on one IP address.  You need to tell windows that it is responsible for only one of the addresses.  You can do this form the command line:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
netsh http add iplisten ipaddress=xxx.xxx.xxx.xxx&lt;br /&gt;
&lt;br /&gt;
Second Glassfish will need to be configured to listen to only one address. In the config.xml for the domain find the network -listeners and add an address to port 80:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: xml" toolbar: true;&gt;&lt;network-listener port="80" protocol="http-listener-1" address="134.36.36.82" transport="tcp" name="http-listener-1" thread-pool="http-thread-pool"&gt;&lt;/network-listener&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-4007324070268316837?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/4007324070268316837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/01/iis-and-glassfish-together.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/4007324070268316837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/4007324070268316837'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/01/iis-and-glassfish-together.html' title='IIS and Glassfish together'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-5506084514807765324</id><published>2011-01-13T09:18:00.001Z</published><updated>2011-01-13T09:18:39.677Z</updated><title type='text'>Firefox and undefined array elements</title><content type='html'>So here's a Javascript question.  Now I admit I'm not a Javascript expert so this ones got me a bit stumped. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In the following code snippet I'm trying to get a function to do something only when it is&lt;br /&gt;
first called.  It can be called with a number of items (identified by an integer I), it&lt;br /&gt;
should call itself only the first time it is called with that arguement.  I have an array (lsaCall)&lt;br /&gt;
with only the first item defined (and set to 0).  If the array element is undefined (or 0) then the function&lt;br /&gt;
calls itsel on a timer.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;var lsaCall = [0];
function loadSubscribedArticles(i,tag,Author){
 
 //alert("lsaCall "+lsaCall[i]);
 if ((lsaCall[i]==undefined) || (lsaCall[i] ==0)) {
  lsaCall[i]=1;
  //alert("Undefined"+lsaCall[i]);
  var int=self.setInterval("loadSubscribedArticles('"+i+"','"+tag+"','"+Author+"')",1000);
  
 }
}
&lt;/pre&gt;&lt;br /&gt;
This works fine and dandy but doesn't work at all in firefox.  It complains that lsaCall &lt;br /&gt;
is undefined (well I know that !)&lt;br /&gt;
Any ideas on how to get this working in firefox ?  Is there a better way of doing it ?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-5506084514807765324?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/5506084514807765324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2011/01/firefox-and-undefined-array-elements.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5506084514807765324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5506084514807765324'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2011/01/firefox-and-undefined-array-elements.html' title='Firefox and undefined array elements'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-6862580759418544843</id><published>2010-09-17T15:36:00.000+01:00</published><updated>2010-09-17T15:36:19.489+01:00</updated><title type='text'>Moving from version 0.6 of Cassandra to version 0.7</title><content type='html'>In order to use the latest build of  Hector  you need to be running a  cluster based on version 0.7 of Cassandra.  For  me this  gave me some problems.  For a start I’m running my cluster on  windows based machines, and it’s been running fine.  However beta 1 of Cassandra 0.7.0 does not include the necessary tools for windows to convert the config files and read the schema.  &lt;br /&gt;
&lt;br /&gt;
So to get my cluster updated I added a linux box to it and installed a version 0.6.0 of Cassandra and joined the cluster.  I installed 0.7.0 on that  and attempted to use config-convertor  to convert storage-conf.xml to Cassandra.yaml.  For some reason that got in a horrible mess so it was back to the original Cassandra.yaml and import the settings manually.   For my simple configuration this wasn’t a pain.&lt;br /&gt;
&lt;br /&gt;
Once that’s done I upgraded the windows machines to version 0.7.0.&lt;br /&gt;
&lt;br /&gt;
The next step is to run schematool.  Without running this, your cluster will not have any schema’s in the database.  This needs to be done from the linux command line:&lt;br /&gt;
&lt;br /&gt;
schematool  134.36.xx.yyy 8080 import&lt;br /&gt;
&lt;br /&gt;
does the job.&lt;br /&gt;
&lt;br /&gt;
See&lt;a href=" http://www.riptano.com/blog/live-schema-updates-cassandra-07"&gt; http://www.riptano.com/blog/live-schema-updates-cassandra-07&lt;/a&gt; and  &lt;a href="http://wiki.apache.org/cassandra/LiveSchemaUpdates"&gt;http://wiki.apache.org/cassandra/LiveSchemaUpdates&lt;/a&gt; for more details.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-6862580759418544843?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/6862580759418544843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/09/moving-from-version-06-of-cassandra-to.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/6862580759418544843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/6862580759418544843'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/09/moving-from-version-06-of-cassandra-to.html' title='Moving from version 0.6 of Cassandra to version 0.7'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-842664965590114533</id><published>2010-08-20T14:05:00.002+01:00</published><updated>2010-08-20T14:16:02.038+01:00</updated><title type='text'>ConsistencyLevel in Hector and Cassandra</title><content type='html'>I started playing with failover in  Casssandra the other day and rapidly found myself  in a bit of a pickle.  I had a 2 node development environment allowing   me to play with Cassandra and start developing Hector programs.  So I decided to turn one machine off and see if my program would carry on as normal.&lt;br /&gt;
&lt;br /&gt;
It didn’t.  Not much of a failover I thought.    To make matters worse if attached via the Cassandra cli client, I could retrieve data from my single node.  What was going on ?&lt;br /&gt;
&lt;br /&gt;
Turns out this was all to do with the consistency of  my cluster.  Take a look at the consistency section of:&lt;br /&gt;
&lt;br /&gt;
http://wiki.apache.org/cassandra/API&lt;br /&gt;
&lt;br /&gt;
There are multiple levels of consistency available in a Cassandra cluster, and they can be different for read and write operations.    What I hadn’t realized is that Hector defaults to a consistency of QUORUM whereas cli defults to a consistency of ONE (I believe).  So with a two node cluster,  Hector will fail on reads if one goes down.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Adding Nodes&lt;/h3&gt;One way to get round the problem is to add more nodes and up the replication level in the conf files to 4.    I added two notes that where not part of the seeding process and used the Autoboostrap option in he conf file to join the cluster.   This  has kind of solved the problem.  I can  now read from one of the bootstrapped nodes if  any of the other nodes goes down, but not from one  of the seed nodes.  I think more work on the configuration and layout of the cluster is needed by me.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Changing the consistency in Hector&lt;/h3&gt;You can of course change the consistency in Hector.  The code here refers to Hector 0.6.15 and above (for now).  The first thing we need to do is implement a consistencylevelpolicy.      Here’s an example based on the default consistency implementation in Hector&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;import me.prettyprint.cassandra.model.*;
import org.apache.cassandra.thrift.ConsistencyLevel;

public final class MyConsistancyLevel implements ConsistencyLevelPolicy {

@Override
public  ConsistencyLevel get(OperationType op) {
   switch (op){
      case READ:return ConsistencyLevel.QUORUM;
      case WRITE: return ConsistencyLevel.ONE;
      default: return ConsistencyLevel.QUORUM; //Just in Case
   }
}
@Override
public ConsistencyLevel get(OperationType op, String cfName) {
   return ConsistencyLevel.QUORUM;
}
}
&lt;/pre&gt;&lt;br /&gt;
In this example we set the READ consistency to QUORUM and the WRITE consistency to ONE.  (I’ve also included a default consistency just in case !).  Once we’ve got this class we can set the consistency for the keyspace like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;ConsistencyLevelPolicy mcl = new MyConsistancyLevel();
ko.setConsistencyLevelPolicy(mcl);
&lt;/pre&gt;&lt;br /&gt;
And that’s it !&lt;br /&gt;
&lt;br /&gt;
Many thanks to Ran Tavory and Colin Vipurs for their help on this.&lt;br /&gt;
&lt;br /&gt;
As ever comments and so on gratefully received.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-842664965590114533?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/842664965590114533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/consistencylevel-in-hector-and.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/842664965590114533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/842664965590114533'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/consistencylevel-in-hector-and.html' title='ConsistencyLevel in Hector and Cassandra'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-1839703928624924981</id><published>2010-08-18T16:21:00.003+01:00</published><updated>2010-08-19T11:53:21.226+01:00</updated><title type='text'>A brief note about using Clusters in Hector V2 API</title><content type='html'>Recently  Hector, the java library for access to Cassandra dB was updated to version 2.    Now it’s time  to explore moving  jBloggyAppy over to the new API.  In this blog I’m briefly  going to look at Hector V2’s clustering options which greatly improve on version 1.    To create a cluster we use getOrCreateCluster from the Hector Factory (HFactory e.prettyprint.cassandra.model.HFactory.*; )  Ran Tavory recommends importing the static library to reduce typing !:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;import static me.prettyprint.cassandra.model.HFactory.*;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Once we’ve done that we create the cluster &lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;Cluster c = HFactory.getOrCreateCluster("MyCluster", "154.36.xx.yyy:9160");
&lt;/pre&gt;&lt;br /&gt;
And that’s it !  &lt;br /&gt;
&lt;br /&gt;
However, note that we are now connected to only the  machine in the cluster that we have named. we can get a list of all machines in the cluster like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;Set &amp;lt;String&amp;gt;hosts= c.getClusterHosts(true); 
Iterator it =hosts.iterator(); 
while (it.hasNext()) {  
   System.out.println(it.next()); 
} 
&lt;/pre&gt;&lt;br /&gt;
The problem here is that we haven't got the port number of each machine in the cluster, nor do can we find out about the topology.  Thanks to the Hector mail list folks for pointing this out.&lt;br /&gt;
&lt;br /&gt;
If we want to know the clusters name:&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;System.out.println(c.describeClusterName());
&lt;/pre&gt;&lt;br /&gt;
Finally should we want to use the cluster with a V1 pool:&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;CassandraClient client =c.borrowClient();
&lt;/pre&gt;&lt;br /&gt;
and release it in a finally clause:&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;} finally {
   c.releaseClient(client);
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-1839703928624924981?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/1839703928624924981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/brief-note-about-using-clusters-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1839703928624924981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1839703928624924981'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/brief-note-about-using-clusters-in.html' title='A brief note about using Clusters in Hector V2 API'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-3028766505424969440</id><published>2010-08-10T19:57:00.001+01:00</published><updated>2010-08-10T19:58:29.086+01:00</updated><title type='text'>Using Java reflection to render a JSON feed</title><content type='html'>In today’s post we are going to look at a method for rendering JSON output from our java web app.  It’s important to note that what I’m going to show relies on a couple of things:&lt;br /&gt;
&lt;br /&gt;
1: I like to use Java beans to encapsulate data between elements of the MVC model.  If more than one element is needed the beans are added to a list.&lt;br /&gt;
&lt;br /&gt;
2: These beans use standard accessor methods  starting with “get” to access elements private methods.  &lt;br /&gt;
&lt;br /&gt;
3: Our controller, a servlet , adds the beans to the request via by setting a attribute and then forwards to the view (usually a  jsp page) using a requestdispatcher.&lt;br /&gt;
&lt;br /&gt;
If you look at the code at &lt;a href="http://github.com/acobley/jBoggyAppy/tree/master/src/uk/ac/dundee/computing/aec/jBloggyAppy"&gt;github&lt;/a&gt;  you’ll see that we have 4 of these bean stores with different accessor methods and private variables.    And here in lies the problem. We could write a JSON encoder that worked on each bean but that’s going to be duplicating a lot of work.  The answer is to use Java Reflection to “look” into the bean and extract it’s accessor methods.  This will allow us to write one servlet that can process any bean or list of beans and convert it to JSON notation.&lt;br /&gt;
&lt;br /&gt;
For more information on reflection look at  &lt;a href="http://java.sun.com/developer/technicalArticles/ALT/Reflection/"&gt;Java Reflection&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
We will use the JSON library from &lt;a href="http://www.json.org/"&gt;JSON.org&lt;/a&gt; to make life easy.&lt;br /&gt;
&lt;br /&gt;
Our Servlet that will generate the JSON will not know what type of bean is being sent to it, or if it is a list of beans.  So rather than deal with a distint class we just deal with  the Object class.  We can get the beans and test for a list like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;Object temp=request.getAttribute("Data");
Class c = temp.getClass();
String className=c.getName();
if (className.compareTo("java.util.LinkedList")==0){
&lt;/pre&gt;&lt;br /&gt;
If it’s not a linked list we will want to get the Object, find all the methods and call the accessor methods.  Here’s our method for doing this which  returns a JSONObject with only values from the bean that actually have data.  In this example “Value” has been obtained from the request using getAttribute.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;private JSONObject  ProcessObject(Object Value){ //Value has been passed to the servlet
 JSONObject Record=new JSONObject();
  
 try {
            Class c = Value.getClass();
            Method methlist[] = c.getDeclaredMethods();
            for (int i = 0; i &lt; methlist.length; i++) {  
              Method m = methlist[i];
             
              String mName=m.getName();
             
                 if (mName.startsWith("get")==true){
                       String Name=mName.replaceFirst("get", "");
                  Class partypes[] = new Class[0];
                  Method meth = c.getMethod(mName, partypes);
                 
                  Object rt= meth.invoke(Value);
                  if (rt!=null){
                   System.out.println(Name+" Return "+ rt);
                   try{
                    Record.put(Name,rt);
                   }catch (Exception JSONet){
                 System.out.println("JSON Fault"+ JSONet);
                 return null;
                }
               
                  }
                 }
            }
            
            
         }
         catch (Throwable e) {
            System.err.println(e);
         }
         return Record;
 }
&lt;/pre&gt;
Dealing with a linked list of objects is just a case of iterating through the list and calling the above object for each bean we want to encode:

&lt;pre class="brush: java" toolbar: true;&gt;if (className.compareTo("java.util.LinkedList")==0){ //Deal with a linked list
 List Data = (List)request.getAttribute("Data"); 
 Iterator iterator;
 JSONObject JSONObj=new JSONObject();
 JSONArray Parts=new JSONArray();
 iterator = Data.iterator();     
 while (iterator.hasNext()){
  Object Value=iterator.next();
  JSONObject obj =ProcessObject(Value);
  try {
   Parts.put(obj);
  }catch (Exception JSONet){
           System.out.println("JSON Fault"+ JSONet);
          }
 }
 try{
  JSONObj.put("Data",Parts);
 }catch (Exception JSONet){
       System.out.println("JSON Fault"+ JSONet);
      }
 if (JSONObj!=null){
  PrintWriter out = response.getWriter();
  out.print(JSONObj);
 } 
&lt;/pre&gt;Our simple code could be extended.  Although it will deal with simple types stored in beans (strings, ints, longs, dates etc) if your bean stores more complex data (arrays or lists) then handling the reflection will need to be a lot more complicated!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-3028766505424969440?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/3028766505424969440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/in-todays-post-we-are-going-to-look-at.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3028766505424969440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3028766505424969440'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/in-todays-post-we-are-going-to-look-at.html' title='Using Java reflection to render a JSON feed'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-2050546296544085266</id><published>2010-08-09T10:54:00.000+01:00</published><updated>2010-08-09T10:54:12.806+01:00</updated><title type='text'>Hector V2 API announced</title><content type='html'>One of the problems of using  “cutting edge” software is that things are always evolving and occasionally  the work you are doing can get left behind.  This has kinda happened with the code I've been working on,  I’ve been working on &lt;a href="http://github.com/acobley/jBoggyAppy"&gt;http://github.com/acobley/jBoggyAppy&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
I’ve been using &lt;a href="http://prettyprint.me/2010/08/06/hector-api-v2/"&gt;Hector&lt;/a&gt;  as the API between Java and Casssandra, building models to encapsulate  data  stored in the database.  However  Hector has just undergone a major overhaul, upgrading the interface to version 2.  This is great and really to be appreciated,  Ran and the team have  made things easier and moved away from the complexities of &lt;a href="http://wiki.apache.org/cassandra/API"&gt;Thrift&lt;/a&gt; .   &lt;br /&gt;
&lt;br /&gt;
I’ve decided I’ll carry on with the code using  the V1 API and then come back and redo it in V2 later.  This should be relatively easy, I’m keeping all the Hector code in one place (Java Bean Connectors) and with luck I’ll just override the current methods with new V2 methods.  The only changes I may need to make to the controllers are in the dB connection method.  The  V2 api implements clustering (which in it self is a useful step forward) but this may change how my code needs to interact.&lt;br /&gt;
&lt;br /&gt;
I’m looking forward to using V2 once I’ve got comments implemented in my jBloggyAppy code !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-2050546296544085266?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/2050546296544085266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/hector-v2-api-announced.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/2050546296544085266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/2050546296544085266'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/hector-v2-api-announced.html' title='Hector V2 API announced'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-1261923423448190989</id><published>2010-08-09T10:31:00.002+01:00</published><updated>2010-08-09T10:37:59.687+01:00</updated><title type='text'>Converting a long to a byte array and back again</title><content type='html'>One thing that may not be immediately obvious is that Cassandra stores all values as a  byte array.  While this is not really important if your are storing a string (converting to a byte array is relatively easy) what if you need to store a date.  Dates in Java are essentially of type log and represent the number of  milliseconds since 1970 (or there abouts).      If you want to store a date you need to convert it to a byte array and back again when going into and out of the key store.    You could use serialization to achieve this, but as this article:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://java.sun.com/developer/technicalArticles/Programming/serialization/"&gt;http://java.sun.com/developer/technicalArticles/Programming/serialization/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
points out serialization can be a slow process.  So,  here I present two  methods to convert a date to and from  a byte array.  &lt;b&gt;I welcome comments on these, I’m sure they can be speeded up and generally be improved&lt;/b&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Converting to a byte array&lt;/h3&gt;Longs are stored as 8 bytes, so converting them is a case of masking off the bottom byte storing it in the array and then shifting the orignal number right 8 bits.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;private  byte[] longToByteArray(long value)
{
byte[] buffer = new byte[8]; //longs are 8 bytes I believe
for (int i = 7; i &gt;= 0; i--) { //fill from the right
 buffer[i]= (byte)(value &amp; 0x00000000000000ff); //get the bottom byte
     
 //System.out.print(""+Integer.toHexString((int)buffer[i])+",");
 value=value &gt;&gt;&gt; 8; //Shift the value right 8 bits
 }
return buffer;
}
&lt;/pre&gt;&lt;h3&gt;Converting back from a byte array to a long&lt;/h3&gt;&lt;br /&gt;
Converting back the other way we use a multiplier to convert each byte to it’s correct value.  This multiplier is shifted left 8 bits each time round the loop.   &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;private long byteArrayToLong(byte[] buffer){
long value=0;
long multiplier=1;
for (int i = 7; i &gt;= 0; i--) { //get from the right
 //System.out.println(Long.toHexString(multiplier)+"\t"+Integer.toHexString((int)buffer[i]));
 value=value+(buffer[i] &amp; 0xff)*multiplier; // add the value * the hex multiplier
 multiplier=multiplier &lt;&lt;8;
 }
return value;
}
&lt;/pre&gt;
&lt;h3&gt;A simple test case&lt;/h3&gt;The following code shows these examples in use, converting a Date to a byte array and back again maintaining it’s value:

&lt;pre class="brush: java" toolbar: true;&gt;long tempnow = System.currentTimeMillis();
Date tempDate= new Date(tempnow);
System.out.println("now "+tempnow);
System.out.println("Native Date "+tempDate);
        
//Convert to Byte Array and print
byte btempnow[]=longToByteArray(tempnow);
System.out.println();
System.out.print("Byte Array ");
displayByteArrayAsHex(btempnow);
        
//and Convert it back again
long converted =byteArrayToLong(btempnow);
tempDate=new Date(converted);
System.out.println("converted now "+converted);
System.out.println("converted  Date "+tempDate);
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-1261923423448190989?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/1261923423448190989/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/converting-long-to-byte-array-and-back.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1261923423448190989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1261923423448190989'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/converting-long-to-byte-array-and-back.html' title='Converting a long to a byte array and back again'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-4312097815002543945</id><published>2010-08-06T10:29:00.002+01:00</published><updated>2010-08-13T16:17:14.569+01:00</updated><title type='text'>jBloggyAppy on Github</title><content type='html'>I've started work integrating the Cassandra code into an actual app.  All the code will be available on github:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://github.com/acobley/jBoggyAppy"&gt;jBloggyAppy&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
The goal of the exercise is:&lt;br /&gt;
&lt;br /&gt;
1: To write a Cassandra based app in Java&lt;br /&gt;
2: The App should use the MVC programming model&lt;br /&gt;
3: The app should implement a Restful interface&lt;br /&gt;
4: There will be no CSS (this is not a design exercise) and only minimal Javascript for any AJAX calls.&lt;br /&gt;
5: Use OpenID to facilitate logins&lt;br /&gt;
&lt;br /&gt;
The code already deals with creating a new user, listing all users and listing the details for one user.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-4312097815002543945?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/4312097815002543945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/jbloggyappy-on-github.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/4312097815002543945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/4312097815002543945'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/jbloggyappy-on-github.html' title='jBloggyAppy on Github'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-7544870930264553281</id><published>2010-08-04T15:36:00.002+01:00</published><updated>2010-08-04T15:36:32.774+01:00</updated><title type='text'>Reading column name value pairs from a Supercolumn for the BloggyAppy</title><content type='html'>In the last blog post we look at reading from normal column families, in this part we are going to look at reading from supercolumns.   We are still folowing the BloggyAppy design from &lt;a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model"&gt;Arin Sarkissian&lt;/a&gt;.  In this design we have a keyspace called columns.   Each entry has a key (that is the title slug from before).  Each supercoulmn uses a TIMEUID as the key/ name and the details of the comment are stored as columns underneath that.  Here’s the structure:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;
Comments: {
 Blog-Slug:{
  Time_UUID_1:{
   Coment: A Comment,
   Email: andy@abc.com
},
Time_UUID_2:{
   Coment: A Comment,
   Email: andy@abc.com
}
}
}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
The first job is to get the comment keys for a particular title slug.  First of all remember that we are going to get all the Time_UUID’s which will be the super columns.  The process is very similar to getting columns in a normal column family.   There are only one major difference, instead of getting a RangeSlice from  the keyspace we will use the  getSuperRangeSlices method from the keyspace.  The KeyRange and slice predicate work in exactly the same way as before.  So to get the map of supercolmns we use:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;Keyspace ks = client.getKeyspace(&amp;quot;BloggyAppy&amp;quot;);
ColumnParent columnParent = new ColumnParent(&amp;quot;Comments&amp;quot;);
          
SlicePredicate slicePredicate = new SlicePredicate();
SliceRange supercolumnRange = new SliceRange();
             
supercolumnRange.setStart(new byte[0]);  
supercolumnRange.setFinish(new byte[0]); supercolumnRange.setReversed(true); 
supercolumnRange.setCount(1000);
slicePredicate.setSlice_range(supercolumnRange);
KeyRange titlesRange = new KeyRange(200); 
titlesRange.setStart_key(&amp;quot;First-Blog&amp;quot;);
titlesRange.setEnd_key(&amp;quot;First-Blog&amp;quot;);
              
Map&amp;lt;String, List&amp;lt;SuperColumn&amp;gt;&amp;gt; supermap =ks.getSuperRangeSlices(columnParent, slicePredicate, titlesRange);
&lt;/pre&gt;&lt;br /&gt;
Now we have the map we can step through the keys (in our example there will be only one) and then for each get the list of supercolumns underneath it.  The only thing to remember here is to convert the column name to type UUId:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;for (String key : supermap.keySet()) {
 List&amp;lt;SuperColumn&amp;gt; columns = supermap.get(key);

 System.out.println(&amp;quot;Key &amp;quot;+key);
 for (SuperColumn column : columns) {
  //print columns with values
  java.util.UUID Name=toUUID(column.getName()) ;
  System.out.println(&amp;quot;Name &amp;quot;+Name);
  }
}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Finally we want to get the names and values  of the columns inside the supercolumn.  The trick here is to get the actual SuperColumn from the keyspace.  Here’s one way to do it (note that column.getName will return a timeUUID in our case):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;
ColumnPath cp = new ColumnPath(&amp;quot;Comments&amp;quot;);
cp.setSuper_column(column.getName());
SuperColumn sc = ks.getSuperColumn(key, cp);
&lt;/pre&gt;&lt;br /&gt;
Now we have the Supercolumn we can just get a list of columns it contains and iterate through them:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;
List&amp;lt;Column&amp;gt; cols=sc.getColumns();
Iterator&amp;lt;Column&amp;gt;itr = cols.iterator(); 
while(itr.hasNext()) {
 Column col = itr.next(); 
 System.out.println(&amp;quot;\t\t&amp;quot;+string(col.getName()) + &amp;quot;\t ==\t&amp;quot; + string(col.getValue()));
}

&lt;/pre&gt;&lt;br /&gt;
We should now have all we need to read columns and supercolumsn from the keyspaces.  The next step will be to encapsulate all this into models for our web application to use.  We’ll start that in our next post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-7544870930264553281?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/7544870930264553281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/reading-column-name-value-pairs-from.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/7544870930264553281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/7544870930264553281'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/reading-column-name-value-pairs-from.html' title='Reading column name value pairs from a Supercolumn for the BloggyAppy'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-6173215204557311012</id><published>2010-08-03T16:13:00.000+01:00</published><updated>2010-08-03T16:13:44.435+01:00</updated><title type='text'>Implementing the comments: Writing a comment as a supercolumn</title><content type='html'>So far we have looked at simple column  families  but now it’s time to  tackle super columns. We are still working with the BloggyAppy design from &lt;a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model"&gt;Arin Sarkissian&lt;/a&gt;.   We are using some code from &lt;a href="http://github.com/rantav/hector/blob/master/src/test/java/me/prettyprint/cassandra/service/KeyspaceTest.java"&gt;Hector’s test code&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Following Arin’s specification the Comments Column Family is going to look like this&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;
Comments: {
 Blog-Slug:{
  Time_UUID_1:{
   Coment: A Comment,
   Email: andy@abc.com
},
Time_UUID_2:{
   Coment: A Comment,
   Email: andy@abc.com
}
}
}
&lt;/pre&gt;&lt;br /&gt;
Lets be clear Blog-Slug will be the Slug entry for the blog that is being commented on.  This is the key we will be looking for.  Under that are the supercolumn entries,  with a key of type UUID.  This contains a number of columns that are the entries for the comments.  So to add a comment  we can do this:&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;
Keyspace ks = client.getKeyspace("BloggyAppy");
ColumnPath cp = new ColumnPath("Comments");
java.util.UUID timeUUID=getTimeUUID();              
cp.setSuper_column(asByteArray(timeUUID));
cp.setColumn(bytes("email"));
ks.insert(slugValue, cp, bytes("andy@abc.com"));
cp.setColumn(bytes("Comment"));
ks.insert(slugValue, cp, bytes("AComment"));

&lt;/pre&gt;&lt;br /&gt;
SlugValue is essentially the title.  Note that getTimeUUID is defined as:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;
public static java.util.UUID getTimeUUID()
     {
return java.util.UUID.fromString(new com.eaio.uuid.UUID().toString());
     }

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-6173215204557311012?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/6173215204557311012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/implementing-comments-writing-comment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/6173215204557311012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/6173215204557311012'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/implementing-comments-writing-comment.html' title='Implementing the comments: Writing a comment as a supercolumn'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-1688317554734669886</id><published>2010-08-03T14:30:00.004+01:00</published><updated>2010-08-03T15:48:57.562+01:00</updated><title type='text'>Reading keys and columns from a simple column family in a Cassandra dB</title><content type='html'>In the first part of these posts I’m going to look at retrieving data from  a Cassandra Keyspace.  We are working with the BloggyAppy design from &lt;a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model"&gt;Arin Sarkissian&lt;/a&gt; and the code is heavily based on the Hector examples at &lt;br /&gt;
&lt;a href="http://wiki.github.com/rantav/hector"&gt;Wiki&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
First up lets look at getting the author details from the  Authors ColumnFamily.    So assuming we have a pool of connections from the Hector pool called “client” we can set the Column Family like this :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;Keyspace ks = client.getKeyspace("BloggyAppy");
//retrieve sample data
ColumnParent columnParent = new ColumnParent("Authors");

&lt;/pre&gt;&lt;br /&gt;
We are going to use the getRangeSlice method from the KeySpace class to search for a single Author or to list all Author details.  This requires a ColumnParent (set above) a slicePredicate  and a  KeyRange.    The keyRange is  used to limit the number of keys that  are returned and to limit the keysearch to a certain range.  The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;KeyRange keyRange = new KeyRange();
keyRange.setStart_key(“”);
keyRange.setEnd_key("");

&lt;/pre&gt;&lt;br /&gt;
These settings will get all Keys in the Keyspace.  If you want to limit the number  you can put a numerical value in the KeyRange constructor:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;KeyRange keyRange = new KeyRange(1);

&lt;/pre&gt;&lt;br /&gt;
This will get just one result.  If you want to look for one Key only (such as the Author Andy) then you can do this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;KeyRange keyRange = new KeyRange(1);
keyRange.setStart_key(“Andy”);
keyRange.setEnd_key("");

&lt;/pre&gt;&lt;br /&gt;
Hopefully you can see that:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;KeyRange keyRange = new KeyRange(100);
keyRange.setStart_key(“Andy”);
keyRange.setEnd_key("Dave");

&lt;/pre&gt;&lt;br /&gt;
Will get at most 100 keys that are between the “Andy” and “Dave” &lt;br /&gt;
&lt;br /&gt;
So we can see how to restrict the number of keys that are returned.  We now need to look at limiting the number of columns from the requested key are returned.   Suppose we have the following &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;Andy
 Tel  == 01382 345078
 Email  == andy@r2-dvd.org
 Address  == QMB
&lt;/pre&gt;&lt;br /&gt;
We may only need the first column (Tel) or all columns  or a slice range in between.  We will use a slice range (that looks a lot like the keyRange !)&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;SliceRange columnRange = new SliceRange();
columnRange.setCount(4);
columnRange.setStart(new byte[0]);
columnRange.setFinish(new byte[0]);
columnRange.setReversed(true);

&lt;/pre&gt;&lt;br /&gt;
Some differences to note here we can change the order of that the columns are returned using setReversed. The start and end of the column Range are byte arrays (so that the columns need note be strings in the dB)  If you want to search for a string (if that makes sense in your app) you can do this of course:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;String start="Email";
byte bStart[]=start.getBytes();
columnRange.setStart(bStart); 

&lt;/pre&gt;&lt;br /&gt;
Finally we can create a slicePredicate form the columnRange and get the keys and columns from the keySpace.  &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;SlicePredicate slicePredicate = new SlicePredicate(); slicePredicate.setSlice_range(columnRange); 
Map&amp;lt;String, List&amp;lt;Column&amp;gt;&amp;gt;  map = ks.getRangeSlices(columnParent, slicePredicate, keyRange); 

&lt;/pre&gt;&lt;br /&gt;
Now we’ve got the map, we’ll just read through it and display the columns:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;for (String key : map.keySet()) { 
 List&amp;lt;Column&amp;gt; 
 columns = map.get(key); 
 //print key  
 System.out.println(key);  
 for (Column column : columns) { 
 //print columns with values 
 System.out.println(&amp;quot;\t&amp;quot; + string(column.getName()) + &amp;quot;\t ==\t&amp;quot; + string(column.getValue())); 
} 
} 

&lt;/pre&gt;&lt;br /&gt;
This should be all we need to get  “records” from a simple column family inside a keyspace.  &lt;br /&gt;
&lt;br /&gt;
If we want to get all posts by a particular author all we need to do is use our AuthorPosts Column family and  use the above code to display the details for each post.    Here’s my complete code for displaying all posts for Author “Andy”:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;public class ReadAuthorPosts {
 public static void main(String[] args) throws Exception{
  // TODO Auto-generated method stub
        CassandraClientPool pool = CassandraClientPoolFactory.INSTANCE.get();
         CassandraClient client = pool.borrowClient(&amp;quot;xxx.yy.36.151&amp;quot;, 9160);
       
         try {
             Keyspace ks = client.getKeyspace(&amp;quot;BloggyAppy&amp;quot;);
             //retrieve sample data
             ColumnParent columnParent = new ColumnParent(&amp;quot;AuthorPosts&amp;quot;);

             SlicePredicate slicePredicate = new SlicePredicate();

             /**
              * this effect how many columns we are want to retrieve
              * also check slicePredicate.setColumn_names(java.util.List&amp;lt;byte[]&amp;gt; column_names)
              * .setColumn_names(new ArrayList&amp;lt;byte[]&amp;gt;()); no columns retrievied at all
              */
             SliceRange columnRange = new SliceRange();
             String Start=&amp;quot;s&amp;quot;;
             //For these beware of the reversed state
             //columnRange.setStart(Start.getBytes());  //Sets the first column name to get
             columnRange.setStart(new byte[0]);  //We'll get them all.
             columnRange.setFinish(new byte[0]); //Sets the last column name to get
             //effect on columns order
             columnRange.setReversed(false); //Changes order of columns returned in keyset
             columnRange.setCount(1000); //Maximum number of columsn in a key
 
             slicePredicate.setSlice_range(columnRange);

             //count of max retrieving keys
             KeyRange keyRange = new KeyRange(1);  //Maximum number of keys to get
             keyRange.setStart_key(&amp;quot;Andy&amp;quot;);
             keyRange.setEnd_key(&amp;quot;&amp;quot;);
             Map&amp;lt;String, List&amp;lt;Column&amp;gt;&amp;gt; map = ks.getRangeSlices(columnParent, slicePredicate, keyRange);

             //printing keys with columns
             for (String key : map.keySet()) {
                 List&amp;lt;Column&amp;gt; columns = map.get(key);
                 //print key
                 System.out.println(key);
                 for (Column column : columns) {
                     //print columns with values
                  java.util.UUID Name=toUUID(column.getName()) ;
              
                     System.out.println(&amp;quot;\t&amp;quot; + Name + &amp;quot;\t ==\t&amp;quot; + string(column.getValue()));
                    DisplayPost(string(column.getValue()));
                 
                 }
             }

             // This line makes sure that even if the client had failures and recovered, a correct
             // releaseClient is called, on the up to date client.
             client = ks.getClient();

         } finally {
             pool.releaseClient(client);
         }
 }
 
 
 public static java.util.UUID toUUID( byte[] uuid )
    {
    long msb = 0;
    long lsb = 0;
    assert uuid.length == 16;
    for (int i=0; i&amp;lt;8; i++)
        msb = (msb &amp;lt;&amp;lt; 8) | (uuid[i] &amp;amp; 0xff);
    for (int i=8; i&amp;lt;16; i++)
        lsb = (lsb &amp;lt;&amp;lt; 8) | (uuid[i] &amp;amp; 0xff);
    long mostSigBits = msb;
    long leastSigBits = lsb;

    com.eaio.uuid.UUID u = new com.eaio.uuid.UUID(msb,lsb);
    return java.util.UUID.fromString(u.toString());
    }
  
  
  private static void DisplayPost(String sKey){
   CassandraClientPool pool = CassandraClientPoolFactory.INSTANCE.get();
   CassandraClient client=null;
   try{
        client = pool.borrowClient(&amp;quot;xxx.yy.36.151&amp;quot;, 9160);
   
        HashMap hm = new HashMap();
        hm.put(&amp;quot;pubDate&amp;quot;, &amp;quot;&amp;quot;);

        
            Keyspace ks = client.getKeyspace(&amp;quot;BloggyAppy&amp;quot;);
            //retrieve sample data
            ColumnParent columnParent = new ColumnParent(&amp;quot;BlogEntries&amp;quot;);

            SlicePredicate slicePredicate = new SlicePredicate();

            /**
             * this effect how many columns we are want to retrieve
             * also check slicePredicate.setColumn_names(java.util.List&amp;lt;byte[]&amp;gt; column_names)
             * .setColumn_names(new ArrayList&amp;lt;byte[]&amp;gt;()); no columns retrievied at all
             */
            SliceRange columnRange = new SliceRange();
            String Start=&amp;quot;s&amp;quot;;
            //For these beware of the reversed state
            //columnRange.setStart(Start.getBytes());  //Sets the first column name to get
            columnRange.setStart(new byte[0]);  //We'll get them all.
            columnRange.setFinish(new byte[0]); //Sets the last column name to get
            //effect on columns order
            columnRange.setReversed(false); //Changes order of columns returned in keyset
            columnRange.setCount(10); //Maximum number of columsn in a key

            slicePredicate.setSlice_range(columnRange);

            //count of max retrieving keys
            KeyRange keyRange = new KeyRange(200);  //Maximum number of keys to get
            keyRange.setStart_key(sKey);
            keyRange.setEnd_key(sKey);
            Map&amp;lt;String, List&amp;lt;Column&amp;gt;&amp;gt; map = ks.getRangeSlices(columnParent, slicePredicate, keyRange);

            //printing keys with columns
            for (String key : map.keySet()) {
                List&amp;lt;Column&amp;gt; columns = map.get(key);
                //print key
                System.out.println(key);
                for (Column column : columns) {
                    //print columns with values
                 String Name=string(column.getName()) ;
             
                    System.out.println(&amp;quot;\t&amp;quot; + Name + &amp;quot;\t ==\t&amp;quot; + string(column.getValue()));
                
                }
            }

            // This line makes sure that even if the client had failures and recovered, a correct
            // releaseClient is called, on the up to date client.
            client = ks.getClient();
        }catch(Exception et){
     System.out.println(&amp;quot;Can't connect to server &amp;quot;+et);
     return;
    }
       
         try{
          pool.releaseClient(client);
         }catch(Exception et){
          System.out.println(&amp;quot;Can't release pool &amp;quot;+et);
         }
       
        
  }
 
}

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-1688317554734669886?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/1688317554734669886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/08/reading-keys-and-columns-from-simple.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1688317554734669886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1688317554734669886'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/08/reading-keys-and-columns-from-simple.html' title='Reading keys and columns from a simple column family in a Cassandra dB'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-8071017841237974370</id><published>2010-07-31T14:33:00.005+01:00</published><updated>2010-08-03T12:23:16.052+01:00</updated><title type='text'>Adding a Author index to our Bloggy App</title><content type='html'>There’s one more point about Arin’s design (&lt;a href=” http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model”&gt; WTF is a SuperColumn? An Intro to the Cassandra Data Model&lt;br /&gt;
&lt;/a&gt; ) which allows you to search by tag or for all posts by searching by a default tag (“__notag__”) .  But what if (as is likely ) we want to get all posts by one author ?  The Answer is  to add a new ColumnFamily to our keyspace that looks the same as the TaggedPosts ColumnFamily but uses the Authors name as the tag.  So our this will look like:&lt;br /&gt;
&lt;pre class="brush: java" toolbar: true;&gt;AuthorPosts : { // CF
     // blog entries created by “Andy"
      Andy: {  // Row key is the tag name
          // column names are TimeUUIDType, value is the row key into BlogEntries
           timeuuid_1 : i-got-a-new-guitar,
           timeuuid_2 : another-cool-guitar,
       },
_AllAuthors_: {  // Row key is the tag name
          // column names are TimeUUIDType, value is the row key into BlogEntries
          timeuuid_1 : i-got-a-new-guitar,
          timeuuid_2 : another-cool-guitar,
      }
}
&lt;/pre&gt;We’ve used a made up tag _allAuthors_ for a row that’s going to store all posts from all authors. And in the conf file we add a column family definition like this:&lt;br /&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;ColumnFamily CompareWith=&amp;quot;TimeUUIDType&amp;quot; Name=&amp;quot;AuthorPosts&amp;quot;/&amp;gt; 
&lt;/pre&gt;We can add the post indexes to our ColumnFamily like this&lt;br /&gt;
&lt;pre class="brush: java"&gt;ColumnPath authorsColumnPath = new ColumnPath("AuthorPosts");

authorsColumnPath.setColumn(asByteArray(timeUUID));
ks.insert(authorValue, authorsColumnPath, slugValue.getBytes());
//And do it for all others
ks.insert("_All-Authors_", authorsColumnPath, slugValue.getBytes());
&lt;/pre&gt;Here authorValue is a string containg the Authors Name that we have used earlier in the code.  timeUUID has been created earlier in the code when we added the TaggedPosts columns.  See the previous post for details of creating this value.&lt;br /&gt;
&lt;br /&gt;
The interesting thing about this is that we are using ColumnFamilys as indexes, in traditional SQL we would simply have done something like “Select * from Posts where Author like ‘Andy’ order by postdate” .  Here in Cassandra we are creating indexes in Column Families so predetermining how we can search the data.  Careful design is needed I think !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-8071017841237974370?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/8071017841237974370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/adding-author-index-to-our-bloggy-app.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/8071017841237974370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/8071017841237974370'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/adding-author-index-to-our-bloggy-app.html' title='Adding a Author index to our Bloggy App'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-1627279384302548530</id><published>2010-07-31T13:01:00.000+01:00</published><updated>2010-07-31T13:01:43.543+01:00</updated><title type='text'>Creating the TaggedPost Column Family</title><content type='html'>Now it’s time to deal with the TaggedPosts Column family.  I like to think of this as the indexing  mechanism  for our  application, it’s this Columnfamily that allows us to get all posts or posts from a particular tag.  Because the Column names are TimeUUIDType,  Arin (who’s design we are working from remember &lt;a href=” http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model”&gt; WTF is a SuperColumn? An Intro to the Cassandra Data Model&lt;/a&gt;)  points out that getting the latest 10 entries is going to be very efficient.&lt;br /&gt;
&lt;br /&gt;
So our entries for this Column family are going to look like:&lt;br /&gt;
&lt;br /&gt;
Tag:{&lt;br /&gt;
 TimeofPost: TitleofPost,&lt;br /&gt;
 TimeofPost:TitleofPost,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Also remember that  Arin’s design has denormalised the tags in the Blog entry so they look like tag1,Tag2,Tag3.   In our test code we’ll use an array of tags for a our test entry.&lt;br /&gt;
&lt;br /&gt;
First up we are going to need a ColumnPath for this Column family:&lt;br /&gt;
&lt;br /&gt;
ColumnPath tagsColumnPath = new ColumnPath(&amp;quot;TaggedPosts&amp;quot;); &lt;br /&gt;
&lt;br /&gt;
So here’s the code:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;String Tags[]={&amp;quot;Daily&amp;quot;,&amp;quot;Ramblings&amp;quot;,&amp;quot;_No-Tag_&amp;quot;};&lt;br /&gt;
columnName = &amp;quot;tags&amp;quot;;                 &lt;br /&gt;
value = &amp;quot;&amp;quot;;                   &lt;br /&gt;
for (int i=0;i&amp;lt;Tags.length; i++){                  &lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; value=value+Tags[i]+&amp;quot;,&amp;quot;;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; String tagKey=Tags[i];  &lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp;tagsColumnPath.setColumn(asByteArray(timeUUID)); &lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp;ks.insert(tagKey, tagsColumnPath, slugValue.getBytes());                                     &lt;br /&gt;
} &lt;br /&gt;
&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
The only  point to note here is that the slugValue has been stored earlier in the code and is essentially the title of the post&lt;br /&gt;
&lt;br /&gt;
Now , there is one major  point to note, that’s the timeUUID.    There are some problems creating this value which is essentially the time of the post, for details on the problems see:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=http://wiki.apache.org/cassandra/FAQ#working_with_timeuuid_in_java&gt;http://wiki.apache.org/cassandra/FAQ#working_with_timeuuid_in_java&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Essentially to create this UUID we are going to use Johann Burkard’s UUID library available from &lt;a href=”http://johannburkard.de/software/uuid/”&gt;http://johannburkard.de/software/uuid/&lt;/a&gt; and some of the code detailed in the Apache Cassandra FAC.  So our timeUUID is generated as:&lt;br /&gt;
&lt;br /&gt;
java.util.UUID timeUUID=getTimeUUID();&lt;br /&gt;
&lt;br /&gt;
Where getTimeUUID() is taken form the Cassandra FAC:&lt;br /&gt;
&lt;br /&gt;
public static java.util.UUID getTimeUUID()&lt;br /&gt;
     {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp;return java.util.UUID.fromString(new com.eaio.uuid.UUID().toString());&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
And that’s all we need to create he TaggedPosts CollumnFamily.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-1627279384302548530?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/1627279384302548530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/creating-taggedpost-column-family.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1627279384302548530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1627279384302548530'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/creating-taggedpost-column-family.html' title='Creating the TaggedPost Column Family'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-525929527158076362</id><published>2010-07-30T13:38:00.002+01:00</published><updated>2010-07-30T13:38:17.803+01:00</updated><title type='text'>Trouble with Time UUIDs and Java</title><content type='html'>This is a place holder, I'm having problems generating time UUIDs  and passing them to Cassandra.  Currently I'm looking at:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://wiki.apache.org/cassandra/FAQ#working_with_timeuuid_in_java"&gt;http://wiki.apache.org/cassandra/FAQ#working_with_timeuuid_in_java&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
for an answer&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-525929527158076362?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/525929527158076362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/trouble-with-time-uuids-and-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/525929527158076362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/525929527158076362'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/trouble-with-time-uuids-and-java.html' title='Trouble with Time UUIDs and Java'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-5618027044167816885</id><published>2010-07-30T11:35:00.005+01:00</published><updated>2010-08-03T13:13:10.625+01:00</updated><title type='text'>Starting to write a Cassandra app in Java</title><content type='html'>I’m going to explore using Java to create an application that uses Caassandra as a  datastore.  To do this I’m going to implement the Bloggy App that is described in Arin Sarkissian’s  introduction to Cassanadra:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model"&gt; WTF is a SuperColumn? An Intro to the Cassandra Data Model&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Creating the keyspace&lt;/h2&gt;Now assuming you’ve got Cassandra up and running  you’ll need to  create the keyspace for the app which describes the column families and other config (such as sorting options on the columns).    You’ll need to read Arin’s web page for more detail but here from that page is the config that needs to be added to storage-conf.xml to create the keyspaces.  You’ll need to do this on each node in your cluster and you’ll need to restart  Cassandra on each node for the keyspaces to be created.   Add this to the Keyspaces section of the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;Keyspace Name=&amp;quot;BloggyAppy&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- other keyspace config stuff --&amp;gt;&lt;br /&gt;
&amp;lt;!-- This is a test app from : http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- CF definitions --&amp;gt;&lt;br /&gt;
&amp;lt;ColumnFamily CompareWith=&amp;quot;BytesType&amp;quot; Name=&amp;quot;Authors&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ColumnFamily CompareWith=&amp;quot;BytesType&amp;quot; Name=&amp;quot;BlogEntries&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;ColumnFamily CompareWith=&amp;quot;TimeUUIDType&amp;quot; Name=&amp;quot;TaggedPosts&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;ColumnFamily CompareWith=&amp;quot;TimeUUIDType&amp;quot; Name=&amp;quot;Comments&amp;quot;&lt;br /&gt;
&lt;br /&gt;
CompareSubcolumnsWith=&amp;quot;BytesType&amp;quot; ColumnType=&amp;quot;Super&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ReplicaPlacementStrategy&amp;gt;org.apache.cassandra.locator.RackUnawareStrategy&amp;lt;/ReplicaPlacementStrategy&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Number of replicas of the data --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ReplicationFactor&amp;gt;2&amp;lt;/ReplicationFactor&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
~ EndPointSnitch: Setting this to the class that implements&lt;br /&gt;
~ AbstractEndpointSnitch, which lets Cassandra know enough&lt;br /&gt;
~ about your network topology to route requests efficiently.&lt;br /&gt;
~ Out of the box, Cassandra provides org.apache.cassandra.locator.EndPointSnitch,&lt;br /&gt;
~ and PropertyFileEndPointSnitch is available in contrib/.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;EndPointSnitch&amp;gt;org.apache.cassandra.locator.EndPointSnitch&amp;lt;/EndPointSnitch&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/Keyspace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Writing data to the keyspace&lt;/h2&gt;&lt;br /&gt;
I’m planning on using Java to  create my application so I’ll need a way to connect to the database.   Cassandra uses &lt;a href=”http://incubator.apache.org/thrift/”&gt;Thrift&lt;/a&gt;  as an API but I’ll use a higher level client, in this case &lt;a href=”http://github.com/rantav/hector"&gt;Hector&lt;/a&gt;.  Download the latest version from:  &lt;a href=http://github.com/rantav/hector/downloads&gt;Hector Downloads&lt;/a&gt; and make sure the files are in your classpath.  There are a couple of example files (and the code here will be very heavily based on these examples)  at the git hub &lt;a href=” http://wiki.github.com/rantav/hector/”&gt;wiki&lt;/a&gt;.  Also look in the test section of the src code  on github for more &lt;a href=” http://github.com/rantav/hector/tree/master/src/test/java/me/prettyprint/cassandra/”&gt;examples&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
More info on Hector is here &lt;a href="http://prettyprint.me/2010/02/23/hector-a-java-cassandra-client/"&gt;http://prettyprint.me/2010/02/23/hector-a-java-cassandra-client/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Connecting to the database&lt;/h3&gt;Connecting to the database is nice and easy,  get a pool instance and borrow a client&lt;br /&gt;
&lt;blockquote&gt;CassandraClientPool pool = CassandraClientPoolFactory.INSTANCE.get();&lt;br /&gt;
CassandraClient client = pool.borrowClient(&amp;quot;xxx.yy.36.151&amp;quot;, 9160);&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
remember to release the connection once you’re done with it.&lt;br /&gt;
&lt;br /&gt;
pool.releaseClient(client);&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Writing an entry&lt;/h3&gt;Before we can write anything to Cassandra we need to set the keyspace we are going to use.  In  this case we are going to use our Blog application keyspace BloggyApp:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Keyspace ks = client.getKeyspace("BloggyAppy");&lt;br /&gt;
&lt;br /&gt;
Suppose we want to add a “record” (to borrow from RDBMS terms), in this case lets add an author record to Authors column family.  First get a column path to the Authors column:&lt;br /&gt;
&lt;br /&gt;
ColumnPath columnPath = new ColumnPath("Authors");&lt;br /&gt;
&lt;br /&gt;
So what we want to do is add a number of “fields” (which are name value pairs) to our “record”  Suppose our “record” is going to look like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Andy&lt;br /&gt;
Tel  == 01555 XXXXX&lt;br /&gt;
Email  == andy@blogspot.org&lt;br /&gt;
Address  == Blogspot&lt;br /&gt;
&lt;br /&gt;
“Andy” is going to be our Key and each of Tel:data, Email:data, Address:data columns in that key.  So to add the Andy key with a email address:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;String key = &amp;quot;Andy&amp;quot;;&lt;br /&gt;
String columnName = &amp;quot;Email&amp;quot;;&lt;br /&gt;
String value = &amp;quot;andy@blogspot.org&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
columnPath.setColumn(columnName.getBytes());&lt;br /&gt;
ks.insert(key, columnPath, value.getBytes());&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
So, here we set the columnpath (email) and then add to the key (andy) this columnpath with  a value. Note that the value is stored as an array of bytes.   We can go on like this to set the telephone number:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;columnName = &amp;quot;Tel&amp;quot;;&lt;br /&gt;
value = &amp;quot;01555 XXXXX&amp;quot;; &lt;br /&gt;
columnPath.setColumn(columnName.getBytes());&lt;br /&gt;
ks.insert(key, columnPath, value.getBytes());&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
If we want to add a new “record” (say for Joe) just change the key (key=”Joe”) and start adding “fields”.  Note we haven’t defined how many fields a key has or what the fields are.  They are added as needed and not all may be present.  This is a major difference to a traditional RDBMS.  One last thing, our bloggy app (as defined in Arin’s article needs a pubdate in a Blog Entry key.  This needs  to be stored as unixtime.  We can do that like this:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;columnName = &amp;quot;pubDate&amp;quot;;&lt;br /&gt;
long now = System.currentTimeMillis();&lt;br /&gt;
Long lnow=new Long(now);&lt;br /&gt;
value = lnow.toString();&lt;br /&gt;
columnPath.setColumn(columnName.getBytes());&lt;br /&gt;
ks.insert(key, columnPath, value.getBytes());&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
The important thing is we convert the long now value to a string before inserting it into the key.&lt;br /&gt;
&lt;br /&gt;
Next time, starting to get some of this info out of Cassandra&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-5618027044167816885?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/5618027044167816885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/starting-to-write-cassandra-app-in-java.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5618027044167816885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5618027044167816885'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/starting-to-write-cassandra-app-in-java.html' title='Starting to write a Cassandra app in Java'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-3627899863644889799</id><published>2010-07-29T12:05:00.000+01:00</published><updated>2010-07-29T12:05:01.521+01:00</updated><title type='text'>A very simple 2 node cassandra cluster on windows XP</title><content type='html'>Today I’ve been setting up a tiny Cassandra cluster in our teaching lab.  I’m (for my sins) running this on  a couple of Windows XP boxes.  This means that for now Cassandra need to be  run from the command prompt and the machine left running.  Setting up on windows is fine, just make sure your JAVA_HOME is set correctly before running.    To get more than one machine talking to each other do the following.&lt;br /&gt;
&lt;br /&gt;
Open the storage-conf.xml file and  look for ListenAddress.  Change this to be the IP address of the the machine you’re working on:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ListenAddress&amp;gt;xxx.yyy.36.151&amp;lt;/ListenAddress&amp;gt;&lt;br /&gt;
  &amp;lt;!-- internal communications port --&amp;gt;&lt;br /&gt;
  &amp;lt;StoragePort&amp;gt;7000&amp;lt;/StoragePort&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do this on both machines.  Now look for the Seeds config entry.  Change this so it lists both the IP’s of each machine.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&amp;lt;Seeds&amp;gt;&lt;br /&gt;
      &amp;lt;Seed&amp;gt;xxx.yyy.36.151&amp;lt;/Seed&amp;gt;&lt;br /&gt;
      &amp;lt;Seed&amp;gt;xxx.yyy.36.150&amp;lt;/Seed&amp;gt;&lt;br /&gt;
  &amp;lt;/Seeds&gt;&lt;br /&gt;
&lt;/blockquote&gt;I also changed the Number of replicas of the data to  the number of machines and to be frank I’m not quite sure if I needed to.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&amp;lt;ReplicationFactor&amp;gt;2&amp;lt;/ReplicationFactor&amp;gt;&lt;/blockquote&gt;&lt;br /&gt;
One other thing, before you are tempted to start either machine change the ClusterName.  I’ve found trying to change the cluster name after  starting Cassandra can cause problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-3627899863644889799?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/3627899863644889799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/very-simple-2-node-cassandra-cluster-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3627899863644889799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/3627899863644889799'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/very-simple-2-node-cassandra-cluster-on.html' title='A very simple 2 node cassandra cluster on windows XP'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-1575055879419482833</id><published>2010-07-27T13:44:00.001+01:00</published><updated>2010-07-27T13:44:35.971+01:00</updated><title type='text'>Reset vs Cancel in HTML forms</title><content type='html'>I’ve been in an interesting discussion today on Twiter on the use of the reset button in forms.  The questioner asks if buttons should be [cancel][submit] or [submit][cancel]?  My objection is that the cancel button should actually be  [reset].   The questioner countered that all OS dialog boxes have a cancel button not a reset,  well that be true, but when creating web pages we are not dealing with OS dialog boxes.   The difference is simple, with a OS dialog box, you close the box when you hit cancel, when you hit a HTML reset button it clears the form.    &lt;br /&gt;
&lt;br /&gt;
Jakob Nielsen has a post dating from  2000  &lt;a href=” http://www.useit.com/alertbox/20000416.html”&gt; Reset and Cancel Buttons&lt;/a&gt; in which he argues that the reset button is bad and shouldn’t be used.  His main problem is that most designers put the rest button next to the submit and so can be hit by mistake.    He also argues that the reset button isn’t really needed, who needs to clear an entire form and start again?  There is also a chance that having the reset button there will slow users down.   Reset does seem unneeded for most cases provided the user can return each element of a form to it’s default state.  &lt;br /&gt;
&lt;br /&gt;
But what about an explicit Cancel button that closes the form and returns the user to a default page?  This would be the equivalent of a OS dialog box so would typically be followed by a “Are you sure yes/no” dialog box which would need to repopulate the form if “no” was selected.  In my opinion a cancel button is useful for:&lt;br /&gt;
&lt;br /&gt;
1: Pop out forms , the cancel button just closes the form.&lt;br /&gt;
2: Multi form pages with the user filling in a lot of information.  A confirm cancellation button is really important here.&lt;br /&gt;
&lt;br /&gt;
So reset buttons should be used sparingly, does a user really need to clear the entire form ?  Cancel buttons should be used to make sure the transaction/form is really cancelled and return the user to the default / last none form page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-1575055879419482833?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/1575055879419482833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/reset-vs-cancel-in-html-forms.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1575055879419482833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1575055879419482833'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/reset-vs-cancel-in-html-forms.html' title='Reset vs Cancel in HTML forms'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-5768862963107226176</id><published>2010-07-20T14:14:00.004+01:00</published><updated>2010-08-06T09:28:20.486+01:00</updated><title type='text'>A few Cassandra links</title><content type='html'>Introduction to Apache Cassandra:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.nosqldatabases.com/main/2010/7/13/introduction-to-apache-cassandra.html"&gt;http://www.nosqldatabases.com/main/2010/7/13/introduction-to-apache-cassandra.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Cassandra: Principles and Application (pdf paper)&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://bit.ly/aSVkEm"&gt;Cassandra: Principles and Application&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
A Quick Introduction to the Cassandra Data Model:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://maxgrinev.com/2010/07/09/a-quick-introduction-to-the-cassandra-data-model/"&gt;http://maxgrinev.com/2010/07/09/a-quick-introduction-to-the-cassandra-data-model/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Do You Really Need SQL to Do It All in Cassandra?&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://maxgrinev.com/2010/07/12/do-you-really-need-sql-to-do-it-all-in-cassandra/"&gt;http://maxgrinev.com/2010/07/12/do-you-really-need-sql-to-do-it-all-in-cassandra/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Update Idempotency: Why It is Important in Cassandra Applications&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://maxgrinev.com/2010/07/12/update-idempotency-why-it-is-important-in-cassandra-applications-2/"&gt;http://maxgrinev.com/2010/07/12/update-idempotency-why-it-is-important-in-cassandra-applications-2/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
And of course the famous WTF is a SuperColumn? An Intro to the Cassandra Data Model&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model"&gt;http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
A collection of excellent articles on using Java with Cassandra:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.sodeso.nl/?p=80"&gt;http://www.sodeso.nl/?p=80&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://spyced.blogspot.com/2010/04/cassandra-fact-vs-fiction.html"&gt;Cassandra: Fact vs fiction&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://spyced.blogspot.com/2010/02/distributed-deletes-in-cassandra.html"&gt;Distributed deletes in the Cassandra database&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Please add more in the comments&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-5768862963107226176?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/5768862963107226176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/few-cassandra-links.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5768862963107226176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/5768862963107226176'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/few-cassandra-links.html' title='A few Cassandra links'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-2769129916522326963</id><published>2010-07-20T10:39:00.000+01:00</published><updated>2010-07-20T10:40:41.710+01:00</updated><title type='text'>How bad cache data in the DNS effected iPhones</title><content type='html'>This isn't really about web programming but it's the sort of annoying thing that might have an effect on any website your running in the craziest way.&lt;br /&gt;
&lt;br /&gt;
Imagine the problem,  all your clients can see your websites or so you think.  Then you notice that if your iphone is connecting via 3g then your website is inaccessible.  Everything works on wireless though.  This happened to me recently and it wasn't just my iPhone.  Other websites (including ones that are in the parent domain to mine) where all accessible.  It was crazy !&lt;br /&gt;
&lt;br /&gt;
So I downloaded an app iNetFactory that allowed ne to do nslookup, this showed that the site in question could not be resolved in the DNS.  Other sites running off the same dns server where resolving just fine.  This was puzzling.&lt;br /&gt;
&lt;br /&gt;
To cut a long story short, after peering at the DNS configuration (its a windows dns server) I decided to look at the servers cache. To do this on a windows DNS box you'll need to open dnsmgmt and click on view/advanced.   drilling down to my parent domain I noticed that the cache contained an entry for  my domain (which it shouldn't).  The entries in this where valid, but incorrect.  I decided to nuke the cache (right click on Cached Lookups and choose clear cache).  This cured the problem.   &lt;br /&gt;
&lt;br /&gt;
It's not pretty and I'm not sure how the bad entry got in there but I've reports from other iPhone users that the sites are now back and accessible.   It's possible this was a case of cache poisoning or possibly a machine with an old entry (it did resemble an old entry) had managed to do it.&lt;br /&gt;
&lt;br /&gt;
I'm keeping an eye on it !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-2769129916522326963?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/2769129916522326963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/how-bad-cache-data-in-dns-effected.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/2769129916522326963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/2769129916522326963'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/how-bad-cache-data-in-dns-effected.html' title='How bad cache data in the DNS effected iPhones'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-8263322600316102681</id><published>2010-07-06T11:56:00.000+01:00</published><updated>2010-07-06T11:56:14.039+01:00</updated><title type='text'>Final step for handling put data, URL decoding</title><content type='html'>As we saw earlier we can get the put data from the body of the HTML request and decode it into name value pairs.  However our values are URL encoded.  That is spaces have been converted to "+" characters and others are encoded into %FF hex style.  See:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://en.wikipedia.org/wiki/Query_string#URL_encoding"&gt;URL encoding at Wikipedia&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
We need to decode this into plain text.  Fortunately the standard java.net package has a URLDecode class that will do the job for us:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/net/URLEncoder.html"&gt;URLDecode man at Sun.com&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
This has two methods, the simpler one (taking only the string to decode as an argument) has been deprecated so we'll not use it.  The second method takes the string to be decoded and a string representing the encoding method.  This is usually (but not always) UTF-8.  So our code to decode the PUT values is now:&lt;br /&gt;
&lt;br /&gt;
URLDecoder dc = new URLDecoder();&lt;br /&gt;
System.out.println("String was "+dc.decode((String)hm.get("Software"),"UTF-8"));&lt;br /&gt;
&lt;br /&gt;
Remember from last time the name value pair is stored in a hashmap (here hm).  "Software" is the name of the field we are going to retrieve.&lt;br /&gt;
&lt;br /&gt;
One last thing to do before sending this off for storing in a database.  In order to avoid Cross Site Scripting attacks we should escape any html in the value field.  This is to stop users putting  text such as &amp;lt;script&amp;gt;alert(&amp;quot;test&amp;quot;)&amp;lt;/script&amp;gt; into the input.  We'll use the commons lang stringescapeutils package to deal with this:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://commons.apache.org/lang/api/org/apache/commons/lang/StringEscapeUtils.html"&gt;String escape utils&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Our code for dealing with the name value pairs now looks like:&lt;br /&gt;
&lt;br /&gt;
String Software=org.apache.commons.lang.StringEscapeUtils.escapeHtml(&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(String)dc.decode((String)hm.get("Software"),"UTF-8"));&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-8263322600316102681?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/8263322600316102681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/final-step-for-handling-put-data-url.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/8263322600316102681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/8263322600316102681'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/final-step-for-handling-put-data-url.html' title='Final step for handling put data, URL decoding'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-7222995160766060552</id><published>2010-07-06T10:41:00.000+01:00</published><updated>2010-07-06T10:41:39.822+01:00</updated><title type='text'>Decoding PUT data</title><content type='html'>As we saw yesterday, for a HTTP PUT command the data arrives in the body of the HTML content.    A simple way to read that data we saw was:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;InputStream is = request.getInputStream();&lt;br /&gt;
char ch;&lt;br /&gt;
for (int i=0; i &lt; request.getContentLength();i++){&lt;br&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;    ch=(char)is.read();&lt;br&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;    System.out.print(ch);&lt;br&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
which will just read the data and send it to stdout.  However want we want to do is get the data and use it as if it had been sent over as standard parameters.    If you look at the data output from the above code you'll see it is sent as name value pairs delimited by &amp;amp; .  So if we our data is being sent from the jquery ajax call as follows:&lt;br /&gt;
&lt;br /&gt;
data: { Module: $('#Module').val(), Software: $('#Software').val()} &lt;br /&gt;
&lt;br /&gt;
This will be encoded as (for example)&lt;br /&gt;
&lt;br /&gt;
Module=ac31004&amp;Software=SQL+Server&lt;br /&gt;
&lt;br /&gt;
Notice that spaces have been encoded as + characters.     &lt;br /&gt;
&lt;br /&gt;
We need to decode this, turning the input into name value pairs which can be sent to our database update code.   There's probably a lot  of ways to do this, some more efficient than others, but we'll look at one way using a hashmap.&lt;br /&gt;
&lt;br /&gt;
In your servlet code create a global hashmap variable (remember to import the util class import java.util.HashMap;) :&lt;br /&gt;
&lt;br /&gt;
private HashMap hm = new HashMap();&lt;br /&gt;
&lt;br /&gt;
Now in our servlet init method add objects that are going to represent the name of input fields in the original html form:&lt;br /&gt;
&lt;br /&gt;
hm.put("Module", "");&lt;br /&gt;
hm.put("Software", ""); &lt;br /&gt;
&lt;br /&gt;
In our put method read the contents of the request body into a Byte array:&lt;br /&gt;
&lt;br /&gt;
InputStream is = request.getInputStream();&lt;br /&gt;
byte Buffer[]= new byte [request.getContentLength()];&lt;br /&gt;
is.read(Buffer);&lt;br /&gt;
&lt;br /&gt;
We can now split this into name value pairs by string tokenising on the &amp;amp; character:&lt;br /&gt;
&lt;br /&gt;
StringTokenizer st = new StringTokenizer (input,"&amp;amp;");&lt;br /&gt;
&lt;br /&gt;
We can no read through all these pairs and String tokenise on the "=" character.   We can then assume that the first of the pair is the name and the second the value.  Using the hashmap we created earlier, we can look to see if the name is in the hashmap and if it is replace the value with the one we've just got from the name value pair.  Doing this we restrict the input to only those fields we defined in the init method when we set up the hashmap.  Here's the code:&lt;br /&gt;
&lt;br /&gt;
StringTokenizer st = new StringTokenizer (input,"&amp;amp;");&lt;br /&gt;
while (st.hasMoreTokens ()) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;String inputPair=st.nextToken ();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st2 = new StringTokenizer (inputPair,"=");&lt;br /&gt;
     &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // First token should be name of input field&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;String name=st2.nextToken();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;String var =st2.nextToken();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; if (hm.containsKey(name)){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hm.put(name, var);&lt;br /&gt;
    &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally to use these values we can just get them from the hashmap.&lt;br /&gt;
&lt;br /&gt;
String Software=(String)hm.get("Software");&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-7222995160766060552?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/7222995160766060552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/decoding-put-data.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/7222995160766060552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/7222995160766060552'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/decoding-put-data.html' title='Decoding PUT data'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7400362863068587019.post-1125450273388487160</id><published>2010-07-05T14:58:00.000+01:00</published><updated>2010-07-05T14:58:04.987+01:00</updated><title type='text'>HTTP PUT,   jquery  and Java Servlets</title><content type='html'>If you are trying to create a RESTFULL interface then you need to implement the HTTP Put method to allow updates.  Now , all browsers will not allow PUT (or DELETE) in a  form method so the  the easiest thing to do is use AJAX (xmlHttpRequest actually) to send over the data.  Now you could handrole the xmlHttpRequest, but thats reinventing the wheel.  Instead we can use JQUERY:&lt;br /&gt;
&lt;br /&gt;
http://api.jquery.com/jQuery.ajax/&lt;br /&gt;
&lt;br /&gt;
So a post can be down as follows (Module and Software are the ids of Input fields in our HTML), $("a") is attaching this to a "a href" statement:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;$(document).ready(function() {&lt;br /&gt;
   // do stuff when DOM is ready&lt;br /&gt;
 &lt;br /&gt;
 $("a").click(function() {&lt;br /&gt;
  $.ajax({&lt;br /&gt;
     type: 'PUT',&lt;br /&gt;
     url: "/Courses/Software",&lt;br /&gt;
     processData : true,&lt;br /&gt;
     data: { Module: $('#Module').val(), Software: $('#Software').val() } , &lt;br /&gt;
     error: function(data) {&lt;br /&gt;
        $('.result').html(data);&lt;br /&gt;
        alert('Error in put.'+data);&lt;br /&gt;
     },&lt;br /&gt;
     success: function(data) {&lt;br /&gt;
        $('.result').html(data);&lt;br /&gt;
        alert('Load was performed with '+data);&lt;br /&gt;
     }&lt;br /&gt;
   });&lt;br /&gt;
      alert($('#Module').val()+" : "+ $('#Software').val());&lt;br /&gt;
    });&lt;br /&gt;
 &lt;br /&gt;
 });&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
The problem is how to handle this is the Java Servlet.  You are probably aware that you can use a doPut(HttpServletRequest request, HttpServletResponse response) method in the servlet to handle the HTTP Post.  The problem is how to get at the data.  My first attempt was to just get the parameters:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;System.out.println("Software:doPut"+request.getParameter("Module"));&lt;br /&gt;
System.out.println("Software:doPut"+request.getParameter("name"));&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
But that doesn't work.  For PUT the data is in the body of the request.  You can see this by looking at the content length:&lt;br /&gt;
&lt;br /&gt;
System.out.println("Content length "+request.getContentLength());&lt;br /&gt;
&lt;br /&gt;
So we need to read the body in our servlet (doPut) like this (simple example):&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;InputStream is = request.getInputStream();&lt;br /&gt;
char ch;&lt;br /&gt;
for (int i=0; i &amp;lt; request.getContentLength();i++){&lt;br /&gt;
   ch=(char)is.read();&lt;br /&gt;
   System.out.print(ch);&lt;br /&gt;
}&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
I'll leave decoding this into name, value pairs until next time&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7400362863068587019-1125450273388487160?l=ac31004.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ac31004.blogspot.com/feeds/1125450273388487160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ac31004.blogspot.com/2010/07/http-put-jquery-and-java-servlets.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1125450273388487160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7400362863068587019/posts/default/1125450273388487160'/><link rel='alternate' type='text/html' href='http://ac31004.blogspot.com/2010/07/http-put-jquery-and-java-servlets.html' title='HTTP PUT,   jquery  and Java Servlets'/><author><name>Andy C</name><uri>http://www.blogger.com/profile/17070199238912480368</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
