<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5893116250220995871</id><updated>2011-11-28T00:31:18.893+01:00</updated><category term='weblogic intellij debug remote'/><category term='Hibernate cache readonly mutable ReadOnlyCach'/><category term='hibernate spring sessionfactory session cache 2nd level cche 1st level cache ehcache'/><category term='pet project'/><category term='MacOSX Macos Parallel Enterprise Architect'/><category term='andreas'/><category term='andreasgeorges'/><category term='Weblogiy p6spy hibernate java'/><category term='cambobo'/><category term='java heap eden teanured permgen'/><category term='georges'/><category term='maven'/><category term='sofware development deploy'/><category term='Google Gmail Email'/><category term='concordion junit testng testing specification based testing java'/><category term='Design Pattern Java'/><title type='text'>A cup of...</title><subtitle type='html'>Java and related stuff</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-6967291833437092735</id><published>2011-02-28T11:17:00.001+01:00</published><updated>2011-02-28T11:17:13.569+01:00</updated><title type='text'>Lucene and Hibernate Search - a small overview</title><content type='html'>&lt;div&gt;&lt;b&gt;Background&amp;nbsp; &lt;/b&gt;&lt;br&gt; For a user visiting your web site it would certainly be nice if the search experience felt like when using Google. To achieve this one can use Hibernate Search and Lucene. A user might then search for almost anything in relation to e.g. an ad, even combining search terms like ad title, location and using wild cards like &amp;#39;*&amp;#39;. If a user misspells a search term suggestions can be shown like: &amp;#39;Did you mean ABC&amp;#39;.&lt;br&gt;Well since we are not Google we can not develop our own search framework, instead we us open source frameworks to helps us achieve what we want. The Apache Software Foundation hosts an excellent framework for doing full text searches - Lucene. On top of Lucene we use Hibernate Search, which provides our domain model with the full text capabilities of Lucene and acts like a bridge between the index model and the object model. &lt;br&gt; I thought I would write something about how Lucene and Hibernate Search works while I still remember how. It is just an overview and I really recommend the books: &lt;a href="http://www.manning.com/hatcher3/" id="tzyb" title="Lucene in Action, Second Edition (ISBN: 1933988177)"&gt;Lucene in Action, Second Edition (ISBN: 1933988177)&lt;/a&gt; and &lt;a href="http://www.manning.com/bernard/" id="e68i" title="Hibernate Searc in Actiopn (ISBN: 1933988649)"&gt;Hibernate Search in Action (ISBN: 1933988649)&lt;/a&gt; for deeper understanding and as reference material.&lt;br&gt;&lt;br&gt;&lt;b&gt;Overview&lt;/b&gt;&lt;br&gt; Before we start delve into details have a look at the below mind map. You will notice that it contains two &amp;quot;legs&amp;quot;: Indexing and Searching. These two legs will form the base of the rest of our discussion. To view the whole mind map click &lt;a href="https://doc-14-88-docs.googleusercontent.com/docs/secure/8bju2puaca73p3bvl0tbham924f299b1/98jfg64693v8grqipuohb6k1gaso4si8/1294120800000/17190791760967981668/17190791760967981668/0ByyyxDxIt0pcYmQ4NjhjMWItNWIyMC00NDg2LWE5MjEtZDU3MzlkN2Y1YTUw?nonce=jjmcb95tqt0mm&amp;amp;user=17190791760967981668&amp;amp;hash=iv17hg8p4f19isccf6vgqtctr0md5a57" id="owhg" title="here"&gt;here&lt;/a&gt; (created with Freemind). Indexing is obviously done prior to searching.&lt;br&gt;&lt;br&gt;&lt;div id="d6lr" style="text-align:left"&gt;&lt;div id="c7-j" style="text-align:center"&gt;&lt;div id="y758" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_238cfbb89hr_b" style="height:277.412px;width:648px"&gt;&lt;br&gt;&lt;a href="https://doc-14-88-docs.googleusercontent.com/docs/secure/8bju2puaca73p3bvl0tbham924f299b1/1cl2gng81ov68h4pdotcja0jsqj6cecp/1294920000000/17190791760967981668/17190791760967981668/0ByyyxDxIt0pcYmQ4NjhjMWItNWIyMC00NDg2LWE5MjEtZDU3MzlkN2Y1YTUw?nonce=kj0siiftpaqf4&amp;amp;user=17190791760967981668&amp;amp;hash=3uf60jjnogg3bu9n1u10jtfpt0pualv8" id="paf4" title="Full pic"&gt;Full pic&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;font size="3"&gt;&lt;b&gt;Indexing&lt;/b&gt;&lt;/font&gt;&lt;br&gt;We will start with left leg - Indexing. &lt;br&gt;&lt;div id="p_nr" style="text-align:center"&gt;&lt;div id="x49i" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_241hsphj4k2_b" style="height:396px;width:282px"&gt;&lt;br&gt;&lt;a href="https://doc-14-88-docs.googleusercontent.com/docs/secure/8bju2puaca73p3bvl0tbham924f299b1/1cl2gng81ov68h4pdotcja0jsqj6cecp/1294920000000/17190791760967981668/17190791760967981668/0ByyyxDxIt0pcYmQ4NjhjMWItNWIyMC00NDg2LWE5MjEtZDU3MzlkN2Y1YTUw?nonce=kj0siiftpaqf4&amp;amp;user=17190791760967981668&amp;amp;hash=3uf60jjnogg3bu9n1u10jtfpt0pualv8" id="h30j" title="Full pic"&gt;Full pic&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;b&gt;Indexing Overview&lt;/b&gt;&lt;br&gt;To be able to do really fast searches indexes need to be created in advance, perhaps triggered from a scheduled job or if you use Hibernate Search when a transaction completes. Indexing is the process that grabs data in the form of plain text (Lucene only understands plain text), builds Documents, analyzes the data and finally creates Indexes. Before the Indexing process starts raw data (e.g. from files or a database ) must be extracted into a format which can be used to create the most fundamental element in Lucene - a Document. When the extraction part is done Documents are built - although still not part of any Index files. When Documents have been built they are analyzed by an Analyzer and tokens are created. Analyzers can remove irrelevant words like &amp;quot;and&amp;quot;, &amp;quot;a&amp;quot; etc, which are common but not that relevant when later on searching in the indexes. Finally the Documents are attached and stored into physical Indexes using an IndexWriter.&lt;br&gt;&lt;div id="gh2v" style="text-align:left"&gt;&lt;div id="djiq" style="text-align:left"&gt;&lt;br&gt;&lt;div id="hnq5" style="text-align:left"&gt;&lt;div id="r3gu" style="text-align:center"&gt;&lt;div id="uqh9" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_239ft8kr3m8_b" style="height:431px;width:483px"&gt;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;b&gt;Indexing Main classes &lt;/b&gt;&lt;br&gt; Some of the main classes used when Indexing are shown in this class diagram.&lt;br&gt;&lt;br&gt;&lt;div id="jl6l" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_229fv3fr7ff_b" style="height:485px;width:899px"&gt;&lt;/div&gt;&lt;br&gt; A &lt;b&gt;Document&lt;/b&gt; represents a collection of fields. You can think of a Document as a database row, where fields in the Document are represented by columns in the table of the row. &lt;br&gt; The analogy with a database has some differences though:&lt;br&gt;&lt;ul&gt;&lt;li&gt; In contrast to the database world a Document does not have different types, in fact it only has String types. Lucene 2.9 added a new type, NumericField (marked as experimental), which can be used for numerical range filtering and sorting.&lt;/li&gt;&lt;li&gt;Another difference is that one Document can have x number of fields while yet another one can have y number of fields. The fields do not even have to have same names in different Documents.&lt;/li&gt;&lt;li&gt;A Document can also have a Field multiple times, e.g. one Book Document could have id, title and isbn10 and another one could have id, title, isbn10, isbn10, isbn10 etc.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt; A sample code snippet to add a Document to an Index using the Lucene API could look like:&lt;br&gt;&lt;br&gt;&lt;div id="ldyl" style="text-align:center"&gt;&lt;a href="http://docs.google.com/File?id=dfxnknzf_228hhg2jnhn_b" target="_blank"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_228hhg2jnhn_b" style="height:100.374px;width:648px"&gt;&lt;/a&gt;&lt;/div&gt;&lt;br&gt; In Hibernate Search you only need to save an instance of an entity an that instance will also be stored or updated in the corresponding Lucene index. The way to inform Hibernate Search of this is by adding a couple of annotations to your entity. E.g. when you persist an instance of Book the Book data will also be persisted to the index of the Book, if the transaction is committed succesfully (Hibernate Search specific annotations are marked in yellow below)&lt;br&gt;&lt;br&gt;&lt;div id="h:el" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_230cwvq5tcp_b" style="height:281px;width:602px"&gt;&lt;br&gt;&lt;br&gt;&lt;/div&gt; A &lt;b&gt;Field &lt;/b&gt;is part of a Document and has a name, text or binary value, and a series of detailed options that describes what Lucene should do with the Field&amp;rsquo;s value. A Document can have more than one Field with the same name, meaning that when a search is issued both fields will be searched for a given search token. &lt;br&gt; For a specific Field we can optionally store the original string value in its entirety in the index, which means that the value can be retrieved by an IndexReader directly from the index. This is useful if one needs a value to be shown in a search result list e.g. Although Index files of course get bigger the more data you store in them - but for a Book title in above example this is quite feasable. &lt;br&gt; If for a specific Field we choose to tokenize the Field&amp;#39;s string value (renamed to analyze in Lucene 3) the Analyzer will break the Fields value into a stream of separate tokens (tokenstream) and make each token search able (tokenization). This is useful for normal text fields (body, title, abstract, etc.) for which we want to have full text search.&lt;br&gt; Some combinations of store and index options are shown in below table:&lt;br&gt;&lt;br&gt;&lt;table border="0" bordercolor="#ffffff" cellpadding="0" cellspacing="0" class="zeroBorder" height="181" width="655"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="width:60%" valign="top"&gt;&lt;p&gt;&lt;b&gt;Example &lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style="width:20%" valign="top"&gt;&lt;p&gt;&lt;b&gt;Store &lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;td style="width:20%" valign="top"&gt;&lt;p&gt;&lt;b&gt;Index&lt;/b&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Book ISBN, phone numbers, Social Security numbers, URLs, personal names, Dates &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Store.YES &lt;/p&gt;&lt;p&gt; Hibernate Search: &lt;/p&gt;&lt;p&gt; @Field(store = Store.YES) &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Index.UN_TOKENIZED &lt;/p&gt;&lt;p&gt; Hibernate Search: &lt;/p&gt;&lt;p&gt; @Field(index = Index.UN_TOKENIZED) &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Book title, book abstract &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Store.YES &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Index.TOKENIZED &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Book body &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Store.NO &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Index.TOKENIZED &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Book type, database primary key (if not &lt;br&gt;&lt;/p&gt;&lt;p&gt;used for searching) &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Store.YES &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Index.NO &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Book tags, hidden Keywords &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Store.NO &lt;/p&gt;&lt;/td&gt;&lt;td style="width:33%" valign="top"&gt;&lt;p&gt; Field.Index.UN_TOKENIZED &lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br&gt; In Hibernate Search annotations are used for mapping domain entity attributes to Lucene Fields. E.g. a Field mapping a ManyToOne relationship in Hibernate Search could look like below, which when inspected in Luke would reveal the Book attributes (yellow) as fields in the Ad index:&lt;br&gt;&lt;div id="i68h" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_234gx6ft6p2_b" style="height:191.154px;width:648px"&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="t_yg" style="text-align:left"&gt;&lt;b&gt;Tokenizing&lt;/b&gt; is the process of cleaning up and breaking down a text into Tokens which the Indexing process can use. Tokenizing is done by an &lt;b&gt;Analyzer&lt;/b&gt; which cleans up text from often meaningless words like e.g. &amp;quot;a&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;and&amp;quot; &amp;quot;to&amp;quot; which are generally to common and not relevant to a user when searching the indexes. During the tokenization process the Analyzer can also discard punctuation, remove accents and lowercase the tokens (normalizing). &lt;br&gt; The analyzer can also reduce words to a common root form called &lt;i&gt;stemming &lt;/i&gt;(e.g. apples becomes apple) which gives the user more relevant results when searching. &lt;i&gt;Lemmatisation&lt;/i&gt; is closely related to stemming but looks also at the context of a word, so e.g. the word &amp;quot;better&amp;quot; has the word &amp;quot;good&amp;quot; as its lemma. Lemmatisation can also be done when analyzing but is not as fast as stemming since it needs to look-up lemmas for words. &lt;br&gt; The content the Analyzer operates on needs to be plain text, so if a PDF file needs tokenization then the raw data first needs to be converted into plain text and only then the Analyzer can do its magic. Finally Analyzers are also used when we are searching. The search string needs to be processed the same way that the indexed text was processed (tokenized) and therefore it is crucial to use the same Analyzer for both indexing and searching.&lt;br&gt;&lt;br&gt; The &lt;b&gt;IndexWriter&amp;#39;s&lt;/b&gt; job is to take the input (a Document), pass the Document through the &lt;b&gt;Analyzer&lt;/b&gt;, and finally create the &lt;b&gt;Index&lt;/b&gt;. The IndexWriter creates a new index or reopens an existing one, adds, removes or updates documents in the Index. Think of an IndexWriter as an something that gives you write access to the index but doesn&amp;rsquo;t let you read or search it. &lt;br&gt; With Hibernate this happens transparently when a flush triggers a change to an indexed entity or collection. Hibernate then adds this change to a queue scoped by a transaction. When a commit operation is issued Hibernate Search will process the queue and apply the changes to the index or indexes. When a transaction is rolled back the queue will just be discarded without processing pending modifications to the index.&lt;br&gt; The IndexWriter keeps pending changes in a memory buffer until a threshold is reached - default is 16MB ram - after which a write to the Index is done (&lt;i&gt;buffering &lt;/i&gt;). The IndexWriter then flushes pending changes to the Index as new segments if: the RAM threshold is reached, a certain number of deletes is reached or if a certain number on new Documents have been added. After a &lt;i&gt;flush&lt;/i&gt; is done by an IndexWriter a Lucene commit needs to take place before any searches done by IndexSearcher can detect changes made. While an IndexWriter is making changes to the index, an IndexReader will not see any of these changes until commit() or close() is called.&lt;br&gt; When adding Documents to Lucene the Documents are not immediately written to disk due to performance reasons. How many to keep in memory before flushing out changes is governed by the mergefactor (default is 10 Documents). The mergeFactor value also means that once the number of segments on the disk has been reached, Lucene will merge these segments into a single segment. &lt;br&gt; In Hibernate Search the property hibernate.search.&amp;lt;indexname&amp;gt;.indexwriter.transaction.merge_factor passed to the SessionFactory is governing this behavior. There is also the property hibernate.search.&amp;lt;indexname&amp;gt;.indexwriter.batch.merge_factor which can be set for batch processes, i.e. when a large number of Documents are indexed (if not set defaults to the transaction version of this property).&lt;br&gt; When calling optimize() on an IndexWriter instance, all in-memory Documents are flushed and all index segments are merged into a single segment, reducing number of files that for the index. &lt;i&gt;Optimizing&lt;/i&gt; an index improves only the speed of searching due to the less number of index files that need to be opened, processed, and&amp;nbsp; searched.&amp;nbsp; Optimize should be done at the end of the indexing process, when you know the index will remain unmodified for a while. &lt;br&gt; Lucene uses a black-list approach when committing deleted documents to the index. This means that&amp;nbsp; the document is simply marked as deleted, which is a very quick operation, but the data corresponding to&amp;nbsp; that document is left in the segment files consuming disk space in the index.&amp;nbsp; It&amp;rsquo;s not until that segment is&amp;nbsp; merged away, either by normal merging over time or by an explicit call to optimize, that these bytes are&amp;nbsp; reclaimed. &lt;br&gt; Finally the &lt;b&gt;Directory&lt;/b&gt; class represents the location of a Lucene index. It is an abstract class that allows its subclasses (three of which are included in Lucene) to store the index as they see fit - in memory (RAMDirectory) or on disk (FSDirectory).&lt;br&gt;&lt;br&gt;&lt;div id="juoa" style="text-align:center"&gt;&lt;br&gt;&lt;/div&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br&gt;&lt;b&gt;&lt;font size="3"&gt;Searching&lt;/font&gt;&lt;br&gt;&lt;/b&gt;Nex up is the right leg - Searching. &lt;b&gt;&lt;br&gt;&lt;/b&gt;&lt;div id="jwgn" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_242fthh3c3c_b" style="height:694.008px;width:648px"&gt;&lt;br&gt;&lt;a href="https://doc-14-88-docs.googleusercontent.com/docs/secure/8bju2puaca73p3bvl0tbham924f299b1/1cl2gng81ov68h4pdotcja0jsqj6cecp/1294920000000/17190791760967981668/17190791760967981668/0ByyyxDxIt0pcYmQ4NjhjMWItNWIyMC00NDg2LWE5MjEtZDU3MzlkN2Y1YTUw?nonce=kj0siiftpaqf4&amp;amp;user=17190791760967981668&amp;amp;hash=3uf60jjnogg3bu9n1u10jtfpt0pualv8" id="djwe" title="Full pic"&gt;Full pic&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;b&gt;Searching Overview&lt;/b&gt;&lt;br&gt;When a user performs a search a Query will be issued against one or more indexes. The actual &lt;b&gt;Query&lt;/b&gt; object is built using a &lt;b&gt;QueryParser&lt;/b&gt; which passes the Query over to an &lt;b&gt;IndexSearcher&lt;/b&gt;. The IndexSearcher can optionally also use a &lt;b&gt;Filter&lt;/b&gt; together with the Query, whereby a subset of the results are returned.&amp;nbsp; A Filter can be anything that makes sense in the context of the search. A Filter could e.g. be created for all results valid only for a given City. Another example could be a Filter where some results are filtered out due to security restrictions. &lt;br&gt;The IndexSearcher returns a &lt;b&gt;TopDocs&lt;/b&gt;&amp;nbsp; instance which contains an ordered array with &lt;b&gt;ScoreDoc &lt;/b&gt;instances. A ScoreDoc instance in turn is holding the id of the Document and a score (a numeric value of relevance) for that &lt;b&gt;Document&lt;/b&gt;. A ScoreDoc is merely a pointer to a Document - not the Document itself. See below picture for an example.&lt;br&gt;&lt;br&gt;&lt;div id="l5y-" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_243gbwpgrc8_b" style="height:433px;width:605px"&gt;&lt;/div&gt;&lt;br&gt;&lt;b&gt;Searching Main Classes&lt;/b&gt;&lt;br&gt;Most of the classes where mentioned above in the overview. Their relationship is roughly as depicted in below class diagram.&lt;br&gt;&lt;br&gt;&lt;div id="iu45" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_244hmxcrwgg_b" style="height:549px;width:841px"&gt;&lt;/div&gt;&lt;br&gt;&lt;div id="mvqd" style="text-align:left"&gt;The &lt;b&gt;Searcher&lt;/b&gt; class is abstract with various overloaded search methods extended by the IndexSearcher. The search method returns an ordered collection of &lt;b&gt;TopDocs&lt;/b&gt; which holds Documents ranked by computed scores. Lucene calculates a score for each of the documents that match a given query. You can specify the number of top results that need to be retrieved by specifying it in the IndexSearcher&amp;rsquo;s search method.&lt;br&gt;When firing of a search a Query is created and issued against an Index using an &lt;b&gt;IndexSearcher&lt;/b&gt;. The IndexSearcher only accepts &lt;b&gt;Query &lt;/b&gt;objects and to create theses we use a QueryParser. An IndexSearcher is basically opening an index in a read-only mode. The IndexSearcher offers some methods to query indexes of which some are implemented in the inherited abstract class Searcher.&lt;br&gt;A &lt;b&gt;QueryParser &lt;/b&gt;translates a user entered search string into a Query object. The syntax which the QueryParser understands is governed by JavaCC (e.g. mathemati* ). An analogy of the search string is to think of it as a SQL expression which needs to be translated into something that the database (or in our case the search engine) can understand. The QueryParser does the translation of the string to something that Lucene understands. &lt;br&gt;A QueryParser also needs an Analyzer to break pieces of the search string into Tokens (same one as when indexing). The Query instance created from the QueryParser is then passed to the IndexSearcher. There are many different flavors of Query objects, some of which are shown below:&lt;br&gt;&lt;div id="tdi2" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_246f42strhp_b" style="height:425.806px;width:648px"&gt;&lt;/div&gt;&lt;br&gt;In the database world when you want to restrict on something you use a &amp;quot;where&amp;quot; condition in the issued query. In Lucene you can do the same using a a &lt;b&gt;Filter&lt;/b&gt;. E.g. a QueryWrappingFilter is wrapping a Query and is usable when you want to restrict on a certain field in your index. Consider a domain entity like Ad. If the Ad has not been verified we might not want to display this Ad in the results to the user. A QueryWrappingFilter is a good choice for doing this and could look like:&lt;br&gt;&lt;br&gt;&lt;div id="i-ov" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_247g4vcckgr_b" style="height:110.338px;width:648px"&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;Instead of using a filter you could also have used a BooleanQuery like below which could yield a query like : +isVerified:true (which can be copied and run on the index in Luke)&lt;br&gt;&lt;div id="uuos" style="text-align:center"&gt;&lt;div id="ixzb" style="text-align:left"&gt;&lt;div id="rry6" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_252rxtvmkfg_b" style="height:121px;width:590px"&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align:left"&gt;In Hibernate Search the syntax for querying is slightly different. Have a look at this example which will return a collection of Hibernate manged instances back to caller. The caller can update or even delete instances whereby the index underneath will also be updated or marked for deletion transparently to the caller upon transaction completion.&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="uwwj" style="text-align:center"&gt;&lt;div id="b9pm" style="text-align:center"&gt;&lt;div id="q.l4" style="text-align:center"&gt;&lt;div id="wbkn" style="text-align:center"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_254hc9vtrdf_b" style="height:164.769px;width:648px"&gt;&lt;/div&gt;&lt;br&gt;&lt;/div&gt;&lt;div style="text-align:left"&gt;Well that concludes our quick overview about Lucene and Hibernate Search. Of course a lot more could be added to this but maybe that will come in the future.&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;&lt;div id="poqt" style="text-align:left"&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-6967291833437092735?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/6967291833437092735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=6967291833437092735' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/6967291833437092735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/6967291833437092735'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2011/02/lucene-and-hibernate-search-small.html' title='Lucene and Hibernate Search - a small overview'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-3769868367233607823</id><published>2010-11-15T10:36:00.006+01:00</published><updated>2010-11-15T10:59:12.671+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cambobo'/><category scheme='http://www.blogger.com/atom/ns#' term='andreasgeorges'/><category scheme='http://www.blogger.com/atom/ns#' term='pet project'/><category scheme='http://www.blogger.com/atom/ns#' term='georges'/><category scheme='http://www.blogger.com/atom/ns#' term='andreas'/><title type='text'>Pet projects are nice...</title><content type='html'>...even nicer if they are finished ad go live. After two years of development during weekends and evenings we are getting close to launch time for our (Andreas an me) little pet project. We have been through 3 stacks of technologies and finally settled on one stack which will be the one we go live with. &lt;br /&gt;Anyway to facilitate our small but fast growing company ;-) we decided to launch this little company web page:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://andreasgeorges.com/"&gt;http://andreasgeorges.com/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is a kind of Ben and Jerry site - the ice cream site - although I promise our little pet project is not about ice creams.&lt;br /&gt;&lt;br /&gt;More to come&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-3769868367233607823?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/3769868367233607823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=3769868367233607823' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3769868367233607823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3769868367233607823'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2010/11/pet-projects-are-nice.html' title='Pet projects are nice...'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-1366458492151961546</id><published>2010-06-03T09:39:00.011+02:00</published><updated>2010-06-03T09:49:32.225+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java heap eden teanured permgen'/><title type='text'>Process heap, Eden, Tenured and Permgen</title><content type='html'>A picture says more than...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_rQklvZkZitQ/TAdedrUdJtI/AAAAAAAADdE/1I6SqKELZhc/s1600/JavaMemory.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 182px;" src="http://1.bp.blogspot.com/_rQklvZkZitQ/TAdedrUdJtI/AAAAAAAADdE/1I6SqKELZhc/s400/JavaMemory.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5478451335657236178" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-1366458492151961546?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/1366458492151961546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=1366458492151961546' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/1366458492151961546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/1366458492151961546'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2010/06/process-heap-eden-tenured-and-permgen.html' title='Process heap, Eden, Tenured and Permgen'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_rQklvZkZitQ/TAdedrUdJtI/AAAAAAAADdE/1I6SqKELZhc/s72-c/JavaMemory.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-7989368055065269971</id><published>2009-11-04T22:15:00.006+01:00</published><updated>2009-11-04T22:32:56.908+01:00</updated><title type='text'>Testing Syntaxhiglighter</title><content type='html'>To add a nice syntax highlightning I to make code easier to read do:&lt;br /&gt;&lt;br /&gt;1 Add this to you Blog template. Go into Layout &gt; Edit template and add this to you head tag:&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: html"&gt;&lt;br /&gt;&lt;head&gt;&lt;br /&gt;&lt;!--   syntaxhighlighter --&gt;&lt;br /&gt;&lt;link href='http://alexgorbatchev.com/pub/sh/2.1.364/styles/shCore.css' rel='stylesheet' type='text/css'/&gt; &lt;br /&gt;&lt;link href='http://alexgorbatchev.com/pub/sh/2.1.364/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/&gt; &lt;br /&gt;&lt;script src='http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shCore.js' type='text/javascript'/&gt; &lt;br /&gt;&lt;script src='http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushCss.js' type='text/javascript'/&gt; &lt;br /&gt;&lt;script src='http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJava.js' type='text/javascript'/&gt; &lt;br /&gt;&lt;script src='http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJScript.js' type='text/javascript'/&gt; &lt;br /&gt;&lt;script src='http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushSql.js' type='text/javascript'/&gt; &lt;br /&gt;&lt;script src='http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushXml.js' type='text/javascript'/&gt; &lt;br /&gt;&lt;script language='javascript'&gt; &lt;br /&gt;SyntaxHighlighter.config.bloggerMode = true;&lt;br /&gt;SyntaxHighlighter.config.clipboardSwf = &amp;#39;http://alexgorbatchev.com/pub/sh/2.1.364/scripts/clipboard.swf&amp;#39;;&lt;br /&gt;SyntaxHighlighter.all();&lt;br /&gt;&lt;/script&gt; &lt;br /&gt;&lt;!--  end syntaxhighlighter --&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2 Surround your code snippet with &lt;br /&gt;&lt;pre class="brush: html"&gt;&lt;br /&gt;    &lt;pre class="brush: java,html...."&gt;&lt;br /&gt;       &lt;br /&gt;    &lt;/pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The result might look like below &lt;br/&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;   @Test&lt;br /&gt;    public void testCreateUser_userIdAlreadyUsed() {&lt;br /&gt;        // Set expectations. For void methods we can not use the normal  expect(...).andReturn(...) idiom&lt;br /&gt;        // instead we use something EasyMock calls matchers - e.g. EasyMock.anyObject()&lt;br /&gt;        mockedActivityLoggerDao.persist((String) anyObject(), (Date) anyObject());&lt;br /&gt;        expectLastCall().anyTimes();&lt;br /&gt;        expect(mockedUserDao.findUserById("existingUserId")).andReturn(Boolean.TRUE).anyTimes();&lt;br /&gt;&lt;br /&gt;        // Stop recording expectations and add all mocks&lt;br /&gt;        replay(mockedActivityLoggerDao, mockedUserDao);&lt;br /&gt;&lt;br /&gt;        // Start the test and do the assertions. Instantiate our class beeing testet and pass it the mocked collaborator&lt;br /&gt;        User user = instanceUnderTest.createNewUser("existingUserId", "password", "James", "Gosssling", UserStatus.pending);&lt;br /&gt;        assertNull(user);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-7989368055065269971?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/7989368055065269971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=7989368055065269971' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/7989368055065269971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/7989368055065269971'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2009/11/testing-syntaxhiglighter.html' title='Testing Syntaxhiglighter'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-238608308536482651</id><published>2009-06-09T21:11:00.003+02:00</published><updated>2009-11-04T22:24:38.757+01:00</updated><title type='text'>Concordion - specification based testing part 2</title><content type='html'>&lt;div id="t_yg" style="text-align: left;"&gt;&lt;br /&gt;See original document at :&amp;nbsp; &lt;a title="Concordion - specification based testing part 2" href="http://docs.google.com/View?id=dfxnknzf_124k93tgkgj" id="k_80"&gt;Concordion - specification based testing part 2&lt;/a&gt; &amp;nbsp; &lt;br&gt;First post : &lt;a title="Concordion - specification based testing part 1" href="http://acupof.blogspot.com/2008/12/concordion-specification-based-testing_30.html" id="ltv4"&gt;Concordion - specification based testing part 1&lt;/a&gt; &lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a id="Background_4789320972234351_84" name="Background_4789320972234351_84"&gt;&lt;/a&gt;&lt;b id="ox7i"&gt;Background&lt;/b&gt;&lt;/h3&gt;&lt;br /&gt;The first part was an introduction to why you might want to use a tool like Concordion. It was more or less based on an internal presentation and used to promote Concordion to management and analysts where I currently work. In this part I will try to explain in more technical terms how it works, how we have setup Concordion in practice and also give a few examples of Concordion test we are running. Also please refer to the excellent Concordion site at : &lt;a title="http://www.concordion.org" href="http://www.concordion.org" id="owp2"&gt;http://www.concordion.org&lt;/a&gt; (by David Peterson). &lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a id="Concordion_basics_615433770875_03314118034555702" name="Concordion_basics_615433770875_03314118034555702"&gt;&lt;/a&gt;&lt;b&gt;Concordion definitions&lt;/b&gt;&lt;/h3&gt;&lt;br /&gt;Let us see how we can achieve our goals as defined in part 1 using Concordion as our testing framework. Before we look at examples there are some basic Concordion definitions we need to be aware of.&amp;nbsp; &lt;br&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A Concordion &lt;b&gt;specification&lt;/b&gt; is a &lt;a name="basics"&gt;well-formed XHTML&lt;br /&gt; document describing a set of functionality&lt;/a&gt; in plain English (or whatever language you would like to use) and also data which is used to instrument what is called a &lt;b&gt;fixture&lt;/b&gt;. The specification is the document where your business analyst or product owner should tell you what the test should do and check. The specification should be verbose enough to enable other stakeholders reading and understanding it. The first draft of the specification could be written in an OpenOffice document a wiki page or a text file - the important thing is that at some point it is converted (most probably by a developer) into a valid XHTML document containing the specification. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;A &lt;b&gt;fixture&lt;/b&gt; is a Java class that uses the specification as input, runs the specification against application code - the Service layer - and produces a &lt;b&gt;report&lt;/b&gt; with green and red colored assertions. For a developer the fixture is basically a JUnit test, only instead of having test data within a Java class we have it externalized into the specification. For a business developer the fixture not important, the report is. The report will tell the business developer if the requirements were met according to the specification.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div id="zwjx" style="text-align: center;"&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_134dkrxcsf5_b" width="315" height="195"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Figure:&lt;/b&gt; From specification and fixture we receive a nice looking report (which we can publish for stakeholders).&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;&lt;b&gt;&lt;b&gt;Concordion specification&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;&lt;br /&gt;A resulting Concordion report layout can look anyway you want it to look - using pictures, links etc. The Concordion specification determines the resulting layout and also how you call your fixture class. How to call your fixture class can be done in different ways. One way I found useful is a table based specification in which you can run a test over and over using different sets of instrumentation data (resembles a Fit test). Concordion provides support for this kind of tests using &lt;i&gt;&lt;a title="concordion:execute" href="http://www.concordion.org/Tutorial.html#executeTable" id="wn:n"&gt;concordion:execute on a table&lt;/a&gt;. &lt;br&gt;&lt;br /&gt;&lt;/i&gt;Below is an example of a specification using a a table based approach. The first part - concordion:execute - will call an underlying method in the fixture class called runConcordionIntegrationTest(....). The passed in values are #clientPartnerNo etc and the data passed in are given in under &lt;i&gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&lt;/i&gt; tags using concordion:set for each parameter. The assertions are done under the&amp;nbsp; &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt; tags where concordion:assertEquals are comparing values from the #result object created by the runConcordionIntegrationTest(....) method. The Result object is implemented as an inner class of the fixture and has a bunch of helper methods returning values that we can use Concordion assertions on. &lt;br&gt;&lt;br /&gt;&lt;div id="ab1-" style="text-align: left;"&gt;&lt;img style="width: 648px; height: 659.542px;" src="http://docs.google.com/File?id=dfxnknzf_144xx89kndq_b"&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Figure: &lt;/b&gt;A &lt;i&gt;&lt;a title="concordion:execute" href="http://www.concordion.org/Tutorial.html#executeTable" id="wn:n"&gt;concordion:execute on a table&lt;/a&gt;&lt;/i&gt; example&lt;br&gt;&lt;br /&gt;&lt;h3&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;Concordion fixture&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;&lt;br /&gt;In our setup we have a small hierarchy of classes in which our main test class is inheriting the BusinessTestCase, which has functionality reused in all our Concordion tests. MyBusinessTest class extends a Spring test class (rollbacks transactions, holds a jdbctemplat etc)&amp;nbsp; and is a convenience class which has helper methods reused in other Concordion tests. &lt;br /&gt;&lt;div id="dr9e" style="text-align: left;"&gt;&lt;img style="width: 392px; height: 354px;" src="http://docs.google.com/File?id=dfxnknzf_148fcrxwpnz_b"&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Figure:&lt;/b&gt; Class hierarchy used. &lt;/div&gt;&lt;br /&gt;In BusinessTestCase there is a method called runConcordion (see figure below):&lt;br /&gt;&lt;table style="width: 778px; height: 386px;" class="zeroBorder" bgcolor="#ffffcc" border="0" cellpadding="3" cellspacing="0"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td width="100%"&gt;&lt;br /&gt;&lt;pre&gt;&lt;a name="l106"&gt;&lt;/a&gt;&lt;font size="1"&gt;&lt;a name="l106"&gt;public abstract class BusinessTestCase&lt;br&gt;{&lt;br&gt;....&lt;br&gt;&lt;/a&gt;&lt;/font&gt;&lt;font size="1"&gt;&lt;a name="l106"&gt;public void runConcordionAndProcessSpecification() throws Throwable&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ConcordionBuilder concordionBuilder = new ConcordionBuilder();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Concordion concordion = concordionBuilder.build();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ResultSummary resultSummary;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (resource != null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;resultSummary = concordion.process(resource, this);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; resultSummary = concordion.process(this);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; resultSummary.print(System.out);&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; // This will write a summary file with one line: &lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; // Rate: &lt;span class="c_rate_succ"&gt;100.0&lt;/span&gt;%. Tests: &lt;span class="c_total"&gt;6&lt;/span&gt;, successes: &lt;span class="c_success"&gt;6&lt;/span&gt;, failures: &lt;span class="c_failure"&gt;0&lt;/span&gt;, exceptions: &lt;span class="c_exception"&gt;0&lt;/span&gt;. &lt;span class="c_rundate"&gt;3/5/09..&lt;/span&gt;&lt;br&gt; // This file is then the used by the wiki portal through small Javascript to show red green statuses&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ConcordionResultWriter.write(this, resultSummary);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; resultSummary.assertIsSatisfied();&lt;br&gt;}&lt;br&gt;....&lt;br&gt;}&lt;/a&gt;&lt;/font&gt;&lt;a name="l106"&gt;&lt;/a&gt;&lt;/pre&gt;&lt;br /&gt; &lt;/td&gt;&lt;br /&gt; &lt;/tr&gt;&lt;br /&gt; &lt;/tbody&gt;&lt;br /&gt; &lt;/table&gt;&lt;br /&gt;&lt;b&gt;Figure:&lt;/b&gt; Small code running the Concordion test and also writing out a file used by our Concordion portal page (Twiki)&lt;br /&gt;&lt;div id="bkev" style="text-align: left;"&gt;&lt;br /&gt;&lt;h3&gt;Concordion portal &lt;br&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;At the end of the day we want to show the output from the Concordion test runs without forcing users to go into each Concordion report to see the individual outcome of a Concordion test run. What we would like is a nice portal page where all Concordion test reports are listed as links to each one of the Concordion reports. The individual detailed Concordion report would most probably only be viewed at when there is an error displayed on the Concordion portal page, or perhaps if somebody wants to read the specification and and get an understanding of a specific business process or use case. The portal page helps give an overivew over all Concordion tests.&lt;br&gt;&lt;br /&gt;To help us achieve this we used Twiki (was already used) in which were developers can enter a link to their Concordion report. The Twiki page also uses some Javascript to parse a also the summary file mentioned above - which helps produce red / green bullets in the twiki page. The Javascript also aggregates the total result and checks that the date of the generated file is todays date. When a Concordion test is not ran during the night it will be flagged with red due to the date check done by the Javascript.&lt;br&gt;&lt;br /&gt;Since we already were using CruiseControl to run our JUnit test suites we decided to let CruiseControl also run the Concordion test suites (any other build server supporting ANt / Junit will work of course). The reports generated by Concordion are stored on an Apache web server and this web server directory is fronted / decorated using a above mentioned wiki page.&lt;br&gt;&lt;br /&gt;We opted to use a Concordion test suite per business module within the system. Each buisness module has its own header in the Twiki - se below picture.&lt;br&gt;&lt;br /&gt;&lt;div id="zutw" style="text-align: left;"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_143ffht6vf5_b" width="767" height="656"&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Figure:&lt;/b&gt; Nightly build portal page for Concordion tests. Different modules have their own section listing the Concordion tests giving a nice quick overview over all tests.&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;h3&gt;Concordion example reports&lt;br&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;The ways to create and layout a report are endless. The layout and the contents of the report would be the responsibility of your business developer to define together with the developer/s. Any data that injected into the actual fixture and displayed in the report should be an business id (e.g. one which can be used from a GUI to look-up the actual data). Do not use an id that does not have meaning to someone outside your development department. An id which means that a business guy needs to use sql to understand what it means is probably not a good id to display in the Concordion report.&lt;br&gt;&lt;br /&gt;&lt;div id="fin5" style="text-align: left;"&gt;&lt;img style="width: 904px; height: 458px;" src="http://docs.google.com/File?id=dfxnknzf_139hf2w7gd9_b"&gt;&lt;br&gt;&lt;br /&gt;&lt;b&gt;Figure:&lt;/b&gt; Concordion test where we used a concordion:table approach, although in this case we only have one row we could easily add more rows to test different paths. This is much like a Fit test - but much easier to understand and use.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Another example report is shown below, not so fancy and no pictures. The Concordion specification tries to use a domain language to express what is the purpose and expected result. Embedded in the Concordion specification are assertions made showing up in green (or red). One thing that Concordion does not have - currently - is reuse of other specifications. In the example below we actually would benefit from a reusable Concordion specification in the setup part of the specification.&lt;br&gt;&lt;br /&gt;&lt;div id="g2bz" style="text-align: left;"&gt;&lt;img style="width: 901px; height: 648px;" src="http://docs.google.com/File?id=dfxnknzf_140htb64wck_b"&gt;&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Finally &lt;/h3&gt;&lt;br /&gt;I listed some of the things you might want to watch out for when writing Concordion below&lt;br&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Do not write to technical Concordion tests. Concordion tests that are not meant to replace unit tests - some tests are just better of as unit tests. Low level unit tests that does not have meaning to anyone except for the guy who actually wrote the test and other developers are better of in a unit test. Once you start writing Concordion tests and have all the "surrounding" environment setup it is really easy to fall into writing every single test as a Concordion test. To many Concordion test on lower level hides the "more important" business tests. An example of a not so intuitive Concordion test which in my opinion would be more suitable as a unit test is given below:&lt;br&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;div id="pcxu" style="text-align: left;"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_136g3jjqzd9_b" width="531" height="164"&gt;&lt;/div&gt;&lt;br /&gt;Do not write big Concordion specifications. Concordion specifications that try to cover to much - different use cases all rolled into one Concordion specification - are hard to read and hard to maintain. Some of my early Concordion tests where far too long and were later on split into to smaller parts. &lt;br&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Write Concordion tests early. Less motivation and the ability to forget things as time passes by makes it harder to write them after a Sprint has completed - and your business guy might not be so keen on writing it afterwards since they moved on to new assignments.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Keep them green. If a Concordion test is starting to show red more often than it shows green it will make stakeholders uninterested at them. Beware of&amp;nbsp; "they are usually broken" comments. Sometimes it might be better to remove a Concordion test from a suite if it has been showing red too long. Keeping them green is easier for a small sized system - but when a system is somewhat big with a lot of interfaces to other systems it is much harder to keep&lt;br /&gt;them green.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Concordion is a great tool to use for your integration test layer. For a developer it is easy to use - if you know JUnit you practically already know how to use Concordion. For your business guys it shine with its tranparency of the test results. Above I mentioned the portal page we use - in the latest Concordion release there is something like a portal page support implemented (di not have the time to check yet).&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br id="ox7i9"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-238608308536482651?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/238608308536482651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=238608308536482651' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/238608308536482651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/238608308536482651'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2009/06/concordion-specification-based-testing.html' title='Concordion - specification based testing part 2'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-4564255060004897683</id><published>2009-03-02T16:33:00.004+01:00</published><updated>2009-03-02T20:54:59.550+01:00</updated><title type='text'>GWT, Tomcat lite and Intellij</title><content type='html'>A normal layout directory of Tomcat lite looks like:&lt;br&gt;&lt;br /&gt;&lt;div id="i6vu" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 298px; height: 200px;" src="http://docs.google.com/File?id=dfxnknzf_129cwdh65k3_b"&gt;&lt;br&gt;&lt;br /&gt;To point to this directory from Intellij use the -Dcatalina.base (Tomcat) property to point to the Tomcat "lite" directory where you have all your configuration and property files set up.&lt;br&gt;&lt;br /&gt;&lt;img style="width: 648px; height: 146.732px;" src="http://docs.google.com/File?id=dfxnknzf_131c3w7kbhn_b"&gt;&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-4564255060004897683?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/4564255060004897683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=4564255060004897683' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4564255060004897683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4564255060004897683'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2009/03/gwt-tomcat-lite-and-intellij.html' title='GWT, Tomcat lite and Intellij'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-5379915170867749212</id><published>2008-12-30T13:07:00.002+01:00</published><updated>2009-02-20T08:14:16.491+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='concordion junit testng testing specification based testing java'/><title type='text'>Concordion - specification based testing part 1</title><content type='html'>&lt;div&gt;&lt;br /&gt;  See original document at &lt;b&gt;&lt;a target="_blank" href="http://docs.google.com/Doc?id=dfxnknzf_114hjs2k5hm" id="hudq" title="Concordion - sepcification based testing part 1"&gt;Concordion - specification based testing part 1&lt;/a&gt;&lt;/b&gt;&lt;br&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;  &lt;br&gt;&lt;br /&gt;Background&amp;nbsp; &lt;/b&gt;&lt;br&gt;&lt;br /&gt;  I am currently working in a banking and finance project where the system handles straight through processing of buy and sell orders coming from the stock exchange. As I started little over a year ago we did not have any automatic integration tests in place, the set of unit tests were in a miserable state with a success rate round 50% - and nobody seemed to care (or have time to care). In previous projects I was used to a strong focus on unit testing and in the long run they always seemed to pay of. Now, one year later our JUnit tests are working, and on top of that we have a large set of automated integration tests using Concordion which are increasing for each milestone. Concordion has really made the business side engaged and dare I say excited to be part of the test writing process. In the past before joining my this company I had been using Fit and also JUnit to help doing integration testing. Fit is a nice tool for writing specifications in html and exercising your system with glue code written in Java (other languages are supported as well). Fit was invented in 2002 by Ward Cunningham and has been further developed into Fitnesse (a wiki frontend to Fit basically) - more info at &lt;a href="http://en.wikipedia.org/wiki/Framework_for_Integrated_Tests" id="nqkf" title="Wikipedia - Fit"&gt;Wikipedia - Fit&lt;/a&gt;. Although Fit is nice it lacks the easy setup that Concordion has - no special Fit runners are needed just invoke your Concordion tests as you would invoke any other JUnit test in your development environment. And on top of being easy for developers, the output looks really great, the Concordion website is really good and finally, the guy who wrote it and is maintaining it (&lt;a href="http://www.davidpeterson.co.uk/"&gt;David&amp;nbsp;Peterson&lt;/a&gt;) is very quick in answering any of your questions on the mailing list of Concordion. The first part of this blog entry is more about why you would want to use Concordion and the second is more technical about how it works and how we have set it up in my current project. The material was used to kick things of where I work - so perhaps it might help you do the same thing at your work. &lt;b&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;  What are our goals ?&lt;/b&gt;&lt;br&gt;&lt;br /&gt;  At the end of the day we want to have a solid system and a happy customer. To achieve this we would like to have a few things like:&lt;br /&gt;  &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;    &lt;li&gt;      Automate testing. Focus on service layer where use case starts, typically an session ejb or transaction demarcated Spring bean.&lt;br /&gt;    &lt;/li&gt;&lt;br /&gt;    &lt;li&gt;      Visualize input and output for developers as well as non developers, thereby minimizing conceptual barriers between developers and non developers.&lt;br /&gt;    &lt;/li&gt;&lt;br /&gt;    &lt;li&gt;      Couple business specifications closer to running code, thereby avoiding divergence.&lt;br /&gt;    &lt;/li&gt;&lt;br /&gt;    &lt;li&gt;      Instrument tests with data outside of actual test code.&lt;br /&gt;    &lt;/li&gt;&lt;br /&gt;  &lt;/ul&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;  So lets go through the goals one by one and later on have a look on more technical details on how Concordion works and how we set things up with a TWiki and CruiseControl.&lt;br&gt;&lt;br /&gt;  &lt;b&gt;&lt;br&gt;&lt;br /&gt;Automating service layer integration tests&lt;/b&gt;&lt;br /&gt;  &lt;br /&gt;&lt;p&gt;&lt;br /&gt;    Fortunately as a Java developer there are a multitude of different testing tools to choose from. Some testing tools are more cross cutting like e.g. CruiseControl and help exercise the actual tests while others are more targeted on different layers of your application stack like JUnit or Selenium. One could picture it as a pyramid where you have most of the running application code at the bottom exercised by developer only tools like JUnit or TestNG. At the top of the pyramid one could use Selenium to test the system through recorded test cases that can run in your continuous integration server (like CruiseControl). Selenium is a bit fragile when user interfaces changes are frequent - so I would prefer to focus more on the service or business layer. I also use EasyMock for testing framework dependent code - e.g. code extending some nasty hierarchy of abstract classes. EasyMock works great and is quite easy to use with the Java5 support they have.&lt;br /&gt;  &lt;/p&gt;&lt;br /&gt;  &lt;img src="http://docs.google.com/File?id=dfxnknzf_115g6t7rhgd_b" style="width: 331px; height: 181px;"&gt;&lt;br&gt;&lt;br /&gt;  &lt;b&gt;&lt;br&gt;&lt;br /&gt;Visualize input and output, minimize barriers&lt;/b&gt;&lt;br&gt;&lt;br /&gt;  JUnit is great as a developer tool for writing unit tests quickly. It makes refactoring easier and helps other developers understand what you as a developer coded. One problem with JUnit is that non developers, e.g. business analysts, do not know or understand what JUnit is actually doing or testing. And if you do not understand something you do not get involved. Concordion on the other side, has the advantage of JUnit (it actually is extending JUnit) and additionally also adds the benefit of visualizing the input and output of a test run. Concordion is a specification tool which encourages non developers to write the specification before actual implementation starts. This is really the biggest strength of Concordion - encouraging discussion between different members of a team and getting the "other side" involved. For a developer to have a specification that can actually be exercised instead of a text document is a great advantage and forces the business developer to think through the business case thoroughly. The requirements are clearer since it is obviously hard to write the actual business implementation if the Concordion specification is not understood. Requirements are interpreted by developers in one way and by testers in another way – and tested against the artifact of developers i.e. the code.&lt;br&gt;&lt;br /&gt;  &lt;b&gt;&lt;br&gt;&lt;br /&gt;Tighter coupling, avoiding divergence. &lt;/b&gt;&lt;br&gt;&lt;br /&gt;  Consider what happens with a specification written in a text document and what happens to the actual application code being developed over a period of time. Which of these two artifacts is closest to the truth on what the application is doing? Or consider an UML class diagram artifact describing the relationship between entities in your application compared to the actual entities as coded and annotated in your running application. Obviously, the application code is closer to the truth on what actually is implemented, rather than an UML artifact or a requirements document. Why? Well, what usually happens over time is that some newly written code is changing rapidly in the beginning and finally stabilizes somewhat. New requirements not foreseen are quickly implemented no meet the deadline - but the original requirement document or UML diagram is not changed accordingly and the description of the application is not up to date. The application code and the high level documents start to diverge from the code. Concordion tries to solve this divergence by tighter coupling of specifications into the code tree and actually having specifications &lt;b&gt;version ed&lt;/b&gt; along with the application code. makes divergence less probable.&lt;br /&gt;  &lt;br /&gt;&lt;div id="t_yg" style="padding: 1em 0pt; text-align: left;"&gt;&lt;br /&gt;    &lt;img src="http://docs.google.com/File?id=dfxnknzf_117dwf96tgx_b" style="width: 313px; height: 234px;"&gt;&lt;br&gt;&lt;br /&gt;    &lt;b&gt;Instrumentation of test data, or test data injection &lt;/b&gt;&lt;br&gt;&lt;br /&gt;    How many times have you not put some hard coded test data into your unit tests? Concordion lets you abstract these test data away and put the test data into the Concordion specification (basically a html file) so that the fixture (the glue between the specification and the application code being tested, basically a Java class) is clean. Furthermore - using a table format in the Concordion specification helps running the same test fixture over and over again with different input data. Below is an example where the same test fixture is run twice - once for each row. The 2 columns to the left are data injected into the test fixture for every run and the asserted data is the green columns. The "Generated Delivery" column is the business object being produced after a successful run and can be used within the actual system for further investigation - especially if the test fails. &lt;img src="http://docs.google.com/File?id=dfxnknzf_126gphd6xc2_b" style="width: 779px; height: 86px;"&gt;&lt;br&gt;&lt;br /&gt;    On part 2 of this blog entry we will look into how Concordion works and how we used it at my current work location.&lt;br /&gt;  &lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-5379915170867749212?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/5379915170867749212/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=5379915170867749212' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/5379915170867749212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/5379915170867749212'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2008/12/concordion-specification-based-testing_30.html' title='Concordion - specification based testing part 1'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-1648701802497023073</id><published>2008-04-07T08:36:00.007+02:00</published><updated>2008-04-07T09:04:19.163+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Weblogiy p6spy hibernate java'/><title type='text'>Spying on SQL in Weblogic using P6Spy</title><content type='html'>Sometimes it might be good to actually see what is going on between your application server and the database. To set the stage for this we ar going to follow these little instructions:&lt;br /&gt;&lt;br /&gt;1 Download P6Spy and unpack to get the jar and spy.properties file. P6Spy is old but still works nice - &lt;a href="http://www.p6spy.com/"&gt;P6Spy&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2 Copy the jar file into an arbitrary folder and let Weblogic know this by adding it &lt;br /&gt;to the classpath. In startWebLogic.cmd do:&lt;br /&gt;set CLASSPATH=%CLASSPATH%;%WEBLOGIC_CLASSPATH%;....C:/...../p6spy-1.3.jar&lt;br /&gt;&lt;br /&gt;3 Copy the spy.properties file to the root location of your server (domain instance) so that it will be picked up on start.&lt;br /&gt;&lt;br /&gt;4 Alter the spy.properties file and change according to what datbase you are using. E.g for Oracle use:&lt;br /&gt;realdriver=oracle.jdbc.driver.OracleDriver&lt;br /&gt;useprefix=true&lt;br /&gt;deregisterdrivers=true&lt;br /&gt;logfile     = C:/bea/..../logs/spy.log&lt;br /&gt;&lt;br /&gt;5 Finally change the config.xml file (root of your domain instance) so that the pool configuration will be:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_rQklvZkZitQ/R_nG-0q6z3I/AAAAAAAAA6c/se3e31Dc-DM/s1600-h/config.xml.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_rQklvZkZitQ/R_nG-0q6z3I/AAAAAAAAA6c/se3e31Dc-DM/s320/config.xml.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5186395228486684530" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now you are able to tail the spy.log file for all SQL statements going on. Very useful for debugging Hibernate stuff.&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-1648701802497023073?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/1648701802497023073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=1648701802497023073' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/1648701802497023073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/1648701802497023073'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2008/04/spying-on-sql-in-weblogic-using-p6spy.html' title='Spying on SQL in Weblogic using P6Spy'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_rQklvZkZitQ/R_nG-0q6z3I/AAAAAAAAA6c/se3e31Dc-DM/s72-c/config.xml.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-5882334770962496908</id><published>2008-04-04T20:29:00.005+02:00</published><updated>2008-10-06T22:56:07.750+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate cache readonly mutable ReadOnlyCach'/><title type='text'>Hibernate cache : UnsupportedOperationException</title><content type='html'>Consider the exception below :&lt;br /&gt;&lt;br /&gt;2008-04-01 15:34:22,828 ERROR org.hibernate.cache.ReadOnlyCache - Application attempted to edit read only item: org.grouter.dao.TheDAO.aCollection#org.grouter.dao.dao.TheClass@148ad&lt;br /&gt;java.lang.UnsupportedOperationException: Can't write to a readonly object&lt;br /&gt;    at org.hibernate.cache.ReadOnlyCache.lock(ReadOnlyCache.java:43)&lt;br /&gt;    at org.hibernate.action.CollectionAction.beforeExecutions(CollectionAction.java:110)&lt;br /&gt;    at org.hibernate.engine.ActionQueue.prepareActions(ActionQueue.java:257)&lt;br /&gt;&lt;br /&gt;If you have this exception it is probably due to you your caching strategy settings for Hibernate beeing set to read-only. This can be set on entity level and also on collection level. If an entity marked as read-only has a collection of another read-only collection then you need to ensure that both the originating entity and the collection of entities are both marked ar mutable="false". This should be set on both entity A and the entities of the collection belonging to entity A. Setting mutable="false" is the same as to say they are immutable, i.e. not changed after creation. &lt;br /&gt;However, this might not solve everything for you. Consider an entity A is set to read-only and has a collection with read-only entities B. If you load A and use a setter on A after beeing loaded the entity will be marked as dirty - above exception will be thrown. Now if A is loaded and a new query is issued to get the collection of read-only B entites and then set on the entity A - setCollection(newColl) - then again the above exception will be thrown.&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-5882334770962496908?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/5882334770962496908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=5882334770962496908' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/5882334770962496908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/5882334770962496908'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2008/04/hibernate-cache-unsupportedoperationexc.html' title='Hibernate cache : UnsupportedOperationException'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-3462415431347751757</id><published>2008-03-19T09:30:00.010+01:00</published><updated>2008-03-19T20:30:10.418+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='weblogic intellij debug remote'/><title type='text'>Remote debug Weblogic or JBoss from Intellij</title><content type='html'>Although I tend to write unit tests for almost everything I write - one java class &lt;-&gt; one junit class - I sometimes have a need to be able to step into the executing code of an application server and debug the running code.  Java has a standard way of debugging remotely for a running Java process which is very nice. &lt;br /&gt;To remote deubg Weblogic from Intellij&lt;br /&gt;1 - Start the application server up with a set of debug switches. In Weblogic 8.1 you would alter the start up script (setup.cmd or something like that) and put: set DEBUG_PORT=19001&lt;br /&gt;set JAVA_OPTIONS_DEBUG=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=%DEBUG_PORT%,suspend=n,server=y&lt;br /&gt;When weblogic starts it will listen for incoming request on port 19001&lt;br /&gt;2 - In Intellij you create a debug configuration. Choose Run / Debug and click +. Choose, in this case, Weblogic and alter settings according below picture. In Weblogic the name of the server is the name of your application under your domain, something like config/mydomain/applicationsnameOfServer.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_rQklvZkZitQ/R-DTw1lNthI/AAAAAAAAA6E/wIN-EPnyLUs/s1600-h/intellij_wls.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_rQklvZkZitQ/R-DTw1lNthI/AAAAAAAAA6E/wIN-EPnyLUs/s320/intellij_wls.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5179372407446418962" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And on the Startup/Connection tab you alter accoring to:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_rQklvZkZitQ/R-DUKVlNtiI/AAAAAAAAA6M/CGJknDaDV60/s1600-h/intellij_wls2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_rQklvZkZitQ/R-DUKVlNtiI/AAAAAAAAA6M/CGJknDaDV60/s320/intellij_wls2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5179372845533083170" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To remote debug JBoss from Intellij:&lt;br /&gt;1 Add this to run.sh &lt;br /&gt;JAVA_OPTS="$JAVA_OPTS -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=4142,suspend=n"&lt;br /&gt;2 Then alter Intelliij debug confiuratino&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_rQklvZkZitQ/R-FbiFlNtjI/AAAAAAAAA6U/7b__OXBKvCg/s1600-h/intellij_jboss_png.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_rQklvZkZitQ/R-FbiFlNtjI/AAAAAAAAA6U/7b__OXBKvCg/s320/intellij_jboss_png.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5179521687624726066" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-3462415431347751757?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/3462415431347751757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=3462415431347751757' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3462415431347751757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3462415431347751757'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2008/03/debug-weblogic-intellij-or-jboss.html' title='Remote debug Weblogic or JBoss from Intellij'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_rQklvZkZitQ/R-DTw1lNthI/AAAAAAAAA6E/wIN-EPnyLUs/s72-c/intellij_wls.png' height='72' width='72'/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-4214579173455389636</id><published>2008-01-31T08:28:00.000+01:00</published><updated>2008-02-10T21:39:07.554+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate spring sessionfactory session cache 2nd level cche 1st level cache ehcache'/><title type='text'>Hibernate Caches</title><content type='html'>                                &lt;b&gt;Background&lt;/b&gt;&lt;br&gt; Hibernate comes with three different caching mechanisms - first level, second level and query cache. Truly understanding how the Hibernate caches work and interact with each other is important when you need to increase performance - just enabling caching in your entity with an annotation (or in classic .hbm.xml mapping file) is easy. But understanding what and how things happens behind the scenes is not. You might even end up with a less performing system if you do not know what you are doing.&lt;br&gt; &lt;br&gt; &lt;b&gt;SessionFactory and Session&lt;br&gt; &lt;/b&gt;The purpose of the Hibernate SessionFactory (called EntityManager in JEE) is to create Sessions, initialize JDBC connections and pool them (using a pluggable provider like C3P0). A SessionFactory is immutable and built from a Configuration holding mapping information, cache information and a lot of other information usually provided by means of a hibernate.cfg.cml file or through a Spring bean configuration.&lt;br&gt; A Session is a unit of work at its lowest level - representing a transaction in database lingua. When a Session is created and operations are done on Hibernate entities, e.g. setting an attribute of an entity, Hibernate does not go of and update the underlying table immediately. Instead Hibernate keeps track of the state of an entity, whether it is dirty or not, and flushes (commits) updates at the end at the end of a unit of work. This is what Hibernate calls the first level cache.&lt;br&gt; &lt;br&gt; &lt;b&gt;The 1st level cache&lt;br&gt; &lt;/b&gt; Definition: The first level cache is where Hibernate keeps track of the possible dirty states of the ongoing Session's loaded and touched entities. The ongoing Session represents a unit of work and is always used and can not be turned of. The purpose of the first level cache is to hinder to many SQL queries or updates beeing made to the database, and instead batch them together at the end of the Session. When you think about the 1st level cache think Session.&lt;br&gt; &lt;br&gt; &lt;div id="ht7_" style="padding: 1em 0pt; text-align: left;"&gt;   &lt;div id="rb.n" style="padding: 1em 0pt; text-align: left;"&gt;     &lt;div id="y843" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 800px; height: 344px;" src="http://docs.google.com/File?id=dfxnknzf_102cm8chxg8"&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;   &lt;/div&gt;   &lt;br&gt; &lt;/div&gt; &lt;b&gt;The 2nd level cache&lt;br&gt; &lt;/b&gt;The 2nd level cache is a process scoped cache that is associated with one SessionFactory. It will survive Sessions and can be reused in new Session by same SessionFactory (which usually is one per application). By default the 2nd level cache is not enabled. &lt;br&gt;The hibernate cache does not store instances of an entity - instead Hibernate uses something called dehydrated state. A dehydrated state can be thought of as a deserialized entity where the dehydrated state is like an array of strings, integers etc and the id of the entity is the pointer to the dehydrated entity. Conceptually you can think of it as a Map which contains the id as key and an array as value. Or something like below for a cache region:&lt;br&gt;&lt;br&gt;{ id -&amp;gt; { atribute1, attribute2, attribute3 } }   &lt;br&gt;{ 1 -&amp;gt; {  "a name", 20, null } }&lt;br&gt;{ 2 -&amp;gt; {  "another name", 30, 4 } }&lt;br&gt;&lt;br&gt;If the entity holds a collection of other entities then the other entity also needs to be cached. In this case it could look something like:&lt;br&gt;&lt;br&gt;{ id -&amp;gt; { atribute1, attribute2, attribute3, Set{item1..n} } }   &lt;br&gt; { 1 -&amp;gt; {  "a name", 20, null , {1,2,5} } }&lt;br&gt; { 2 -&amp;gt; {  "another name", 30, 4 {4,8}} }&lt;br&gt; &lt;br&gt;The actual implementation of the 2nd level cache is not done by Hibernate (there is a simple Hashtable cache available, not aimed for production though). Hibernate instead has a plugin concept for caching providers which is used by e.g. EHCache.&lt;br&gt;&lt;br&gt;&lt;b&gt;Enabling the 2nd level cache and EHCache&lt;/b&gt;&lt;br&gt;To get the 2nd level cache working you need to do 2 things:&lt;br&gt; &lt;b&gt;1 Cache Strategy.&lt;/b&gt; Enable a cache strategy for your Hibernate entity - either in the class with an annotation or in the hibernate mapping xml file if you are stuck with pre java5. This can be done for an entity by providing this little snippet into your hbm.xml file (a better place is to store the cache setting strategy in hibernate.cg.xml file )&lt;br&gt;&lt;br&gt;&amp;lt;class name="org.grouter.domain.entities.Router" table="ROUTER"&amp;gt;&lt;br&gt;    &amp;lt;cache usage="transactional|read-write|nonstrict-read-write|read-only" /&amp;gt;&lt;br&gt;    &amp;lt;id ...&lt;br&gt;&amp;lt;/class&amp;gt;&lt;br&gt; &lt;br&gt;or using an annotation for your entity (if you are on java5 or greater)&lt;br&gt;&lt;br&gt;@Entity&lt;br&gt;@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)&lt;br&gt;public class Router { ... }&lt;br&gt;&lt;pre class="programlisting"&gt;And as mentioned above if you want to cache collections of an entity you need to specify caching on collection level:&lt;br&gt;&amp;lt;class name="org.grouter.domain.entities.Router" table="ROUTER"&amp;gt;&lt;br&gt;    &amp;lt;cache usage="transactional|read-write|nonstrict-read-write|read-only"/&amp;gt;&lt;br&gt;    &amp;lt;id ...&lt;br&gt;    &amp;lt;set name="nodes"&amp;gt;&lt;br&gt;        &amp;lt;cache usage="transactional|read-write|nonstrict-read-write|read-only"/&amp;gt;&lt;br&gt;        ...&lt;br&gt;    &amp;lt;/set&amp;gt;&lt;br&gt;&amp;lt;/class&amp;gt;&lt;br&gt;&lt;/pre&gt; Hibernate has something called a cache region which by default will be the full qualified name of your Java class. And if you like me are a fan of convention over configuration you will use the default region for an entity. A cache region will also be needed for the collection using the full qualified name of the Java class plus the name of the collection name (i.e. org.grouter.domain.entities.Router.nodes)&lt;br&gt;&lt;br&gt;&lt;b&gt;2 Cache provider.&lt;/b&gt; Setting up the physical caching for a cache provider. If you are using EHCache - which is the most common choice i dear to say - then you will need to specify some settings for the cache regions of your entities in a file called ehcache.xml.  The EHCache will look for this file in the classpath and if not found it will fallback to ehcache-failsafe.xml which resides in the ehcache.jar library  A typical sample for an EHCache configuration could look like (see mind map below for explanations):&lt;br&gt;&lt;br&gt;&amp;lt;cache name="org.grouter.domain.entities.Router" maxElementsInMemory="1000" eternal="false" timeToLiveSeconds="600" overflowToDisk="false"/&amp;gt;&lt;br&gt;and&lt;br&gt;&amp;lt;cache name="org.grouter.domain.entities.Router.nodes" maxElementsInMemory="1000" eternal="false" timeToLiveSeconds="600" overflowToDisk="false"/&amp;gt;&lt;br&gt;&lt;br&gt;The name maps to the name of the cache region of your entity. The attribute maxelementsInMemory needs to be set so that Hibernate does not have to swap in and out elements from the cache. A good choice for a read only cache would be as many entities there are in the database table the entity represents. The attribute eternal, if set to true means that any time outs specified will be ignored and entities put into the cache from Hibernate will live for ever.&lt;br&gt;Below is a mindmap for the second level cache and how it relates to the SessionFactory and the 1st level cache.    &lt;div id="f_-y" style="padding: 1em 0pt; text-align: left;"&gt;&lt;div id="e1bu" style="padding: 1em 0pt; text-align: left;"&gt;&lt;a target="_blank" href="File?id=dfxnknzf_99f2m4n3ht"&gt;&lt;div id="y0yq" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 1000px; height: 730px;" src="http://docs.google.com/File?id=dfxnknzf_103xtw5bsdf"&gt;&lt;/div&gt;&lt;br&gt;&lt;/a&gt;   &lt;/div&gt;   &lt;b&gt;The Query cache&lt;br&gt;&lt;/b&gt;The Query cache of Hibernate is not on by default. It uses two cache regions called org.hibernate.cache.StandardQueryCache and org.hibernate.cache.UpdateTimestampsCache. The first one stores the query along with the parameters to the query as a key into the cache and the last one keeps track of stale query results. If an entity part of a cached query is updated the the query cache evicts the query and its cached result from the query cache. Of course to utilize the Query cache the returned and used entities must be set using a cache strategy as discussed previously. A simple load( id ) will not use the query cache but instead if you have a query like:&lt;br&gt;&lt;br&gt;&lt;div&gt;&lt;table bgcolor="#ffffcc" border="0" cellpadding="3" cellspacing="0" height="71" width="994"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="100%"&gt;&lt;pre&gt;Query query = session.createQuery("from Router as r where r.created = :creationDate");&lt;br&gt;query.setParameter("creationDate", new Date());&lt;br&gt;query.setCacheable(true);&lt;br&gt;List l = query.list(); // will return one instance with id 4321&lt;a name="l106"&gt;&lt;/a&gt;&lt;a name="l106"&gt;&lt;/a&gt;&lt;/pre&gt;       &lt;/td&gt;     &lt;/tr&gt;     &lt;/tbody&gt;   &lt;/table&gt;&lt;/div&gt;&lt;br&gt;Hibernate will cache using as key the query and the parameters the value of the if of the entity. &lt;br&gt;{ query,{parameters}}    ---&amp;gt;   {id of cached entity}&lt;br&gt;{"from Router as r where r.id= :id and r.created = :creationDate", [ new Date() ] } ----&amp;gt; [ 4321 ] ]&lt;br&gt;&lt;b&gt;&lt;br&gt;&lt;div id="y8z9" style="padding: 1em 0pt; text-align: left;"&gt;&lt;a href="File?id=dfxnknzf_101f6qctrf5" target="_blank"&gt;&lt;div id="xmkc" style="padding: 1em 0pt; text-align: left;"&gt;&lt;div id="isn8" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 950px; height: 698px;" src="http://docs.google.com/File?id=dfxnknzf_105cgq9j7g2"&gt;&lt;/div&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;Pragmatic approach to the 2nd level cache&lt;br&gt;&lt;/b&gt;How do you now if you are hitting the cache or not? One way is using Hibernates SessionFactory to get statistics for cache hits. In your SessionFactory configuration you can enable the cache statistics by:&lt;br&gt;&lt;br&gt;                 &amp;lt;prop key="hibernate.show_sql"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br&gt;                &amp;lt;prop key="hibernate.format_sql"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br&gt;                &amp;lt;prop key="hibernate.use_sql_comments"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br&gt;                &amp;lt;prop key="hibernate.cache.use_query_cache"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br&gt;                &amp;lt;prop key="hibernate.cache.use_second_level_cache"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br&gt;                &amp;lt;prop key="hibernate.generate_statistics"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br&gt;                &amp;lt;prop key="hibernate.cache.use_structured_entries"&amp;gt;true&amp;lt;/prop&amp;gt;&lt;br&gt;&lt;br&gt;The you might want to write a unit test to verify that you indeed are hitting the cache. Below is some sample code where the unit test is extending Springs &lt;a name="l106"&gt;excellent AbstractTransactionalDataSourceSpringContextTests&lt;/a&gt;&lt;br&gt;&lt;br&gt; &lt;div&gt;&lt;table bgcolor="#ffffcc" border="0" cellpadding="3" cellspacing="0" height="349" width="967"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="100%"&gt;&lt;pre&gt;&lt;a name="l106"&gt;public class MessageDAOTest extends AbstractDAOTests  // which extends AbstractTransactionalDataSourceSpringContextTests&lt;br&gt;{&lt;br&gt;   public void testCache() &lt;br&gt;    {&lt;br&gt;        long numberOfMessages = jdbcTemplate.queryForInt("SELECT count(*) FROM message ");&lt;br&gt;        System.out.println("Number of rows :" + numberOfMessages);&lt;br&gt;        final String cacheRegion = Message.class.getCanonicalName();&lt;br&gt;        SecondLevelCacheStatistics settingsStatistics = sessionFactory.getStatistics().&lt;br&gt;            getSecondLevelCacheStatistics(cacheRegion);&lt;br&gt;        StopWatch stopWatch = new StopWatch();&lt;br&gt;        for (int i = 0; i &amp;lt; 10; i++)&lt;br&gt;        {&lt;br&gt;            stopWatch.start();&lt;br&gt;            messageDAO.findAllMessages();&lt;br&gt;            stopWatch.stop();&lt;br&gt;            System.out.println("Query time : " + stopWatch.getTime());&lt;br&gt;            assertEquals(0, settingsStatistics.getMissCount());&lt;br&gt;            assertEquals(numberOfMessages * i, settingsStatistics.getHitCount());&lt;br&gt;            stopWatch.reset();&lt;br&gt;            System.out.println(settingsStatistics);&lt;br&gt;            endTransaction();&lt;br&gt;&lt;br&gt;            // spring creates a transaction when test starts - so we first end it then start a new in the loop&lt;br&gt;            startNewTransaction();&lt;br&gt;        }&lt;br&gt;    }&lt;/a&gt;&lt;br&gt;&lt;a name="l106"&gt;}&lt;/a&gt;&lt;/pre&gt;       &lt;/td&gt;     &lt;/tr&gt;     &lt;/tbody&gt;   &lt;/table&gt; &lt;/div&gt;&lt;br&gt;The output could looke something like:&lt;br&gt;&lt;br&gt;  &lt;div&gt;&lt;table bgcolor="#ffffcc" border="0" cellpadding="3" cellspacing="0" height="218" width="994"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="100%"&gt;&lt;pre&gt;&lt;a name="l106"&gt;30 Jan 08 23:37:14  INFO org.springframework.test.AbstractTransactionalSpringContextTests:323 - Began transaction (1): &lt;br&gt;transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager@ced32d]; default rollback = true&lt;br&gt;Number of rows :6&lt;br&gt;Query time : 562&lt;br&gt;SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=6,elementCountInMemory=6,elementCountOnDisk=0,sizeInMemory=8814]&lt;br&gt;30 Jan 08 23:37:15  INFO org.springframework.test.AbstractTransactionalSpringContextTests:290 - Rolled back transaction &lt;br&gt;after test execution&lt;br&gt;30 Jan 08 23:37:15  INFO org.springframework.test.AbstractTransactionalSpringContextTests:323 - Began transaction (2): &lt;br&gt;transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager@ced32d]; default rollback = true&lt;br&gt;Query time : 8&lt;br&gt;SecondLevelCacheStatistics[hitCount=6,missCount=0,putCount=6,elementCountInMemory=6,elementCountOnDisk=0,sizeInMemory=8814]&lt;br&gt;30 Jan 08 23:37:15  INFO org.springframework.test.AbstractTransactionalSpringContextTests:290 - Rolled back transaction &lt;br&gt;after test execution&lt;br&gt;30 Jan 08 23:37:15  INFO org.springframework.test.AbstractTransactionalSpringContextTests:323 - Began transaction (3): &lt;br&gt;transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager@ced32d]; default rollback = true&lt;br&gt;Query time : 11&lt;/a&gt;&lt;a name="l106"&gt;&lt;/a&gt;&lt;/pre&gt;       &lt;/td&gt;     &lt;/tr&gt;     &lt;/tbody&gt;   &lt;/table&gt;&lt;br&gt;Another way to spy on what Hibernate is doing is to proxy the jdbc driver used by a proxy driver. One excellent one I use is p6spy which will show you exactly what is issued over a JDBC connection to the actual backend database. For other tips have a look below in the mindmap.&lt;br&gt; &lt;/div&gt; &lt;pre&gt;&lt;a name="l106"&gt;&lt;/a&gt;&lt;/pre&gt;&lt;b&gt;&lt;div id="fne3" style="padding: 1em 0pt; text-align: left;"&gt;&lt;a href="File?id=dfxnknzf_100f563b3w4" target="_blank"&gt;&lt;div id="cmyf" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 950px; height: 384px;" src="http://docs.google.com/File?id=dfxnknzf_106d8dk8msj"&gt;&lt;/div&gt;&lt;/a&gt;&lt;/div&gt;&lt;/b&gt; &lt;/div&gt; &lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-4214579173455389636?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/4214579173455389636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=4214579173455389636' title='49 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4214579173455389636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4214579173455389636'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2008/01/background-hibernate-comes-with-three.html' title='Hibernate Caches'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>49</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-4448608652946576984</id><published>2007-11-23T09:23:00.000+01:00</published><updated>2007-11-23T09:27:13.261+01:00</updated><title type='text'>Maven book</title><content type='html'>Found this very nice information about Maven at: &lt;a href="http://www.sonatype.com/book/index.html"&gt;Maven book&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-4448608652946576984?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/4448608652946576984/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=4448608652946576984' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4448608652946576984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4448608652946576984'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/11/maven-book.html' title='Maven book'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-8567325947980581998</id><published>2007-10-23T10:49:00.000+02:00</published><updated>2007-10-23T10:50:40.895+02:00</updated><title type='text'>Maven tips - loading resource for unit test</title><content type='html'>Got a question the other day about how to load a resource for a unit test in Maven. I knew I had the same problem over a year ago but could not remember the exact way to solve it. As always Maven's email list is the number one source of knowledge - and I knew I read this really good post about this problem  (here is the post at &lt;a href="http://www.nabble.com/-M2--classpath-problem-with-surefire-t141363s177.html"&gt;link to post&lt;/a&gt;). &lt;br&gt;To recap the problem is how classloaders work in Java. In the case of running a Unit test in Maven using the Surefire plugin you end up with a class loader hierarchy like this:&lt;br&gt; 1   System classloader - where Maven runs&lt;br&gt; 1.2 Plugin classloader - created by maven&lt;br&gt; 1.3 Surefire classloader - created by Surefire&lt;br&gt; 1.4 Unit tests&lt;br&gt; &lt;br&gt; So if you do load your resources like this using Classloader it will not work - instead ask the class  for the class loader and get the reource from that classloader&lt;br&gt; &lt;br&gt; &lt;div&gt;   &lt;table bgcolor="#ffffcc" border="0" cellpadding="3" cellspacing="0" width="100%"&gt;     &lt;tbody&gt;     &lt;tr&gt;       &lt;td width="100%"&gt;         &lt;pre&gt;ClassLoader.getSystemResourceAsStream("test.properties");  // does not work&lt;br&gt;this.getClass().getClassLoader().getSystemResourceAsStream("test.properties"); // works&lt;br&gt;&lt;/pre&gt;       &lt;/td&gt;     &lt;/tr&gt;     &lt;/tbody&gt;   &lt;/table&gt; &lt;/div&gt; &lt;br&gt; &lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-8567325947980581998?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/8567325947980581998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=8567325947980581998' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/8567325947980581998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/8567325947980581998'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/10/got-question-other-day-about-how-to_5208.html' title='Maven tips - loading resource for unit test'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-2566581648186520278</id><published>2007-10-17T15:11:00.000+02:00</published><updated>2007-10-17T15:43:43.029+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sofware development deploy'/><title type='text'>Software lessons - do not forget df -h</title><content type='html'>During a four months develoment period the project was reaching one major milestone: acceptance tests. Working long hours and fixing those final show stoppers is always an unpleasant thing to do - but I has to be done. &lt;br /&gt;Friday afternoon and we have a final build for the customer arriving on Monday to do the acceptance testing. Puh we made it - or at least that was the fealing when leaving the office heading home.&lt;br /&gt;Monday morning. I come into the office early and find out that we can not loginto the system. What? After 30 minutes I realize that the release and installation did not install that little jboss config file - the file that is cruicial for login to work. So on to my desk get some java and start reading emails. &lt;br /&gt;"Hey Georges - Jboss is not starting. Could you and x have a look". Over to x desk and start the quest for "why jboss does not start". The installation of the software is a bit complex using jboss template xml files and replacing placeholders in those files using the sed command (check out Maven Assemblies to simplify building release). After a while see a strange behaviour of files beeing cropped. Our initial assumption was that the sed did not work if some fields where empty, our next assumption was that there was something wrong with buffers on this Solaris machine.&lt;br /&gt;&lt;br /&gt;Finally after doing a df -h we see that we are out of disk space.&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-2566581648186520278?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/2566581648186520278/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=2566581648186520278' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/2566581648186520278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/2566581648186520278'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/10/software-lessons-do-not-forget-df-h.html' title='Software lessons - do not forget df -h'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-5098418558494643101</id><published>2007-08-09T22:38:00.000+02:00</published><updated>2008-09-09T15:28:58.331+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design Pattern Java'/><title type='text'>Desing pattern - generic dao</title><content type='html'>&lt;b id="ox7i"&gt;Background&lt;/b&gt;&lt;br id="ox7i0"&gt; A year back I worked in a project where we wanted to extend an system handling an auction site. The system used DAOs and had CRUD operations spread in different DAOs. To simplify and generalize the CRUD operations the Generic DAO (Java5) pattern was implemented. The Generic DAO pattern was proposed on a Hibernate forum and picked up by Christian Bauer who implemented it in the &lt;a id="ox7i1" href="http://www.hibernate.org/400.html" target="_blank" title="Caveat"&gt;Caveat&lt;/a&gt; example application. It is also discussed in the second edition of the Hibernate book - &lt;a id="ox7i2" href="http://www.amazon.com/Java-Persistence-Hibernate-Christian-Bauer/dp/1932394885" target="_blank" title="Java persistence with Hibernate"&gt;Java persistence with Hibernate&lt;/a&gt; and on a post at &lt;a id="ox7i3" href="http://www.hibernate.org/328.html" target="_blank" title="Hibernate"&gt;&lt;b id="ox7i4"&gt;Hibernate&lt;/b&gt;&lt;/a&gt;&lt;b id="ox7i5"&gt;.&lt;/b&gt;&lt;br id="ox7i6" style="font-weight: bold;"&gt; &lt;br id="ox7i7" style="font-weight: bold;"&gt; &lt;b id="ox7i8"&gt;Enter the pattern&lt;/b&gt;&lt;br id="ox7i9"&gt; The &lt;a id="ox7i10" href="http://grouter.berlios.de/" target="_blank" title="grouter"&gt;grouter&lt;/a&gt; (a small open source message router I am working on) system contains a set of components - as depicted below - where the core-domain component is responsible for providing persistence and transaction demarcation. The core-domain component uses Hibernate entities and Spring to provide this services to clients like the presentation-web component. There is also an option to use Ejb3 stateless beans instead of Spring - only that road needs more work since everything else in the grouter is using Spring.&lt;br id="ox7i11"&gt; &lt;div id="ox7i12" style="padding: 1em 0pt; text-align: left;"&gt;   &lt;img id="ox7i13" src="http://docs.google.com/File?id=dfxnknzf_80fkdd52dj"&gt; &lt;/div&gt; To avoid duplicating CRUD operations I adopted the proposed Generic DAO pattern as described by Christian Bauer at the Hibernate website. The pattern relies on Java5 generics and consists of:&lt;br id="ox7i14"&gt; &lt;a id="ox7i15" href="http://svn.berlios.de/wsvn/grouter/trunk/modules/core/core-domain/src/main/java/org/grouter/domain/dao/GenericDAO.java" target="_blank" title="GenericDAO"&gt;GenericDAO&lt;/a&gt; - The GenericDAO interface specifies the CRUD operations using Java5 generics. GenericDAO is a  generic type interface that has two type parameters - T and ID. These type parameters are later replaced by type arguments when the generic type is instantiated.&lt;br id="ox7i16"&gt; &lt;a id="ox7i17" href="http://svn.berlios.de/wsvn/grouter/trunk/modules/core/core-domain/src/main/java/org/grouter/domain/dao/spring/GenericHibernateDAO.java" target="_blank" title="GenericHibernateDAO"&gt;GenericHibernateDAO&lt;/a&gt; - The abstract GenericHibernateDAO class provides an implementation of the GenericDAO interface using two type parameter. It subclasses the Spring class HibernateSuport to get Springs support for handling the Hibernate Sessionfactory and Sessions.&lt;br id="ox7i18"&gt; &lt;a id="ox7i19" href="http://svn.berlios.de/wsvn/grouter/trunk/modules/core/core-domain/src/main/java/org/grouter/domain/dao/ejb3/GenericEjb3DAO.java" target="_blank" title="GenericEjb3DAO"&gt;GenericEjb3DAO&lt;/a&gt; - Just like &lt;a id="ox7i20" href="http://svn.berlios.de/wsvn/grouter/trunk/modules/core/core-domain/src/main/java/org/grouter/domain/dao/spring/GenericHibernateDAO.java" target="_blank" title="GenericHibernateDAO"&gt;GenericHibernateDAO&lt;/a&gt; but in this case we are using Ejb3 and the EnitityManager instead of  Hibernates SessionFactory which is injected from the JEE container. There is also a MessageDAO implemenation called MessageDAOBean (only it is not used in the grouter).&lt;br id="ox7i21"&gt; &lt;a id="ox7i22" href="http://svn.berlios.de/wsvn/grouter/trunk/modules/core/core-domain/src/main/java/org/grouter/domain/dao/MessageDAO.java" target="_blank" title="MessageDAO"&gt;MessageDAO&lt;/a&gt; - This interface specifies non CRUD operations specific for the Message enitity.&lt;br id="ox7i23"&gt; &lt;a id="ox7i24" href="http://svn.berlios.de/wsvn/grouter/trunk/modules/core/core-domain/src/main/java/org/grouter/domain/dao/spring/MessageDAOImpl.java" target="_blank" title="MessageDAOImpl"&gt;MessageDAOImpl&lt;/a&gt; - MessageDAOImpl implements the MessageDAO interface and also extends the abstract class GenericHibernateDAO and instantiates a parametrized type of that generic type in its constructor.      &lt;br id="ox7i25"&gt; &lt;br id="ox7i26"&gt; Below is an UML diagram of the classes discussed above.&lt;br id="ox7i27"&gt; &lt;div id="ox7i28" style="padding: 1em 0pt; text-align: left;"&gt;        &lt;div id="ox7i29" style="padding: 1em 0pt; text-align: left;"&gt;         &lt;img id="ox7i30" src="http://docs.google.com/File?id=dfxnknzf_79dzfgw5cz"&gt;&lt;br id="ox7i31"&gt;         &lt;br id="ox7i32"&gt;         You are free to check out the source code for the grouter - see this &lt;a id="ox7i33" title="page" target="_blank" href="http://grouter.berlios.de/documentation.php"&gt;page&lt;/a&gt; on how to do that.&lt;br id="ox7i34"&gt;       &lt;/div&gt; &lt;/div&gt; &lt;br id="ox7i35"&gt; &lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-5098418558494643101?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/5098418558494643101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=5098418558494643101' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/5098418558494643101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/5098418558494643101'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/08/background-year-back-i-worked-in.html' title='Desing pattern - generic dao'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-7258716230258527163</id><published>2007-08-06T23:20:00.000+02:00</published><updated>2007-08-09T22:58:00.140+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design Pattern Java'/><title type='text'>Design pattern - command</title><content type='html'>&lt;span style="FONT-WEIGHT:bold"&gt;Background&lt;/span&gt;&lt;br/&gt; When designing a message router (see open source project &lt;a href="http://grouter.berlios.de/" target="_blank" title="grouter"&gt;grouter&lt;/a&gt; ) I wanted to decouple the senders from the receivers using an internal queue and potentially a JMS queue. The Command Pattern let me do just that.&lt;br/&gt; &lt;br/&gt; &lt;span style="FONT-WEIGHT:bold"&gt;Enter the pattern&lt;br/&gt; &lt;/span&gt;Definition: In a command pattern objects represent actions  - command objects. A command pattern decouples the sender from the receiver. The sender creates commands which are read by the receiver. The receiver then calls execute (or some other method defined by the interface for the commands) not knowing what and how to do the unit of work - which the command itself knows.&lt;br/&gt; The grouter contains inbound &lt;a href="http://svn.berlios.de/wsvn/grouter/trunk/grouter/modules/core/core-domain/src/main/java/org/grouter/domain/entities/EndPoint.java?op=file&amp;amp;rev=0&amp;amp;sc=0" target="_blank" title="EndPoint"&gt;EndPoint&lt;/a&gt; readers and outbound &lt;a href="http://svn.berlios.de/wsvn/grouter/trunk/grouter/modules/core/core-domain/src/main/java/org/grouter/domain/entities/EndPoint.java?op=file&amp;amp;rev=0&amp;amp;sc=0" target="_blank" title="EndPoint"&gt;EndPoint&lt;/a&gt; writers using an internal queue. An &lt;a href="http://svn.berlios.de/wsvn/grouter/trunk/grouter/modules/core/core-domain/src/main/java/org/grouter/domain/entities/EndPoint.java?op=file&amp;amp;rev=0&amp;amp;sc=0" target="_blank" title="EndPoint"&gt;EndPoint&lt;/a&gt; in the grouter domain represents a source or destination of different types (&lt;a href="http://svn.berlios.de/wsvn/grouter/trunk/grouter/modules/core/core-domain/src/main/java/org/grouter/domain/entities/EndPointType.java?op=file&amp;amp;rev=0&amp;amp;sc=0" target="_blank" title="EndPointType"&gt;EndPointType&lt;/a&gt; ), e.g. JMS or ftp. A reader should ideally only read from an inbound EndPoint, create a command (&lt;a href="http://svn.berlios.de/wsvn/grouter/trunk/grouter/modules/core/core-router/src/main/java/org/grouter/core/command/AbstractCommand.java?op=file&amp;amp;rev=0&amp;amp;sc=0" target="_blank" title="AbstractCommand"&gt;AbstractCommand&lt;/a&gt; ) and pass it to the internal queue. On the other side of the queue an &lt;a href="http://svn.berlios.de/wsvn/grouter/trunk/grouter/modules/core/core-domain/src/main/java/org/grouter/domain/entities/EndPoint.java?op=file&amp;amp;rev=0&amp;amp;sc=0" target="_blank" title="EndPoint"&gt;EndPoint&lt;/a&gt; writer (command consumer) would pop the internal queue and call a special method on the command object instance ( execute() ). The command consumer should be designed in a general way and thereby able to handle different kind of commands - still maintaining a template for how to handle commands (backing up, validating and sending).&lt;br/&gt; EndPoint writers (command consumers) and &lt;a href="http://svn.berlios.de/wsvn/grouter/trunk/grouter/modules/core/core-domain/src/main/java/org/grouter/domain/entities/EndPoint.java?op=file&amp;amp;rev=0&amp;amp;sc=0" target="_blank" title="EndPoint"&gt;EndPoint&lt;/a&gt; readers (command producers) could then be grouped together to form nodes in the message router.&lt;br/&gt; &lt;div style="PADDING:1em 0pt; TEXT-ALIGN:left"&gt;   &lt;img src="http://docs.google.com/File?id=dfxnknzf_74qxrnr5gq" style="WIDTH:640px"/&gt;&lt;br/&gt;   &lt;a href="http://docs.google.com/Doc?id=dfxnknzf_70cwd6v8" title="Full size"&gt;Full   size&lt;/a&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-7258716230258527163?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/7258716230258527163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=7258716230258527163' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/7258716230258527163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/7258716230258527163'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/08/background-when-designing-message.html' title='Design pattern - command'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-3837304833114939908</id><published>2007-08-03T11:40:00.000+02:00</published><updated>2007-08-03T11:43:02.709+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven tips - sources and intellij project files</title><content type='html'>To generate Idea Intellij project files and download sources for 3rd party dependencies:&lt;br&gt;&lt;br&gt;mvn idea:idea -DdownloadSources=true&lt;br&gt;&lt;br&gt;This can also be added to your pom for the idea plugin (or Eclipse and Netbeans - just look up the plugin docs).&lt;br&gt;&lt;br&gt;&amp;lt;project&amp;gt;&lt;br&gt; [...]&lt;br&gt; &amp;lt;build&amp;gt;&lt;br&gt;   [...]&lt;br&gt;   &amp;lt;plugins&amp;gt;&lt;br&gt;     &amp;lt;plugin&amp;gt;&lt;br&gt;       &amp;lt;groupid&amp;gt;org.apache.maven.plugins&amp;lt;/groupid&amp;gt;&lt;br&gt;       &amp;lt;artifactid&amp;gt;maven-idea-plugin&amp;lt;/artifactid&amp;gt;&lt;br&gt;       &amp;lt;configuration&amp;gt;&lt;br&gt;         &amp;lt;!--jdkName&amp;gt;1.5.0_06&amp;lt;/jdkName--&amp;gt;&lt;br&gt;         &amp;lt;downloadsources&amp;gt;true&amp;lt;/downloadsources&amp;gt;&lt;br&gt;         &amp;lt;downloadjavadocs&amp;gt;true&amp;lt;/downloadjavadocs&amp;gt;&lt;br&gt;         &amp;lt;dependenciesaslibraries&amp;gt;true&amp;lt;/dependenciesaslibraries&amp;gt;&lt;br&gt;       &amp;lt;/configuration&amp;gt;      &amp;lt;/plugin&amp;gt;&lt;br&gt;   &amp;lt;/plugins&amp;gt;&lt;br&gt;   [...]&lt;br&gt; &amp;lt;/build&amp;gt;&lt;br&gt; [...]&lt;br&gt;&amp;lt;/project&amp;gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-3837304833114939908?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/3837304833114939908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=3837304833114939908' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3837304833114939908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3837304833114939908'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/08/to-generate-idea-intellij-project-files.html' title='Maven tips - sources and intellij project files'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-1222509076179890479</id><published>2007-08-03T11:19:00.000+02:00</published><updated>2007-08-03T11:32:37.078+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven tips - compiler plugin</title><content type='html'>&lt;p&gt;   Usually you get off by using target and source for a java 1.4 or java 1.5 compiler to produce 1.3 class files. However I bumped into a problem with a class extending an abstract class in the javax.sql package, which in java 1.4 had a new abstract method. I could not get the 1.5 compiler using maven to build that class with target and source set to 1.3. The compiler complained that I had to implement that method even though I should not have to. &lt;br&gt;&lt;/p&gt;&lt;p&gt;To solve this I configured the compiler plug in according to below snippet:&lt;br&gt;&lt;/p&gt;&lt;br&gt;&amp;lt;project&amp;gt;&lt;br&gt;&lt;pre&gt;  [...]&lt;br&gt;  &amp;lt;build&amp;gt;&lt;br&gt;    [...]&lt;br&gt;    &amp;lt;plugins&amp;gt;&lt;br&gt;      &amp;lt;plugin&amp;gt;&lt;br&gt;&lt;br&gt;          &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br&gt;          &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;&lt;br&gt;          &amp;lt;configuration&amp;gt;&lt;br&gt;            &amp;lt;compilerVersion&amp;gt;1.3&amp;lt;/compilerVersion&amp;gt;&lt;br&gt;            &amp;lt;executable&amp;gt;${jdk1.3.home}/bin/javac.exe&amp;lt;/executable&amp;gt;&lt;br&gt;            &amp;lt;encoding&amp;gt;ISO-8859-1&amp;lt;/encoding&amp;gt;&lt;br&gt;            &amp;lt;verbose&amp;gt;true&amp;lt;/verbose&amp;gt;&lt;br&gt;            &amp;lt;target&amp;gt;1.1&amp;lt;/target&amp;gt;&lt;br&gt;            &amp;lt;source&amp;gt;1.3&amp;lt;/source&amp;gt;&lt;br&gt;            &amp;lt;fork&amp;gt;true&amp;lt;/fork&amp;gt;&lt;br&gt;          &amp;lt;/configuration&amp;gt;&lt;br&gt;        &amp;lt;/plugin&amp;gt;&lt;br&gt;    &amp;lt;/plugins&amp;gt;&lt;br&gt;    [...]&lt;br&gt;  &amp;lt;/build&amp;gt;&lt;br&gt;  [...]&lt;br&gt;&amp;lt;/project&amp;gt;&lt;br&gt;&lt;br&gt;&lt;/pre&gt; This worked fine. It forks of a new process using the command line to do the compilation. Command lines in windows are - well - not good. There is a size limitation of 2K (win2k) and 4K (WinXP). At some point I had another problem where maven just spit out that it could not parse the output of the error log. This had to do with exactly that - the command line being to long - in my case it was ~14000 characters. The project had a lot of dependencies. Fortunately for that maven project I could switch back to using jdk1.5 with target and source 1.3.&lt;br&gt;&lt;br&gt;More info at &lt;a title="maven-compiler-plugin" href="http://maven.apache.org/plugins/maven-compiler-plugin/"&gt;maven-compiler-plugin&lt;/a&gt; &lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-1222509076179890479?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/1222509076179890479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=1222509076179890479' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/1222509076179890479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/1222509076179890479'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/08/usually-you-get-off-by-using-target-and.html' title='Maven tips - compiler plugin'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-8335401841341705971</id><published>2007-06-18T14:57:00.000+02:00</published><updated>2007-08-01T10:42:57.093+02:00</updated><title type='text'>Why I do no like ClearCase</title><content type='html'>1 It is slow... no matter what the Rational salesguy tells you - those 1-4 secs of delays are making me crazy. &lt;br /&gt;2 Their client applications are far from good AND they do not run on my Intel Mac :-( How about making the ClearCase Explorer handle a flat view? The tools needs some consilidation since some functionality can be found in one tool and other in another.&lt;br /&gt;3 Clearcase do not integrate well with other open source projects. Continous integration - like Continuum - does not handle Clearcase. How about beeing able to work against ClearCase from Eclipse? I see guys in my project switching to a ClearCase tool from Eclipse just to be able to edit the read only file.&lt;br /&gt;4 Try working off line! How do you do that? Nobody at my client site seem to do this.&lt;br /&gt;5 It is expensive, very expensive. And you need someone who can administer their server/s.&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-8335401841341705971?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/8335401841341705971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=8335401841341705971' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/8335401841341705971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/8335401841341705971'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/06/why-i-do-no-like-clearcase.html' title='Why I do no like ClearCase'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-499146118712186726</id><published>2007-04-23T21:54:00.000+02:00</published><updated>2007-08-03T15:33:10.070+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design Pattern Java'/><title type='text'>Design Pattern - Strategy</title><content type='html'>&lt;span style="FONT-WEIGHT:bold"&gt;Background&lt;/span&gt;&lt;br/&gt; On a project I worked a couple of years back we used JMS to decouple subsystems and also provide distribution of workload - worked great. Now this system was relatively big with over 100 working nodes. Every time when the application server was restarted all clients (a lot of them) lost contact with the application servers message broker (JBoss) and we started to get those lovely &lt;font size="-1"&gt;org.jboss.mq.SpyJMS­Exception. The basic problem was understanding of how JMS works and that you should always register an exception listener on the JMS connection. In an effort to solve the the reconnect problem and also hide some of the JMS plumbing code I developed a small set of classes. The classes have been refactored completely and can now be found at my open source message router ( see &lt;/font&gt;&lt;a href="http://svn.berlios.de/wsvn/grouter/trunk/grouter/modules/common/common-util/src/main/java/org/grouter/common/jms/?rev=0&amp;amp;sc=0" target="_blank" title="Source code (grouter)"&gt;source code - grouter&lt;/a&gt;&lt;font size="-1"&gt; ) along with unit tests.&lt;/font&gt;&lt;br/&gt; &lt;br/&gt; &lt;span style="FONT-WEIGHT:bold"&gt;Enter the pattern&lt;/span&gt;&lt;br/&gt; Definition: A strategy pattern is an encapsulation of an exchangeable algorithm using an interface or an abstract class.&lt;br/&gt; &lt;br/&gt; Consider a use case where a client wants to use JMS destination - a queue or a topic. The client does not want to know how to reconnect to a message broker if this message broker is restarted and a connection is lost. How to reconnect should not be the concern of the client - it should be hidden to the client who only needs to tell the Destination what "Strategy" to use. In the below class diagram a Destination class has an association to a RebindBehavior - in this case an abstract class but it could also be an interface. Upon instantiation (or through a setter) on the Destination a client can specify which strategy it wants to use for a rebind scenario if/when a message broker is restarted. How - the algorithm - is hidden by the abstract class and its subclasses. The strategy can be changed in run time if needed and is not statically compiled into the Destination class.&lt;br/&gt; &lt;div style="PADDING:1em; TEXT-ALIGN:center"&gt;   &lt;a href="File?id=dfxnknzf_69c2mgtcgv" target="_blank"&gt;&lt;img src="http://docs.google.com/File?id=dfxnknzf_69c2mgtcgv" style="WIDTH:100%"/&gt;&lt;/a&gt; &lt;/div&gt; &lt;a href="http://docs.google.com/Doc?id=dfxnknzf_52cvxkvx" target="_blank" title="Full size (new window)"&gt;Full size (new window)&lt;/a&gt;&lt;br/&gt; &lt;br/&gt; A client wanting to listen to messages from a JMS queue could look like below (code is from a JMSReader in the open source &lt;a href="http://grouter.berlios.de" title="grouter"&gt;grouter&lt;/a&gt; project I am working on)&lt;br/&gt; &lt;span class="s1"&gt;&lt;a name="l106"&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class="s1"&gt;&lt;br/&gt; &lt;/span&gt; &lt;div&gt;   &lt;table bgcolor="#ffffcc" border="0" cellpadding="3" cellspacing="0" width="100%"&gt;     &lt;tbody&gt;     &lt;tr&gt;       &lt;td width="100%"&gt;         &lt;pre&gt;&lt;a name="l106"&gt;    &lt;span class="s0"&gt;private &lt;/span&gt;&lt;span class="s1"&gt;AbstractDestination initConnection(Node node) &lt;/span&gt;&lt;span class="s0"&gt;throws &lt;/span&gt;&lt;span class="s1"&gt;Exception &lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l107"&gt;    { &lt;br/&gt;&lt;/a&gt;&lt;a name="l108"&gt;        Map endPointContext = node.getInBound().getEndPointContext(); &lt;br/&gt;&lt;/a&gt;&lt;a name="l109"&gt;        String destinationName = (String) endPointContext.get(JMS_DESTINATIONNAME); &lt;br/&gt;&lt;/a&gt;&lt;a name="l110"&gt;        String queueConnectionFactory = (String) endPointContext.get(JMS_CONNECTIONFACTORY); &lt;br/&gt;&lt;/a&gt;&lt;a name="l111"&gt;        String contextFactory = (String) endPointContext.get(JMS_CONTEXTFACTORY); &lt;br/&gt;&lt;/a&gt;&lt;a name="l112"&gt;        String urlPkgPrefixes = (String) endPointContext.get(JMS_URLPKGPREFIXES); &lt;br/&gt;&lt;/a&gt;&lt;a name="l113"&gt;        String providerUrl = node.getInBound().getUri();    &lt;br/&gt;&lt;/a&gt;&lt;a name="l114"&gt;        &lt;span class="s0"&gt;boolean &lt;/span&gt;&lt;span class="s1"&gt;isQueue = Boolean.parseBoolean((String) endPointContext.get(JMS_ISQUEUE)); &lt;/span&gt;&lt;/a&gt;&lt;a name="l115"&gt;&lt;br/&gt;&lt;/a&gt;&lt;a name="l116"&gt;        AbstractDestination destination; &lt;br/&gt;&lt;/a&gt;&lt;a name="l117"&gt;        &lt;span class="s0"&gt;if &lt;/span&gt;&lt;span class="s1"&gt;(isQueue) &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l118"&gt;        { &lt;br/&gt;&lt;/a&gt;&lt;a name="l119"&gt;            &lt;span class="s2"&gt;// Queue destination&lt;/span&gt;&lt;span class="s1"&gt; &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l120"&gt;            destination = &lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;QueueListenerDestination(destinationName, queueConnectionFactory, &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l121"&gt;                    &lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;NeverRebind(), getInitialContext(providerUrl, contextFactory, urlPkgPrefixes), &lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l122"&gt;                    &lt;span class="s0"&gt;null&lt;/span&gt;&lt;span class="s1"&gt;, AcknowledgeMode.CLIENT_ACKNOWLEDGE); &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l123"&gt;        } &lt;span class="s0"&gt;else&lt;/span&gt;&lt;span class="s1"&gt; &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l124"&gt;        { &lt;br/&gt;&lt;/a&gt;&lt;a name="l125"&gt;            &lt;span class="s2"&gt;// Topic destination&lt;/span&gt;&lt;span class="s1"&gt; &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l126"&gt;            destination = &lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;TopicListenerDestination(destinationName, queueConnectionFactory, &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l127"&gt;                    &lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;NeverRebind(), getInitialContext(providerUrl, contextFactory, urlPkgPrefixes), &lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l128"&gt;                    &lt;span class="s0"&gt;null&lt;/span&gt;&lt;span class="s1"&gt;, AcknowledgeMode.CLIENT_ACKNOWLEDGE); &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l129"&gt;        } &lt;br/&gt;&lt;/a&gt;&lt;a name="l130"&gt;        &lt;span class="s0"&gt;try&lt;/span&gt;&lt;span class="s1"&gt; &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l131"&gt;        { &lt;br/&gt;&lt;/a&gt;&lt;a name="l132"&gt;            destination.bind(); &lt;br/&gt;&lt;/a&gt;&lt;a name="l133"&gt;        } &lt;span class="s0"&gt;catch &lt;/span&gt;&lt;span class="s1"&gt;(Exception e) &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l134"&gt;        { &lt;br/&gt;&lt;br/&gt;&lt;/a&gt;&lt;a name="l135"&gt;            &lt;span class="s0"&gt;throw new &lt;/span&gt;&lt;span class="s1"&gt;Exception(e.getMessage(), e); &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l136"&gt;        } &lt;br/&gt;&lt;/a&gt;&lt;a name="l137"&gt;        &lt;span class="s0"&gt;return &lt;/span&gt;&lt;span class="s1"&gt;destination; &lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;a name="l138"&gt;    }&lt;/a&gt; &lt;/pre&gt;       &lt;/td&gt;     &lt;/tr&gt;     &lt;/tbody&gt;   &lt;/table&gt; &lt;/div&gt; &lt;br/&gt; &lt;br/&gt; Hope this helps clarify a very simple but strong pattern. Another use case could be to define a logging behavior - log to file, log to database etc.&lt;br/&gt; &lt;br/&gt; &lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-499146118712186726?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/499146118712186726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=499146118712186726' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/499146118712186726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/499146118712186726'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/04/strategy-pattern-strategy-is-basically.html' title='Design Pattern - Strategy'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-3388806398904241149</id><published>2007-04-20T12:21:00.001+02:00</published><updated>2007-04-20T12:21:44.241+02:00</updated><title type='text'>JavaOne 2007 - Creating Amazing Web Interfaces with Ajax</title><content type='html'>This guy was a rockstar last year and well worth watching - Ben Galbraith&lt;p&gt;&amp;quot;...In this session, Dion Almaer and Ben Galbraith of Ajaxian.com&lt;br&gt;demonstrate exactly how to create rich web interfaces by using modern&lt;br&gt;techniques pioneered by the Ajax community. They do this by presenting&lt;br&gt;a variety of specific interface scenarios and case studies.&amp;quot;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-3388806398904241149?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/3388806398904241149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=3388806398904241149' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3388806398904241149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3388806398904241149'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/04/javaone-2007-creating-amazing-web.html' title='JavaOne 2007 - Creating Amazing Web Interfaces with Ajax'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-1542184382855708385</id><published>2007-04-17T21:30:00.000+02:00</published><updated>2007-04-23T11:10:39.190+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MacOSX Macos Parallel Enterprise Architect'/><title type='text'>Windows app in MacOS - Parallel</title><content type='html'>I am quite happy with everything on my Mac. It is easy, looks good, has the power of Unix shells coupled with a GUI that looks great. One thing missing though on my Mac is an application I use for UML modeling - Enterprise Architect. EA is easy and fun to use - and fast. Never ever do modeling in Visio - demand to use a real UML tool like EA. I have use TogetherJ in the past but Borland has managed to mess that tool up and moved it to the messy and sluggish Eclipse platform.&lt;br /&gt;To use EA on my Mac I have installed - Parallel Desktop. I have tried PD previously (and VMVare back when I used a windowz pc) but since their latest release when they introduced something they called coherent mode it really looks and behavs great. Coherent mode makes a win app behave like an MacOS application frame. You can minimize it, tab through to it etc. Have a look on the attached pic:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_rQklvZkZitQ/RiUgnCUEjmI/AAAAAAAAAgw/DP2onQdMROg/s1600-h/parallel_coherent.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_rQklvZkZitQ/RiUgnCUEjmI/AAAAAAAAAgw/DP2onQdMROg/s320/parallel_coherent.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5054482011801292386" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-1542184382855708385?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/1542184382855708385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=1542184382855708385' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/1542184382855708385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/1542184382855708385'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/04/windows-app-in-macos-parallel.html' title='Windows app in MacOS - Parallel'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_rQklvZkZitQ/RiUgnCUEjmI/AAAAAAAAAgw/DP2onQdMROg/s72-c/parallel_coherent.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-4386261122074032989</id><published>2007-03-16T12:06:00.000+01:00</published><updated>2007-04-23T11:11:14.147+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Google Gmail Email'/><title type='text'>Access your company mail i gmail</title><content type='html'>I love the gmail interface and thought it would be nice to have the same interface for my company's mail also. To do so login to gmail and go to settings and click tab "Accounts" then add a new account "Get mail from other accounts:"&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_rQklvZkZitQ/Rfp64ycquDI/AAAAAAAAAgE/xXlXgn3x1lo/s1600-h/gmailsettings.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_rQklvZkZitQ/Rfp64ycquDI/AAAAAAAAAgE/xXlXgn3x1lo/s320/gmailsettings.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5042477848827967538" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Next in the pop up add the company email address and the url to the pop server at your company:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_rQklvZkZitQ/Rfp_wScquFI/AAAAAAAAAgU/sVJd-qVgWMA/s1600-h/edit_mail_account.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_rQklvZkZitQ/Rfp_wScquFI/AAAAAAAAAgU/sVJd-qVgWMA/s320/edit_mail_account.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5042483200357218386" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If everything works out fine gmail will start importing you old mail into gmail and you will get something like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_rQklvZkZitQ/RfqAFCcquGI/AAAAAAAAAgc/n4L_xxfZkjI/s1600-h/gmail_with_cefalo_mail.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_rQklvZkZitQ/RfqAFCcquGI/AAAAAAAAAgc/n4L_xxfZkjI/s320/gmail_with_cefalo_mail.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5042483556839503970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Good luck&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-4386261122074032989?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/4386261122074032989/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=4386261122074032989' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4386261122074032989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4386261122074032989'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/03/access-your-company-mail-i-gmail.html' title='Access your company mail i gmail'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_rQklvZkZitQ/Rfp64ycquDI/AAAAAAAAAgE/xXlXgn3x1lo/s72-c/gmailsettings.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-3439720908544652012</id><published>2007-02-19T21:30:00.000+01:00</published><updated>2007-02-19T21:31:37.781+01:00</updated><title type='text'>Quotes</title><content type='html'>"...premature optimization is the root of all evil." - Donald Knuth&lt;br /&gt;&lt;br /&gt;"With great powers come great responsibilities" - Spiderman&lt;br /&gt;&lt;br /&gt;"premature generalization is the root of all evil" - ?&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-3439720908544652012?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/3439720908544652012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=3439720908544652012' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3439720908544652012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3439720908544652012'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/02/quotes.html' title='Quotes'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-3492935908972455687</id><published>2007-02-19T21:29:00.000+01:00</published><updated>2007-02-19T21:30:14.015+01:00</updated><title type='text'>Reducing I/O on a central CVS/Cruisecontrol server</title><content type='html'>I know of two ways to reduce I/O on a cvs/build machine. One concerns the CruiseControl builds and one concerns how CVS handles updates from developers/users.&lt;br /&gt;&lt;br /&gt;Normally you schedule CruiseControl to run every x min and poll cvs if there are any modifications made. This is today done using the a modification set with type cvs. By changing this to use a modification set of type compound and altering CVSROOT commitinfo to produce a loginfo file on user/developer commits one could reduce I/O to actually happen only when somebody has comitted anything into the CVS repository. The commitinfo file can be used to produce commit files for different cvs modules - thereby one could let the compound modicification set in CruisControl for one build use one file as a trigger to actually do a cvs update (and giving us I/O on io).&lt;br /&gt;&lt;br /&gt;The second way of reducing this I/O traffic has to do with how CVS works. Normally when a user or developer does a CVS update all the local entries are sent of to the central cvs server which does an update locally -&gt; producing a lot of I/O for every update. One way of getting rid of this I/O traffic is to reconfigure cvs (something like /etc/init.d -&gt; cvs -T /cvstmp -f --allow-root=/opt/utm/pse/src pserver) so that instead of writing temp files to disk is writes it to a mounted internal memory location. This will speed up updates (~10times) and make the I/O traffic a lot less.&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-3492935908972455687?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/3492935908972455687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=3492935908972455687' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3492935908972455687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3492935908972455687'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/02/reducing-io-on-central-cvscruisecontrol.html' title='Reducing I/O on a central CVS/Cruisecontrol server'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-3117708606482321594</id><published>2007-02-19T21:19:00.000+01:00</published><updated>2007-02-19T21:21:11.961+01:00</updated><title type='text'>Maven tips - deploy dependency internally</title><content type='html'>Sometimes you may not find a 3rd party dependency on the Internet - or you need to upload some company library to you corporate internal Maven2 repository. Define this in your local settings.xml file:&lt;br /&gt;  &lt;div class="post"&gt;&lt;server&gt;&lt;/server&gt;&lt;br /&gt;xxxxxxxx&lt;br /&gt;&lt;br /&gt;Then issue this command  :&lt;br /&gt;$ mvn deploy:deploy-file -DgroupId=test -DartifactId=test -Dversion=1.0.0 -DgeneratePom=true -Dpackaging=jar -Dfile=test-1.0.0.jar -DrepositoryId=buildserver -Durl=scp://theipaddresss:/home/bob/public_html/maven2&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-3117708606482321594?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/3117708606482321594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=3117708606482321594' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3117708606482321594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/3117708606482321594'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/02/maven-tips-deploy-dependency-internally.html' title='Maven tips - deploy dependency internally'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-5188684530994089141</id><published>2007-02-19T21:17:00.000+01:00</published><updated>2007-08-03T11:34:23.582+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven tips - skip tests</title><content type='html'>Sometimes somebody checks in something that breaks - compilation error. Or even something that breaks the Unit tests run with the Maven build. &lt;br /&gt;In Maven a compile error or a unit test failure both breaks the build - and sometimes we need to continue working even though the unit tests are not working (perhaps bob the mighty Java guru is fixing it...). Anyway, to skip tests do:&lt;br /&gt;&lt;br /&gt;$mvn -Dmaven.test.failure.ignore=true  clean install&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-5188684530994089141?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/5188684530994089141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=5188684530994089141' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/5188684530994089141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/5188684530994089141'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/02/maven-tips-skip-tests.html' title='Maven tips - skip tests'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-11295212969794172</id><published>2007-02-19T20:11:00.000+01:00</published><updated>2007-08-03T11:37:31.325+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven tips - downloadSources</title><content type='html'>To generate Idea Intellij project files and download sources for 3rd party dependencies:&lt;br /&gt;&lt;br /&gt;mvn idea:idea -DdownloadSources=true&lt;br /&gt;&lt;br /&gt;This can also be added to your pom for the idea plugin (or Eclipse and Netbeans - just look up the plugin docs).&lt;br /&gt;&lt;br /&gt;&lt;project&gt;&lt;br /&gt;  [...]&lt;br /&gt;  &lt;build&gt;&lt;br /&gt;    [...]&lt;br /&gt;    &lt;plugins&gt;&lt;br /&gt;      &lt;plugin&gt;&lt;br /&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;&lt;br /&gt;        &lt;artifactId&gt;maven-idea-plugin&lt;/artifactId&gt;&lt;br /&gt;        &lt;configuration&gt;&lt;br /&gt;          &lt;!--jdkName&gt;1.5.0_06&lt;/jdkName--&gt;&lt;br /&gt;          &lt;downloadSources&gt;true&lt;/downloadSources&gt;&lt;br /&gt;          &lt;downloadJavadocs&gt;true&lt;/downloadJavadocs&gt;&lt;br /&gt;          &lt;dependenciesAsLibraries&gt;true&lt;/dependenciesAsLibraries&gt;&lt;br /&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;&lt;br /&gt;    &lt;/plugins&gt;&lt;br /&gt;    [...]&lt;br /&gt;  &lt;/build&gt;&lt;br /&gt;  [...]&lt;br /&gt;&lt;/project&gt;&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-11295212969794172?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/11295212969794172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=11295212969794172' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/11295212969794172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/11295212969794172'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/02/maven-tips-downloadsources.html' title='Maven tips - downloadSources'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-4340181332101813456</id><published>2007-01-22T15:29:00.000+01:00</published><updated>2007-08-03T11:57:49.129+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Maven build failure - old xerces jar</title><content type='html'>Today I suddenly started to get test failures - which showed up as failures when trying to parse a Spring xml file for DAO beans. A nice little stack trace showed up (in the Surefire report produced by Maven):&lt;br /&gt;&lt;br /&gt;-------------------------------------------------------------------------------&lt;br /&gt;Test set: com.xyz.classifieds.data.dao.CategoryDAOTest&lt;br /&gt;-------------------------------------------------------------------------------&lt;br /&gt;Tests run: 5, Failures: 0, Errors: 5, Skipped: 0, Time elapsed: 0.077 sec &lt;&lt;&lt; FAILURE!&lt;br /&gt;testClass(com.xyz.classifieds.data.dao.CategoryDAOTest)  Time elapsed: 0.009 sec  &lt;&lt;&lt; ERROR!&lt;br /&gt;org.springframework.beans.factory.BeanDefinitionStoreException: Unable to validate using XSD: Your JAXP provider [org.apache.xerces.jaxp.DocumentBuilderFactoryImpl@533bdf] does not support XML Schema. Are you running on Java 1.4 or below with Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.&lt;br /&gt;    at org.springframework.beans.factory.xml.DefaultDocumentLoader.createDocumentBuilderFactory(DefaultDocumentLoader.java:102)&lt;br /&gt;...&lt;br /&gt;   &lt;br /&gt;Struggling to find why suddenly my maven build test started to fail took me a couple of hours. Using mvn test -X is a good way of finding out what actually is put on the Surefire plugin (unit test) classpath. However doing so did not reveal some old Xerces jar laying around before the actual Xercer jar I was trying ot use. The actual version of Xerces used was indicating the latest - but probably some of the other dependencies held an Implementation conflicting with the Xercer jar. If I find time I will investigate (probably never) more on which dependecny pulled in some classs already present in Xerces. I finally had to resort to putting the latest and greatest Xerces jar in the $JAVA_HOME/lib/endorsed folder to get it first in my classpath.&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-4340181332101813456?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/4340181332101813456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=4340181332101813456' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4340181332101813456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/4340181332101813456'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/01/maven-build-failure-old-xerces-jar.html' title='Maven build failure - old xerces jar'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5893116250220995871.post-9176603042149134593</id><published>2007-01-20T09:10:00.000+01:00</published><updated>2007-01-20T09:13:50.554+01:00</updated><title type='text'>First cup</title><content type='html'>Just testing&lt;div class="blogger-post-footer"&gt;&lt;!-- Site Meter --&gt;
&lt;script type="text/javascript" src="http://s44.sitemeter.com/js/counter.js?site=s44acupof"&gt;
&lt;/script&gt;
&lt;noscript&gt;
&lt;a href="http://s44.sitemeter.com/stats.asp?site=s44acupof" target="_top"&gt;
&lt;img src="http://s44.sitemeter.com/meter.asp?site=s44acupof" alt="Site Meter" border="0"/&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;!-- Copyright (c)2006 Site Meter --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5893116250220995871-9176603042149134593?l=acupof.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://acupof.blogspot.com/feeds/9176603042149134593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5893116250220995871&amp;postID=9176603042149134593' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/9176603042149134593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5893116250220995871/posts/default/9176603042149134593'/><link rel='alternate' type='text/html' href='http://acupof.blogspot.com/2007/01/first-cup.html' title='First cup'/><author><name>Georges Polyzois</name><uri>http://www.blogger.com/profile/04193718081164776201</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
