tag:blogger.com,1999:blog-15883905805963527442024-03-13T01:55:41.809+01:00Captain Gazza's Log...I'm a principal software engineer mainly focused on java technology. Although unfortunately I'm often involved in analysis and design I'm basically a developer...I love codingAndreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.comBlogger23125tag:blogger.com,1999:blog-1588390580596352744.post-41171548593625172062016-03-29T20:40:00.000+02:002016-03-29T21:31:13.628+02:00Randomizing top-n results in Solr So, after shuffling a bit [1] the top-n search results returned by Solr, you may want to effectively randomize them in a *non-repeatable* way. Why? I don't know...I'm just enjoying some coding experiment while I'm travelling :)<br />
<br />
What I want to do is: run a query and (pseudo) randomly reorder the first top results. I will be using again the query reranking feature, but this time, I need a re-ranking query that produces different results each time is invoked.<br />
<br />
I created a simple function [2] (i.e. a <i>ValueSourceParser</i> plus a <i>ValueSource</i> subclasses) that is based on a (threaded-local) <i>java.util.Random</i> instance which simply returns a (pseudo) random number each time it is invoked.<br />
<br />
Once the two classes have been packed in a jar, put under the <i>lib</i> folder and configured in <i>solrconfig.xml</i> with the name <b>rnd</b>:<br />
<br />
<div style="color: #3933ff; font-family: Monaco; font-size: 11px; line-height: normal;">
<span style="color: #009193;"><</span><span style="color: #4e9192;">valueSourceParser</span><span style="color: black;"> </span><span style="color: #932192;">name</span><span style="color: black;">=</span>"rnd"<span style="color: black;"> </span><span style="color: #932192;">class</span><span style="color: black;">=</span>"com.faearch.search.function.RandomValueSourceParser"<span style="color: #009193;">/></span></div>
<div style="color: #3933ff; font-family: Monaco; font-size: 11px; line-height: normal;">
<span style="color: #009193;"><br /></span></div>
I only need to use it in a re-rank query using the boost parser:<br />
<br />
<span style="font-family: "monaco"; font-size: 10.833333015441895px;"><span style="color: #009193;"><</span></span><span style="color: #4e9192; font-family: "monaco"; font-size: 10.833333015441895px;">requestHandler ...></span><br />
<div>
<div style="font-family: Monaco; font-size: 11px; line-height: normal;">
<span style="color: #009193;"> <</span><span style="color: #4e9192;">str</span> <span style="color: #932192;">name</span>=<span style="color: #3933ff;">"rqq"</span><span style="color: #009193;">></span>{!boost b=<b>rnd()</b> v=$q}<span style="color: #009193;"><</span><span style="color: #009193; font-size: 11px;">/</span><span style="color: #4e9192; font-size: 11px;">str</span><span style="color: #009193; font-size: 11px;">></span></div>
<div style="font-family: Monaco; font-size: 11px; line-height: normal;">
<span style="color: #009193;"> <</span><span style="color: #4e9192;">str</span> <span style="color: #932192;">name</span>=<span style="color: #3933ff;">"rq"</span><span style="color: #009193;">></span>{!rerank reRankQuery=$rqq reRankDocs=100 reRankWeight=1.2}<span style="color: #009193;"><</span><span style="color: #009193; font-size: 11px;">/</span><span style="color: #4e9192; font-size: 11px;">str</span><span style="color: #009193; font-size: 11px;">></span></div>
<div style="font-family: Monaco; font-size: 11px; line-height: normal;">
<span style="color: #009193; font-size: 11px;">...</span></div>
<div style="font-family: Monaco; font-size: 11px; line-height: normal;">
<br /></div>
<div style="line-height: normal;">
You can now start Solr, index some document, run several times the same query (by default ordered by score) and see what happens. Don't forget to include the score in the field list (fl) parameter; in this way you will see the concrete effect of the multiplicative random boost:</div>
<div style="line-height: normal;">
<br /></div>
<div style="line-height: normal;">
<u>http://...?q=shoes&fl=score,*</u></div>
<div style="line-height: normal;">
<br /></div>
<div style="line-height: normal;">
1st time</div>
<div style="line-height: normal;">
<br /></div>
<div style="line-height: normal;">
<span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;"><result</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"response"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">numFound</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"2"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">start</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"0"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">maxScore</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"0.32487732"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;">
</span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="title" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;">doc</span><span style="color: navy; font-family: monospace; font-size: 12px; white-space: pre;">></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"product_name"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>shoes B</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"score"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>0.32487732</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span>></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">doc</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="title" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;">doc</span><span style="color: navy; font-family: monospace; font-size: 12px; white-space: pre;">></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"product_name"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>shoes A</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"score"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>0.22645184</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span>></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">doc</span>></span></div>
<div style="line-height: normal;">
<span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">result</span>></span></div>
<div style="line-height: normal;">
<br /></div>
<div style="line-height: normal;">
2nd time (ooops that's the same order...don't worry, it's the randomness, and I indexed only 2 docs, see the score value, which is different from the previous example)</div>
<div style="line-height: normal;">
<br /></div>
<div style="line-height: normal;">
<span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;"><result</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"response"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">numFound</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"2"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">start</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"0"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">maxScore</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"0.61873287"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;">
</span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="title" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;">doc</span><span style="color: navy; font-family: monospace; font-size: 12px; white-space: pre;">></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"product_name"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>shoes B</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"score"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>0.61873287</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span>></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">doc</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="title" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;">doc</span><span style="color: navy; font-family: monospace; font-size: 12px; white-space: pre;">></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"product_name"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>shoes A</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"score"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>0.3067757</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span>></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">doc</span>></span></div>
<div style="line-height: normal;">
<span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">result</span>></span></div>
<div style="line-height: normal;">
</div>
<div style="line-height: normal;">
3rd time</div>
<div style="line-height: normal;">
<br /></div>
<div style="line-height: normal;">
<span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;"><result</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"response"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">numFound</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"2"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">start</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"0"</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">maxScore</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"0.24988756"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;">
</span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="title" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;">doc</span><span style="color: navy; font-family: monospace; font-size: 12px; white-space: pre;">></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"product_name"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>shoes A</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"score"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>0.24988756</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span>></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">doc</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="title" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;">doc</span><span style="color: navy; font-family: monospace; font-size: 12px; white-space: pre;">></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"product_name"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>shoes B</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">str</span>></span></div>
<div style="line-height: normal;">
<span style="font-family: monospace; font-size: 12px; white-space: pre;"> </span><span style="color: navy; font-family: monospace; font-size: 11.666666030883789px; white-space: pre;"><</span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span> <span class="attribute" style="background-repeat: no-repeat no-repeat; color: teal; margin: 0px; padding: 0px;">name</span>=<span class="value" style="background-repeat: no-repeat no-repeat; color: #dd1144; margin: 0px; padding: 0px;">"score"</span>></span><span style="font-family: monospace; font-size: 12px; white-space: pre;"><b>0.22548665</b></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">float</span>></span><span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">doc</span>></span></div>
<div style="line-height: normal;">
<span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"></<span class="title" style="background-repeat: no-repeat no-repeat; margin: 0px; padding: 0px;">result</span>></span></div>
<div>
<span class="tag" style="background-repeat: no-repeat no-repeat; color: navy; font-family: monospace; font-size: 12px; margin: 0px; padding: 0px; white-space: pre;"><br /></span></div>
<div style="line-height: normal;">
See you next time ;)</div>
<div style="line-height: normal;">
<br /></div>
<div style="line-height: normal;">
[1] http://andreagazzarini.blogspot.it/2015/11/shuffling-top-results-with-query-re.html</div>
<div style="line-height: normal;">
[2] https://gist.github.com/agazzarini/a802eff3b50c03fae2364458719be94e</div>
</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-84056679858239205692015-11-08T19:42:00.000+01:002015-11-08T19:42:21.091+01:00Shuffling top results in Solr with query re-ranking You built a cool e-commerce portal on top of Apache Solr; brands and shops are sending you their data in CSV and you index everything with a little effort, just a matter of few commands (more than one as the content of each CSV slightly changes between sources).<br />
<br />
Now it's search time but...yes, there's a but: sometimes, the first top results (10, 20, 30 or more) belong to the same shop (or the same brand), even if other shops (or brands) have that kind / type of product.<br />
<br />
For instance, a search for "shirt"<br />
<ul>
<li>returns 5438 results in 109 pages (60 results / page)</li>
<li>the first 118 results (the first two pages) belong to the "C0C0BABE" brand </li>
<li>starting from the 119 result, other brands appear</li>
</ul>
This could be a problem, because sooner or later other brands will complain about that "hiding" issue: the impression rate of the third page is definitely lower than the first page. As consequence of that, it seems like your website is selling only items from "C0C0BABE". <br />
<br />
What can we do? Results need to be sorted by score, another criterion would necessarily compromise the computed relevancy.<br />
<br />
Well, in this scenario, I discovered the Query Re-Ranking [1] capability of Solr; I know, it is not a new feature, it has been introduced in Solr very long time ago...I never met before a scenario like this ("<i>Mater artium necessitas</i>") <br />
<br />
From the official Solr Reference Guide:<br />
<br />
<i>"Query Re-Ranking allows you to run a simple query (A) for matching
documents and then re-rank the top N documents using the scores from a
more complex query (B). Since the more costly ranking from query B is
only applied to the top N documents it will have less impact on
performance then just using the complex query B by itself"</i><br />
<br />
The component interface is very simple. You need to provide three parameters:<br />
<ul>
<li><b>reRankQuery</b>: this is the query that will be used for re-ranking;</li>
<li><b>reRankDocs</b>: the (minimum) number of top N results to re-rank; Solr could increase that number during the re-ranking</li>
<li><b>reRankWeight</b>: a multiplicative factor applied to the score of the documents matching the <u>reRankQuery</u> and, at the same time, belonging to the top <b>reRankDocs</b> set. For each of them, that additional score will be added to the original score of the document (i.e. the score resulting from the main query)</li>
</ul>
Cool! But the actual question was: what about the reRankQuery?? I should emulate a random behaviour, like random querying a field with a non-structured content. At the end that has been exactly what I did: I saw in the schema a non-structured field, the product description, which contains free text. <br />
<br />
Then I created a copy of such field in another searchable "shuffler" (Text)field , with a minimum text analysis (standard tokenization, lowercasing, word delimiter):<br />
<blockquote class="tr_bq">
<span style="color: #38761d;"><field</span> <b><span style="color: purple;">name</span></b>=<span style="color: blue;">"shuffler" </span><b><span style="color: purple;">type</span></b>=<span style="color: blue;">"unstemmed-text"</span> <b><span style="color: purple;">indexed</span></b>=<span style="color: blue;">"true"</span> ...<span style="color: #38761d;">/></span><br />
<span style="color: #38761d;"><copyField</span> <b><span style="color: purple;">src</span></b>=<span style="color: blue;">"prd_descr"</span> <b><span style="color: purple;">dest</span></b>=<span style="color: blue;">"shuffler"</span><span style="color: #38761d;">/></span></blockquote>
As last thing, I configured the request handler with the re-rank parameters as follow:<br />
<blockquote class="tr_bq">
<span style="color: #38761d;"><str</span> <b><span style="color: purple;">name</span></b>=<span style="color: blue;">"rqq"</span><span style="color: #38761d;">></span><br />
{!lucene q.op=OR df=shuffler v=$rndq}<br />
<span style="color: #38761d;"></str></span><br />
<span style="color: #38761d;"><str</span> <b><span style="color: purple;">name</span></b>=<span style="color: blue;">"rq"</span><span style="color: #38761d;">></span><br />
{!rerank reRankQuery=$rqq reRankDocs=220 reRankWeight=1.2}<br />
<span style="color: #38761d;"></str></span> </blockquote>
As you can see I'm using a plain Solr query parser for executing a search on the "shuffler" field mentioned above. What about the $rndq parameter? That is the query, which should contain a (probably long) list of terms. I defined a default value like this:<br />
<blockquote class="tr_bq">
<span style="color: #38761d;"><str</span> <b><span style="color: purple;">name</span></b>=<span style="color: blue;">"rndq"</span><span style="color: #38761d;">></span><br />
(just top bottom button style fashion up down chic elegance ... )<br />
<span style="color: #38761d;"></str></span> </blockquote>
What is the goal here? The default operator of the query parser has been set to OR so the <b>reRankQuery</b> will give a chance to the first <b>reRankDocs</b> to collect an additional "bonus" score if their <i>shuffler</i> field contains one or (better) more terms provided in the $rdnq parameter.<br />
<br />
The default value, of course, will be always the same, but a client could provide an its own $rndq parameter with a list of terms different for each request.<br />
<br />
For the other parameters (<b>reRankWeight</b> and <b>reRankDocs</b>) those are the values that work for me...you should run some test with your dataset and try / adjust them.<br />
<br />
The overall stuff is not precise, is not so deterministic...but it works ;) <br />
<br />
----------------------------------------------------- <br />
<br />
[1] https://cwiki.apache.org/confluence/display/solr/Query+Re-Ranking <br />
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-39807229336453813722015-10-17T19:54:00.002+02:002016-01-11T14:38:37.598+01:00How to do Integration tests with Solr 5.x<blockquote class="tr_bq">
<span style="background-color: yellow;"><i>Please keep in mind that what is described below is valid only if you have a Solr instance with a single core. Thanks to <a class="g-profile" href="https://plus.google.com/106247029640344817659" target="_blank">+Alessandro Benedetti</a> for<span class="short_text" id="result_box" lang="en"> <span class="hps">alerting me</span></span> on this </i></span><span style="background-color: yellow;"><i><span class="short_text" id="result_box" lang="en"><span class="hps">sneaky stuff ;)</span></span> </i></span></blockquote>
I recently migrated a project [1] from Solr 4.x to Solr 5.x (actually Solr 5.3.1), and the only annoying stuff has been a (small) refactoring of my integration test suite.<br />
<br />
Previously, I always used the cool Maven Cargo plugin for running and stopping Solr (ehmm Jetty with a solr.war deployed in) before and after my suite. For those who are still using Solr 4.x here [2] there's the configuration. It is just a matter of a single command: <br />
<br />
> maven install<br />
<br />
Unfortunately, Solr 5.x is no longer (formally) a web application, so I'd need to find another way to run the integration suite. After googling a bit I wasn't able to find a solution so I asked to myself : "How do Solr folks run their integration tests?" and I find this artifact [3] on the Maven repository: <i>solr-test-framework</i>..."well, the name sounds good", I said. <br />
<br />
Effectively, I found a lot of already built things that do a lot of stuff for you. In my case, I only had to change a bit my integration suite superclass; actually a simple change because I had to extend from <i>org.apache.solr.SolrJettyTestBase.</i><br />
<br />
This class provides methods for starting and stopping Jetty (yes, still Jetty because even formally Solr is no longer a JEE web application, actually it still is, and it comes bundled with a Jetty, which provides the HTTP connectivity). Starting the servlet container in your methods is up to you, by means of the several createJetty(...) static methods. Instead, that class provides a <i>@BeforeClass</i> annotated method which stops Jetty at the end of the execution, of course in case it has been previously started.<br />
<br />
You can find my code here [4], any feedback is warmly welcome ;) <br />
<br />
--------------------------<br />
[1] <a href="https://github.com/agazzarini/SolRDF" target="_blank">https://github.com/agazzarini/SolRDF</a><br />
[2] <a href="https://github.com/agazzarini/SolRDF/blob/solrdf-1.0/solrdf/solrdf-integration-tests/pom.xml" target="_blank">pom.xml using the Maven Cargo plugin and Solr 4.10.4 </a><br />
[3] <a href="http://mvnrepository.com/artifact/org.apache.solr/solr-test-framework/5.3.1" target="_blank">http://mvnrepository.com/artifact/org.apache.solr/solr-test-framework/5.3.1</a><br />
[4] <a href="https://github.com/agazzarini/SolRDF/blob/master/solrdf/solrdf-integration-tests/src/test/java/org/gazzax/labs/solrdf/integration/IntegrationTestSupertypeLayer.java" target="_blank">SolRDF test superclass using the solr-test-framework</a>Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-92124418178059790652015-06-07T17:43:00.000+02:002015-06-07T22:49:15.247+02:00Towards a scalable Solr-based RDF Store <a href="https://github.com/agazzarini/SolRDF" target="_blank">SolRDF</a> (i.e. Solr + RDF) is a set of Solr extensions for managing (index and search) RDF data.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://cloud.githubusercontent.com/assets/7569632/7524584/5971e1ba-f503-11e4-940e-72e808677c48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://cloud.githubusercontent.com/assets/7569632/7524584/5971e1ba-f503-11e4-940e-72e808677c48.png" width="200" /></a></div>
<br />
<br />
In a <a href="http://andreagazzarini.blogspot.it/2014/12/a-solr-rdf-store-and-sparql-endpoint-in.html" target="_blank">preceding post</a> I described how to quickly set-up a standalone SolRDF instance in two minutes; here, after some work more or less described in <a href="https://github.com/agazzarini/SolRDF/issues/44" target="_blank">this issue</a>, I'll describe in few steps how to run SolRDF in a simple cluster (using SolrCloud). The required steps are very similar to what you (hopefully) already did for the standalone instance. <br />
<br />
<h2>
All what you need </h2>
<ul>
<li><i>A shell</i> (in case you are on the dark side of the moon, all steps can be easily done in Eclipse or whatever IDE) </li>
<li><i>Java</i> 7</li>
<li><i>Apache Maven</i> (3.x)</li>
<li><i>Apache Zookeeper</i> (I'm using the 3.4.6 version)</li>
<li><i>git (optional, you can also download the repository from GitHub as a zipped file)</i></li>
</ul>
<br />
<i></i><br />
<h2>
Start Zookeeper </h2>
<br />
Open a shell and type the following <br />
<br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># cd $ZOOKEPER_HOME/bin</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># ./zkServer -start</b></span></i></span><br />
<br />
That will start Zookeeper in background (start-foreground for foreground mode). By default it will listen on localhost:2181<br />
<br />
<h2>
Checkout <a href="https://github.com/agazzarini/SolRDF" target="_blank">SolRDF</a> </h2>
<br />
If it is the first time you hear about SolRDF you need to clone the repository. Open another shell and type the following:<br />
<br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># cd /tmp</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># git clone https://github.com/agazzarini/SolRDF.git solrdf-download</b></span></i></span><br />
<br />
Alternatively, if you've already cloned the repository you have to pull the latest version, or finally, if you don't have git, you can download the whole repository from here.<br />
<br />
<h2>
Build and Run SolRDF nodes </h2>
<br />
For this example we will set-up a simple cluster consisting of a collection with two shards.<br />
<br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># cd solrdf-download/solrdf</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># mvn -DskipTests \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Dlisten.port=$PORT \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Dindex.data.dir=$DATA_DIR \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -DskipTests \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Dulog.dir=ULOG_DIR \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Dzk=ZOOKEEPER_HOST_PORT \ </b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Pcloud \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> clean package cargo:run</b></span></i></span><br />
<br />
Where<br />
<ul>
<li><b>$PORT</b> is the hosting servlet engine listen port;</li>
<li><b>$DATA_DIR</b> is the directory where Solr will store its datafiles (i.e. the index)</li>
<li><b>$ULOG_DIR</b> is the directory where Solr will store its transaction logs. </li>
<li><b>$ZOOKEEPER_HOST_PORT</b> is the Zookeeper listen address (e.g. localhost:2181)</li>
</ul>
The
very first time you run this command a lot of things will be
downloaded, Solr included. At the end you should see something like
this:<br />
<br />
<pre><code>[INFO] Jetty 7.6.15.v20140411 Embedded started on port [8080]
[INFO] Press Ctrl-C to stop the container...</code></pre>
<br />
<a href="http://127.0.0.1:8080/solr/#/store" target="_blank">the first node of SolRDF is up and running! </a><br />
<br />
(The command above assume the node is running on localohost:8080)<br />
<br />
The second node can be started by opening another shell and re-executing the command above<br />
<br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># cd solrdf-download/solrdf</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># mvn -DskipTests \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Dlisten.port=$PORT \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Dindex.data.dir=$DATA_DIR \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -DskipTests \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Dulog.dir=ULOG_DIR \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> -Pcloud \</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b> cargo:run</b></span></i></span><br />
<br />
Note: <br />
<ul>
<li>"clean package" options have been omitted: you've already did that in the previous step</li>
<li>you need to declare different parameters values (port, data dir, ulog dir) if you are on the same machine</li>
<li>you can use the same parameters values if you are on a different machine</li>
</ul>
If you open the administration console you should see something like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir09ZojmhdCdas-Oet5_wfdRWLQhxPeW-GUx73HRjs14VpCOZ17QxkU0U4XxYFsGtUoqPOcnoCWTTmg1fdGnjGlhmPBVJIqprX4D-H4PBV6JPiGTBDh73qRJJTc3dy0FZ2DK7BNLgLlMY/s1600/Selection_004.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="99" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir09ZojmhdCdas-Oet5_wfdRWLQhxPeW-GUx73HRjs14VpCOZ17QxkU0U4XxYFsGtUoqPOcnoCWTTmg1fdGnjGlhmPBVJIqprX4D-H4PBV6JPiGTBDh73qRJJTc3dy0FZ2DK7BNLgLlMY/s320/Selection_004.png" width="320" /></a></div>
<br />
<br />
<h2>
(Distributed) Indexing </h2>
<br />
Open another shell and type the following (assuming a node is running on localhost:8080):<br />
<br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># curl -v http://localhost:8080/solr/store/update/bulk \<br /> -H "Content-Type: application/n-triples" \<br /> --data-binary @/tmp/solrdf-download/solrdf/src/test/resources/sample_data/bsbm-generated-dataset.nt </b></span></i></span><br />
<br />
Wait a moment...ok! <a href="http://127.0.0.1:8080/solr/#/store" target="_blank">You just added 5007 triples</a>! They've been distributed across the cluster: you can see that by opening the administration consoles of the participating nodes. Selecting the "store" core of each node, you can see how many triples have been assigned to that specific node.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi10NdrE7JSIspFU0gF-TUQQws53w5mZIZDjOvSLFZu3lKAb0eZqJJuOan_TJrz7_A7fv5Lh1lyjM_TegGsw02siLO7pT5IUxZoT5GcRxpHjJuxTHRwy9vfu0aQ50658QtaepVzG-Ayh2g/s1600/admins.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="101" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi10NdrE7JSIspFU0gF-TUQQws53w5mZIZDjOvSLFZu3lKAb0eZqJJuOan_TJrz7_A7fv5Lh1lyjM_TegGsw02siLO7pT5IUxZoT5GcRxpHjJuxTHRwy9vfu0aQ50658QtaepVzG-Ayh2g/s320/admins.png" width="320" /></a></div>
<br />
<br />
<h2>
Querying</h2>
<br />
Open another shell and type the following:<br />
<br />
<span style="font-size: x-small;"><i><b><span style="color: #444444;"># curl "http://127.0.0.1:8080/solr/store/sparql" \<br /> --data-urlencode "q=SELECT * WHERE { ?s ?p ?o } LIMIT 10" \<br /> -H "Accept: application/sparql-results+json"<br />... <br /><br /># curl "http://127.0.0.1:8080/solr/store/sparql" \<br /> --data-urlencode "q=SELECT * WHERE { ?s ?p ?o } LIMIT 10" \<br /> -H "Accept: application/sparql-results+xml"<br />...</span></b></i></span><br />
In the examples above I'm using only (for indexing and querying) the node running on localhost:8080 but you can send the query to any node in the cluster. For instance you can re-execute the query above with the other node (assuming it is running on localhost:8081):<br />
<br />
<span style="font-size: x-small;"><i><b><span style="color: #444444;"># curl "http://127.0.0.1:8081/solr/store/sparql" \<br /> --data-urlencode "q=SELECT * WHERE { ?s ?p ?o } LIMIT 10" \<br /> -H "Accept: application/sparql-results+json"<br />... </span></b></i></span><br />
<br />
You will get the same results.<br />
<br />
Is that ready for a production scenario? No, absolutely not. I think a lot needs to be done on indexing and querying optimization side. At the moment only the functional side has been covered: the integration test suite includes about 150 SPARQL queries (ASK, CONSTRUCT, SELECT and DESCRIBE) and updates (e.g. INSERT, DELETE) taken from the LearningSPARQL book [1], that are working regardless the target service is running as a standalone or clustered instance.<br />
<br />
I will run the first benchmarks as soon as possible but honestly at the moment I don't believe I'll see high throughputs. <br />
<br />
Best,<br />
Andrea<br />
<br />
[1] http://www.learningsparql.com Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-75312192432313384692015-04-19T21:03:00.000+02:002015-04-19T21:03:02.919+02:00RDF Faceting with Apache Solr: SolRDF<i>"Faceted search, also called faceted navigation or faceted
browsing, is a technique for accessing information organized according
to a faceted classification system, allowing users to explore a
collection of information by applying multiple filters."</i><br />
<i>(Source: Wikipedia)</i><br />
<br />
Apache Solr built-in faceting capabilities are nicely described in
the official Solr Reference Guide [1] or in the Solr Wiki [2].<br />
In SolRDF, due to the nature of the underlying data, faceted search
assumes a shape which is a bit different from traditional faceting over
structured data. For instance, while in a traditional Solr schema we
could have something like this:<br />
<br />
<span style="font-size: x-small;"><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"title"</span> .../><br /><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"author"</span> .../></span><br />
<span style="font-size: x-small;"><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"publisher"</span> .../></span><br />
<span style="font-size: x-small;"><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"publication_year"</span> .../></span><br />
<span style="font-size: x-small;"><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"isbn"</span> .../></span><br />
<span style="font-size: x-small;"><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"subject"</span> .../><br />... </span><br />
<br />
In SolRDF data is always represented as a sequence of triples, that is, a
set of assertions (aka statements), representing the state of a given
entity by means of three / four compounding members: a <b>s</b>ubject, a <b>p</b>redicate, an <b>o</b>bject and an optional <b>c</b>ontext.
The holding schema, which is described better in a <a href="https://github.com/agazzarini/SolRDF/wiki/Schema" target="_blank">dedicated section</a> of this Wiki, is, simplifying, something like this:<br />
<br />
<span style="font-size: x-small;"><span style="color: #666666;"><!-- Subject --> </span></span><br />
<span style="font-size: x-small;"><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"s"</span> .../></span><br />
<br />
<span style="font-size: x-small;"><span style="color: #666666;"><!-- Predicate --> </span></span><br />
<span style="font-size: x-small;"><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"p"</span> .../></span><br />
<span style="font-size: x-small;"> </span><br />
<span style="color: #666666;"><span style="font-size: x-small;"><!-- Object --></span></span><br />
<span style="font-size: x-small;"><<span style="color: #38761d;">field</span> <span style="color: purple;">name</span>=<span style="color: blue;">"o"</span> .../></span><br />
<br />
A "book" entity would be represented, in RDF, in the following way:<br />
<br />
<span style="color: #444444;"><span style="background-color: white;"><span style="font-size: x-small;"><#xyz><br /> <b>dc</b>:title <span style="color: blue;">"La Divina Commedia"</span> ; <br /> <b>dc</b>:creator <span style="color: blue;">"Dante Alighieri"</span> ;<br /> <b>dc</b>:publisher <span style="color: blue;">"ABCD Publishing"</span>;<br /> ... </span></span></span><br />
<br />
A faceted search makes sense only when the target aggregation field
or criteria leads to a literal value, a number, something that can be
aggregated. That's the reason you will see, in a traditional Solr that indexes books, a request like this:<span style="font-size: x-small;"> </span><br />
<br />
<div style="text-align: left;">
<span style="font-size: x-small;">facet<span class="pl-k">=</span><span style="color: blue;"><span class="pl-c1">true</span></span><span class="pl-k"> </span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><span style="color: purple;"><span class="pl-k">&</span></span>facet<span class="pl-k">.</span>field<span class="pl-k">=</span><span style="color: blue;">year</span><span class="pl-k"> </span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><span style="font-size: x-small;"><span style="color: purple;"><span class="pl-k">&</span></span></span>facet<span class="pl-k">.</span>field<span class="pl-k">=</span><span style="color: blue;">subject</span>
<span class="pl-k"> </span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><span style="font-size: x-small;"><span style="color: purple;"><span class="pl-k">&</span></span></span>facet<span class="pl-k">.</span>field<span class="pl-k">=</span><span style="color: blue;">author</span></span></div>
<span style="font-size: x-small;"><b> </b></span><b> </b><br />
<div class="highlight highlight-Java">
In the example above, we are requesting facets for three fields:
year, subject and author.<br />
<br />
In SolRDF we don't have such "dedicated"
fields like year or author, but we always have <b>s</b>, <b>p</b>, <b>o</b> and an optional <b>c</b>. Faceting on those fields, although perfectly possible using plain Solr
facet fields (e.g. <i>facet.field=s&facet.field=p</i>), doesn't make much
sense because they are always URI or blank nodes.<br />
<br />
Instead, the field
where faceting reveals its power is the object. But again, asking
for plain faceting on <b>o</b> field (i.e. facet.field=o), will result in a
facet that aggregates apples and bananas: each object represents a
different meaning, it could have a different domain and data-type. We
need a way to identify a given range of objects.<br />
<br />
In RDF, what determines the range of the object of a given triple, is
the second member, the predicate. So instead of indicating what is the
target field of a given facet, we will indicate a query that selects a
given range of objects values. An example will be surely more clear.<br />
</div>
<div class="highlight highlight-Java">
Solr (field) faceting:<br />
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-size: small;"><span style="font-size: x-small;">facet=<span style="color: blue;">true</span><span style="color: purple;">&</span>facet.field=</span><span style="color: blue;"><span style="font-size: x-small;">author</span></span> </span></div>
<pre></pre>
SolRDF (field) faceting:<br />
<br />
<div style="text-align: left;">
<span style="font-size: x-small;">facet=<span style="color: blue;">true</span><span style="color: purple;">&</span>facet.field.q=<span style="color: blue;">p:<http://purl.org/dc/elements/1.1/creator></span></span></div>
<div style="text-align: center;">
<br /></div>
The query will select all objects having an author as value, and then
faceting will use those values. The same concept can be applied to range
faceting. <br />
<br /></div>
<div class="highlight highlight-Java">
<h2>
Facet Fields </h2>
<br />
Traditional field faceting is supported on SolRDF: you can have a field (remember: <b>s</b>,<b>p</b>,<b>o</b> or <b>c</b>) to be treated as a facet by means of the <i>facet.field</i> parameter. All other parameters described in the Solr Reference Guide [1] are supported. Some examples: <br />
<br />
<h4>
Ex #1: field faceting on predicates with a minimum count of 1</h4>
<h4>
</h4>
</div>
<div class="highlight highlight-Java">
<span style="font-size: x-small;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><br /><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <br /><span style="color: purple;">&</span>facet.field=<span style="color: blue;">p</span> <br /><span style="color: purple;">&</span>facet.mincount=<span style="color: blue;">1</span> </span></div>
<div class="highlight highlight-Java">
<br />
</div>
<div class="highlight highlight-Java">
<h4>
Ex #2: field faceting on subjects and predicates with a different minimum count </h4>
<h4>
<br /></h4>
<div class="highlight highlight-Java">
<span style="font-size: x-small;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><span style="color: purple;"> </span></span></div>
<div class="highlight highlight-Java">
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <span style="color: purple;"> </span></span></div>
<div class="highlight highlight-Java">
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet.field=<span style="color: blue;">p</span> <br /><span style="color: purple;"><span style="color: purple;"><span style="color: purple;">&</span></span></span><span style="color: purple;"><span style="color: purple;"><span style="color: black;">facet.field</span>=<span style="color: blue;">s</span> <br /><span style="color: purple;"><span style="color: purple;"></span></span></span>&</span><span style="color: purple;"></span>f.s.facet.mincount=<span style="color: blue;">1</span> </span></div>
<span style="font-size: x-small;"><span style="color: purple;">&</span><span style="color: purple;"></span>f.p.facet.mincount=<span style="color: blue;">1</span>0 </span></div>
<div class="highlight highlight-Java">
<br />
</div>
<div class="highlight highlight-Java">
<h4>
Ex #3: field faceting on predicates with a prefix (Dublin Core namespace) and minimum count constraints</h4>
<h4>
</h4>
</div>
<div class="highlight highlight-Java">
</div>
<div class="highlight highlight-Java">
</div>
<div class="highlight highlight-Java">
</div>
<div class="highlight highlight-Java">
</div>
<div class="highlight highlight-Java">
</div>
<div class="highlight highlight-Java">
</div>
<div class="highlight highlight-Java">
</div>
<div class="highlight highlight-Java">
<div class="highlight highlight-Java">
<span style="font-size: x-small;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><br /><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <br /><span style="color: purple;">&</span>facet.field=<span style="color: blue;">p</span> <br /><span style="color: purple;">&</span>facet.prefix=<span style="color: blue;"><http://purl.org/dc</span></span> </div>
<div class="highlight highlight-Java">
<br />
</div>
<div class="highlight highlight-Java">
<h2>
Object Queries Faceting </h2>
<br />
Facet field queries have basically the same meaning of facet fields: the
only difference is that, instead on indicating a target field, faceting
is always done on the <b>o</b>(bject) field, and you can indicate, with a query, what are the objects that will be faceted. Some examples:<br />
<br />
<h4>
Ex #1: faceting on publishers</h4>
<br />
<span style="font-size: x-small;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><br /><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <br /><span style="color: purple;">&</span>facet.object.q=<span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/publisher></span></span><br />
<br />
<h4>
Ex #2: faceting on names (creators or collaborators)</h4>
<br />
<span style="font-size: x-small;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><br /><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <br /><span style="color: purple;">&</span>facet.object.q=<span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/creator></span> <span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/collaborator></span></span><br />
<br />
<h4>
Ex #3: faceting on relationships of a given resource</h4>
<br />
<span style="font-size: x-small;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><br /><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <br /><span style="color: purple;">&</span>facet.object.q=s<span style="color: blue;"></span>:<span style="color: blue;"><http://example.org#xyz></span> <span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/relation></span></span><br />
<br />
<span style="color: blue;"><span style="color: black;">The <i>facet.field.q</i> parameter can be repeated using an optional progressive number as suffix in the parameter name: </span></span><br />
<br />
<h4>
Ex #4: faceting on creators and languages</h4>
<br />
<span style="font-size: x-small;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><br /><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <br /><span style="color: purple;">&</span>facet.object.q=<span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/creator></span> <span style="color: blue;"><span style="color: purple;">&</span><span style="color: black;">facet.object.q</span>=<span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/language></span><span style="color: blue;"></span></span><span style="color: blue;"></span></span><br />
<span style="font-size: x-small;"><span style="color: blue;"></span></span><br />
or <br />
<br />
<span style="font-size: x-small;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><br /><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <br /><span style="color: purple;">&</span>facet.object.q<b>.1</b>=<span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/creator></span> </span><span style="color: blue;"><span style="font-size: x-small;"><span style="color: purple;">&</span><span style="color: black;">facet.object.q<b>.2</b></span>=<span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/language></span></span><span style="color: blue;"></span></span><span style="color: blue;"></span><br />
<span style="color: blue;"></span> <br />
In this case you will get a facet for each query, keyed using the query itself: <br />
<br />
<span style="color: blue; font-size: x-small;"><span style="color: black;"><<span style="color: #38761d;">lst</span> <span style="color: purple;">name</span>=<span style="color: blue;">"facet_counts"</span>><br /> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span>=<span style="color: blue;">"facet_fields"</span>><br /> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;">=<span style="color: blue;">"<b>p:<http: creator="" dc="" elements="" purl.org=""></http:></b>"</span>><br /> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span><span style="color: #38761d;">int</span> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"Ross, Karlint"</span>>12</span></span></div>
</div>
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"Earl, James"</span>>9</span></span></span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"Foo, John"</span>>9</span></span></span><br />
<span style="font-size: x-small;"> ...</span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span>/</span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span></span></span>><br /> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span>lst </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"<b>p:<http: dc="" elements="" language="" purl.org=""></http:></b>"</span>><br /> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"en"</span>>3445</span></span></span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"de"</span>>2958</span></span></span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"it"</span>>2865</span></span></span><br />
<span style="font-size: x-small;"> ...</span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span>/</span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span></span></span>><br /> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span>/</span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span></span></span></span></span>></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"> </span></span></span></span></span><br />
<span style="font-size: x-small;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;">/</span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span></span></span></span></span>> </span></span></span><br />
<br />
<span style="color: blue;"><span style="color: black;">The suffix in the parameter name is not required, but it is useful to indicate an alias for each query:</span></span><br />
<br />
<span style="font-size: x-small;"><span style="color: blue;"><span style="color: black;">q=<span style="color: blue;">SELECT * WHERE { ?s ?p ?o } </span><br /><span style="color: purple;">&</span>facet=<span style="color: blue;">true</span> <br /><span style="color: purple;">&</span>facet.object.q<b>.1</b>=<span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/creator></span></span></span></span><br />
<span style="font-size: x-small;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: purple;">&</span><span style="color: black;">facet.object.q<b>.2</b></span>=<span style="color: blue;">p</span>:<span style="color: blue;"><http://purl.org/dc/elements/1.1/language> </span></span> </span> </span></span><br />
<span style="font-size: x-small;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">&</span>facet.object.q<b>.alias.1</b>=<span style="color: blue;">author </span></span></span></span><br />
<span style="font-size: x-small;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: purple;">&</span><span style="color: black;">facet.object.q<b>.alias.2</b></span>=<span style="color: blue;">language</span></span> </span> </span></span><br />
<span style="font-size: x-small;"><span style="color: blue;"></span></span><br />
The response in this case will be (note that each facet is now associated with the alias):<br />
<br />
<span style="color: blue; font-size: x-small;"><span style="color: black;"><<span style="color: #38761d;">lst</span> <span style="color: purple;">name</span>=<span style="color: blue;">"facet_counts"</span>><br /> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span>=<span style="color: blue;">"facet_fields"</span>><br /> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;">=<span style="color: blue;">"<b>author</b>"</span>><br /> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span><span style="color: #38761d;">int</span> </span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"Ross, Karlint"</span>>12</span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"></</span></span><span style="color: #38761d;">int></span></span></span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"Earl, James"</span>>9</span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"></</span></span><span style="color: #38761d;">int></span></span></span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"Foo, John"</span>>9</span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"></</span></span><span style="color: #38761d;">int></span></span></span><br />
<span style="font-size: x-small;"> ...</span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span>/</span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span></span></span>><br /> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span>lst </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"<b>language</b>"</span>><br /> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"en"</span>>3445</span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"></</span></span><span style="color: #38761d;">int></span></span></span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"de"</span>>2958</span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"></</span></span><span style="color: #38761d;">int></span></span></span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">int</span></span></span></span></span> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: purple;">name</span></span></span></span></span>=<span style="color: blue;">"it"</span>>2865</span></span></span><span style="color: blue; font-size: x-small;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"></</span></span><span style="color: #38761d;">int></span></span></span><br />
<span style="font-size: x-small;"> ...</span><br />
<span style="font-size: x-small;"> <span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span>/</span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span></span></span>><br /> </span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span>/</span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span></span></span></span></span>></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><</span></span></span></span>/</span></span><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: blue;"><span style="color: black;"><span style="color: #38761d;">lst</span></span></span></span></span></span></span></span></span>> </span></span></span><br />
<span style="color: blue;"><span style="color: black;"><br /></span></span>
<br />
<h2>
Object Range Queries Faceting</h2>
<br />
Range faceting is described in the Solr Reference Guide [1] or in the
Solr Wiki [2]. You can get this kind of facet on all fields that
support range queries (e.g. dates and numerics).<br />
A request like this:<br />
<br />
<span style="font-size: x-small;">facet.range=<span style="color: blue;">year</span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet.range.start=<span style="color: blue;">2000</span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet.range.end=<span style="color: blue;">2015</span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet.range.gap=<span style="color: blue;">1</span></span><br />
<br />
will produce a response like this:<br />
<pre></pre>
<div class="highlight highlight-Java">
<pre></pre>
<lst name="facet_ranges"></lst><span style="font-size: x-small;"><lst name="facet_ranges"><<span style="color: #38761d;">lst</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"facet_ranges"</span>><br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">lst</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"year"</span>><br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">lst</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"counts"</span>><br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">int</span> <span style="color: purple;">name</span>=<span style="color: blue;">"2000"</span>>3445</lst><lst name="facet_ranges"></</lst><lst name="facet_ranges"><span style="color: #38761d;">int</span>><br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">int</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"2001"</span>>2862</lst><lst name="facet_ranges"></</lst><lst name="facet_ranges"><span style="color: #38761d;">int</span>><br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">int</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"2002"</span>>2776</lst><lst name="facet_ranges"></</lst><lst name="facet_ranges"><span style="color: #38761d;">int</span>><br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">int</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"2003"</span>>2865</lst><lst name="facet_ranges"></</lst><lst name="facet_ranges"><span style="color: #38761d;">int</span>><br /> ... <br /> </lst><lst name="facet_ranges"></</lst><lst name="facet_ranges"><span style="color: #38761d;">lst</span>> <br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">int</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"gap"</span>>1</lst><lst name="facet_ranges"></</lst><lst name="facet_ranges"><span style="color: #38761d;">int</span>><br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">int</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"start"</span>>2000</lst></<lst name="facet_ranges"><span style="color: #38761d;">int</span>><br /> </lst><<lst name="facet_ranges"><span style="color: #38761d;">int</span> </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"end"</span>>2010</lst><lst name="facet_ranges"></</lst><lst name="facet_ranges"><span style="color: #38761d;">int</span>><br /> </lst><lst name="facet_ranges"></</lst></span><lst name="facet_ranges"><span style="font-size: x-small;"><span style="color: #38761d;">lst</span>><br /> ...</span><br /> </lst><br />
As briefly explained before, with semi-structured data like RDF we don't
have "year" or "price" or whatever strictly dedicated field for
representing a given concept; we always have 3 or 4 fields:<br />
<ul>
<li>a s(ubject)</li>
<li>a p(redicate)</li>
<li>an o(bject)</li>
<li>and optionally a c(ontext)</li>
</ul>
Requesting something like this:<br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;">facet<span class="pl-k">.</span>range<span class="pl-k">=</span><span style="color: blue;">o</span></span><br />
<br />
wouldn't work: we would mix again apples and bananas. In addition, without
knowing in advance the domain of the target value (e.g. integer, double,
date) how could we express a valid <i>facet.range.start</i>, <i>facet.range.end</i> and <i>facet.range.gap</i>? <br />
<br />
Range faceting for <b>s</b> or <b>p</b> or <b>c</b> attributes doesn't make any sense at all because the corresponding URI datatype (i.e. string) doesn't support range queries. <br />
<br />
In order to enable range faceting on SolRDF, the default <i>FacetComponent</i>
has been replaced with a custom subclass that does something I called
Objects Range Query Faceting, which is actually a mix between facet
ranges and facet queries.<br />
<ul class="task-list">
<li>
<b>Facet</b> because, of course, the final results are a set of facets</li>
<li>
<b>Object</b> because faceting uses the o(bject) field</li>
<li>
<b>Range</b> because what we are going to compute are facet ranges</li>
<li>
<b>Queries</b> because instead of indicating the target
attribute in request (by means of facet.range parameter), this kind of
faceting requires a facet.range.q which is a query (by default parsed by
the Solr Query Parser) that selects the objects (i.e. the "o"
attribute) of all matching triples (i.e. SolrDocument instances) and
then calculates the ranges on them.<br />
</li>
</ul>
In this way, we can issue a request like this:<br />
<span style="font-size: x-small;"><br /></span>
<div class="highlight highlight-Java">
<span style="font-size: x-small;">facet<span class="pl-k">.</span>range<span class="pl-k">.</span>q<span class="pl-k">=</span><span style="color: blue;">p<span class="pl-k">:</span><span class="pl-k"><</span>http<span class="pl-k">:</span><span class="pl-c">//a.b.c#start_year></span></span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&<span style="color: black;">f</span></span>acet<span class="pl-k">.</span>range<span class="pl-k">.</span>start<span class="pl-k">=</span><span style="color: blue;"><span class="pl-c1">2000</span></span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet<span class="pl-k">.</span>range<span class="pl-k">.</span>end<span class="pl-k">=</span><span style="color: blue;"><span class="pl-c1">2010</span></span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet<span class="pl-k">.</span>range<span class="pl-k">.</span>gap<span class="pl-k">=</span><span style="color: blue;"><span class="pl-c1">1</span></span></span></div>
<br />
or like this <br />
<br />
<div class="highlight highlight-Java">
<span style="font-size: x-small;">facet<span class="pl-k">.</span>range<span class="pl-k">.</span>q<span class="pl-k">=</span><span style="color: blue;">p<span class="pl-k">:</span><span class="pl-k"><</span>http<span class="pl-k">:</span><span class="pl-c">//c.d.e#release_date></span> </span><span style="color: purple;"> </span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet<span class="pl-k">.</span>range<span class="pl-k">.</span>start<span class="pl-k">=</span><span style="color: blue;"><span class="pl-c1">2000</span><span class="pl-k">-</span><span class="pl-c1">01</span><span class="pl-k">-</span>10T17<span class="pl-k">:</span><span class="pl-c1">00</span><span class="pl-k">:</span>00Z </span></span><br />
<span style="font-size: x-small;"><span style="color: blue;"></span><span style="color: purple;">&</span>facet<span class="pl-k">.</span>range<span class="pl-k">.</span>end<span class="pl-k">=</span><span style="color: blue;"><span class="pl-c1">2010</span><span class="pl-k">-</span><span class="pl-c1">01</span><span class="pl-k">-</span>10T17<span class="pl-k">:</span><span class="pl-c1">00</span><span class="pl-k">:</span>00Z</span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet<span class="pl-k">.</span>range<span class="pl-k">.</span>gap<span class="pl-k">=</span><span style="color: blue;"><span class="pl-k">+</span>1MONTH</span></span></div>
<br />
You can also have more than one <i>facet.range.q</i> parameter. In this case the facet response will look like this:<br />
<br />
<span style="font-size: x-small;"><lst name="facet_ranges"><lst </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"facet_ranges"</span>><br /> </lst><lst name="facet_ranges"><lst </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"p:<http: a.b.c="" start_year="">"</http:></span>><br /> </lst><lst name="facet_ranges"><lst </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"counts"</span>><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"2000"</span>>3445</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>="<span style="color: blue;">2001"</span>>2862</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"2002"</span>>2776</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"2003"</span>>2865</lst><lst name="facet_ranges"></int><br /> ...<br /> </lst><lst name="facet_ranges"></lst><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"gap"</span>>1</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"start"</span>>2000</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"end"</span>>2010</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"></lst><br /> </lst><lst name="facet_ranges"><lst </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"p:<http: c.d.e="" release_date="">"</http:></span>><br /> </lst><lst name="facet_ranges"><lst </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"counts"</span>><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"2000-03-29T17:06:02Z"</span>>2516</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"2001-04-03T21:30:00Z"</span>>1272</lst><lst name="facet_ranges"></int><br /> ...<br /> </lst><lst name="facet_ranges"></lst> </lst></span><br />
<span style="font-size: x-small;"><lst name="facet_ranges"> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"gap"</span>>+1YEAR</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"start"</span>>2000-01-10T17:00:00Z</lst><lst name="facet_ranges"></int><br /> </lst><lst name="facet_ranges"><int </lst><lst name="facet_ranges"><span style="color: purple;">name</span>=<span style="color: blue;">"end"</span>>2010-01-10T17:00:00Z</lst></span><lst name="facet_ranges"><span style="font-size: x-small;"></int><br /> </lst><br /> ... </span></lst><br />
<br />
Aliasing is supported in the same way that has been described for Facet Objects Queries. The same request above with aliases would be:<br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;">facet.range.q.1=<span style="color: blue;">p:<http: a.b.c="" start_year=""></http:></span><br /><span style="color: purple;">&</span>facet.range.q.alias.1=<span style="color: blue;">start_year_alias</span><br /><span style="color: purple;">&</span>facet.range.q.hint.1=num <-- as="" default="" eric="" font="" is="" num="" optional="" the="" value=""></--></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet.range.start.1=<span style="color: blue;">2000</span><span style="color: purple;"> </span></span><br />
<span style="font-size: x-small;"><span style="color: purple;">&</span>facet.range.end.1=<span style="color: blue;">2010</span><br /><span style="color: purple;">&</span>facet.range.gap.1=<span style="color: blue;">1</span><br /><span style="color: purple;">&</span>facet.range.q.2=<span style="color: blue;">p:<http: c.d.e="" release_date=""></http:></span><br /><span style="color: purple;">&</span>facet.range.q.alias.2=<span style="color: blue;">release_date_alias</span><br /><span style="color: purple;">&</span>facet.range.q.hint.2=<span style="color: blue;">date</span><br /><span style="color: purple;">&</span>facet.range.start.2=<span style="color: blue;">2000-01-10T17:00:00Z</span><br /><span style="color: purple;">&</span>facet.range.end.2=<span style="color: blue;">2010-01-10T17:00:00Z</span><br /><span style="color: purple;">&</span>facet.range.gap.2=<span style="color: blue;">+1MONTH</span></span><http: a.b.c="" start_year=""><http: c.d.e="" release_date=""><span style="font-size: x-small;"><span style="color: blue;"></span><br /></span><br />Note in the response the aliases instead of the full queries:</http:></http:><br />
<span style="font-size: x-small;"><http: a.b.c="" start_year=""><http: c.d.e="" release_date=""><br /><lst name="facet_ranges"></lst></http:></http:></span>
<span style="font-size: x-small;"><lst <span style="color: purple;">name</span>=<span style="color: blue;">"facet_ranges"</span>><br /> <lst <span style="color: purple;">name</span>=<span style="color: blue;">"<b>start_year_alias</b>"</span>><br /> <lst <span style="color: purple;">name</span>=<span style="color: blue;">"counts"</span>><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"2000"</span>>3445</int><br /> <int <span style="color: purple;">name</span>="<span style="color: blue;">2001"</span>>2862</int><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"2002"</span>>2776</int><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"2003"</span>>2865</int><br /> ...<br /> </lst><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"gap"</span>>1</int><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"start"</span>>2000</int><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"end"</span>>2010</int><br /> </lst><br /> <lst <span style="color: purple;">name</span>=<span style="color: blue;">"<b>release_date_alias</b>"</span>><br /> <lst <span style="color: purple;">name</span>=<span style="color: blue;">"counts"</span>><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"2000-03-29T17:06:02Z"</span>>2516</int><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"2001-04-03T21:30:00Z"</span>>1272</int><br /> ...<br /> </lst> </span><br />
<span style="font-size: x-small;"> <int <span style="color: purple;">name</span>=<span style="color: blue;">"gap"</span>>+1YEAR</int><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"start"</span>>2000-01-10T17:00:00Z</int><br /> <int <span style="color: purple;">name</span>=<span style="color: blue;">"end"</span>>2010-01-10T17:00:00Z</int><br /> </lst><br /> ... </span><http: a.b.c="" start_year=""><http: c.d.e="" release_date=""><br /><lst name="facet_ranges"></lst></http:></http:>
<http: a.b.c="" start_year=""><http: c.d.e="" release_date=""><a href="http://agazzarini.github.io/SolRDF/facets-examples.xml" target="_blank">Here</a> you can find a sample response containing all facets described above.</http:></http:><br />
<br />
You can find the same content of this post in the SolRDF Wiki [3]. As usual any feedback is warmly welcome!<br />
<br />
-------------------------------------<br />
[1] <a href="https://cwiki.apache.org/confluence/display/solr/Faceting" target="_blank">https://cwiki.apache.org/confluence/display/solr/Faceting</a><br />
[2] <a href="https://wiki.apache.org/solr/SolrFacetingOverview" target="_blank">https://wiki.apache.org/solr/SolrFacetingOverview</a> <br />
[3] <a href="https://github.com/agazzarini/SolRDF/wiki" target="_blank">https://github.com/agazzarini/SolRDF/wiki</a> </div>
<div class="highlight highlight-Java">
</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-18431851128532361022015-04-05T18:57:00.000+02:002015-04-06T07:18:57.973+02:00RDF Faceting: Query Facets + Range facets = Object Ranges Queries Facets Faceting on semi-structured data like RDF is definitely (at least for me) an interesting topic.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
The <a href="https://github.com/agazzarini/SolRDF/issues/28" target="_blank">issue #28</a> and the <a href="https://github.com/agazzarini/SolRDF/issues/47" target="_blank">issue #47</a> track the progresses about that feature on <a href="https://github.com/agazzarini/SolRDF" target="_blank">SolRDF</a>: RDF Faceting.<br />
I just committed a stable version of one of those kind of faceting: facets objects ranges queries (<a href="https://github.com/agazzarini/SolRDF/issues/28" target="_blank">issue #28</a>). You can find <a href="https://github.com/agazzarini/SolRDF/wiki/Faceted-search" target="_blank">here</a> a draft documentation about how faceting works in SolRDF. <br />
<br />
In a <a href="http://andreagazzarini.blogspot.it/2015/03/rdf-meets-solr-rdf-faceting-first.html" target="_blank">preceding article</a> I described how a plain and basic SPOC faceting works; here I introduce this new type of faceting: <b>Object Ranges Queries Facets</b>.<br />
<br />
<a href="https://cwiki.apache.org/confluence/display/solr/Faceting#Faceting-RangeFaceting" target="_blank">Range Faceting</a> is an already built-in feature in Solr: you can get this facets on all fields that support range queries (e.g. dates and numerics). For instance, asking for something like this:<br />
<br />
<span style="font-size: x-small;"><b>facet.range</b>=<span style="color: blue;">year</span></span><br />
<span style="font-size: x-small;"><b>facet.range.start</b>=<span style="color: blue;">2000</span></span><br />
<span style="font-size: x-small;"><b>facet.range.end</b>=<span style="color: blue;">2015</span></span><br />
<span style="font-size: x-small;"><b>facet.range.gap</b>=<span style="color: blue;">1</span></span><br />
<br />
you will get the following response:<br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;"><<b><span style="color: purple;">lst</span></b> <b>name</b>=<span style="color: blue;">"facet_ranges"</span>></span><br />
<span style="font-size: x-small;"> <<b><span style="color: purple;">lst</span></b> <b>name</b>=<span style="color: blue;">"year"</span>></span><br />
<span style="font-size: x-small;"> <<b><span style="color: purple;">lst</span></b> <b>name</b>=<span style="color: blue;">"counts"</span>></span><br />
<span style="font-size: x-small;"> <<span style="color: purple;"><b>int</b></span> <b>name</b>=<span style="color: blue;">"2000"</span>>3445</<span style="color: purple;"><b>int</b></span>></span><br />
<span style="font-size: x-small;"> <<span style="color: purple;"><b>int</b></span> <b>name</b>=<span style="color: blue;">"2001"</span>>2862</<span style="color: purple;"><b>int</b></span>></span><br />
<span style="font-size: x-small;"> <<span style="color: purple;"><b>int</b></span> <b>name</b>=<span style="color: blue;">"2002"</span>>2776</<span style="color: purple;"><b>int</b></span>></span><br />
<span style="font-size: x-small;"> <<span style="color: purple;"><b>int</b></span> <b>name</b>=<span style="color: blue;">"2003"</span>>2865</<span style="color: purple;"><b>int</b></span>></span><br />
<span style="font-size: x-small;"> ... </span><br />
<span style="font-size: x-small;"> </<b><span style="color: purple;">lst</span></b>> </span><br />
<div>
<span style="font-size: x-small;"> <<span style="color: purple;"><b>int</b></span> <b>name</b>=<span style="color: blue;">"gap"</span>>1</<span style="color: purple;"><b>int</b></span>></span><br />
<span style="font-size: x-small;"> <<span style="color: purple;"><b>int</b></span> <b>name</b>=<span style="color: blue;">"start"</span>>2000</<span style="color: purple;"><b>int</b></span>></span><br />
<span style="font-size: x-small;"> <<span style="color: purple;"><b>int</b></span> <b>name</b>=<span style="color: blue;">"end"</span>>2010</<span style="color: purple;"><b>int</b></span>></span><br />
<span style="font-size: x-small;"> </<b><span style="color: purple;">lst</span></b>> </span><br />
<span style="font-size: x-small;"> ...</span><br />
<span style="font-size: large;">Plain range faceting on RDF schema? mmm....</span><br />
<br />
SolRDF indexes semi-structured data, so we don't have arbitrary fields like year, creation_date, price and so on...we <u>always</u> have these fields:<br />
<ul>
<li><b>s</b>(ubject)</li>
<li><b>p</b>(redicate)</li>
<li><b>o</b>(bject) </li>
<li>and optionally a <b>c</b>(ontext)</li>
</ul>
So here comes the question: how can I get the right domain values for my range facets? I don't have an explicit "year" or "price" or whatever attribute.<br />
See the following data, which is a simple RDF representation of two projects (#xyz and #kyj):<br />
<br />
<span style="font-size: x-small;">@prefix xsd: &lt;</span><span style="font-size: x-small;"><span style="font-size: x-small;">http://www.w3.org/2001/XMLSchema#&gt;</span> .</span> <br />
<span style="font-size: x-small;">@prefix abc: &lt;http://a.b.c#&gt; .</span> <br />
<span style="font-size: x-small;">@prefix cde: &lt;http://c.d.e#&gt; .</span> <br />
<br />
<span style="font-size: x-small;"><#xyz> </span><br />
<span style="font-size: x-small;"> abc:start_year "2001"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:integer ;</span><br />
<span style="font-size: x-small;"> abc:end_year "2003"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:integer ;</span><br />
<span style="font-size: x-small;"> cde:first_prototype_date </span><span style="font-size: x-small;">2001-06-15"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:date ;</span><br />
<span style="font-size: x-small;"> cde:last_prototype_date "</span><span style="font-size: x-small;">2002-06-30"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:date ;</span><br />
<span style="font-size: x-small;"> cde:release_date </span><span style="font-size: x-small;">"2003-10-10"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:date .</span><br />
<br />
<span style="font-size: x-small;"><#kyj> </span><br />
<span style="font-size: x-small;"> abc:start_year "2002"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:integer ;</span><br />
<span style="font-size: x-small;"> abc:end_year "2007"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:integer ;</span><br />
<span style="font-size: x-small;"> cde:first_prototype_date </span><span style="font-size: x-small;">2003-09-27"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:date ;</span><br />
<span style="font-size: x-small;"> cde:last_prototype_date "</span><span style="font-size: x-small;">2005-08-24"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:date ;</span><br />
<span style="font-size: x-small;"> cde:release_date </span><span style="font-size: x-small;">"2007-03-10"</span><span style="font-size: x-small;"><span style="font-size: x-small;">^^</span>xsd:date .</span><br />
<br />
<span style="font-size: x-small;"><span style="font-size: small;">The following table illustrates how the same data is indexed within Solr:</span></span><br />
<table border="0" cellpadding="3" style="text-align: center;">
<tbody>
<tr>
<th>S(ubject)</th><th>P(redicate)</th><th>O(bject)</th>
</tr>
<tr style="background-color: #e6e6e6;">
<td><span style="background-color: #eeeeee;">#xyz</span></td>
<td><span style="background-color: #eeeeee;">http://a.b.c#start_year</span></td>
<td><span style="background-color: #eeeeee;">"2001"^^xsd:integer</span></td>
</tr>
<tr style="background-color: #d2d2d2;">
<td>#xyz</td>
<td>http://a.b.c#end_year</td>
<td>"2003"^^xsd:integer</td>
</tr>
<tr style="background-color: #c6c6c6;">
<td>#xyz</td>
<td>http://c.d.e#first_prototype_date</td>
<td>"2001-06-15"^^xsd:date</td></tr>
<tr align="left"><td colspan="3">...</td></tr>
</tbody></table>
<br />
As you can see, the "logical" name of the attribute that each triple represents is in the <b>P</b> column, while the value of that attribute is in the <b>O</b> cell. This is the main reason the plain Solr range faceting here wouldn't work: a request like this:<br />
<br />
<div style="text-align: center;">
<i>facet.range=<b>o</b></i></div>
<br />
would mix apples and bananas. In addition, without knowing in advance the domain of the target value (e.g. integer, double, date, datetime) how could we express a valid <i>facet.range.start</i>, <i>facet.range.end</i> and <i>facet.range.gap</i>?<br />
<br />
Requesting the same thing for <b>s</b> or <b>p</b> attributes doesn't make any sense at all because the datatype (string) doesn't support this kind of faceting. <br />
<br />
<span style="font-size: large;">Object Ranges Queries Facets</span> <br />
<br />
In order to enable a range faceting that makes sense on SolRDF, I replaced the default <i>FacetComponent</i> with a custom subclass that does something I called <b>Object Ranges Queries Facets</b>, which is actually a mix between <i>facet ranges</i> and <i>facet queries</i>.<br />
<ul>
<li><b><b>Object</b> </b>because the target field is the <b>o</b>(bject) </li>
</ul>
<ul>
<li><b>Facet </b>because, of course, the final results are facets </li>
</ul>
<ul>
<li><b>Range</b> because what we are going to compute are facet ranges</li>
</ul>
<ul>
<li><b>Queries</b> because instead of indicating the target attribute in request (by means of <i>facet.range</i> parameter), this kind of faceting requires a <i>facet.range.q</i> which is a query (by default parsed by the Solr Query Parser) that selects the objects (i.e. the "o" attribute) of all matching triples (i.e. <i>SolrDocument</i> instances) and then calculates the ranges on top of them.</li>
</ul>
Returning to our example, we could issue a request like this:<br />
<br />
<div style="text-align: left;">
<span style="font-size: x-small;"><b>facet.range.q</b>=<span style="color: blue;"><i>p:<http://a.b.c#start_year></i></span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><b>facet.range.start</b>=<span style="color: blue;">2000</span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><b>facet.range.end</b>=<span style="color: blue;">2010</span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><b>facet.range.gap</b>=<span style="color: blue;">1</span></span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
or like this</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><b>facet.range.q</b>=<span style="color: blue;"><i>p:<http://c.d.e#release_date></i></span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><b>facet.range.start</b>=<span style="color: blue;">2000-01-10T17:00:00Z</span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><b>facet.range.end</b>=</span><span style="font-size: x-small;"><span style="color: blue;">2010-01-10T17:00:00Z</span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><b>facet.range.gap</b>=<span style="color: blue;">+1MONTH</span></span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
You can have more than one <i>facet.range.q</i> parameter. In this case the facet response will look like this:</div>
<div style="text-align: left;">
<br /></div>
<<b><span style="color: purple;">lst</span></b> <b>name</b>=<span style="color: blue;">"facet_ranges"</span>><br />
<<b><span style="color: purple;">lst</span></b> <b>name</b>=<span style="color: blue;">"</span><span style="color: blue;"><b><span style="font-size: small;"><span style="color: blue;"><i>p:<http://a.b.c#start_year></i></span></span></b>"</span>><br />
<<b><span style="color: purple;">lst</span></b> <b>name</b>=<span style="color: blue;">"counts"</span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="2000">3445</<span style="color: purple;"><b>int</b></span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="2001">2862</<span style="color: purple;"><b>int</b></span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="2002">2776</<span style="color: purple;"><b>int</b></span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="2003">2865</<span style="color: purple;"><b>int</b></span>><br />
... <br />
</<b><span style="color: purple;">lst</span></b>> <br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="gap">1</<span style="color: purple;"><b>int</b></span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="start">2000</<span style="color: purple;"><b>int</b></span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="end">2010</<span style="color: purple;"><b>int</b></span>><br />
</<b><span style="color: purple;">lst</span></b>><br />
<<b><span style="color: purple;">lst</span></b> <b>name</b>=<span style="color: blue;">"</span><span style="color: blue;"><b><span style="font-size: small;"><span style="color: blue;"><i>p:<http://c.d.e#release_date></i></span></span></b>"</span>><br />
<<b><span style="color: purple;">lst</span></b> <b>name</b>=<span style="color: blue;">"counts"</span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="2000-03-29T17:06:02Z">2516</<span style="color: purple;"><b>int</b></span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="2001-04-03T21:30:00Z">1272</<span style="color: purple;"><b>int</b></span>><br />
... <br />
</<b><span style="color: purple;">lst</span></b>> <<span style="color: purple;"><b>int</b></span> <b>name</b>="gap">+1YEAR</<span style="color: purple;"><b>int</b></span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="start">2000-01-10T17:00:00Z</<span style="color: purple;"><b>int</b></span>><br />
<<span style="color: purple;"><b>int</b></span> <b>name</b>="end">2010-01-10T17:00:00Z</<span style="color: purple;"><b>int</b></span>><br />
</<b><span style="color: purple;">lst</span></b>> <br />
...<br />
<br />
You can do more with request parameters, query aliasing and shared parameters. Please have a look at <a href="https://github.com/agazzarini/SolRDF/wiki/Faceted%20search#facet-objects-ranges-queries" target="_blank">SolRDF Wiki</a>.<br />
<br />
As usual, feedbacks are warmly welcome ;)</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-40357236688491965822015-03-07T18:10:00.000+01:002015-03-16T10:44:29.175+01:00RDF meets Solr: S P O C Faceting<a href="https://github.com/agazzarini/SolRDF" target="_blank">SolRDF</a> is a Solr extension for indexing and searching RDF data.<br />
In a <a href="http://andreagazzarini.blogspot.it/2014/12/a-solr-rdf-store-and-sparql-endpoint-in.html" target="_blank">preceding post</a> I explained how to set-up SolRDF in two minutes, leveraging Maven for automatically building and installing the whole stuff.<br />
<br />
Once installed, you can index data by issuing a command like this:<br />
<br />
<span style="font-size: x-small;">> curl -v http://localhost:8080/solr/store/update/bulk?commit=true -H "Content-Type: application/n-triples" --data-binary @/path-to-your-data/data.nt</span><br />
<br />
and then, you can execute a SPARQL query in this way:<br />
<br />
<span style="font-size: x-small;">> curl "http://127.0.0.1:8080/solr/store/sparql" --data-urlencode "q=<b>SELECT * WHERE { ?s ?p ?o } LIMIT 10</b>" -H "Accept: application/sparql-results+xml"</span><br />
<br />
Now, since the whole stuff is running within a full text search engine, why don't we try to combine some of the cool features of Solr with SPARQL results?<br />
<br />
The underlying idea is: SPARQL results serialization is standardized in several W3C documents and therefore cannot be changed. We need a way to embed those results in another response that will contain additional information like metadata, facets and so on.<br />
<br />
Solr query response sounds perfect to accomplish this goal: I have only to replace the <result> section with a <sparql> document (note I'm specifically talking about the XML response writer, I implemented only this writer at this moment; other formats are coming in the next episodes...). Running a query like this<br />
<br />
<span style="font-size: x-small;">/sparql?<b>facet=true</b>&<b>facet.field=p</b></span><span style="font-size: x-small;"><span style="font-size: x-small;">&<b>start=100</b></span></span><span style="font-size: x-small;"><span style="font-size: x-small;"><span style="font-size: x-small;">&<b>rows=10</b></span></span>&q=SELECT * WHERE {?s ?p ?o}</span><br />
<br />
I can get the following response (note the mix between SPARQL and Solr results):<br />
<br />
<span style="font-size: x-small;"><response></span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>lst name="responseHeader"></span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>int name="status">0</span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>int name="QTime">31</span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>str name="query">SELECT * WHERE{ ?s ?p ?o}</span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>/lst></span><br />
<span style="font-size: x-small;"> <b><result name="response" numFound="3875" start="100" maxScore="1.0"></b> </span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"> <</span>sparql></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>head></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>variable name="s"/></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>variable name="p"/></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>variable name="o"/></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>/head></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>results></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>result></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>binding name="s"></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>uri>http://example/book2</b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>/binding></b></span><br />
<span style="font-size: x-small;"><b> ... </b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>/result></b></span><br />
<span style="font-size: x-small;"><b> ... </b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>/results></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><</span>/sparql></b></span><br />
<span style="font-size: x-small;"><b> </b></span><span style="font-size: x-small;"><b><span style="font-size: x-small;"><b></result</b></span>> </b></span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>lst name="facet_counts"></span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>lst name="facet_queries"/></span><br />
<b><span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>lst name="facet_fields"></span></b><br />
<b><span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>lst name="p"></span></b><br />
<b><span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>int name="</span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>http://example.org/ns#price>">231</span></b><b><span style="font-size: x-small;"><b><span style="font-size: x-small;"><span style="font-size: x-small;"><</span></span></b>/int</span></b><b><span style="font-size: x-small;">></span></b><br />
<b><span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>int name="</span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>http://purl.org/dc/elements/1.1/creator>">1432</span></b><b><span style="font-size: x-small;"><b><span style="font-size: x-small;"><span style="font-size: x-small;"><</span></span></b>/int</span></b><b><span style="font-size: x-small;">></span></b><br />
<b><span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>int name="</span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>http://purl.org/dc/elements/1.1/title>">2212</span></b><b><span style="font-size: x-small;"><b><span style="font-size: x-small;"><span style="font-size: x-small;"><</span></span></b>/int</span></b><b><span style="font-size: x-small;">></span></b><br />
<b><span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>/lst></span></b><br />
<span style="font-size: x-small;"> </span><b><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>/lst></span></b><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>lst name="facet_dates"/></span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>lst name="facet_ranges"/></span><br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>/lst></span><br />
<span style="font-size: x-small;"><span style="font-size: x-small;"><</span>/response></span> <br />
<br />
<span style="font-size: small;">The first </span>question is: what does trigger that hybrid search? I would like to maintain the standard SPARQL endpoint functionality so a good compromise could be the following:<br />
<ul>
<li>if the query string contains only a <b>q</b> parameter then the plain SPARQL endpoint will execute the query. It will return a standard SPARQL-Result response;</li>
<li>if the query string contains also other parameters (at the moment I considered only the <b>facet</b>, <b>facet.field</b>, <b>rows</b> and <b>start</b> parameters) then a hybrid search will be executed, therefore providing results in the mixed mode listed above.</li>
</ul>
As usual, any feedback is warmly welcome! Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-83594958833657262182015-02-10T18:45:00.001+01:002015-02-10T18:46:11.345+01:00SPARQL Integration tests with SolRDFLast year, I got a chance to give some contribution to a wonderful project, <a href="https://code.google.com/p/cumulusrdf" target="_blank">CumulusRDF</a>, an RDF store on a cloud-based architecture. The Integration Test Suite was one of the most interesting task I worked on.<br />
<br />
There, I used JUnit for running some examples coming from <a href="http://www.learningsparql.com/" target="_blank">Learning SPARQL by Bob DuCharme (O'Reilly, 2013)</a>. Both O'Reilly and the Author (BTW thanks a lot) gave me permissions to do that in the project.<br />
<br />
So, when I set up the first prototype of <a href="http://agazzarini.github.io/SolRDF/" target="_blank">SolRDF</a>, I wondered how I could create a complete (integration) test suite for doing more or less the same thing...and I came to the obvious conclusion that something of that work could be reused.<br />
<br />
Something had to be changed. mainly because CumulusRDF uses Sesame as underlying RDF framework, while <a href="http://agazzarini.github.io/SolRDF/" target="_blank">SolRDF</a> uses Jena...but at the end it was a minor change...they are both valid, easy and powerful. <br />
<br />
So, for my <a href="https://github.com/agazzarini/SolRDF/blob/master/solrdf/src/test/java/org/gazzax/labs/solrdf/integration/LearningSparql_ITCase.java" target="_blank">LearningSPARQL_ITCase</a> I needed:<br />
<ul>
<li>A setup method for loading the example data;</li>
<li>A teardown method for cleaning up the store; </li>
</ul>
The example data is provided, in the LearningSPARQL website, in <a href="http://www.learningsparql.com/2ndeditionexamples/index.html" target="_blank">several files</a>. Each file can contain: a small dataset or a query or an expected result (in tabular format). So, returning to my tests, the flow should load the small dataset X, run the query Y and verify the results Z. <br />
<br />
Although <a href="http://andreagazzarini.blogspot.it/2014/12/a-solr-rdf-store-and-sparql-endpoint-in.html" target="_blank">this post</a> illustrates how to load a sample dataset in <a href="http://agazzarini.github.io/SolRDF/" target="_blank">SolRDF</a>, this is something that you can do from the command line, and not in a JUnit test. Instead, using Jena, in my Unit tests, I load the data in SolRDF using these few lines:<br />
<br />
<span style="font-size: x-small;"><span style="color: #38761d;">// DatasetAccessor provides access to </span></span><br />
<span style="font-size: x-small;"><span style="color: #38761d;">// remote datasets using SPARQL 1.1 Graph Store HTTP Protocol</span></span><br />
<span style="font-size: x-small;">DatasetAccessor dataset = DatasetAccessorFactory.createHTTP(<url>);</url></span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;"><span style="color: #38761d;">// Load a local memory model</span></span><br />
<span style="font-size: x-small;">Dataset memoryDataset = DatasetFactory.createMem();</span><br />
<span style="font-size: x-small;">Model memoryModel = memoryDataset.getDefaultModel(); </span><br />
<span style="font-size: x-small;">memoryModel.read(dataURL, ...);</span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;"><span style="color: #38761d;">// Load the memory model in the remote dataset</span></span><br />
<span style="font-size: x-small;">dataset.add(memoryModel);</span><br />
<br />
Ok, data has been loaded! In another post I will explain what I did, in <a href="http://agazzarini.github.io/SolRDF/" target="_blank">SolRDF</a>, for supporting the <a href="http://www.w3.org/TR/sparql11-http-rdf-update/" target="_blank">SPARQL 1.1 Graph Store HTTP Protocol</a>. Keep in mind that the protocol is not fully covered at the moment. <br />
<br />
Now, it's time to run a query and check the results. As you can see I'll execute the same query twice: the first is against a memory model, the second towards SolRDF. In this way, assuming the memory model of Jena is perfectly working, I will be able to check and compare results coming from the remote dataset (i.e. coming from SolRDF):<br />
<br />
<span style="font-size: x-small;">final Query query = QueryFactory.<i>create</i>(readQueryFromFile(...));</span><br />
<span style="font-size: x-small;">QueryExecution execution = null;</span><br />
<span style="font-size: x-small;">QueryExecution memExecution = null; </span><br />
<span style="font-size: x-small;"> <b><span style="color: #741b47;">try</span></b> {</span><br />
<span style="font-size: x-small;"> execution = QueryExecutionFactory.<i>sparqlService</i>(SOLRDF_URL, query);</span><br />
<span style="font-size: x-small;"> memExecution = QueryExecutionFactory.<i>create</i>(query, memoryDataset);</span><br />
<br />
<span style="font-size: x-small;"> ResultSet rs = execution.execSelect();</span><br />
<span style="font-size: x-small;"> ResultSet mrs = memExecution.execSelect();</span><br />
<span style="font-size: x-small;"> <i>assertTrue</i>(ResultSetCompare.<i>isomorphic</i>(rs, mrs));</span><br />
<span style="font-size: x-small;"> } <b><span style="color: #741b47;">catch</span></b> (...) {</span><br />
<span style="font-size: x-small;"> ...</span><br />
<span style="font-size: x-small;"> } <span style="color: #741b47;"><b>finally</b></span> {</span><br />
<span style="font-size: x-small;"><span style="color: #38761d;"> // Close executions </span></span><br />
<span style="font-size: x-small;"> }</span><br />
<br />
After that, the RDF store needs to be cleared. Although the Graph Store protocol would come in our help, it cannot be implemented in Solr because some HTTP methods (i.e. PUT and DELETE) cannot be used in <i>RequestHandlers</i>. The <i>SolrRequestParsers</i>, which is the first handler of the incoming requests, allows those methods only for <i>/schema</i> and <i>/config</i> requests. So while a clean up could be easily done using something like this:<br />
<br />
<span style="font-size: x-small;">dataset.deleteDefault();</span><br />
<br />
Or, in HTTP:<br />
<br />
<pre class="defn">DELETE /rdf-graph-store?default HTTP/1.1
Host: example.com</pre>
<br />
I cannot implement such behaviour in Solr. After checking the <i>SolrConfig</i> and <i>SolrRequestParsers</i> classes I believe the most, non RDF, simple way to clean up the store is:<br />
<br />
<span style="font-size: x-small;">SolrServer solr = new HttpSolrServer(SOLRDF_URI);</span><br />
<span style="font-size: x-small;">solr.deleteByQuery("*:*");</span><br />
<span style="font-size: x-small;">solr.commit();</span><br />
<br />
I know, that has nothing to do with RDF and with the Graph Store protocol, but I wouldn't like to change the Solr core and at the moment that represents a good compromise. After all, that code resides only in my unit tests.<br />
<br />
That's all! I just merged all those stuff in the master so feel free to have a look. If you want to run the integration test suite you can do that from command line:<br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;"># cd $SOLRDF_HOME</span><br />
<span style="font-size: x-small;"># mvn clean install</span><br />
<br />
or in Eclipse, using the predefined Maven launch configuration <i>solrdf/src/dev/eclipse/run-integration-test-suite.launch. </i>Just right-click on that file e choose "Run as..."<br />
<br />
Regardless the way: you will see these messages:<br />
<br />
(build section)<br />
<br />
<span style="color: #999999;"><span style="font-size: x-small;"><span style="color: #666666;">[INFO] -----------------------------------------------------------------<br />[INFO] Building Solr RDF plugin 1.0<br />[INFO] -----------------------------------------------------------------</span> </span></span><br />
<br />
(unit tests section)<br />
<br />
<span style="font-size: x-small;"><span style="color: #666666;">-------------------------------------------------------<br /> T E S T S<br />------------------------------------------------------- </span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;">...</span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;">Tests run: 12, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.691 sec</span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;">Tests run: 15, Failures: 0, Errors: 0, Skipped: 0</span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;"><br /></span></span>
<span style="font-size: x-small;"><span style="color: #666666;">(cargo section. It starts the embedded Jetty)</span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;"><br /></span></span>
<span style="font-size: x-small;"><span style="color: #666666;">[INFO] [beddedLocalContainer] Jetty 7.6.15.v20140411 Embedded starting...</span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;">...</span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;">[INFO] [beddedLocalContainer] Jetty 7.6.15.v20140411 Embedded started on port [8080]</span></span><br />
<br />
(integration tests section)<br />
<br />
<span style="font-size: x-small;"><span style="color: #666666;">------------------------------------------------------<br /> T E S T S<br />-------------------------------------------------------<br /><b>Running org.gazzax.labs.solrdf.integration.LearningSparql_ITCase</b><br />[INFO] <b>Running Query with prefixes test...</b><br />[INFO] [store] webapp=/solr path=<b>/rdf-graph-store</b> params={default=} status=0 QTime=712 <br />...</span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;">[DEBUG] <solrdf-00092> : Query type 222, incoming Accept header...</solrdf-00092></span></span> <br />
<br />
(end)<br />
<span style="font-size: x-small;"><span style="color: #666666;"><br /></span></span>
<span style="font-size: x-small;"><span style="color: #666666;">[INFO] [store] Closing main searcher on request.<br />...</span></span><br />
<span style="font-size: x-small;"><span style="color: #666666;">[INFO] [beddedLocalContainer] Jetty 7.6.15.v20140411 Embedded is stopped<br />[INFO] ------------------------------------------------------------------------<br />[INFO] BUILD SUCCESS<br />[INFO] ------------------------------------------------------------------------<br />[INFO] Total time: 42.302s<br />[INFO] Finished at: Tue Feb 10 18:19:21 CET 2015<br />[INFO] Final Memory: 39M/313M<br />[INFO] --------------------------------------------------</span></span><br />
<br />
Best,<br />
Andrea Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-40351598340632241262014-12-21T11:40:00.000+01:002015-06-26T19:11:42.507+02:00A Solr RDF Store and SPARQL endpoint in just 2 minutes How to store and query RDF data in Solr? Here is a quick guide, just 2 minute / 5 steps and you will get that ;)<br />
<h4>
1. All what you need </h4>
<ul>
<li><i>A shell</i> (in case you are on the dark side of the moon, all steps can be easily done in Eclipse or whatever IDE) </li>
<li><i>Java</i> (7)</li>
<li><i>Apache Maven</i> (3.x)</li>
<li><i>git </i></li>
</ul>
<br />
<ul>
</ul>
<h4>
2. Checkout <a href="https://github.com/agazzarini/SolRDF" target="_blank">SolRDF</a> code</h4>
Open a shell and type the following:<br />
<br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># cd /tmp</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># git clone https://github.com/agazzarini/SolRDF.git solrdf-download</b></span></i></span><br />
<br />
<h4>
3. Build and Run <a href="https://github.com/agazzarini/SolRDF" target="_blank">SolRDF</a> </h4>
<br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># cd solrdf-download/solrdf</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># mvn clean install</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># cd solrdf-integration-tests </b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># mvn clean package cargo:run</b></span></i></span><br />
<span style="font-size: x-small;"><i><span style="color: #444444;"></span></i></span><br />
The very first time you run this command a lor of things will be downloaded, Solr included. At the end you should see something like this:<br />
<br />
<pre><code>[INFO] Jetty 7.6.15.v20140411 Embedded started on port [8080]
[INFO] Press Ctrl-C to stop the container...</code></pre>
<span style="font-size: x-small;"><i><span style="color: #444444;"></span></i></span><br />
<a href="http://127.0.0.1:8080/solr/#/store" target="_blank">SolRDF is up and running! </a><br />
<br />
<h4>
4. Add some data</h4>
<span style="font-size: x-small;"><i><span style="color: #444444;"></span></i></span>Open another shell and type the following:<br />
<br />
<span style="font-size: x-small;"><i><span style="color: #444444;"><b># curl -v http://localhost:8080/solr/store/update/bulk?commit=true \<br /> -H "Content-Type: application/n-triples" \<br /> --data-binary @/tmp/solrdf-download/solrdf/src/test/resources/sample_data/bsbm-generated-dataset.nt </b></span></i></span><br />
<br />
Wait a moment...ok! <a href="http://127.0.0.1:8080/solr/#/store" target="_blank">You just added (about) 5000 triples</a>! <br />
<br />
<h4>
5. Execute some query</h4>
<span style="font-size: x-small;"><i><span style="color: #444444;"></span></i></span>Open another shell and type the following:<br />
<br />
<span style="font-size: x-small;"><i><b><span style="color: #444444;"># curl "http://127.0.0.1:8080/solr/store/sparql" \<br /> --data-urlencode "q=SELECT * WHERE { ?s ?p ?o } LIMIT 10" \<br /> -H "Accept: application/sparql-results+json"<br />... <br /><br /># curl "http://127.0.0.1:8080/solr/store/sparql" \<br /> --data-urlencode "q=SELECT * WHERE { ?s ?p ?o } LIMIT 10" \<br /> -H "Accept: application/sparql-results+xml"<br />...</span></b></i></span><br />
<br />
Et voilà ! Enjoy! I'm still working on that...any suggestion about this idea is warmly welcome...and if you meet some annoying bug feel free to give me a shout ;)Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-84322561233374156342014-12-01T11:01:00.001+01:002014-12-20T10:32:39.481+01:00Loading RDF (i.e. custom) data in Solr<br />
<blockquote class="tr_bq">
Update: <a href="https://github.com/agazzarini/SolRDF" target="_blank">SolRDF</a>, a working example of the topic discussed in this post is <a href="https://github.com/agazzarini/SolRDF" target="_blank">here</a>. Just <a href="https://github.com/agazzarini/SolRDF/wiki/Get-me-up-and-running-in-2-minutes" target="_blank">2 minutes</a> and you will be able to index and query RDF data in Solr.</blockquote>
<br />
The Solr built-in <a href="https://cwiki.apache.org/confluence/display/solr/Uploading+Data+with+Index+Handlers" target="_blank"><i>UpdateRequestHandler</i></a> supports several formats of input data. It delegates the actual data loading to a specific <a href="https://lucene.apache.org/solr/4_10_2/solr-core/org/apache/solr/handler/loader/ContentStreamLoader.html" target="_blank"><i>ContentStreamLoader</i></a>, depending on the content type of the incoming request (i.e. the Content-type header of the HTTP request). Currently, these are the available content types declared in the <i>UpdateRequestHandler </i>class:<br />
<ul>
<li><i>application/xml</i> or <i>text/xml</i></li>
<li><i>application/json</i> or <i>text/json</i></li>
<li><i>application/csv</i> or <i>text/csv</i></li>
<li><i>application/javabin</i></li>
</ul>
So, a client has several options to send its data to Solr; all what it needs is to prepare those data in a specific format and call the <i>UpdateRequestHandler</i> (usually located at <i>/update</i> endpoint) specifying the corresponding content type<br />
<br />
<span style="font-size: x-small;">> curl http://localhost:8080/solr/update -H "Content-Type: text/json" --data-binary @/home/agazzarini/data.json</span><br />
<br />
The <i>UpdateRequestHandler</i> can be extended, customized, and replaced; so we can write our own <i>UpdateRequestHandler</i> that accepts a custom format, adding a new content type or overriding the default set of supported content types.<br />
<br />
In this brief post, I will describe how to use <a href="http://jena.apache.org/" target="_blank">Jena</a> to load RDF data in Solr, in any format supported by <a href="https://jena.apache.org/documentation/io/" target="_blank">Jena IO API</a>.<br />
This is a quick and easy task mainly because:<br />
<ul>
<li>the <i>UpdateRequestHandler</i> already has the logic to index data </li>
<li>the <i>UpdateRequestHandler</i> can be easily extended </li>
<li>Jena already provides all the parsers we need</li>
</ul>
So doing that, is just a matter of subclassing <a href="https://lucene.apache.org/solr/4_10_2/solr-core/org/apache/solr/handler/UpdateRequestHandler.html" target="_blank"><i>UpdateRequestHandler</i></a> in order to override the content type registry:<br />
<br />
<span style="font-size: x-small;"><b><span style="color: #741b47;">public class</span></b> RdfDataUpdateRequestHandler <span style="color: #741b47;"><b>extends</b></span> UpdateRequestHandler</span><br />
...<br />
<span style="font-size: x-small;"> <b><span style="color: #741b47;">protected</span></b> Map<string contentstreamloader=""> createDefaultLoaders(NamedList parameters) {<br /> <span style="color: #741b47;"><b>final</b></span> Map<String, ContentStreamLoader> registry </string></span><br />
<span style="font-size: x-small;"> = <span style="color: #741b47;"><b>new</b></span> HashMap<String, ContentStreamLoader>();<br /> <span style="color: #741b47;"><b>final </b></span>ContentStreamLoader loader = </span><span style="font-size: x-small;"><span style="font-size: x-small;"><span style="color: #741b47;"><b>new</b></span></span> <b>RdfDataLoader();</b><br /> <span style="color: #741b47;"><b>for</b></span> (<b>final</b> Lang language : RDFLanguages.getRegisteredLanguages()) {<br /> registry.put(language.getContentType().toHeaderString(), loader);<br /> }<br /> <span style="color: #741b47;"><b>return</b></span> registry;<br /> }</span><br />
<br />
As you can see, the registry is a simple Map that associates a content type (e.g. "application/xml") with an instance of <a href="https://lucene.apache.org/solr/4_10_2/solr-core/org/apache/solr/handler/loader/ContentStreamLoader.html" target="_blank"><i>ContentStreamLoader</i></a>. For our example, since the different content types will always map to RDF data, we create an instance of a dedicated <i>ContentStreamLoader</i> (<i>RdfDataLoader</i>) once; that instance will be associated with all built-in content types in Jena. That means each time an incoming request will have a content type like <br />
<ul>
<li><i>text/turtle</i></li>
<i>
</i>
<li><i>application/turtle</i></li>
<i>
</i>
<li><i>application/x-turtle</i></li>
<i>
</i>
<li><i>application/rdf+xml</i></li>
<i>
</i>
<li><i>application/rdf+json</i></li>
<i>
</i>
<li><i>application/ld+json</i></li>
<i>
</i>
<li><i>text/plain (for n-triple)</i></li>
<i>
</i>
<li><i>application/n-triples</i></li>
<li>(others) </li>
</ul>
Our <i>RdfDataLoader</i> will be in charge to parse and load the data. Note that the above list is not exhaustive, there a lot of other content types registered in Jena (See the <a href="https://jena.apache.org/documentation/javadoc/arq/org/apache/jena/riot/RDFLanguages.html" target="_blank"><i>RDFLanguages</i></a> class). <br />
<br />
So, what about the format of the data? Of course, it still depends on the content type of your RDF data, and most important, it has nothing to do with those data we used to send to Solr (i.e. <i>SolrInputDocuments</i> serialized in some format).<br />
<br />
The RdfDataLoader is a subclass of ContentStreamLoader <br />
<br />
<span style="font-size: x-small;"><b><span style="color: #741b47;">public class</span></b> RdfDataLoader <span style="color: #741b47;"><b>extends</b></span> ContentStreamLoader</span><br />
<br />
and, not surprisingly, it overrides the load() method:<br />
<br />
<span style="font-size: x-small;"><b><span style="color: #741b47;">public void</span></b> load()</span><br />
<span style="font-size: x-small;"> <span style="color: #741b47;"><b>final</b></span> SolrQueryRequest request, <br /> <span style="color: #741b47;"><b>final</b></span> SolrQueryResponse response,<br /> <span style="color: #741b47;"><b>final</b></span> ContentStream stream, <br /> <span style="color: #741b47;"><b>final</b></span> UpdateRequestProcessor processor) <span style="color: #741b47;"><b>throws</b></span> Exception {</span><br />
<br />
<span style="font-size: x-small;"> <span style="color: #741b47;"><b>final</b></span> PipedRDFIterator<Triple> iterator = <span style="color: #741b47;"><b>new</b></span> PipedRDFIterator<Triple>();<br /> <span style="color: #741b47;"><b>final</b></span> PipedRDFStream</span><span style="font-size: x-small;"><span style="font-size: x-small;"><</span>Triple> inputStream </span><span style="font-size: x-small;"> = <span style="color: #741b47;"><b>new</b></span> PipedTriplesStream(iterator); </span><br />
<span style="font-size: x-small;"><span style="color: #38761d;"> // We use an executor for running the parser in a separate thread</span><br /> <span style="color: #741b47;"><b>final</b></span> ExecutorService executor = Executors.newSingleThreadExecutor();</span><br />
<span style="font-size: x-small;"> <span style="color: #741b47;"><b>final</b></span> Runnable parser = new Runnable() {<br /> <b><span style="color: #741b47;">public</span></b> <b><span style="color: #741b47;">void</span></b> run() {<br /> <b><span style="color: #741b47;">try</span></b> {<br /> RDFDataMgr.parse(<br /> inputStream, <br /> stream.getStream(), <br /> RDFLanguages.contentTypeToLang(stream.getContentType()));<br /> } <b><span style="color: #741b47;">catch</span></b> (<span style="color: #741b47;"><b>final </b></span>IOException exception) {</span><br />
<span style="font-size: x-small;"> ... </span><br />
<span style="font-size: x-small;"> }<br /> }<br /> };</span><br />
<br />
<span style="font-size: x-small;"> executor.submit(parser);</span><br />
<span style="font-size: x-small;"> <b><span style="color: #741b47;">while</span></b> (iterator.hasNext()) {<span style="color: #741b47;"><b> </b></span></span><br />
<span style="color: #741b47; font-size: x-small;"><b> final</b></span><span style="font-size: x-small;"> Triple triple = iterator.next();</span><br />
<span style="font-size: x-small;"><span style="color: #38761d;"> // create and populate the Solr input document</span></span><br />
<span style="font-size: x-small;"> <span style="color: #741b47;"><b>final</b></span> SolrInputDocument document = <span style="color: #741b47;"><b>new</b></span> SolrInputDocument(); </span><br />
<span style="font-size: x-small;"> ...</span><br />
<span style="font-size: x-small;"> <span style="color: #38761d;"> // create the update command </span></span><br />
<span style="font-size: x-small;"> <span style="color: #741b47;"><b>final</b></span> AddUpdateCommand command = <span style="color: #741b47;"><b>new</b></span> AddUpdateCommand(request);</span><br />
<span style="font-size: x-small;"><span style="color: #38761d;"> // populate it with the input document we just created</span><br /> command.<span style="color: blue;">solrDoc</span> = document;</span><br />
<br />
<span style="font-size: x-small;"><span style="color: #38761d;"> // add the document to index</span><br /> processor.processAdd(command);</span><br />
<span style="font-size: x-small;"> } </span><br />
<span style="font-size: x-small;">}</span><br />
<br />
That's all...now, once the request handler has been registered within Solr (i.e. in solrconfig.xml), with a file containing RDF data in n-triples format, we can send to Solr a command like this:<br />
<br />
<span style="font-size: x-small;">> curl http://localhost:8080/solr/store/update -H <b>"Content-Type: application/n-triples"</b> --data-binary @/home/agazzarini/triples_dogfood.nt</span><br />
<br />
<br />Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-58708551317607037912014-11-10T08:38:00.001+01:002014-12-07T21:54:52.514+01:00Preloading data at Solr startupYesterday, I was explaining to a friend of mine something about Solr. So I had several cores with different configurations and some sample data.<br>
<br>
While switching between one example and another I just realized that each (first) time I had to load and index the sample data manually. That was good for the very first time, but after that, it was just a repetitive work. So I started looking for some helpful built-in thing...and I found it (at least I think): the SolrEventListeners<br>
<br>
SolrEventListener is an interface that defines a set of callbacks on several Solr lifecycle events:<br>
<ul>
<li><span style="font-size: x-small;"><b><span style="color: #4c1130;">void</span></b> postCommit()</span></li>
<li><span style="font-size: x-small;"><b><span style="color: #4c1130;">void</span></b> postSoftCommit()</span></li>
<li><span style="font-size: x-small;"><b><span style="color: #4c1130;">void</span></b> newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher currentSearcher)</span> </li>
</ul>
For this example, I'm not interested in the two first callbacks because the corresponding invocations will happen, as their name suggests, after hard and soft commit events.<br>
The interesting method is instead newSearcher(...) which allows me to register a custom event listener associated with two events:<br>
<ul>
<li>firstSearcher</li>
<li>newSearcher</li>
</ul>
In Solr, the Index Searcher which serves requests at a given time is called the current searcher. At startup time, there's no current searcher because the first one is created; hence we are in the "firstSearcher" event, which is exactly what I was looking for ;)<br>
<br>
When another (i.e new)
searcher is opened, it is prepared (i.e. auto-warmed) while the current one still serves the incoming requests. When the new searcher is ready, it will become the current
searcher, it will handle any new search requests, and the old searcher
will be closed (as soon as all requests it was servicing finish). This scenario is where the "newSearcher" callback is invoked.<br>
<br>
As you can see, the callback method for those two events is the same, there's no a "firstSearcher" and a "newSearcher" method. The difference resides in the input arguments: for "firstSearcher" events there's no a currentSearcher so the second argument is null; this is obviously not true for "newSearcher" callbacks where both first and second arguments contain a valid searcher reference.<br>
<br>
Returning to my scenario, all what I need is <br>
<ul>
<li>to declare that listener in solrconfig.xml</li>
<li>a concrete implementation of SolrEventListener</li>
</ul>
In solrconfig.xml, within the <i><udateHandler></i> section I can declare my listener<br>
<br><span style="font-size: x-small;"><listener <b><span style="color: #741b47;">event</span></b>=<span style="color: blue;">"firstSearcher"</span> <b><span style="color: #741b47;">class</span></b>=<span style="color: blue;">"a.b.c.SolrStartupListener"></span></span><br>
<span style="font-size: x-small;"> <str <b><span style="color: #741b47;">name</span></b>=<span style="color: blue;">"datafile"></span>${solr.solr.home}/sample/data.xml&lt;/str></span><br><span style="font-size: x-small;"></listener></span><br>
<br>
The listener will be initialized with just one parameter, the file that contains the sample data. Using the "event" attribute I can inform Solr about the kind of event I'm interested on (i.e firstSearcher).<br>
<br>
The implementation class is quite simple: it extends SolrEventListener:<br>
<br>
<b><span style="color: #741b47;">public class</span></b> SolrStartupListener <span style="color: #741b47;"><b>implements</b></span> SolrEventListener<br>
<br>
in the init(...) method it retrieves the input argument:<br>
<br>
<span style="color: #999999;">@Override</span><br>
<span style="color: #741b47;"><b>public void</b></span> init(<span style="color: #741b47;"><b>final</b></span> NamedList args) {<br>
<span style="color: #741b47;"><b>this.</b></span><span style="color: blue;">datafile</span> = (String) args.get(<span style="color: blue;">"datafile"</span>);<br>
}<br>
<br>
last, the newSearcher method preloads the data:<br>
<br>
LocalSolrQueryRequest request = null;<br>
<b><span style="color: #741b47;">try</span></b> {<br>
<span style="color: #38761d;">// 1. Create the arguments map for the update request</span><br>
<span style="color: #741b47;"><b>final</b></span> NamedList<string> args = new SimpleOrderedMap<string>();<br> args.add(</string></string><br>
<string><string> UpdateParams.<span style="color: blue;">ASSUME_CONTENT_TYPE</span>, <span style="color: blue;"> </span></string></string><br>
<string><string><span style="color: blue;"> "text/xml"</span>);<br> addEventParms(currentSearcher, args);<br><br> <span style="color: #38761d;">// 2. Create a new Solr (update) request</span><br> request = <span style="color: #741b47;"><b>new</b></span> LocalSolrQueryRequest(</string></string><br>
<string><string> newSearcher.getCore(), </string></string><br>
<string><string> args);<br> <br> <span style="color: #38761d;">// 3. Fill the request with the (datafile) input stream</span><br> </string></string><string><string><span style="color: #741b47;"><b>final</b></span> List<contentstream> streams = <b><span style="color: #741b47;">new</span></b> ArrayList<contentstream>();<br> streams.add(<b><span style="color: #741b47;">new</span></b> ContentStreamBase() {<br> <span style="color: #999999;"> @Override</span><br> <span style="color: #741b47;"><b>public</b></span> InputStream getStream() <span style="color: #741b47;"><b>throws</b></span> IOException {<br> <span style="color: #741b47;"><b>return new</b></span> FileInputStream(<span style="color: blue;">datafile</span>);<br> }<br> });<br> <br> request.setContentStreams(streams);<br> <br> <span style="color: #38761d;">// 4. Creates a new Solr response</span><br> </contentstream></contentstream></string></string><string><string><contentstream><contentstream><span style="color: #741b47;"><b>final</b></span> SolrQueryResponse response = </contentstream></contentstream></string></string><br>
<string><string><contentstream><contentstream><span style="color: #741b47;"><b> new</b></span> SolrQueryResponse();<br> <br> <span style="color: #38761d;">// 5. And finally call invoke the update handler</span><br> SolrRequestInfo.setRequestInfo(<span style="color: #741b47;"><b> </b></span></contentstream></contentstream></string></string><br>
<string><string><contentstream><contentstream><span style="color: #741b47;"><b> new</b></span> SolrRequestInfo(request, response))</contentstream></contentstream></string></string><br>
<br>
<string><string><contentstream><contentstream> newSearcher</contentstream></contentstream></string></string><br>
<string><string><contentstream><contentstream> .getCore()</contentstream></contentstream></string></string><br>
<string><string><contentstream><contentstream> .getRequestHandler(<span style="color: blue;">"/update"</span>)</contentstream></contentstream></string></string><br>
<string><string><contentstream><contentstream> .handleRequest(request, response); </contentstream></contentstream></string></string><br>
<string><string><contentstream><contentstream> <br> } <b><span style="color: #741b47;">finally</span></b> {<br> request.close();<br> }</contentstream></contentstream></string></string><br>
<br>
<string><string><contentstream><contentstream>Et voilà , if you start Solr you will see sample data loaded. Other than avoiding me a lot of repetitive tasks, this could be useful when you're using a SolrCore as a NoSql storage, like for example if you are storing SKOS vocabularies for synonyns, translations and broader / narrower searches. </contentstream></contentstream></string></string>Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-90228644268179470962014-10-23T19:44:00.001+02:002014-10-23T19:45:26.689+02:00SPARQL Integration tests with jena-nosqlIn a <a href="http://andreagazzarini.blogspot.it/2014/09/integration-tests-with-jena-nosql-and.html" target="_blank">previous post</a> I illustrated how to set up a working environment<span class="orm"> with <a href="https://github.com/agazzarini/jena-nosql" target="_blank">jena-nosql</a> using either <a href="http://lucene.apache.org/solr/" target="_blank">Apache Solr</a> or <a href="http://cassandra.apache.org/" target="_blank">Apache Cassandra</a>. Now it's time to write some integration tests. </span><br />
<br />
<span class="orm">The goal of the <a href="https://github.com/agazzarini/jena-nosql" target="_blank">jena-nosql</a></span> project is to have <a href="http://jena.apache.org/" target="_blank">Apache Jena</a>, one of the most popular RDF frameworks, bound with your favourite NoSQL database.<br />
<br />
Among a lot of things that Jena can do, SPARQL definitely plays an important role so, in my project, I want to make sure the data model of the underlying pluggable storages is able to efficiently support all the query language features.<br />
<br />
As a first step I need an integration test for running SPARQL verifiable examples. In order to do that I will set up two Jena Models, in the @Before method: a first coming from jena-nosql:<br />
<br />
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> StorageLayerFactory factory = StorageLayerFactory.getFactory();</span><br />
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> Dataset dataset = DatasetFactory.create(factory.getDatasetGraph()); </span><br />
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> Model jenaNoSqlModel = dataset.getDefaultModel(); </span><br />
<br />
and a second using the default in-memory Jena Model:<br />
<br />
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> Model inMemoryModel = DatasetFactory.createMem().getDefaultModel(); </span><br />
<br />
Now what I need is a set of verifiable scenarios, each of one consisting of<br />
<ul>
<li>one or more dataset to load </li>
<li>a query</li>
<li>the corresponding query results</li>
</ul>
I would need this "triplet" for each scenario...and as you can imagine, that's a huge work!<br />
<br />
Fortunately, some time ago I bought a cool book, <a href="http://www.learningsparql.com/" target="_blank">"Learning SPARQL"</a> which had a lot of downloadable examples. After re-having a quick look, I realized that was exactly what I need :)<br />
<br />
Each example in the book is associated with three files:<br />
<ul>
<li>a file containing a short dataset</li>
<li>a file containing a query </li>
<li>a file containing results in a human readable way</li>
</ul>
Perfect! I don't need the third file because the verification can be done by comparating the execution of the load / query sequence both in jena-nosql and in-memory model (assuming the Jena in memory model is perfectly working)<br />
<br />
So before running each scenario both models are loaded with the example dataset:<br />
<br />
<span style="font-size: x-small;">jenaNoSqlModel.read(dataset, ...); </span><br />
<span style="font-size: x-small;"><span style="font-size: x-small;">inMemoryModel.read(dataset, ...); </span> </span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;"><span style="color: #38761d;">// Make sure data has been loaded and graphs are isomorphic</span></span><br />
<span style="font-size: x-small;">assertFalse(</span><span style="font-size: x-small;">jenaNoSqlModel.isEmpty());</span><br />
<span style="font-size: x-small;">assertTrue(</span><span style="font-size: x-small;">jenaNoSqlModel.isIsomorphicWith(inMemoryModel));</span><br />
<br />
Once did that, it's time to execute the query associated with the example and then verify the results on both models:<br />
<br />
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> Query query = QueryFactory.create(readQueryFromFile(queryFile));</span><br />
<span style="font-size: x-small;">assertTrue(</span><span style="font-size: x-small;"> ResultSetCompare.isomorphic(</span><br />
<span style="font-size: x-small;"> QueryExecutionFactory.create(query, </span><span style="font-size: x-small;">jenaNoSqlModel).execSelect(),</span><br />
<span style="font-size: x-small;"> QueryExecutionFactory.create(query, inMemory</span><span style="font-size: x-small;">Model).execSelect());</span><br />
<br />
For simplicity here I'm <u>wrongly</u> using jena resources like QueryExecution (you should close that in a <i>finally</i> block) and I didn't write any exception handling code.<br />
<br />
I'm still working on that, but if you want to have a quick look <a href="https://github.com/agazzarini/jena-nosql/blob/master/jena-nosql-integration-tests/src/test/java/org/gazzax/labs/jena/nosql/fwk/learningSPARQL/LearningSparql_ITCase.java" target="_blank">here</a>'s the code. As explained in previous posts you can run this test against one of the available storages (Solr or Cassandra):<br />
<br />
<pre><code> </code><code><code>></code> mvn clean install -P <b>cassandra</b>-2x </code></pre>
<pre><code> </code><code><code>></code> mvn clean install -P <b>solr</b>-4x </code></pre>
<br />Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-66665297491506398912014-09-06T15:15:00.001+02:002014-09-06T16:38:53.996+02:00Integration tests with jena-nosql and SolrThe main goal of the <a href="https://github.com/agazzarini/jena-nosql" target="_blank">jena-nosql</a> project is to have a framework for building a set of noSQL storage bindings for Apache Jena.<br>
<br>
So the idea is that using a piece of code like this<br>
<br>
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> StorageLayerFactory factory = StorageLayerFactory.getFactory();</span><br>
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> Dataset dataset = DatasetFactory.create(factory.getDatasetGraph()); </span><br>
<span style="font-size: x-small;"></span><span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> Model model = dataset.getDefaultModel().read(...); </span><br>
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> Query query = QueryFactory.create(...);</span><br>
<span style="font-size: x-small;"><b><span style="color: #741b47;">final</span></b> ResultSet resultset = QueryExecutionFactory.create(query, dataset)).execSelect();</span> <div><span style="font-size: x-small;">factory.getClientShutdownHook().close();</span><br>
<br>
I'd be able to insert and query some data using Jena API.<br>
But where? That actually depends on the binding we choose. At the moment, in order to "test" the framework idea I created two modules: one for Cassandra and the other for Solr.<br>
<br>
As you can see in the project there's a module for doing <a href="https://github.com/agazzarini/jena-nosql/tree/master/jena-nosql-integration-tests" target="_blank">integration tests</a>. There, I had to think, before running those tests, some way to start one storage or another in a transparent way. <br>
<br>
As you probably know, if you read some other post of mine, I am a big fan of Apache Maven, and I must say that in these situations it is a very great and productive tool.<br>
<br>
In the <a href="http://andreagazzarini.blogspot.it/2014/08/integration-tests-with-jena-nosql-and.html" target="_blank">previous post</a> I (briefly) explained how to start the integration test suite with a backing Apache Cassandra. Here I'll do the same but using Apache Solr.<br>
<br>
There isn't an official Maven plug-in for Solr, this is the main difference with Cassandra. So after googling a bit I decided to use Cargo.<br>
<br>
Cargo has a nice and powerful Maven plug-in that I configured within a <b>solr-4x</b> profile in my pom.xml. Doing so I'm able to run<br>
<br>
<pre><code> > mvn clean install -P solr-4x </code></pre>
<br>
The very first time you run this command, Maven, as usual, will download all required dependencies including the solr war. Once did that, it will <br>
<ul>
<li>start an embedded Jetty instance with Solr deployed inside;</li>
<li>run the integration test suite;</li>
<li>stop Jetty </li>
</ul>
<div class="singleline" id="gollum-editor-edit-summary">
<label class="jaws" for="wiki_commit"></label>So, at the end, running the same test suite against one storage or another, it is just a matter of using a different Maven profile in the build ;)</div>
</div>Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-25904221553117428742014-08-21T17:02:00.001+02:002014-09-06T14:26:00.782+02:00Integration tests with jena-nosql and CassandraIn this post I will illustrate the integration tests infrastructure I used for the <a href="https://github.com/agazzarini/jena-nosql" target="_blank">jena-nosql</a> project on my GitHub account.<br />
<br />
This article has been "copied" from the project Wiki, you can find the original content <a href="https://github.com/agazzarini/jena-nosql/wiki/Dev_Guide#integration-tests" target="_blank">here</a>.<br />
<br />
The core of the project itself is not associated with a specific storage, so a set of
integration tests that run towards a (mini)instance of a not-well-known target
storage is required in order to make sure about the functional
correctness of each binding.<br />
<br />
Within the project you can see a (Maven) module dedicated to integration
tests: the <a href="https://github.com/agazzarini/jena-nosql/tree/master/jena-nosql-integration-tests" target="_blank">jena-nosql-integration-tests</a>. It is configured with
the Maven Failsafe plugin [1] to run tests, during the integration-test
phase, against a running instance of the target storage.<br />
<br />
And here comes the beauty, because the target storage is not predefined,
but instead depends on what is the runtime binding module that has been choosen. So basically
the same set of integration tests could be run against Cassandra,
HBase, Accumulo or another storage.<br />
<br />
How can we maintain the same set of
tests and at the same time start a test instance of one storage or
another? Maven profiles is the answer (at least for me): within the
<a href="http://pom.xml/">pom.xml</a> of the <a href="https://github.com/agazzarini/jena-nosql/tree/master/jena-nosql-integration-tests" target="_blank">jena-nosql-integration-tests</a>, I defined one profile for
each storage (at the time of writing there's just one profile ;) ).<br />
<br />
So for example the <b>cassandra-2x</b> profile declares the usage of the
Cassandra Maven Plugin [2] that <br />
<ul class="task-list">
<li>starts an embedded instance of Cassandra <b>before</b> all integration tests</li>
<li>stops that instance <b>after</b> the last integration test</li>
</ul>
So, at the end, if you want to run the integration test suite
against Cassandra, just cd to jena-nosql project directory (where the top level
pom.xml is located) and run Maven as follows:<br />
<br />
<pre><code> > mvn clean install -P cassandra-2x </code></pre>
<pre><code> </code></pre>
You don't need to set any permission or any configuration because the
embedded instance will "live" within the target build folder.<br />
<br />
[1] <a href="http://maven.apache.org/surefire/maven-failsafe-plugin">http://maven.apache.org/surefire/maven-failsafe-plugin</a><br />
[2] <a href="http://mojo.codehaus.org/cassandra-maven-plugin">http://mojo.codehaus.org/cassandra-maven-plugin</a> <br />
<div class="suggester-container">
</div>
<div class="singleline" id="gollum-editor-edit-summary">
</div>
<div class="form-actions">
</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-876214396116753602014-08-18T13:38:00.001+02:002014-08-21T15:25:51.647+02:00Jena-nosql: A NoSQL adapter for Apache Jena<div dir="ltr">
Few days ago I started this project on github. </div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
<a href="https://github.com/agazzarini/jena-nosql">https://github.com/agazzarini/jena-nosql</a></div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
The overall design rounds around the <i>Abstract Factory</i> design pattern [1].<br />
As you can see from the following diagram, the <i>StorageLayerFactory</i> class plays the role of the <i>AbstractFactory</i>
and therefore defines the contract that each concrete implementor (i.e.
family) must provide in order to create concrete products for a
specific kind of storage. </div>
<div dir="ltr">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/agazzarini/jena-nosql/wiki/images/AbstractFactory.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="117" src="https://github.com/agazzarini/jena-nosql/wiki/images/AbstractFactory.png" width="320" /></a></div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
<br /></div>
On top of that, each binding module defines the "concrete" layer that is in charge to provide<br />
<ul class="task-list">
<li>an implementation of the StorageLayerFactory (i.e. the Concrete Factory);</li>
<li>a concrete implementation of each (abstract) product defined in the diagram below (i.e. the Concrete Products)</li>
</ul>
Here you can see the same diagram as above but with the
"Cassandra" family members (note that only 4 members are shown in order
to simplify the diagram) <br />
<div dir="ltr">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/agazzarini/jena-nosql/wiki/images/CassandraAbstractFactory.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="144" src="https://github.com/agazzarini/jena-nosql/wiki/images/CassandraAbstractFactory.png" width="320" /></a></div>
<div dir="ltr">
</div>
<div dir="ltr">
Feel free to take a look and let me know your thoughts.</div>
<div dir="ltr">
Gazza</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-90963492736073069022011-03-14T07:31:00.001+01:002012-02-04T20:04:14.021+01:00SOLR: implementing an "Exact Match" BATH profile compliant field<div xmlns="http://www.w3.org/1999/xhtml">
If you want to expose a Z3950 interface for your IR probably sooner or later you will meet the BATH profile, which is basically a set of rules that promotes standards behaviours between Z3950 servers.<br />
Aims of those specification is to determine a list of searches (fields, attributes) that should be supported by a Z3950 server endpoint.<br />
I won't discuss in this article about how to set up a Z3950 endpoint using SOLR behind the scenes because there are a lot of places where you can find such information.<br />
Instead, I will write down a brief note about the so-called "Exact Match" search, which is one of the most interesting part of the story...<br />
Just to directly go to the problem. The following are the specification of the "Exact Match" search:<br />
<ul>
<li><strong>Position</strong>: first in field</li>
<li><strong>Truncation</strong>: do not truncate</li>
<li><strong>Completeness</strong>: complete field</li>
<li><strong>Structure</strong>: phrase</li>
</ul>
This is a pretty simple scenario with a little issue / question (that after this reading could be still open because what are you reading is just my interpretation of the story, not the absolute truth). In general the definition is quite clear: <br />
<ol>
<li>you (as server endpoint) must search within the given index assuming that the match should be done keeping in mind that the user entered terms (i.e. search string) must be considered as a starting value (first in field). </li>
<li>the user entered terms are supposed to be "complete words" (do no truncate)</li>
<li>what the user entered is a complete field (e.g a complete title or author name)</li>
</ol>
So if in our index there's a document with <span style="color: #000099;"><em>Alessandro Manzoni</em></span> as author, an exact match query will find this document only and only if user entered values are <br />
<span style="color: #000099;"><em>Alessandro Manzoni, alessandro manzoni</em></span><span style="color: #000099;"> </span>(assuming a minimal text analysis is done with lowercasing)<br />
for example the following queries won't match that document: <br />
<span style="color: #000099;"><em>manzoni alessandro, Manzoni alessandro</em></span><br />
because proximity search is not mentioned in the specification (ok, it's useful in real life but that's another story)<br />
Another type of text analysis that, in my opinion, could be applied without violating the specification, is removing intra-word delimiters. Lets do an example. If I have<br />
<span style="color: #000099;"><em>Manzoni, Alessandro.</em></span><br />
It's hard to imagine that a user will be able to do an exact match query by tiping exactly what is written in the index. Instead I think should be better (both at index and query time) remove the intra-word delimiters (including trailing punctuation) and make life easier...in this way these queries:<br />
<span style="color: #000099;"><em>manzoni alessandro, manzoni,alessandro., manzoni alessandro..,manzoni.alessandro,</em></span><br />
will find this document. So what are the appropriate manipulation that a SOLR field needs in order to accomodate that "Exact Match" requirement?<br />
If I should strictly adhere to bath requirements, my field should be a simple string like this:<br />
<span style="color: #000099;"><field name</span>=<span style="color: #660000;">"author"</span> <span style="color: #000099;">type</span>=<span style="color: #660000;">"string"</span> <span style="color: #000099;">indexed</span>=<span style="color: #660000;">"true"</span><span style="color: #000099;">/></span><br />
<span style="color: black;">but referring to the last example, only a search for </span><br />
<span style="color: #000099;"><em>Manzoni, Alessandro. </em></span><span style="color: black;">(with exact punctuation)</span><br />
will match the corresponding document, and that's not exactly what we want.<br />
Another approach would be to assign a solr.TextField type to our field. On top of that lowercase and tokenizer filter will do the remaining part. Let's take another example. This time the author is<br />
<span style="color: #000099;">Contessa Serbelloni Mazzanti Viendalmare</span><br />
<span style="color: black;">Following the mentioned approach this input value will be transformed in this way:</span><br />
<div dir="ltr">
<span style="color: #660000; font-size: small;"><em>Contessa Serbelloni Mazzanti Viendalmare</em></span><span style="color: #660000; font-size: small;"> </span><span style="color: black; font-size: small;">(original)</span></div>
<span style="color: #660000; font-size: small;"><em>contessa serbelloni mazzanti viendalmare</em></span><span style="color: #660000; font-size: small;"> </span><span style="color: black; font-size: small;">(lowercase)</span><br />
<span style="color: #660000; font-size: small;"><em>contessa, serbelloni, mazzanti, viendalmare </em></span><span style="color: black; font-size: small;">(word tokenizer)</span><br />
<span style="color: black;">If a user enter the following query</span><br />
<span style="color: #000099;">"</span><span style="color: #000099;"><em>contessa Serbelloni MAZZANTI viendalmare</em></span><span style="color: #000099;">"</span><br />
<span style="color: black;">a match will be found. Now, the reason why this is not sufficient for our bath profile compliant can be found in the specification of the "Exact Match" search</span><br />
<ul>
<li dir="ltr"><strong>Position</strong>: <u>first in field</u></li>
<li dir="ltr"><strong>Truncation</strong>: do not truncate</li>
<li dir="ltr"><strong>Completeness</strong>: <u>complete field</u></li>
<li dir="ltr"><strong>Structure</strong>: <u>phrase</u></li>
</ul>
First in field means that, in order to match a document, the indexed field must contains user entered terms (with the given order because is a "phrase" search) in the first position. In addition, complete field means that what the user entered is supposed to be the complete value of the target field. So, the indexing approach followed above will violate these two preconditions. How? Here it is: if the user enter the following:<br />
<span style="color: #000099;">"</span><span style="color: #000099;"><em>MAZZANTI viendalmare</em></span><span style="color: #000099;">"</span><br />
a match with the same document will still be found because terms are in the target indexed field with the given order. But they aren't at the start of the field and they don't represent the whole literal value. So, even if a little bit better, this approach don't work.<br />
<br />
Briefly, here what I did in order to satisty the "Exact Match" requirement. Both at index and query time, starting with <br />
<span style="color: #000099;"><em><br /></em></span><br />
<span style="color: #000099;"><em>Contessa Serbèlloni, Mazzà nti Viendalmarè.</em></span><br />
<br />
<h2>
<span style="color: black; font-size: small;">a) Keyword Tokenizer</span></h2>
<span style="color: black;">At this time I don't want to tokenize my input value so this filter basically does nothing, leaving the value as is (treating the whole string as a single token).</span><br />
<h2>
<span style="color: black; font-size: small;">b) Lowercase</span></h2>
<span style="color: black;">As mentioned above, this is the first filter that we will apply. That will result in the following transformation:</span><br />
<span style="color: #000099;"><em>contessa serbèlloni, mazzà nti viendalmarè.</em></span><br />
<h2>
<span style="color: black; font-size: small;">c) Diacritics replacement</span></h2>
<span style="color: black;">Another important normalization that we will apply is a diacritic replacement, both at index and query time. This will ensure that a value like:</span><br />
<span style="color: #000099;"><em>à ndréà gà zzarìnì </em></span><span style="color: black;">it will be replaced with </span><span style="color: #000099;"><em>andrea gazzarini. </em></span><span style="color: black;">In our example:</span><br />
<span style="color: #000099;"><em>contessa serbelloni, mazzanti viendalmare.</em></span><br />
<h2>
<span style="color: black; font-size: small;">d) Intra-word delimiter removal</span></h2>
<span style="color: black;">As briefly mentioned above, this latter filter will remove the intra-world delimiter, including spaces. Note,because this is the important thing, that after applying this filter, I'm not splitting the original input value in several tokens: the tokens is always 1 and will be:</span><br />
<span style="color: #000099;"><em>contessaserbellonimazzantiviendalmare</em></span><br />
<span style="color: black;">That's all. As last note remember that the described chain should be applied both at index and query time. So running some examples will find that the requirements is fully satisfied.</span><br />
<ul>
<li><span style="color: black;">Searching </span><span style="color: #000099;"><em>Contessa serbelloni mazzanti viendalmare</em></span><span style="color: black;"> will produce 1 result;</span></li>
<li><span style="color: black;">Searching </span><span style="color: #000099;"><em>serbelloni mazzanti </em></span><span style="color: black;">will produce no result;</span></li>
<li dir="ltr"><span style="color: black;">Searching </span><span style="color: #000099;"><em>Contessa serbelloni mazzanti </em></span><span style="color: black;">will produce no result;</span></li>
<li dir="ltr"><span style="color: black;">Searching </span><span style="color: #000099;"><em>Contessa serbel loni maz zanti vien dal mare</em></span><span style="color: black;"> will produce 1 result; ok, this could be intended as a violation and I agree with you...I'm thinking about that...in the meantime lets say that this "bug" is very useful because (the searcher) you couldn't know how the author name is exactly written;</span></li>
</ul>
<span style="color: black;">Your comments will be very appreciated and of course, if you have some suggestions, enhancements, give me a shout.</span><br />
<span style="color: black;"><em>Gazza</em></span><br />
<img height="1" src="https://blogger.googleusercontent.com/tracker/1588390580596352744-9096349273607306902?l=andreagazzarini.blogspot.com" width="1" /></div>Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com1tag:blogger.com,1999:blog-1588390580596352744.post-46179134891676884562009-12-25T08:13:00.000+01:002011-09-10T08:19:36.515+02:00Implementing a Diameter Peer State Machine using Test Driven Development (Part 3).Just a brief riepilogue of what are the missing points :<br />
<br />
- When a peer is in "Closed" state and receives a START signal it must<br />
<ol>
<li>take a I-Snd-Conn-Req action : <span style="font-weight: bold;">this is currently a missing point;</span></li>
<li>change its state to Wait-Conn-Ack : we did that in the last episode :)</li>
</ol>
- When a peer is in "Closed" state and receives a R-Conn-CER signal it must :<br />
<ol>
<li>take the following 3 actions : R-Accept, Process-CER and R-Snd-CEA.</li>
<li>change its state to R-Open.</li>
</ol>
So, concerning this episode, we are going to add the behaviour requested by the R-Conn-CER signal, leaving out for the moment all what is concerning actions. That means we will concentrate only on state transistion.<br />
<br />
Following the same approach we used for the "Start" signal, we can write another test method :<br />
<br />
<span style="color: #990000;"><span style="font-weight: bold;"><span style="color: #660000;">public class</span></span><span style="color: #660000;"> </span></span>PeerStateMachineTestCase<br />
{<br />
<span style="color: white;">....</span><span style="color: #999999;">@Test</span><br />
<span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">public </span>void rConnCerSignal()<br />
<span style="color: white;">...</span>{<br />
<span style="color: white;">......</span>Peer peer = <span style="color: #660000; font-weight: bold;">new</span> Peer();<br />
<span style="color: white;">......</span>peer.signal(PeerEventType.<span style="color: #000099;">R_CONN_CER</span>);<br />
<br />
<span style="color: #ffcccc;">......</span><span style="font-style: italic;">assertTrue</span>(peer.currentStateIs(peer.<span style="color: #000099;">R_OPEN</span>);<br />
<span style="color: white;">...</span>}<br />
}<br />
<br />
PeerEventType.R_CONN_CER is not giving any compiler warning because we already added it in the first part.<br />
What is really missing(from a compiler perspective) is a R_OPEN member instance on Peer class:<br />
<br />
<span style="color: #660000; font-weight: bold;">public class</span> Peer<br />
{<br />
<span style="color: #660000; font-weight: bold;"> </span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">final</span> State <span style="color: #000099;">CLOSED</span> = <span style="color: #660000; font-weight: bold;">new </span>State(){};<br />
<span style="color: #660000; font-weight: bold;"> </span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">final</span> State <span style="color: #000099;">WAIT_CONN_ACK</span> = <span style="color: #660000; font-weight: bold;">new </span>State(){};<span style="color: #660000;"><br /></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">final</span> State <span style="color: #000099;">R_OPEN</span> = <span style="color: #660000; font-weight: bold;">new </span>State(){};<span style="color: #660000;"></span><br />
...<br />
...<br />
}<br />
<br />
Now our test compiles fine but it gives us a red bar: after PeerEventType.<span style="color: #000099;">R_CONN_CER <span style="color: black;">signal</span></span> has been received peer is not (as expected) in R_OPEN state but in WAIT_CONN_ACK :(<br />
This is reasonable if we remember the Peer.signal(...) implementation we did last time :<br />
<br />
<span style="color: #660000; font-weight: bold;">public</span> void signal(PeerEventType type)<br />
{<br />
<span style="color: #000099;"><span style="color: white;">....</span>currentState</span> = <span style="color: #000099;">WAIT_CONN_ACK</span>;<br />
}<br />
<br />
With the new R_CONN_CER signal this implementation is not working anymore so we need to rewrite the method in order to let the peer properly react to a given signal. The most obvious solution could be :<br />
<br />
<span style="color: #660000; font-weight: bold;">public</span> void signal(PeerEventType type)<br />
{<br />
<span style="color: #000099;"><span style="color: white;">....</span><span style="color: black;"><span style="color: #660000; font-weight: bold;">if</span> </span></span>(<span style="color: #000099;">currentState</span> == CLOSED)<br />
<span style="color: #000099;"><span style="color: white;">....<span style="color: black;">{</span></span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: #000099;"><span style="color: black;"><span style="color: #660000; font-weight: bold;">if</span> </span></span>(type == START)<br />
<span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: black;">{</span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....</span><span style="color: black;"><span style="color: #660000; font-weight: bold;"></span></span></span><span style="color: #000099;">currentState</span> = <span style="color: #000099;">WAIT_CONN_ACK</span>;<br />
<span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....<span style="color: black;">}</span></span></span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: black;"></span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: #000099;"><span style="color: white;"><span style="color: black;"><span style="color: #660000; font-weight: bold;"><br /></span></span></span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....<span style="color: black;"></span></span></span><span style="color: #000099;"><span style="color: white;"><span style="color: black;"><span style="color: #660000; font-weight: bold;">else</span> <span style="color: #660000; font-weight: bold;">if</span><span style="color: #660000;"> <span style="color: black;">(type</span></span> </span></span></span>== R_CONN_CER)<br />
<span style="color: #000099;"><span style="color: white;"></span></span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: black;">{</span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....</span><span style="color: black;"><span style="color: #660000; font-weight: bold;"></span></span></span><span style="color: #000099;">currentState</span> = <span style="color: #000099;">R_OPEN;</span><br />
<span style="color: #000099;"><span style="color: white;">....</span></span><span style="color: #000099;"><span style="color: white;">....<span style="color: black;">}</span></span></span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: black;"></span><span style="color: #000099;"><span style="color: white;"></span></span><span style="color: #000099;"><span style="color: white;"><span style="color: black;"><span style="color: #660000; font-weight: bold;"> </span></span></span></span><br />
<span style="color: #000099;"><span style="color: white;">....<span style="color: black;">} <span style="color: #660000; font-weight: bold;"></span></span></span></span><span style="color: #000099;"><span style="color: white;"></span></span><br />
}<br />
<br />
Without any doubt it's working but<br />
<ol>
<li>If you have a look at the state machine table defined on RFC 3588 you'll quickly realize that this approach will result in a looot of "if / else if" statements;</li>
<li>personally I believe that the transition state is something related with the state itself, while in the implementation above we made that part of the Peer logic.</li>
</ol>
In addition, each time a new state needs to be added you must :<br />
<ol>
<li>Add a new state member instance;</li>
<li>Modify the signal method.</li>
</ol>
What I'm trying to suggest is the following : if<br />
<ol>
<li>we already have something that tell us what is the current state;</li>
<li>that thing is an object (an instance of State)</li>
<li>obviously that object could have its own state and methods;</li>
</ol>
Why don't we put the state transition logic within the each State? With this approach we need to modify a little bit the State interface introduced in part one adding a new method and a new exception :<br />
<br />
<span style="font-style: italic;">(Interface State)</span><br />
<span class="Apple-tab-span" style="white-space: pre;"></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">void </span></span>signal(PeerEventType eventType) <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">throws </span></span>WrongEventException;<br />
<br />
Now each instance of State must implements this method which is supposed to<br />
<ol>
<li>Change the state of the hosting Peer instance (remember that our State instances are inner classes);</li>
<li>Raise an exception if a wrong (not allowed) signal is received;</li>
</ol>
So for example, the inner CLOSED State instance will do something like that :<br />
<br />
<span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">final</span> State <span style="color: #000099;">CLOSED</span> = <span style="color: #660000; font-weight: bold;">new </span>State()<br />
<span style="color: white;">....</span><span style="color: #660000; font-weight: bold;"></span>{<br />
<span style="color: white;">....</span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void </span></span>signal(PeerEventType eventType) <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">throws </span></span>WrongEventException<br />
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"></span></span><span style="color: white;">....</span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span">{</span></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">switch</span> (eventType)<br />
<span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;">{</span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">case</span> <span style="color: #000099;">START</span> :<br />
<span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;">{</span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....</span><span style="color: #000099; font-weight: bold;"></span><span style="color: white;"><span style="color: black;"><span style="color: #000099;">currentState</span> = <span style="color: #000099;">WAIT_CONN_ACK</span>;</span></span><br />
<span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;"></span><span style="color: white;"><span style="color: black;"><span style="color: #660000; font-weight: bold;">break</span>;</span></span><br />
<span style="color: white;"></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;">}</span></span><br />
<span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">case</span> <span style="color: #000099;">R_CONN_CER</span> :<br />
<span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;">{</span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....</span><span style="color: #000099; font-weight: bold;"></span><span style="color: white;"><span style="color: black;"><span style="color: #000099;">currentState</span> = <span style="color: #000099;">R_OPEN</span>;</span></span><br />
<span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;"></span><span style="color: white;"><span style="color: black;"><span style="color: #660000; font-weight: bold;">break</span>;</span></span><br />
<span style="color: white;"></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;">}</span></span><br />
<span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;">default</span> :<br />
<span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;">{</span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;"></span><span style="color: white;"><span style="color: black;"><span style="color: #000099;"><span style="color: #660000; font-weight: bold;">throw new </span></span></span></span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"></span></span>WrongEventException(<span style="color: #000099;">"Some useful message"</span>)<span style="color: white;"><span style="color: black;"><span style="color: #000099;"></span>;</span></span><span style="color: white;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"><span style="color: black;"></span></span><span style="color: white;"><span style="color: black;"></span></span><span style="color: white;"></span><span style="color: white;"><span style="color: black;"><span style="color: #660000; font-weight: bold;"></span></span></span><br />
<span style="color: white;"></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;"></span></span><span style="color: white;">....<span style="color: black;">}</span></span><br />
<span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....<span style="color: black;">}</span></span><br />
<span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"></span></span><span style="color: white;"></span><span style="color: white;">....</span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span">}</span></span><span style="color: white;"></span><span style="color: #660000; font-weight: bold;"></span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span"></span></span><span style="color: white;">....</span><span style="color: #660000; font-weight: bold;"></span>};<br />
<br />
Of course, in order to get things working as expected, we need to modify the Peer.signal method :<br />
<br />
<span style="color: #660000; font-weight: bold;">public</span> void signal(PeerEventType type) <span style="color: #660000; font-weight: bold;">throws</span> WrongEventTypeException<br />
{<br />
<span style="color: white;">....</span><span style="color: #000099;">currentState</span>.signal(type);<br />
}<br />
<br />
Now our 2 test methods should correctly work.<br />
<br />
See you soon for the last part :)<br />
<br />
Ciao<br />
AndreaAndreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-57245273868617114602009-10-23T17:58:00.006+02:002011-09-10T08:18:44.503+02:00Implementing a Diameter Peer State Machine using Test Driven Development (Part 2).So, next step is to test what happens if (following the state machine picture on the previous post) a START signal is sent to our peer.<br />
According with RFC 3588 specification, if a peer, that is in CLOSED state, successfully processes the START signal two things happen:<br />
<ul>
<li>the peer must take a "I-Snd-Conn-Req" action;</li>
<li>a state transition occurs : the peer passes from CLOSED to WAIT-CONN_ACK state;</li>
</ul>
In this article we will take care about the second point.<br />
Well, returning to our test case, we have to add another <span style="color: #666666;">@Test</span> method :<br />
<br />
<span style="color: #990000;"><span style="font-weight: bold;"><span style="color: #660000;">public class</span></span><span style="color: #660000;"> </span></span>PeerStateMachineTestCase<br />
{<br />
<br />
<span style="color: #999999;">....@Test</span><br />
....<span style="color: #660000; font-weight: bold;">public </span>void startSignal()<br />
....{<br />
.......Peer peer = <span style="color: #660000; font-weight: bold;">new</span> Peer();<br />
.......peer.signal(PeerEventType.<span style="color: #000099; font-style: italic;">START</span>);<br />
<br />
.......<span style="font-style: italic;">assertTrue</span>(peer.currentStateIs(peer.<span style="color: #000099;">WAIT_CONN_ACK</span>);<br />
....}<br />
}<br />
<br />
Obviously, this test method doesn't compile : we don't have a signal() method and a WAIT_CONN_ACK member variable on our Peer class.<br />
So first of all we will insert the missing method :<br />
<br />
<span style="color: #660000; font-weight: bold;">public void </span>signal(PeerEventType eventType)<br />
{<br />
}<br />
<br />
after that, Peer class needs a new State instance member :<br />
<br />
<span style="color: #660000; font-weight: bold;">final</span> State <span style="color: #000099;">WAIT_CONN_ACK</span> = <span style="color: #660000; font-weight: bold;">new </span>State(){};<br />
<br />
This is how our Peer class behaves :<br />
<br />
<span style="color: #660000; font-weight: bold;">public class</span> Peer<br />
{<br />
<span style="color: #660000; font-weight: bold;"> </span><span style="color: #660000;">....</span><span style="color: #660000; font-weight: bold;">final</span> State <span style="color: #000099;">CLOSED</span> = <span style="color: #660000; font-weight: bold;">new </span>State(){};<br />
<span style="color: #660000; font-weight: bold;"> </span><span style="color: #660000;">....</span><span style="color: #660000; font-weight: bold;">final</span> State <span style="color: #000099;">WAIT_CONN_ACK</span> = <span style="color: #660000; font-weight: bold;">new </span>State(){};<br />
<br />
<span style="color: #660000;">....</span><span style="color: #660000; font-weight: bold;">public void </span>signal(PeerEventType eventType){}<br />
<br />
<span style="color: #660000;">....</span><span style="color: #660000; font-weight: bold;">boolean </span>currentStateIs(State state)<br />
....{<br />
<span style="color: #660000;">........</span><span style="color: #660000; font-weight: bold;">return true</span>;<br />
....}<br />
}<br />
Now the test method (and the enclosing testcase) compiles fine. But after running, we get a red bar. Why? There is one explicit problem : transition state doesn't really happen on peer instance so the assertion fails. I mean, the peer is not on WAIT_CONN_ACK State. Actually is not in any state because the currentStateIs() method is returning <span style="color: #660000; font-weight: bold;">true</span> everytime :)<br />
In order to see that all is properly working we need to introduce another peer member instance that represents the current state of the peer.<br />
Well, considering that we already have a type for this new member (State class), we can insert (in Peer class):<br />
<br />
<span style="color: #660000; font-weight: bold;">private </span>State <span style="color: #333399;">currentState</span>;<br />
<br />
With this new variable, I can rewrite the currentStateIs() method in the following way :<br />
<br />
<span style="color: #660000; font-weight: bold;">boolean </span>currentStateIs(State state)<br />
{<br />
<span style="color: #660000;">....</span><span style="color: #660000; font-weight: bold;">return </span><span style="color: #000099;">currentState</span> == state;<br />
}<br />
<br />
Introducing that change causes a failure in the first test we saw in part I. Well, in order to fix that we need to initialize the "currentState" member instance :<br />
<br />
<span style="color: #660000; font-weight: bold;">private </span>State <span style="color: #000099;">currentState</span> = <span style="color: #000099;">CLOSED</span>;<br />
<br />
Now the <span style="color: #666666;">@Test</span> initialState() is working while the <span style="color: #999999;">@Test</span> startSignal() is failing :(.<br />
Why? because nothing on the peer instance is causing the required state transition and the assertion on the currentStateIs() fails because the peer is still in CLOSED state.<br />
Again, what is the minimum change / adjustment we would do in order to get things working? This is the failing test :<br />
<br />
<span style="color: #990000;"><span style="font-weight: bold;"><span style="color: #660000;">public class</span></span><span style="color: #660000;"> </span></span>PeerStateMachineTestCase<br />
{<br />
....<span style="color: #999999;">@Test</span><br />
<span style="color: #660000;">....</span><span style="color: #660000; font-weight: bold;">public </span>void startSignal()<br />
...{<br />
......Peer peer = <span style="color: #660000; font-weight: bold;">new</span> Peer();<br />
......peer.signal(PeerEventType.<span style="color: #000099;">START</span>);<br />
<br />
......assertTrue(peer.currentStateIs(peer.<span style="color: #000099;">WAIT_CONN_ACK</span>);<br />
...}<br />
}<br />
<br />
Yes, we can do the state transition in the signal() method :<br />
<br />
<span style="color: #660000; font-weight: bold;">public</span> void signal(PeerEventType type)<br />
{<br />
<span style="color: #000099;">....currentState</span> = <span style="color: #000099;">WAIT_CONN_ACK</span>;<br />
}<br />
<br />
In this way, the test will succeed because after calling the signal() method the peer state is WAIT_CONN_ACK as required.<br />
<br />
See you soon for third episode :)<br />
Bye<br />
AndreaAndreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-50865465292561842622009-05-30T19:57:00.008+02:002011-09-10T08:18:23.685+02:00Implementing a Diameter Peer State Machine using Test Driven Development (Part 1).<div>
RFC3588 (Diameter Base Protocol), specifically par. 5.6, contains specification about a finite state machine that MUST be observed by all Diameter implementations.</div>
<div style="text-align: center;">
<br /></div>
<div>
In this article we will see how to implement a peer state machine using Test Driven Development. Note that this is only the first part of the whole article. </div>
<div>
The following is an extract (just the first entry) of the RFC table (you can found that on the previously mentioned paragraph) that illustrates the peer state machine : </div>
<div>
<br /></div>
<div>
<img alt="" border="0" id="BLOGGER_PHOTO_ID_5342282171490064162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsrBr29AEo1UY2UFep7xDle9cKiMY5YS9iUitzfXZBkcyIkskwJlJhjTzgGAA3hjKVXJROlRmXQNP2xeyB0coAK7mDfm02eTjWtBaneeTOXMytCpOPZVck7dZ9Yc_PinMhRAvyN89F4B4/s400/Immagine.bmp" style="cursor: hand; cursor: pointer; display: block; height: 79px; margin: 0px auto 10px; text-align: center; width: 400px;" />I choose that entry because "Closed" is the peer initial state. </div>
<div>
As you can see when the peer is in that state it can receive only two kind of events:</div>
<div>
<br /></div>
<div>
1) Start : A diameter application has signaled that a connection should be initiated with the peer;</div>
<div>
2) R-Conn-CER : An acknowledgement is received stating that the transport connection has been established, and the associated Capability Exchange Request (CER) has arrived.</div>
<div>
<br /></div>
<div>
The first event must be associated with the following action on the peer : </div>
<div>
<br /></div>
<div>
1) I-Snd-Conn-Req (Initiator Sends Connection Request) : A transport connection is initiated with the peer;</div>
<div>
<br /></div>
<div>
After the peer successfully processed the action its new state MUST be "Wait-Conn-Ack".</div>
<div>
<br /></div>
<div>
The second event, R-Conn-CER, is firing the following actions on the peer :</div>
<div>
<br /></div>
<div>
1) R-Accept : The incoming connection associated with the R-Conn-CER is accepted as the responder connection;</div>
<div>
2) Process-CER : The CER associated with the R-Conn-CER is processed.</div>
<div>
3) R-Snd-CEA (Receiver Sends CEA)</div>
<div>
<br /></div>
<div>
After those three actions, the peer must be in "R-Open" state.</div>
<div>
<br /></div>
<div>
Well, of course if you have a look at the whole table there are a lot of states / actions / events but for simplicity we can assume that we are handling only with the "Closed" state. The whole article can be applied to other table entries.</div>
<div>
<br /></div>
<div>
First implicit requirement is that we should have a Peer class, it must have an internal state and the initial value of that state should be "Closed". </div>
<div>
So, for a first implementation of our test case I'd like to write something like this :</div>
<div>
<br /></div>
<div>
package com.gazzax.diameter.peer;</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public class</span></span> PeerStateMachineTestCase</div>
<div>
{</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #666666;">@Test</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">public </span></span>void initialState()</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>{</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>Peer peer = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span>Peer();</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>assertTrue(peer.currentStateIs(peer.CLOSED));</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>}</div>
<div>
}</div>
<div>
<br /></div>
<div>
Obviously, the test doesn't compile for several reasons; First of all, we need a Peer class :) So let's create it!</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">package </span></span>com.gazzax.diameter.peer;</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public class</span></span> Peer</div>
<div>
{</div>
<div>
}</div>
<div>
<br /></div>
<div>
One little step ahead! But it is not sufficient because the TestCase still doesn't compile :( There's no a currentStateIs(...) method on the Peer class!</div>
<div>
Note that that method is accepting a parameter that represents a peer state. Peer's states are typed instance members of peer class and they have a default visibility. Why? Because in that way we can see / use them on our test case without breaking encapsulation (PeerStateMachineTestCase and Peer are in the same package even if they usually reside in different source folders) </div>
<div>
<br /></div>
<div>
NOTE : the current state of the peer <span class="Apple-style-span" style="font-weight: bold;">IS NOT</span> exposed (it is a private member). You can only have an indirect / read-only access through the currentStateIs(...) method.</div>
<div>
This is done because we don't want break enapsulation and therefore peer state invariants.</div>
<div>
<br /></div>
<div>
Anyway, the state machine table suggests that </div>
<div>
<br /></div>
<div>
- a peer, regardless its state, should be able to receive a signal;</div>
<div>
- the concrete handling of that signal (fired actions and next state) depends on the current state of the peer; </div>
<div>
<br /></div>
<div>
So, this suggests me that a peer state itself shuold be able to receive a signal. Here is the peer state interface:</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">package </span></span>com.gazzax.diameter.peer;</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public interface</span></span> State </div>
<div>
{</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">void </span></span>signal(PeerEventType event) <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">throws </span></span>WrongEventException;</div>
<div>
}</div>
<div>
<br /></div>
<div>
Where </div>
<div>
<br /></div>
<div>
- <span class="Apple-style-span" style="font-weight: bold;">PeerEventType </span>is an enumeration of all defined event types; for the current example it will look like this :</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">package </span></span>com.gazzax.diameter.peer;</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public enum</span></span> PeerEventType</div>
<div>
{</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #000099;"><span class="Apple-style-span" style="font-style: italic;">START</span></span>,</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #000099;"><span class="Apple-style-span" style="font-style: italic;">R_CONN_CER</span></span></div>
<div>
}</div>
<div>
<br /></div>
<div>
- <span class="Apple-style-span" style="font-weight: bold;">WrongEventException </span>: that will be thrown when the received event type is violating the rules defined on the peer state machine table. I mean, when the peer will receive a wrong event according with its current state. I mean, when the current state of the peer doesn't recognize the received event type as valid.</div>
<div>
<br /></div>
<div>
We left the TestCase with compilation errors. We need a currentStateIs(State peerState) method. Let's write it with a dummy implementation!</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public class</span></span> Peer</div>
<div>
{</div>
<div>
<b><span class="Apple-style-span" style="color: #660000;">private final</span></b> State CLOSED; </div>
<div>
<br /></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">boolean </span></span>currentStateIs(State state)</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>{</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">return false</span></span>; </div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>}</div>
<div>
} </div>
<div>
<br /></div>
<div>
Now code should compile :) </div>
<div>
Run again the test case and you will see the red bar! Bad? Absolutely not, that means "Progress"! Another little step ahead!</div>
<div>
<br /></div>
<div>
What is the minimal thing / adjustment that we could do in order to get a green bar? </div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public class</span></span> Peer</div>
<div>
{</div>
<div>
<b><span class="Apple-style-span" style="color: #660000;">private final</span></b> State CLOSED; </div>
<div>
<br /></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">boolean </span></span>currentStateIs(State state)</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>{</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">return true</span></span>; </div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>}</div>
<div>
} </div>
<div>
<br /></div>
<div>
Run again the test and...et voilà ! We got a green bar! Another little step ahead!</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-10873236768999722222009-05-15T09:07:00.010+02:002011-09-10T08:25:56.663+02:00Dependency Injection with EJB 2.x<div>
Very often, I see in an EJB 2.x environment message driven or session beans with the following code : </div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> onMessage(Message message) </span></div>
<div>
<span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span>Connection connection = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">null</span></span>;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">try</span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Context ctx = new Context();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">DataSource datasource = (DataSource)ctx.lookup(<span class="Apple-style-span" style="color: #3366ff;">"jdbc/ds"</span>);</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span> </span></span><span class="Apple-style-span">Connection connetion = ....</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Do somethign with connection</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(NamingException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Do something</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(SQLException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Do something </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">finally </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span>{ connection.close(); } <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(Exception ignore) {}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
...or (better) using a service locator : </div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> onMessage(Message message) </span></div>
<div>
<span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Connection connection = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">null</span></span>;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try</span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">ServiceLocator serviceLocator = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span>ServiceLocator();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">DataSource datasource = serviceLocator.getDataSource(<span class="Apple-style-span" style="color: #3366ff;">"jdbc/ds"</span>);</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Connection connetion = ....</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Do somethign with connection</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span> </span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(NamingException exception) </span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Do something</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(SQLException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Do something </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span> </span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">finally </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span>{ connection.close(); } <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">catch</span></span>(Exception ignore) {}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
What is the problem? That piece of code (doesn't matter if it belongs to a session or a message driven bean) should IMO contains only business logic; </div>
<div>
I mean, the logic that should make sense, from a business point of view, of that EJB.</div>
<div>
Now, again, what is the problem? JDBC Code? Why don't we use a Data Gateway (or in general a data access pattern)? </div>
<div>
Yes, that's right, but that's not the point. </div>
<div>
Let's make a strong precondition supposing that jdbc code is part of business logic. </div>
<div>
What else?</div>
<div>
<br /></div>
<div>
Look at this line of code :</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(NamingException exception)</span></div>
<div>
<span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #009900;">// Do something</span></span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
This exception is thrown when some problem occurs with naming service. The funny thing is that we are looking up the resource (a datasource in this case) each time this method is called. What is the problem?</div>
<div>
<br /></div>
<div>
There are at least three issues :</div>
<div>
<br /></div>
<div>
1) Each call to Context.lookup(...) is theoretically a remote call. Here that call is done each time a message arrives. You may think that code could be optimized, looking up the resource the first time, but you must in any case catch the Naming Exception (even if the lookup isn't really executed)</div>
<div>
2) What you need is the resource that is bound with the naming service under the name "jdbc/ds", not the naming service itself. Once you got it, you have all what you need in order to retrieve valid database connections. So you should use that lookup code once and only once.</div>
<div>
3) NamingException is not a business excepiton...the corresponding "throwing" code it's not part of the business logic too, but the onMessage(), where only the business logic should be, must contain the try-catch statement in order to handle a scenario where a naming service occurs...<span class="Apple-style-span" style="font-weight: bold;">EACH TIME THE CODE IS EXECUTED!.</span></div>
<div>
<br /></div>
<div>
The usage of a service locator doesn't solve the problem completely : even if we cache the resource (on service locator), we will avoid the 1) & 2) but not the 3th issue. </div>
<div>
In fact the signature of the getDatasource(...) method is throwing a NamingException and therefore the calling code must catch it everytime.</div>
<div>
<br /></div>
<div>
The ideal solution should:</div>
<div>
<br /></div>
<div>
1) make a lookup call only once;</div>
<div>
2) catch the naming exception only once (when the lookup call is executed)</div>
<div>
3) in case of naming exception (naming service failure) the call should be repeated until the resource is available.</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> GxMessageDriven <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">implements </span></span>MessageDrivenBean, MessageListener</span></div>
<div>
<span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">private </span></span>DataSource <span class="Apple-style-span" style="color: #3333ff;">datasource</span>;</span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> onMessage()</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Here we can use directly the datasource instance that </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"> </span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="color: #009900;"> </span></span><span class="Apple-style-span" style="color: #009900;"> </span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="color: #009900;"> </span></span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// has been self-injected in ejbCreate() method at startup.</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Connection connection = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">null</span></span>;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">connection = <span class="Apple-style-span" style="color: #3333ff;">datasource</span>.getConnection()</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(SQLException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">...</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">finally </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span>{ connection.close } <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(Exception ignore){}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> ejbCreate()</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Using a service locator should be better</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Context ctx = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span>InitialContext();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">datasource </span>= (DataSource) ctx.lookup(<span class="Apple-style-span" style="color: #3366ff;">"jdbc/ds"</span>);</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(NamingException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// This ejb cannot be initialized because a needed resource cannot be retrieved </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
As you can see the lookup code (and the corresponding catch of the NamingException) is executed only once in the ejbCreate().</div>
<div>
The first obvious consequence is that within onMessage() method the datasource member instance is used directly because it is already intialized.</div>
<div>
There's only remaining open issue : what happens if the lookup fails in the ejbCreate? Basically that means the onMessage method will throw a NullPointerException and obviously we don't want that :) </div>
<div>
If you are thinking about an if statement within the onMessage method : </div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">if </span></span>(<span class="Apple-style-span" style="color: #3333ff;">datasource </span>!= null)</span></div>
<div>
<span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">....</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
That means probably you didn't read my previous post : <span class="Apple-style-span" style="font-weight: bold;">I hate if statements </span>:) I think is better to equipe the ejb component with a state pattern in the following way :</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;">1) create a member instance which will represent the current state of the component: </span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span>MessageListener <span class="Apple-style-span" style="color: #3333ff;">currentState</span>;</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;">2) create one inner class which represents the WORKING state:</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">final </span></span>MessageListener WORKING = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span>MessageListener()</span></div>
<div>
<span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> onMessage()</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Here we can use directly the datasource instance that </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"> </span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="color: #009900;"> </span></span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// has been self-injected in ejbCreate() method at startup.</span></span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Connection connection = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">null</span></span>;</span></div>
<div>
<span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">try </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">connection = <span class="Apple-style-span" style="color: #3333ff;">datasource</span>.getConnection()</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(SQLException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">...</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">finally </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span>{ connection.close } <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">catch</span></span>(Exception ignore){}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;">3) Create another inner class which represents the OFF state : </span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">final </span></span>MessageListener OFF = <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">new </span></span>MessageListener()</span></div>
<div>
<span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> onMessage(Message message)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Context ctx = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span>InitialContext();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">datasource = (DataSource) ctx.lookup("jdbc/ds");</span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// State change : OFF --> WORKING</span> </span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentState </span>= WORKING;</span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Process the message</span></span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"> </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentState</span>.onMessage(message);</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(NamingException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Don't change current state...resource is not yet available</span></span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"> </span> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;">4) Update the memeber instance variable in order to set the OFF state as default state.</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span>MessageListener <span class="Apple-style-span" style="color: #3333ff;">currentState </span>= OFF;</span></div>
<div>
<br /></div>
<div>
At this point, you should probably see that the ejbCreate is no longer useful because the check is made by the OFF state the first time the component raises up.</div>
<div>
<br /></div>
<div>
So, the final code should look like this :</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> GxMessageDriven <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">implements </span></span>MessageDrivenBean, MessageListener</span></div>
<div>
<span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private final </span></span>MessageListener OFF = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span>MessageListener()</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> onMessage(Message message)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Context ctx = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span>InitialContext();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">datasource </span>= (DataSource) ctx.lookup(<span class="Apple-style-span" style="color: #3366ff;">"jdbc/ds"</span>);</span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// State change : OFF --> WORKING </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">currentState = WORKING;</span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Process the message using the working state</span></span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"> </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">currentState.onMessage(message);</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(NamingException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Don't change current state...resource is not yet available</span></span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"> </span> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private final</span></span> MessageListener WORKING = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span>MessageListener()</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> onMessage()</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Here we can use directly the datasource instance that </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"> </span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="color: #009900;"> </span></span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// has been self-injected in ejbCreate() method at startup.</span></span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">Connection connection = <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">null</span></span>;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">connection = <span class="Apple-style-span" style="color: #3333ff;">datasource</span>.getConnection()</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(SQLException exception)</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">//...</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">finally </span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">try </span></span>{ connection.close } <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">catch</span></span>(Exception ignore){}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span>DataSource <span class="Apple-style-span" style="color: #3333ff;">datasource</span>;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span>MessageListener <span style="color: #3333ff;">currentState</span>= OFF;</span></div>
<div>
<span class="Apple-style-span">}</span></div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-30058551663827425242009-02-13T09:21:00.009+01:002011-09-10T08:17:05.519+02:00Apache Qpid Committer!Hi all, it happened about two months ago...I became an Apache Committer for Qpid project (http://qpid.apache.org)!<br />
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"><span class="Apple-style-span" style="font-style: italic;">"Just a brief note, we have voted Andrea on as a committer, </span><span class="Apple-style-span" style="font-style: italic;">all the accounts and details have<br />been completed and he now has Karma! A warm welcome to the team Andrea."</span></span></div>
<div>
<br /></div>
<div>
YAHOOOO!!!</div>
<div>
<div>
<br /></div>
<div>
Basically I developed (I'm still developing) a JMX / WS-DM adapter for Qpid broker in order to enable remote management using one of the mentioned technologies...I already knew JMX but WS-DM was (is still so :) ) completely unknown so at the end is a nice challenge :)</div>
<div>
<br /></div>
<div>
If you are interested on that here you are some useful links :</div>
<div>
<br /></div>
<div>
- Apache Qpid home page : <a href="http://qpid.apache.org/">http://qpid.apache.org</a> </div>
<div>
- This is what I've done (really what I'm still doing...) : <a href="http://qpid.apache.org/qman-qpid-management-bridge.html">http://qpid.apache.org/qman-qpid-management-bridge.html</a></div>
<div>
<br /></div>
<div>
...and last but not least...</div>
<div>
<br /></div>
<div>
<a href="http://people.apache.org/list_G.html#agazzarini">http://people.apache.org/list_G.html#agazzarini</a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Best regards,</div>
<div>
Andrea</div>
</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com2tag:blogger.com,1999:blog-1588390580596352744.post-91946143750400397582008-12-03T08:36:00.004+01:002011-09-10T08:26:26.181+02:00IF-LESS code : State / Strategy Pattern<div>
We have a simple class that is looping on a given List<string>. Requirement are :</string></div>
<div>
<br /></div>
<div>
1) Service must preserve the first value of the list;</div>
<div>
2) Each other element must be printed in uppercase</div>
<div>
3) At the end of the loop the "Exit" string must be printed out;</div>
<div>
<br /></div>
<div>
The first version is the following :</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public class</span></span> Service {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">String <span class="Apple-style-span" style="color: #3333ff;">theFirst</span>;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">public void</span></span> loop(List</span><string><span class="Apple-style-span"> strings){</span></string></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">int </span></span>index = 0;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">for </span></span>(String string : strings) {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">if </span></span>(index == 0) {</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">theFirst = string;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">} <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">else </span></span>{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">System.out.println(string.toUpperCase());</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">index++;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">System.out.println("<span class="Apple-style-span" style="color: #3333ff;">Exit"</span>);</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Ok, brief and (moreless) clear; Let's try to modify a little bit that class; First, I'd introduce a compose method in order isolate what needs to be done </div>
<div>
for middle iterations (uppercase printing) so I'll introduce :</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private void</span></span> uppercase(String value) {</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>System.out.println(value.toUppercase());</div>
<div>
}</div>
<div>
<br /></div>
<div>
Next, I don't like the explicit loop & condition logic. The tasks that need to be executed in the current example are very simple but let's try to imagine a more complicated task </div>
<div>
(for initial and middle iteration) : the code should result complicated to understand...</div>
<div>
<br /></div>
<div>
I'd prefer to isolate those tasks in a separate method / class.</div>
<div>
So, in order to do that, let's introduce an Iteration interface that represents the task that needs to be executed on a given iteration.</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="color: #33cc00;">// Determines what needs to be done on a given iteration</span></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">interface </span></span></span><span class="Apple-style-span">Iteration </span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">void </span></span>execute(String value);</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
we have two concrete implementors; something like that:</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">Iteration </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">firstIteration </span>= <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span></span><span class="Apple-style-span">Iteration</span><span class="Apple-style-span">() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> execute(String value) {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Store the value of the first element</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span">Iteration </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">middleIteration </span>= <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">new </span></span></span><span class="Apple-style-span">Iteration</span><span class="Apple-style-span">() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">public void</span></span> execute(String value) {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">uppercase</span>(value);</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
Now, each task should be responsible to execute its logic and in addition should provide some mechanism to compute & execute the next iteration. </div>
<div>
In order to do that we change a little the Iteration interface and the hosting class introducing a new Iterator member that is initialized on the loop() method.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">interface </span></span></span><span class="Apple-style-span">Iteration </span><span class="Apple-style-span">{</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">void </span></span>execute();</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span">Iteration </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">firstIteration </span>= <span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span></span><span class="Apple-style-span">Iteration</span><span class="Apple-style-span">() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public </span></span>void execute() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"> </span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// Store the value of the iterator.next() that is the first element of the list;</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span">Iteration </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">middleIteration </span>= <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">new </span></span></span><span class="Apple-style-span">Iteration</span><span class="Apple-style-span">() {</span></div>
<div>
<span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> execute() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">uppercase(<span class="Apple-style-span" style="color: #3333ff;">iterator</span>.next());</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span></span><span class="Apple-style-span">Iterator</span><string><span class="Apple-style-span"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">iterator</span>;</span></string></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-style-span">...</span></div>
<div>
<span class="Apple-style-span"><br /></span></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">public void</span></span> loop(List</span><string><span class="Apple-style-span"> strings) {</span></string></div>
<div>
<span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #3333ff;">iterator </span>= strings.iterator();</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
At this point we need to maintain a reference to the current iteration. So let's introduce another instance member :</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span>Iteration <span class="Apple-style-span" style="color: #3333ff;">currentIteration </span>= <span class="Apple-style-span" style="color: #3333ff;">firstIteration</span>; </span></div>
<div>
<br /></div>
<div>
The initial value of this currentIteration is obviously the previously declared inner class "firstIteration". After that the loop method should be changed in order to start the loop : </div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> loop(List</span><string><span class="Apple-style-span"> strings) {</span></string></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">iterator </span>= strings.iterator();</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentIteration</span>.execute();</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
Next, we need a way to continue the execution of the loop. We can do that introducing another method :</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span> nextIteration() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentIteration </span>= (<span class="Apple-style-span" style="color: #3333ff;">iterator</span>.hasNext()) ? <span class="Apple-style-span" style="color: #3333ff;">middleIteration</span>: <span class="Apple-style-span" style="color: #3333ff;">noIteration</span>;</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentIteration</span>.execute();</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
</div>
<div>
ok, ok, I know...this is still a conditional logic but is not exaclty the same as the previous one...I'm not deal with indexes or temporary variables...just with the given collection...</div>
<div>
As you can saw, we need another instance of Iteration inner interface for determine what needs to be done when the end of the loop is reached.</div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private final</span></span> </span><span class="Apple-style-span">Iteration </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">noIteration </span>= <span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">new </span></span></span><span class="Apple-style-span">Iteration</span><span class="Apple-style-span">() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">public void</span></span> execute() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">System.out.println(<span class="Apple-style-span" style="color: #3366ff;">"Exit"</span>);</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<br /></div>
<div>
That's all! Do you think I'm paranoic? :)....mmmmmm...yes! Note that the code above is just an exercise and the benefits are not evident because the starting class is very simple (I mean, the logic of the initial version of that class) but I can ensure you that they are more evident when those things are applied to a more complicated scenario...</div>
<div>
<br /></div>
<div>
This is the final version of the IlLessService :</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public class</span></span></span><span class="Apple-style-span"> </span>IfLessService {</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>String<span class="Apple-style-span"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">theFirst</span></span><span class="Apple-style-span">;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">private </span></span></span><span class="Apple-style-span">ListIterator<string></string></span><string><span class="Apple-style-span"> <span class="Apple-style-span" style="color: #3333ff;">iterator</span>;</span></string></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">interface</span></span> Iteration {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">void </span></span></span>execute();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-style-span" style="white-space: pre;"><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="color: #009900;"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// What needs to be done in the first iteration?</span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private final</span></span></span><span class="Apple-style-span"> </span><span class="Apple-style-span">Iteration <span class="Apple-style-span">firstIteration</span>= </span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span></span><span class="Apple-style-span">Iteration() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span></span><span class="Apple-style-span"> </span><span class="Apple-style-span">execute() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">theFirst </span></span>= <span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">iterator</span></span>.next();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">executeNextIteration</span>();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">};</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-style-span" style="white-space: pre;"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// And in the middle iteration(s)?</span></span></span></div>
<div>
<span class="Apple-style-span"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private final</span></span> </span><span class="Apple-style-span">Iteration </span></span><span class="Apple-style-span"><span class="Apple-style-span">middleIteration </span></span><span class="Apple-style-span">=</span><span class="Apple-style-span"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;">new </span></span><span class="Apple-style-span">Iteration() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span></span><span class="Apple-style-span"> execute() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span" style="color: #3333ff;">uppercase</span></span></span><span class="Apple-style-span">(<span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">iterator</span></span>.next());</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">executeNextIteration</span>();</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">};</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-style-span" style="white-space: pre;"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;">// And when the iteration will terminate?</span></span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">private final</span></span><span class="Apple-style-span" style="color: #660000;"> </span></span><span class="Apple-style-span">Iteration </span><span class="Apple-style-span"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">noIteration </span></span></span><span class="Apple-style-span">=</span><span class="Apple-style-span"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">new </span></span></span><span class="Apple-style-span">Iteration() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span></span><span class="Apple-style-span"> </span><span class="Apple-style-span">execute() {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">System.out.println("Exit");</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">};</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private</span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"> </span></span></span><span class="Apple-style-span">Iteration <span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentIteration </span></span>= <span class="Apple-style-span" style="color: #3333ff;">firstIteration</span>;</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">public void</span></span></span><span class="Apple-style-span"> </span><span class="Apple-style-span">loop(List</span><string><span class="Apple-style-span"> strings){</span></string></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">iterator </span></span>= strings.listIterator();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentIteration</span></span>.execute();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;">private void</span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"> </span></span></span><span class="Apple-style-span">uppercase(String aString) {</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">System.out.println(aString.toUpperCase());</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;">private void</span></span></span><span class="Apple-style-span"> </span><span class="Apple-style-span">executeNextIteration(){</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentIteration </span></span>= (<span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">iterator</span></span>.hasNext()) ? <span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">middleIteration</span></span>: <span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">noIteration</span></span>;</span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #3333ff;">currentIteration</span></span>.execute();</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span"> <span class="Apple-tab-span" style="white-space: pre;"> </span></span></span><span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span">}</span></div>
<div>
<span class="Apple-style-span" style="color: #33ccff;"><br /></span></div>
<div>
Regards,</div>
<div>
Andrea</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com0tag:blogger.com,1999:blog-1588390580596352744.post-50994411618906789902008-11-14T11:22:00.008+01:002011-09-10T08:26:11.846+02:00IF-LESS code : State Pattern<span class="Apple-style-span" style="font-size: small;">Hi all, let's start with a post on this interesting topic (at least for me) with a simple example.</span><br />
<div>
<span class="Apple-style-span" style="font-size: small;">We have an interface named </span><span class="Apple-style-span" style="font-style: italic;"><span class="Apple-style-span" style="font-size: small;">IService </span></span><span class="Apple-style-span" style="font-size: small;">that represents a generic service. The interface offers three methods : </span><span class="Apple-style-span" style="font-style: italic;"><span class="Apple-style-span" style="font-size: small;">start</span></span><span class="Apple-style-span" style="font-size: small;">(), </span><span class="Apple-style-span" style="font-style: italic;"><span class="Apple-style-span" style="font-size: small;">stop</span></span><span class="Apple-style-span" style="font-size: small;">() and </span><span class="Apple-style-span" style="font-style: italic;"><span class="Apple-style-span" style="font-size: small;">isRunning</span></span><span class="Apple-style-span" style="font-size: small;">(). </span><br />
<div>
<span class="Apple-style-span" style="font-size: small;"><br /></span></div>
<div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public interface</span></span></span><span class="Apple-style-span" style="font-size: small;"> IService {</span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-size: small;"> </span></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">void </span></span></span><span class="Apple-style-span" style="font-size: small;">start(); </span><span class="Apple-style-span" style="color: #33cc00;"><span class="Apple-style-span" style="font-size: small;">// Starts the service.</span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-size: small;"> </span></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">void </span></span></span><span class="Apple-style-span" style="font-size: small;">stop(); /</span><span class="Apple-style-span" style="color: #33cc00;"><span class="Apple-style-span" style="font-size: small;">/ Stops the service. </span></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-size: small;"> </span></span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">boolean </span></span></span><span class="Apple-style-span" style="font-size: small;">isRunning(); </span><span class="Apple-style-span" style="color: #33cc00;"><span class="Apple-style-span" style="font-size: small;">// Returns true if the service is running.</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: small;">}</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"><br /></span></div>
<div>
<span class="Apple-style-span" style="font-size: small;">While looking at the following implementation, I wasn't satisfied about the conditional statements on start() and stop() method :</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"><br /></span></div>
<div>
<div>
<span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public class</span></span></span><span class="Apple-style-span" style="font-size: small;"> ServiceImpl </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">implements </span></span></span><span class="Apple-style-span" style="font-size: small;">IService {</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">private volatile</span></span></span><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">boolean </span></span></span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">started</span></span><span class="Apple-style-span" style="font-size: small;">;</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">private </span></span></span><span class="Apple-style-span" style="font-size: small;">Thread </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">thread</span></span><span class="Apple-style-span" style="font-size: small;">;</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public synchronized void</span></span></span><span class="Apple-style-span" style="font-size: small;"> start() { </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">if </span></span></span><span class="Apple-style-span" style="font-size: small;">(</span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">started</span></span><span class="Apple-style-span" style="font-size: small;">) {</span></span></div>
<div>
<span class="Apple-style-span" style="color: red;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: black;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">return</span></span></span><span class="Apple-style-span" style="font-size: small;">;</span></span></span></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">started </span></span><span class="Apple-style-span" style="font-size: small;">= </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">true</span></span></span><span class="Apple-style-span" style="font-size: small;">;</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">thread </span></span><span class="Apple-style-span" style="font-size: small;">= ... </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// Create your daemon implementation.</span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">thread</span></span><span class="Apple-style-span" style="font-size: small;">.setDaemon(</span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">true</span></span></span><span class="Apple-style-span" style="font-size: small;">);</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">thread</span></span><span class="Apple-style-span" style="font-size: small;">.start();</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> }</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">public synchronized</span></span></span><span class="Apple-style-span" style="font-size: small;"> void stop()</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> { </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">if </span></span></span><span class="Apple-style-span" style="font-size: small;">(!</span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">started</span></span><span class="Apple-style-span" style="font-size: small;">) {</span></span></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">return</span></span></span><span class="Apple-style-span" style="font-size: small;">;</span></span></div>
<div>
<span class="Apple-style-span"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">started </span></span><span class="Apple-style-span" style="font-size: small;">= </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">false</span></span></span><span class="Apple-style-span" style="font-size: small;">;</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">thread</span></span><span class="Apple-style-span" style="font-size: small;">.interrupt();</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">try </span></span></span><span class="Apple-style-span" style="font-size: small;">{</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">thread</span></span><span class="Apple-style-span" style="font-size: small;">.join();</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> }</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">catch </span></span></span><span class="Apple-style-span" style="font-size: small;">(InterruptedException ignore) { </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> }</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> }</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">public synchronized boolean</span></span></span><span class="Apple-style-span" style="font-size: small;"> isRunning() {</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="font-size: small;">return </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">started</span></span><span class="Apple-style-span" style="font-size: small;">;</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"> }</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;">}</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"><br /></span></div>
</div>
<div>
<span class="Apple-style-span" style="font-size: small;">To be honest, what I don't like is :</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;"><br /></span></div>
<div>
<span class="Apple-style-span" style="font-size: small;">- Maintaining the state of the service in a boolean member and therefore relying on that in order to know if the service is alive or not (the isRunning method)</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;">- Conditional logic used for checking everytime the (start & stop) methods are called if the service is alive or not. I think the service should know that without using a boolean member to remember! An example : if you are driving a car, how do you know that it's running? You know that because it's running and you're driving! ;-) and not because after turned it on you put a post-it on the dashboard with "RUNNING" written over! </span></div>
<div>
<span class="Apple-style-span" style="font-size: small;">I mean : it's the status itself that suggests you what's going on!</span></div>
<div>
<span class="Apple-style-span" style="font-size: small;">As result of that, I prefer this version of the service implementation:</span></div>
<div style="text-align: left;">
<span class="Apple-style-span" style="font-size: small;"><br /></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"></span><br />
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public class</span></span></span><span class="Apple-style-span" style="font-size: small;"> IfLessService </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">implements </span></span></span><span class="Apple-style-span" style="font-size: small;">IService {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">private </span></span></span><span class="Apple-style-span" style="font-size: small;">Thread </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">_watcher</span></span><span class="Apple-style-span" style="font-size: small;">;</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">/**</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> * RUNNING STATE.</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> */</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">private final</span></span></span><span class="Apple-style-span" style="font-size: small;"> IService running = </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">new </span></span></span><span class="Apple-style-span" style="font-size: small;">IService() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public boolean</span></span></span><span class="Apple-style-span" style="font-size: small;"> isRunning()</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">return true</span></span></span><span class="Apple-style-span" style="font-size: small;">; </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// We are inside the running state and so...</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public void</span></span></span><span class="Apple-style-span" style="font-size: small;"> start() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// Nothing to do here...it is already started.</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public void</span></span></span><span class="Apple-style-span" style="font-size: small;"> stop() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">_watcher</span></span><span class="Apple-style-span" style="font-size: small;">.interrupt(); </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">try </span></span></span><span class="Apple-style-span" style="font-size: small;">{</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">_watcher</span></span><span class="Apple-style-span" style="font-size: small;">.join();</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">catch </span></span></span><span class="Apple-style-span" style="font-size: small;">(InterruptedException ignore)</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> { </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-size: small;"> </span></span><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">state </span></span><span class="Apple-style-span" style="font-size: small;">= </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">notRunning</span></span><span class="Apple-style-span" style="font-size: small;">;</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> };</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> /**</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> * NOT RUNNING STATE.</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> */</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">private final</span></span></span><span class="Apple-style-span" style="font-size: small;"> IService notRunning = </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">new </span></span></span><span class="Apple-style-span" style="font-size: small;">IService() { </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public boolean</span></span></span><span class="Apple-style-span" style="font-size: small;"> isRunning() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">return false</span></span></span><span class="Apple-style-span" style="font-size: small;">; </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// We are inside the not running state and so...</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public synchronized void</span></span></span><span class="Apple-style-span" style="font-size: small;"> start() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-size: small;"> </span></span><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">_watcher</span></span><span class="Apple-style-span" style="font-size: small;"> = </span><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">...</span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// Create your daemon implementation...</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">_watcher</span></span><span class="Apple-style-span" style="font-size: small;">.setDaemon(</span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">true</span></span></span><span class="Apple-style-span" style="font-size: small;">);</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">_watcher</span></span><span class="Apple-style-span" style="font-size: small;">.start();</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> // ...and make a state change too...from NOT-RUNNING to RUNNING.</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">state </span></span><span class="Apple-style-span" style="font-size: small;">= </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">running</span></span><span class="Apple-style-span" style="font-size: small;">;</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">public void</span></span></span><span class="Apple-style-span" style="font-size: small;"> stop() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// Nothing to do here...it is already stopped. </span></span></span><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> </span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> } </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }; </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> </span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// Default initial state is stopped (not running).</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">private </span></span></span><span class="Apple-style-span" style="font-size: small;">IService </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">state </span></span><span class="Apple-style-span" style="font-size: small;">= </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">notRunning</span></span><span class="Apple-style-span" style="font-size: small;">;</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">public synchronized void</span></span></span><span class="Apple-style-span" style="font-size: small;"> start() { </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">state</span></span><span class="Apple-style-span" style="font-size: small;">.start(); </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// Current state delegation</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size: small;">public synchronized void</span></span></span><span class="Apple-style-span" style="font-size: small;"> stop() { </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">state</span></span><span class="Apple-style-span" style="font-size: small;">.stop(); </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// Current state delegation</span></span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;"> </span></span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">public boolean</span></span></span><span class="Apple-style-span" style="font-size: small;"> isRunning() {</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> </span><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="color: #660000;"><span class="Apple-style-span" style="font-size: small;">return </span></span></span><span class="Apple-style-span" style="color: #3333ff;"><span class="Apple-style-span" style="font-size: small;">state</span></span><span class="Apple-style-span" style="font-size: small;">.isRunning(); </span><span class="Apple-style-span"><span class="Apple-style-span" style="color: #009900;"><span class="Apple-style-span" style="font-size: small;">// Current state delegation</span></span></span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;"> }</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;">}</span></span></div>
<div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;">Now the service implementation is delegating the execution of the IService methods to the current internal state. Those states are themselves implementors of IService interface. We have two states : running and notRunning. </span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;">Note that the responsibility of each state is not only to manage the "state" of the object at a specific moment but also to provide an eventual state transition: for example when the service is not running (state = notRunning), if you call the start() method there will be a state transition (state = running).</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><span class="Apple-style-span" style="font-size: small;">Any comment would be very very appreciated...</span></span></div>
<div>
<span class="Apple-style-span" style="font-size: 13px;"><br /></span></div>
</div>
</div>
</div>
</div>
Andreahttp://www.blogger.com/profile/11441190939598229208noreply@blogger.com3