<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
    <title>Milen Dyankov's blog</title>
    <link rel="alternate" type="text/html" href="http://milen.commsen.com/" />
    
    <id>tag:milen.commsen.com,2010-04-05://1</id>
    <updated>2012-02-01T07:21:17Z</updated>
    <subtitle>Mostly technical notes and thoughts, hopefully useful for someone else as well</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.01</generator>

<feedburner:info uri="milendyankov" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://milen.commsen.com/atom.xml" /><feedburner:emailServiceId>MilenDyankov</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://milen.commsen.com/atom.xml" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Fmilen.commsen.com%2Fatom.xml" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><entry>
    <title>Liferay Beginner's Guide - review</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/jFG1NSWVLY4/liferay-beginners-guide---review.html" />
    <id>tag:milen.commsen.com,2012://1.23</id>

    <published>2012-02-01T06:34:59Z</published>
    <updated>2012-02-01T07:21:17Z</updated>

    <summary><![CDATA[ As I promised a few weeks ago, in this post I'll share my thoughts about &quot;Liferay Beginner's Guide&quot;&nbsp;book. As with earlier reviews, don't expect any judgments, recommendations or generalizations. Those are to be made by you. I'll only concentrate...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="book" label="book" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="cms" label="CMS" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="portal" label="portal" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;&lt;img alt="" align="right" src="https://www.packtpub.com/sites/default/files/imagecache/productview/7003OS_Liferay%20Beginner's%20Guidecov_Low.jpg" /&gt;&lt;/p&gt; &lt;p&gt;As &lt;a href="http://milen.commsen.com/2012/01/liferay-beginners-guide.html"&gt;I promised a few weeks ago&lt;/a&gt;, in this post I'll share my thoughts about &amp;quot;&lt;a href="http://www.packtpub.com/build-deploy-maintain-liferay-portal-beginners-guide/book"&gt;Liferay Beginner's Guide&amp;quot;&lt;/a&gt;&amp;nbsp;book. As with earlier reviews, don't expect any judgments, recommendations or generalizations. Those are to be made by you. I'll only concentrate on what I found interesting (or boring) and worth mentioning (for one reason or another). So let me try to summarize over 350 pages in a few lines.&lt;/p&gt;
        &lt;p&gt;The first thing to mention is that you will not have to write a single line of code &lt;i&gt;(apart from configuration)&lt;/i&gt;. This book seems to be meant for ..., hmm. I was about to write &amp;quot;administrators&amp;quot; but thats not the right term here. Please help me find the English term for a adventurous webmaster who goes like - download, make a couple of clicks to configure and then &amp;quot;go live&amp;quot;.  In another words, I have the impression the authors goal was to show that Liferay is just as easy to install and configure as all these popular CMS systems written in PHP.  Whether that's the truth or not, you'll have to decide for yourself.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; The first 60 pages will teach you to ... install. No, sure it's not that hard to install Liferay. The book will teach you to install everything you &lt;i&gt;(may eventually)&lt;/i&gt; need - Java, MySQL, OpenOffice, and then a combination of Liferay and a few of the major application servers out there&lt;i&gt; (like JBoss, Glassfish, Weblogic)&lt;/i&gt;.  Don't expect any detailed description or explanation of what's where in configuration files. The book goes like &lt;i&gt;&amp;quot;copy the file&amp;quot;&lt;/i&gt;, &lt;i&gt;&amp;quot;click here&amp;quot;&lt;/i&gt; and &lt;i&gt;&amp;quot;type this there&amp;quot;&lt;/i&gt;. If this procedure fails for some reason, you'll have to look for help somewhere else. &lt;br /&gt; &lt;br /&gt; Also the whole installation part assumes your OS is Windows. As most of you probably still use this &amp;quot;state of the art&amp;quot; OS, the approach is probably OK if you install locally to give it try.  But once you decide to go on-line, you'll have to either pay the price for Windows hosting or find another book to tell you how to do the same installation and configuration in some &amp;quot;better suited for the net&amp;quot; OS. &lt;br /&gt; &lt;br /&gt; The next 200 pages will walk you through portal configuration as well as site and content management. As usual, some things are better explained then other, but if you are a novice you'll get the idea of how Liferay was meant to work.  By the way, in case you want my advice, as soon as you think you have figured it all out, go read the chapter again. If the impression remains, switch to more advanced book. No, don't get me wrong, it's not that there is something wrong with the book. Just keep in mind, it was meant to be for beginners and some Liferay features &lt;i&gt;(permissions for example) &lt;/i&gt;deserve a book of their own.&lt;br /&gt; &lt;br /&gt; The most odd &lt;i&gt;(at least for me)&lt;/i&gt; part of the book is in the next 60 or so pages and attempts to explain how to set up an on-line shop. I have to admit, the authors do their best to explain the Liferay's out of the box features in this context. But the question that still bothers me is &amp;quot;&lt;i&gt;Why would beginner be interested in setting up on-line store with Liferay?&lt;/i&gt;&amp;quot; I mean, are there chapters about setting up an on-line shops in any &amp;quot;&lt;i&gt;A popular CMS written in PHP beginner's guide&lt;/i&gt;&amp;quot;  book? I have no idea what was the authors' intention. Perhaps, showing up that Liferay is more than simply CMS. Well it is! It's a portal! But it's definitely not an e-commerce suite! The fact that out of the box you get a couple of portlets which have some basic product catalog and shopping cart functionality, does not make it such. Setting up an on-line store is &lt;u&gt;NOT&lt;/u&gt; about having a shopping cart on the web site. It's rather complex subject that requires good understating of security and at least some understanding of what terms like &lt;i&gt;&amp;quot;Product bundling&amp;quot;&lt;/i&gt;, &lt;i&gt;&amp;quot;SKU&amp;quot;&lt;/i&gt;, &amp;quot;&lt;i&gt;Price lists&lt;/i&gt;&amp;quot;,&amp;nbsp;&lt;i&gt;&amp;quot;Upselling&amp;quot;&lt;/i&gt;,&lt;i&gt; &amp;quot;Cross-selling&amp;quot;&lt;/i&gt;, etc mean.&amp;nbsp;Sorry for emphasizing this but please trust me, even if you memorize the whole chapter, you are &lt;u&gt;NOT&lt;/u&gt; ready to go live with your first on-line store.&amp;nbsp;&lt;br /&gt; &lt;br /&gt; OK, this post became too long so time to sum it up.  The book is definitely for beginners. But actually it's a good thing, as I don't recall any other Liferay book targeting this audience. So if you are trying to figure out what is Liferay, what it offers and where you are supposed to click, then it may be an useful guide. Of course, It will not tell you the whole story, but at least it will answer most of the questions a beginner asks. It's very likely the book will significantly reduce the time you spend googling for answers. It may even save me and many other people some time, as we would eventually spend less time answering basic questions on Liferay forums ;).&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/D8TD837cBGQLldsnRD_kSFuWG8Q/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/D8TD837cBGQLldsnRD_kSFuWG8Q/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/D8TD837cBGQLldsnRD_kSFuWG8Q/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/D8TD837cBGQLldsnRD_kSFuWG8Q/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=jFG1NSWVLY4:At884e2oCMU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=jFG1NSWVLY4:At884e2oCMU:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=jFG1NSWVLY4:At884e2oCMU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=jFG1NSWVLY4:At884e2oCMU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=jFG1NSWVLY4:At884e2oCMU:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=jFG1NSWVLY4:At884e2oCMU:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/jFG1NSWVLY4" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2012/02/liferay-beginners-guide---review.html</feedburner:origLink></entry>

<entry>
    <title>Liferay Beginner's Guide</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/n42rMpCVSKc/liferay-beginners-guide.html" />
    <id>tag:milen.commsen.com,2012://1.22</id>

    <published>2012-01-13T10:18:30Z</published>
    <updated>2012-01-18T08:57:49Z</updated>

    <summary><![CDATA[ If you are following any Liferay related sites, forums, tweets, ..., then for sure you've heard about the new book titled &quot;Liferay Beginner's Guide&quot;. The book was released in December 2011 and it is getting a lot more attention...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="book" label="book" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;&lt;img alt="" align="right" src="https://www.packtpub.com/sites/default/files/imagecache/productview/7003OS_Liferay%20Beginner's%20Guidecov_Low.jpg" /&gt;&lt;/p&gt; &lt;p&gt;If you are following any Liferay related sites, forums, tweets, ..., then for sure you've heard about the new book titled &amp;quot;&lt;a href="http://www.packtpub.com/build-deploy-maintain-liferay-portal-beginners-guide/book"&gt;Liferay Beginner's Guide&lt;/a&gt;&amp;quot;.  The book was released in December 2011 and it is getting a lot more attention that I would ever expect. To be honest I'm kind of surprised there are so many Liferay beginners out there. So I volunteered to review the book hoping to check for myself whether all this buzz is only the result of good marketing strategy or it really provides the beginners with the answers they need.&lt;/p&gt;
        &lt;p&gt;While I don't consider myself a Liferay expert, during the last few years, besides developing Liferay extensions, I had a chance to help a few people start using Liferay in both my company and Liferay forums. I'm curious whether this book would have been any helpful in those cases if it existed back then.&lt;/p&gt;&lt;p&gt;The good news is, a couple of days ago I received my e-book copy and started reading. Hopefully in a few weeks I'll be able to post a review which eventually will help you decide whether it's worth buying. Meanwhile you can &lt;a href="http://www.packtpub.com/sites/default/files/7003OS-Chapter-01-Planning-Your-Portal.pdf?utm_source=packtpub&amp;amp;utm_medium=free&amp;amp;utm_campaign=pdf"&gt;check the free chapter&lt;/a&gt; to get an idea of how the book is written, organized and styled.&lt;/p&gt;&lt;p&gt;And of course, if you are one of those how have already read the book, do not hesitate to comment and point out things you found good, bad, odd or in any other way worth mentioning.&amp;nbsp;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/lP11RpB8j_TXe64ccvIucwuNZxA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lP11RpB8j_TXe64ccvIucwuNZxA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/lP11RpB8j_TXe64ccvIucwuNZxA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lP11RpB8j_TXe64ccvIucwuNZxA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=n42rMpCVSKc:hWypumYovck:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=n42rMpCVSKc:hWypumYovck:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=n42rMpCVSKc:hWypumYovck:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=n42rMpCVSKc:hWypumYovck:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=n42rMpCVSKc:hWypumYovck:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=n42rMpCVSKc:hWypumYovck:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/n42rMpCVSKc" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2012/01/liferay-beginners-guide.html</feedburner:origLink></entry>

<entry>
    <title>Simple mobile device emulator in Firefox</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/UajsxFXHrWg/simple-mobile-device-emulator-in-firefox.html" />
    <id>tag:milen.commsen.com,2011://1.21</id>

    <published>2011-10-27T23:22:12Z</published>
    <updated>2011-10-28T00:03:51Z</updated>

    <summary><![CDATA[After my &quot;Pluggable mobile device detection&quot; presentation during Liferay Europe Symposium&nbsp;a lot of people asked about the mobile device emulator I was using. The truth is, it's not a real &quot;emulator&quot; but a simple combination of html page and a...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Software" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="tips and tricks" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="android" label="Android" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="blackberry" label="BlackBerry" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="emulator" label="emulator" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="firefox" label="Firefox" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ipad" label="iPad" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="iphone" label="iPhone" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mobiledevice" label="mobile device" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="userscript" label="user script" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;After my &amp;quot;Pluggable mobile device detection&amp;quot; presentation during &lt;a href="http://www.liferay.com/events/liferay-symposiums/europe-2011/agenda"&gt;Liferay Europe Symposium&lt;/a&gt;&amp;nbsp;a lot of people asked about the mobile device emulator I was using. The truth is, it's not a real &amp;quot;emulator&amp;quot; but a simple combination of html page and a Firefox user script. However, it does the trick and for most people seems to be good enough (at least for a start). So, I made a promise to share it and finally found the time to blog about it.&lt;/p&gt;
        &lt;p&gt;But&amp;nbsp;before I go into details, here is a short video which demonstrates what it does (for those of you who didn't attend Liferay Europe Symposium and have no idea what I'm writing about):&lt;/p&gt; &lt;p&gt;&lt;iframe width="560" height="315" src="http://www.youtube.com/embed/__gvtlJ-KLI" frameborder="0" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/p&gt; &lt;p&gt;&lt;br /&gt; Now the details. First, make sure you have recent Firefox version installed. You'll also need one of the following Firefox extensions:&lt;/p&gt; &lt;ul&gt;     &lt;li&gt;&lt;a href="http://scriptish.org/"&gt;Scriptish&lt;/a&gt;&amp;nbsp;&lt;/li&gt;     &lt;li&gt;&lt;a href="https://addons.mozilla.org/pl/firefox/addon/greasemonkey/"&gt;Greasemonkey&lt;/a&gt;&amp;nbsp;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;&lt;i&gt;NOTE: I've only tested it with Scriptish but it should work with Greasemonkey as well.&lt;/i&gt;  &lt;br /&gt; &lt;br /&gt; Having this in place you are ready to &amp;quot;&lt;i&gt;install&lt;/i&gt;&amp;quot; the emulator. It's source code is available on &lt;a href="https://github.com/azzazzel/phone_emulator"&gt;GitHub&lt;/a&gt;. The &lt;span style="font-family: 'Courier New'; "&gt;page&lt;/span&gt;&amp;nbsp;folder contains the host page together with required js, css and image files. I personally have  &lt;a href="http://httpd.apache.org/"&gt;Apache&lt;/a&gt; running locally on my machine so I have these files in its &lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;DocumentRoot&amp;gt;&lt;/span&gt; and access the emulator via &lt;a href="http://localhost/phone_emulator.html"&gt;http://localhost/phone_emulator.html&lt;/a&gt;. However feel free to use any HTTP server you like (it may even work if you simply put it into a folder and access it via &lt;a href="file:///path/to/folder/phone_emulator.html"&gt;file:///path/to/folder/phone_emulator.html&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; The HTML file provides the GUI:&lt;/p&gt;   &lt;ul&gt;&lt;li&gt;the URL text box&lt;/li&gt;&lt;li&gt;the device tabs (it uses &lt;a href="http://www.barelyfitz.com/projects/tabber/"&gt;tabifier library&lt;/a&gt; to create the tabs from &lt;span style="font-family: 'Courier New'; "&gt;div&lt;/span&gt; elements)&lt;/li&gt;&lt;li&gt;the background image and the&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;iframe&lt;/span&gt;&amp;nbsp;element for each device&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you wish to add more devices simply&lt;/p&gt;  &lt;ul&gt;&lt;li&gt;add the following code replacing &lt;span style="font-family: 'Courier New'; "&gt;${...} &lt;/span&gt;with appropriate values&lt;br /&gt;&lt;code class="block"&gt;&amp;lt;div class=&amp;quot;device&amp;quot; title=&amp;quot;&lt;b&gt;${TEXT TO BE DISPLAYED IN THE TAB}&lt;/b&gt;&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;lt;div id=&amp;quot;&lt;b&gt;${UNIQUE DEVICE ID}&lt;/b&gt;&amp;quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;input &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;type=&amp;quot;hidden&amp;quot; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;class=&amp;quot;deviceUA&amp;quot; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;id=&amp;quot;&lt;b&gt;${UNIQUE DEVICE ID}&lt;/b&gt;_ua&amp;quot; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;value=&amp;quot;&lt;b&gt;${DEVICE'S USER AGENT STRING}&lt;/b&gt;&amp;quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;iframe &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;class=&amp;quot;deviceResult&amp;quot; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;id=&amp;quot;&lt;b&gt;${UNIQUE DEVICE ID}&lt;/b&gt;_result&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;add appropriate CSS styles to display the background image and position the iframe&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;span class="Apple-style-span"&gt;Finally, you need to install the &lt;a href="https://github.com/azzazzel/phone_emulator/raw/master/userscript/phone_emulator.user.js"&gt;user script&lt;/a&gt;. Its purpose is to omit &amp;quot;same origin&amp;quot; policy and load requested URL in every available &lt;span style="font-family: 'Courier New'; "&gt;iframe&lt;/span&gt;, each time changing the &lt;span style="font-family: 'Courier New'; "&gt;User-Agent&lt;/span&gt; header appropriately. The scripts is by default hooked to&amp;nbsp;&lt;/span&gt;&lt;a style="text-decoration: none; " href="http://localhost/phone_emulator.html"&gt;http://localhost/phone_emulator.html&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&amp;nbsp;location and will not run if you have placed the HTML file somewhere else. However you may edit the&amp;nbsp;&lt;br /&gt;     &lt;code class="block"&gt;// @include        http://localhost/phone_emulator.html* &lt;/code&gt;line and provide one or more different locations.&lt;br /&gt;     &lt;br /&gt;     This is it! Just type&amp;nbsp;&lt;/span&gt;&lt;a style="text-decoration: none; " href="http://localhost/phone_emulator.html"&gt;http://localhost/phone_emulator.html&lt;/a&gt;&amp;nbsp;&lt;span class="Apple-style-span"&gt;in Firefox and you should have the emulator runnig. To make sure you have installed it correctly, check the little green&amp;nbsp;&lt;/span&gt;&lt;a href="http://scriptish.org/"&gt;Scriptish&lt;/a&gt;&amp;nbsp;ic&lt;span class="Apple-style-span"&gt;on in Firefox's status bar. It should say that 1 user script is enabled.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="Apple-style-span"&gt;     &lt;br /&gt;     &lt;u&gt;&lt;b&gt;Disclaimer&lt;/b&gt;&lt;/u&gt;:&lt;br /&gt;     &lt;b&gt;&lt;i&gt;This is not a real emulator and should not be used as such. It was NOT tested and is known to have at least the following issues/limitations:&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;                    &lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;the rendering is done by Firefox which may support a lot more features then actual device's browser&lt;/li&gt;&lt;li&gt;it only emulates the page in the provided location. If you click on a link it the emulator it will be loadded using standard Firefox&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New'; "&gt;User-Agent&amp;nbsp;&lt;/span&gt;header!&lt;/li&gt;&lt;li&gt;some Javascripts (particularly Google APIs) and/or CSS may cause conflicts and not display properly&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You've been warned, use it on your own risk ;) And of course if you feel you can make it better, extend it or build something else on top of it, go ahead and do so (just let me know).&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Oya_xHZHdzx4F7Zc3sIUvkJZ4n8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Oya_xHZHdzx4F7Zc3sIUvkJZ4n8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Oya_xHZHdzx4F7Zc3sIUvkJZ4n8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Oya_xHZHdzx4F7Zc3sIUvkJZ4n8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=UajsxFXHrWg:_iak1lmCD0k:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=UajsxFXHrWg:_iak1lmCD0k:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=UajsxFXHrWg:_iak1lmCD0k:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=UajsxFXHrWg:_iak1lmCD0k:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=UajsxFXHrWg:_iak1lmCD0k:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=UajsxFXHrWg:_iak1lmCD0k:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/UajsxFXHrWg" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2011/10/simple-mobile-device-emulator-in-firefox.html</feedburner:origLink></entry>

<entry>
    <title>Liferay - preserve GWT portlet state between reloads</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/YoXAaEUPHis/liferay-preserve-gwt-portlet-state-between-reloads.html" />
    <id>tag:milen.commsen.com,2011://1.20</id>

    <published>2011-03-23T05:53:31Z</published>
    <updated>2011-03-24T08:34:06Z</updated>

    <summary><![CDATA[One of the problems with GWT (which is even more noticeable in portal environment) is preserving it's&nbsp;state&nbsp;between page reloads. In a GWT-only application (or single portlet on the page case) one can give user no other option but using only...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="tips and tricks" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cookie" label="cookie" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="gwt" label="GWT" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="javascript" label="javascript" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="portlet" label="portlet" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sessvarsjs" label="sessvars.js" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;One of the problems with GWT &lt;i&gt;(which is even more noticeable in portal environment)&lt;/i&gt; is preserving it's&amp;nbsp;state&amp;nbsp;between page reloads. In a GWT-only application &lt;i&gt;(or single portlet on the page case)&lt;/i&gt; one can give user no other option but using only GWT controls to practically avoid page reloads. In most cases however this is not really possible nor wise thing to do. In portlet environments in particular, reloading the page is a very commmon thing to do, giving all portlets a chance to refresh their content after some action has taken place. The thing is, GWT portlets will, by default, render their initial state, which may not be what user expects. &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;&lt;p&gt;For example, consider the GWT &lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt; portlet I was using in my previous posts&amp;nbsp;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://milen.commsen.com/2011/01/liferay-gwt-portlet-how-to-make-it-instanceable-and-use-gwt-rpc.html"&gt;&lt;span style="font-family: Verdana; "&gt;Liferay GWT portlet - how to make it &amp;quot;instanceable&amp;quot; and use GWT RPC&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family: Verdana; "&gt;&amp;nbsp;and&amp;nbsp;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://milen.commsen.com/2011/03/liferay-gwt-portlet-replacing-gwt-rpc-with-json.html"&gt;Liferay GWT portlet - replacing GWT-RPC with JSON&lt;/a&gt;.&lt;/span&gt;&amp;nbsp;Imagine user has entered a chatroom. Then she clicks on some other portlet on the page. The page is reloaded and &lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt; portlet returns to it's initial state. The user will have to enter the room again every time she clicks on another portlet. Let's see how this can be fixed.&lt;/meta&gt;&lt;/p&gt;
        &lt;p&gt;Many people think about GWT state as a summary of the states of all used GWT widgets (text fields, combo boxes, grids, tabs, ...). Instead I prefer to think in terms of application or &amp;quot;business logic&amp;quot; states. If you change the point of view, it may turn around not all GUI components contain significant information that must be saved and restored. For example it may be not so important to have particular tab selected or value of particular text box updated. &amp;nbsp; &amp;nbsp;&lt;/p&gt;&lt;p&gt;In case of &lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt; portlet, there are 2 states:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: 'Courier New'; "&gt;initial state&lt;/span&gt; - the user is not in a chatroom (she may never entered one or just left one)&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: 'Courier New'; "&gt;chatroom entered&lt;/span&gt; &amp;nbsp;- the user is&amp;nbsp;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;in a chatroom&amp;nbsp;&amp;nbsp;&lt;/meta&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In fact this is made very clear in the code by providing 2 methods&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/master/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/Chatroom.java#L180"&gt;displayInitialState&lt;/a&gt;&lt;/span&gt; and &lt;span style="font-family: 'Courier New'; "&gt;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/master/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/Chatroom.java#L167"&gt;displayChatroomState&lt;/a&gt;&lt;/span&gt; responsible for rendering appropriate GUI elements in particular states. Up until now during &lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt; initialization the&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New'; "&gt;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/master/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/Chatroom.java#L180"&gt;displayInitialState&lt;/a&gt;&amp;nbsp;&lt;/span&gt;method was called. To fix the above problem the&amp;nbsp;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;initialization&amp;nbsp;has to be changed to call appropriate method depending on what is the current state. The question is where &lt;i&gt;(on the client side)&lt;/i&gt; one can store portlet state information so it survives page reloads.&lt;/meta&gt;&lt;/p&gt;&lt;p&gt;The obvious answer is &amp;quot;cookies&amp;quot;. However it has some drawbacks &lt;i&gt;(the major one being the fact that they may be unsupported/disabled in some browsers)&lt;/i&gt;. Fortunately back in 2008&amp;nbsp;&lt;a href="http://www.thomasfrank.se/about.html"&gt;Thomas Frank&lt;/a&gt;&amp;nbsp;wrote and made public a very clever JavaScript library called&amp;nbsp;&lt;a href="http://www.thomasfrank.se/sessionvars.html"&gt;sessvars.js&lt;/a&gt;&amp;nbsp;which uses &lt;span style="font-family: 'Courier New'; "&gt;widow.name&lt;/span&gt; property to store information that need to survive page reloads. In order to use it in the portlet it has to be added to the page and this is what &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/5fc9f5914f7d38e354b6398616d03528ff36d8fd"&gt;this commit&lt;/a&gt; does.&lt;/p&gt;&lt;p&gt;Now in order to actually save and load portlet state, the &lt;span style="font-family: 'Courier New'; "&gt;ChatroomPortlet&lt;/span&gt;&amp;nbsp;object&amp;nbsp;(defined &amp;nbsp;in &lt;span style="font-family: 'Courier New'; "&gt;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/eebb9c725b46a937c948977f3f47a703d34884e1/docroot/js/chatrooms.js"&gt;chatrooms.js&lt;/a&gt;)&lt;/span&gt;&amp;nbsp;has to be extended with 2 new methods: &lt;span style="font-family: 'Courier New'; "&gt;setState&lt;/span&gt; and &lt;span style="font-family: 'Courier New'; "&gt;getState.&lt;/span&gt;&amp;nbsp;These methods respectively write to or read from a map&lt;i&gt; (key being portlet id and value portlet state)&lt;/i&gt; which thanks to&amp;nbsp;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://www.thomasfrank.se/sessionvars.html"&gt;sessvars.js&lt;/a&gt;&amp;nbsp;can survive page reloads.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Having this prepared, the&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt; class can be refactored to render portlet differently depending on it's state. This can be combined with GWT's history mechanism to handle clicks on browser's back and forward buttons. &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/eebb9c725b46a937c948977f3f47a703d34884e1/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/Chatroom.java"&gt;This is how modified the code looks like&lt;/a&gt;. Basically the steps were as follows:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;provide&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;saveState&lt;/span&gt; method to both save the current state and add history token&lt;/li&gt;&lt;li&gt;call &lt;span style="font-family: 'Courier New'; "&gt;saveState&lt;/span&gt;&amp;nbsp;method every time portlet state changes&lt;/li&gt;&lt;li&gt;provide&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;handleState&lt;/span&gt; method to render portlet UI according to current state&amp;nbsp;&lt;/li&gt;&lt;li&gt;make&amp;nbsp;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt;&amp;nbsp;class implement&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;ValueChangeHandler&lt;/span&gt; and provide&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;onValueChange&lt;/span&gt;&amp;nbsp;method to handle history tokens.&amp;nbsp;&lt;/meta&gt;&lt;/li&gt;&lt;li&gt;provide &lt;span style="font-family: 'Courier New'; "&gt;getStateFromToken&lt;/span&gt; method to retrieve the portlet state from history token.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;All of the above mentioned changes are in &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/eebb9c725b46a937c948977f3f47a703d34884e1"&gt;this commit&lt;/a&gt;. Feel free to explore what has changed and how.&amp;nbsp;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/CRZJ_ot3hy5tJEGy-UOZKwb7_Jo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CRZJ_ot3hy5tJEGy-UOZKwb7_Jo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/CRZJ_ot3hy5tJEGy-UOZKwb7_Jo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/CRZJ_ot3hy5tJEGy-UOZKwb7_Jo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=YoXAaEUPHis:Eiqhu_LB73w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=YoXAaEUPHis:Eiqhu_LB73w:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=YoXAaEUPHis:Eiqhu_LB73w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=YoXAaEUPHis:Eiqhu_LB73w:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=YoXAaEUPHis:Eiqhu_LB73w:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=YoXAaEUPHis:Eiqhu_LB73w:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/YoXAaEUPHis" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2011/03/liferay-preserve-gwt-portlet-state-between-reloads.html</feedburner:origLink></entry>

<entry>
    <title>Liferay GWT portlet - replacing GWT-RPC with JSON </title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/a_eMFOvK-Mc/liferay-gwt-portlet-replacing-gwt-rpc-with-json.html" />
    <id>tag:milen.commsen.com,2011://1.19</id>

    <published>2011-03-17T17:05:14Z</published>
    <updated>2011-03-17T23:02:52Z</updated>

    <summary><![CDATA[This is a continuation of my previous post Liferay GWT portlet - how to make it &quot;instanceable&quot; and use GWT RPC. The approach described there uses Liferay specific functionality called &nbsp;PortalDelegateServlet. This way one can easily use GWT RPC which...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="gwt" label="GWT" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="javascript" label="javascript" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="json" label="JSON" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="portlet" label="portlet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p style="text-align: justify; "&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;span style="font-family: Verdana; "&gt;This is a continuation of my previous post &lt;/span&gt;&lt;a href="http://milen.commsen.com/2011/01/liferay-gwt-portlet-how-to-make-it-instanceable-and-use-gwt-rpc.html"&gt;&lt;span style="font-family: Verdana; "&gt;Liferay GWT portlet - how to make it &amp;quot;instanceable&amp;quot; and use GWT RPC&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family: Verdana; "&gt;. The approach described there uses Liferay specific functionality called &amp;nbsp;&lt;/span&gt;&lt;a href="http://longgoldenears.blogspot.com/2008/03/portaldelegateservlet-servlet-session.html"&gt;&lt;span style="font-family: 'Courier New'; "&gt;PortalDelegateServlet&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family: Verdana; "&gt;. This way one can easily use GWT RPC which somewhat simplifies client-server communication. However if you need to develop a JSR 286 portlet you need a more standard compatible way of doing AJAX calls. For this reason JSR 286 defines &lt;span style="font-family: 'Courier New'; "&gt;serverResource&lt;/span&gt; method and this post will show how to refactor the code to replace GWT RPC calls with exchanging JSON messages using serverResource method.&lt;/span&gt;&lt;/meta&gt;&lt;/p&gt;
        &lt;p&gt;&lt;span style="font-size: medium; "&gt;&lt;span style="font-family: Verdana; "&gt;&lt;u&gt;&lt;b&gt;Let GWT know the prtlet URLs&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; "&gt;&lt;br /&gt; &lt;/span&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;First thing to do is to tell GWT what are the proper URLs to call the portlet. Therefore creating a&amp;nbsp;&lt;/span&gt; &lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt;&lt;span style="font-family: Verdana; "&gt;&amp;nbsp;instance based on portlet id only, is no longer enough. To overcome this you need to provide a JavaScript object holding portlet URLs. &lt;/span&gt;&lt;i&gt;&lt;span style="font-family: Verdana; "&gt;I, for example, have called it&amp;nbsp;&lt;span style="font-size: small; "&gt;&lt;span style="font-family: 'Courier New'; "&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre; color: rgb(0, 0, 0); "&gt;ChatroomPortlet&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;and it's defined in&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/df808f66e36b1e0257c3d31bcd869779960f08a8/docroot/js/chatrooms.js"&gt;&lt;i&gt;chatrooms.js&lt;/i&gt;&lt;/a&gt;&lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;&amp;nbsp;file. &lt;/span&gt;&lt;/i&gt; &lt;/meta&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;Then, in &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/df808f66e36b1e0257c3d31bcd869779960f08a8/docroot/view.jsp"&gt;view.jsp&lt;/a&gt;, create and store that object instead of portlet id. &lt;i&gt;Of course for the purpose of this example only &lt;span style="font-family: 'Courier New'; "&gt;resourceURL&lt;/span&gt; is needed but in a real world scenario you'll probably also need &lt;span style="font-family: 'Courier New'; "&gt;renderURL&lt;/span&gt; and &lt;span style="font-family: 'Courier New'; "&gt;actionURL&lt;/span&gt;.&lt;/i&gt; To map this JavaScript object to GWT class create JSNI class&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/df808f66e36b1e0257c3d31bcd869779960f08a8/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/ChatroomJsObject.java"&gt;ChatroomJsObject&lt;/a&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;Next you need to modify &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/df808f66e36b1e0257c3d31bcd869779960f08a8/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/Chatroom.java"&gt;&lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt;'s&lt;/a&gt; constructor to accept &lt;span style="font-family: 'Courier New'; "&gt;ChatroomJsObject&lt;/span&gt; instead of &lt;span style="font-family: 'Courier New'; "&gt;String&lt;/span&gt; representing portlet id. Of course this reflects how &lt;span style="font-family: 'Courier New'; "&gt;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/df808f66e36b1e0257c3d31bcd869779960f08a8/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/GWTEntryPoint.java"&gt;GWTEntryPoint&lt;/a&gt;&lt;/span&gt; creates &lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt; instances.&amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;Have a look at &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/df808f66e36b1e0257c3d31bcd869779960f08a8"&gt;my commit&lt;/a&gt; to see what has changed.&lt;/span&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&amp;nbsp;&lt;/p&gt;   &lt;h2&gt;&lt;span style="font-size: medium; "&gt;&lt;span style="font-family: Verdana; "&gt;&lt;u&gt;&lt;b&gt;Create the JSR 286 portlet&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt; &lt;p style="text-align: justify; "&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;Now you need to write a portlet and implement &lt;span style="font-family: 'Courier New'; "&gt;serveResource&lt;/span&gt; method. Basically the method contains the same logic that used to be in &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/9a084048e203bbf3c6642c522ceb60c51e8a480b/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/server/ChatroomServiceImpl.java"&gt;ChatroomServiceImpl&lt;/a&gt;. The only difference is that now it gets its input form JSON object and responds with JSON object. The portlet code is available &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/7da4cef3a7b9978da60c553d1704778ad280af30/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/server/ChatroomPortlet.java"&gt;here&lt;/a&gt;.&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: Verdana; "&gt;Of course don't forget to replace the default &lt;span style="font-family: 'Courier New'; "&gt;MVCPortlet&lt;/span&gt; with your own in &lt;span style="font-family: 'Courier New'; "&gt;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/7da4cef3a7b9978da60c553d1704778ad280af30/docroot/WEB-INF/portlet.xml"&gt;portlet.xml&lt;/a&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;Again &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/7da4cef3a7b9978da60c553d1704778ad280af30"&gt;there is commit&lt;/a&gt; which does above modifications, so you can check what has changed.&lt;/span&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;span style="font-size: medium; "&gt;&lt;span style="font-family: Verdana; "&gt;&lt;u&gt;&lt;b&gt;Update GWT client-server calls&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt; &lt;p style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;Having the portlet ready, it's time to change the GWT code to send and receive JSON to &lt;span style="font-family: 'Courier New'; "&gt;resourceURL&lt;/span&gt; instead of using GWT RPC. For this to work you need to add 2 GWT modules to &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/03a0e357411efae82fdd8160620b81c5b8e2b64b/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/Chatrooms.gwt.xml"&gt;Chatrooms.gwt.xml&lt;/a&gt;:&amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt;&lt;span style="font-family: Verdana; "&gt;&amp;lt;inherits name=&amp;quot;com.google.gwt.http.HTTP&amp;quot; /&amp;gt;&lt;br /&gt; &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;&amp;lt;inherits name=&amp;quot;com.google.gwt.json.JSON&amp;quot; /&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;To be able to convert JSON response to GWT class you'll have to provide another JSNI class &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/03a0e357411efae82fdd8160620b81c5b8e2b64b/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/ChatroomMessageJsObject.java"&gt;ChatroomMessageJsObject&lt;/a&gt;.&amp;nbsp;Finally the &lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt; class itself needs to be updated:&lt;/span&gt;&lt;/p&gt; &lt;ul&gt;     &lt;li style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;replace the body of &lt;span style="font-family: 'Courier New'; "&gt;sendMessageToServer&lt;/span&gt; method to create JSON object and send it to the portlet bu using RequestBuilder&lt;/span&gt;&lt;/li&gt;     &lt;li style="text-align: justify; "&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;replace the body of &lt;span style="font-family: 'Courier New'; "&gt;getMessages&lt;/span&gt; method to covert JSON object from response to list of ChatroomMessageJsObject to be displayed.&lt;/span&gt;&lt;/li&gt;     &lt;li style="text-align: justify; "&gt;&lt;span class="Apple-style-span" style="font-family: Verdana; "&gt;convert &lt;span style="font-family: 'Courier New'; "&gt;lastMessageTime&lt;/span&gt; form &lt;span style="font-family: 'Courier New'; "&gt;Date&lt;/span&gt; to &lt;span style="font-family: 'Courier New'; "&gt;long&lt;/span&gt; as there are some issues with passing dates in JSON&lt;/span&gt;&lt;/li&gt; &lt;/ul&gt; &lt;p style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;As usual you can refer to &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/03a0e357411efae82fdd8160620b81c5b8e2b64b"&gt;my commit&lt;/a&gt; to get an idea what and how has changed.&amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&lt;span style="font-family: Verdana; "&gt;That's it. You are ready. Optionally you can do some cleanup by removing unused classes &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/aa6b4a76b195316446df10e21b20d905e4ba77be"&gt;like I did&lt;/a&gt;. &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;p style="text-align: justify; "&gt;&amp;nbsp;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/kxarIfJEEVtw3-YG-f4j7DILdFk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kxarIfJEEVtw3-YG-f4j7DILdFk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/kxarIfJEEVtw3-YG-f4j7DILdFk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kxarIfJEEVtw3-YG-f4j7DILdFk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=a_eMFOvK-Mc:CQNCIGbGzCg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=a_eMFOvK-Mc:CQNCIGbGzCg:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=a_eMFOvK-Mc:CQNCIGbGzCg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=a_eMFOvK-Mc:CQNCIGbGzCg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=a_eMFOvK-Mc:CQNCIGbGzCg:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=a_eMFOvK-Mc:CQNCIGbGzCg:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/a_eMFOvK-Mc" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2011/03/liferay-gwt-portlet-replacing-gwt-rpc-with-json.html</feedburner:origLink></entry>

<entry>
    <title>Liferay multi-device extension</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/GYBxrf0svAk/liferay-multidevice-extension.html" />
    <id>tag:milen.commsen.com,2011://1.18</id>

    <published>2011-03-10T04:52:15Z</published>
    <updated>2011-03-10T06:08:57Z</updated>

    <summary><![CDATA[&nbsp;&nbsp;Almost every portal related RFI/RFP my company has received in the last couple of years contained some requirements about mobile version. Fortunately the times when every device had it's own idea of how web content should be served are gone....]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mobile" label="mobile" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="wurfl" label="WURFL" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;&amp;nbsp;&amp;nbsp;Almost every portal related RFI/RFP my company has received in the last couple of years contained some requirements about mobile version. Fortunately the times when every device had it's own idea of how web content should be served are gone. Nowdays we can afford to pretty much ignore &lt;a href="http://en.wikipedia.org/wiki/Wireless_Markup_Language"&gt;WML&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/CHTML"&gt;C-HTML&lt;/a&gt;, ... as almost any modern device understands at least &lt;a href="http://en.wikipedia.org/wiki/XHTML_Mobile_Profile"&gt;XHTML Mobile Profile&lt;/a&gt;. However this does not always mean there can be one mobile version for all. Here are some typical requirements:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;make a dedicated version for iPhone (imitate iPhone interface to make it look like native application)&lt;/li&gt;&lt;li&gt;allow to switch between mobile and desktop version if device is smartphone&lt;/li&gt;&lt;li&gt;provide alternative input methods if device does not have QWERTY keyboard&lt;/li&gt;&lt;li&gt;design dedicated version for tablets&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I have spent some time thinking about how to address this issues with &lt;a href="http://www.liferay.com"&gt;Liferay Portal&lt;/a&gt;. Having some experience with &lt;a href="http://wurfl.sourceforge.net"&gt;WURFL&lt;/a&gt;, &lt;a href="http://www.volantis.com/"&gt;Volantice&lt;/a&gt;&amp;nbsp;and designing web applications for mobile devices in general, I thought it would be great if I could dynamically change Liferay's look and feel based on device capabilities. And this is how &lt;a href="http://sourceforge.net/projects/liferaymultidev/"&gt;Liferay multi-device extension&lt;/a&gt; was born. &amp;nbsp;&lt;/p&gt;
        &lt;p&gt;Actually now there are 3 Liferay plug-ins which work together to deliver this functionality:&lt;/p&gt; &lt;ul&gt;     &lt;li&gt;&lt;p&gt;&lt;span style="font-family: 'Courier New'; "&gt;multi-device-ext plugin&lt;/span&gt; (&lt;a href="https://github.com/azzazzel/liferay-multi-device-ext"&gt;https://github.com/azzazzel/liferay-multi-device-ext&lt;/a&gt;) is the core plug-in. It provides the look and feel change logic, generic data model and &amp;quot;extension points&amp;quot; for other plug-ins which deliver things like device recognition and rule definition. It does so by employing Liferay's internal bus and can dynamically switch to new implementation when compatible plug-in is deployed. If you know how to replace Lucene with Solr, you know what I'm talking about. &amp;nbsp; &amp;nbsp;&lt;/p&gt;&lt;/li&gt;     &lt;li&gt;&lt;span style="font-family: 'Courier New'; "&gt;wurfl-web&lt;/span&gt; (&lt;a href="https://github.com/azzazzel/liferay-wurfl-web"&gt;https://github.com/azzazzel/liferay-wurfl-web&lt;/a&gt;) plug-in delivers device recognition based on WURFL. It contains WURFL API but does not contain WURFLD DB and patches. By default it expects to find the database in &lt;span style="font-family: 'Courier New'; "&gt;${liferay.home}/wurfl/wurfl-latest.zip&lt;/span&gt; however you may change this in portal-ext.properties:&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;&lt;code class="blockWhite"&gt;# Wurfl's main devices file&lt;br /&gt; wurfl.main=${liferay.home}/wurfl/wurfl-latest.zip &amp;nbsp; &amp;nbsp;&lt;br /&gt; &lt;br /&gt; # Wurfl's patch files&lt;br /&gt; wurfl.patches=&amp;nbsp;&lt;/code&gt;&lt;/p&gt; &lt;ul&gt;     &lt;li&gt;&lt;span style="font-family: 'Courier New'; "&gt;device-rules-hook&lt;/span&gt; (&lt;a href="https://github.com/azzazzel/liferay-device-rules-hook"&gt;https://github.com/azzazzel/liferay-device-rules-hook&lt;/a&gt;) extends Liferay's look and feel management interface by adding additional tab &amp;quot;Device Rules&amp;quot;. At the moment rules can be based on device's brand, model, operating system, browser and pointing method as well as whether the device is tablet, has QWERTY keyboard &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Here is how it works: &lt;iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/2CvY4eLWMHQ" frameborder="0" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/p&gt;  &lt;p&gt;The plug-ins are not yet in Liferay community plug-ins repository. I could'n figure out how to upload the EXT plugin and the &amp;nbsp;other two make no sense without it. You can download plug-ins from here:&amp;nbsp;&lt;a href="http://sourceforge.net/projects/liferaymultidev/files/"&gt;http://sourceforge.net/projects/liferaymultidev/files/&lt;/a&gt;&amp;nbsp;or get the source code from&amp;nbsp;&lt;a href="https://github.com/azzazzel"&gt;https://github.com/azzazzel&lt;/a&gt;&amp;nbsp;and build them yoursef.&amp;nbsp;If you do so, please let me know what you think.&lt;/p&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Y1-Le01B0ixNN24ScfKFBxcCZuA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Y1-Le01B0ixNN24ScfKFBxcCZuA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Y1-Le01B0ixNN24ScfKFBxcCZuA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Y1-Le01B0ixNN24ScfKFBxcCZuA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=GYBxrf0svAk:isubs_Kwolo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=GYBxrf0svAk:isubs_Kwolo:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=GYBxrf0svAk:isubs_Kwolo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=GYBxrf0svAk:isubs_Kwolo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=GYBxrf0svAk:isubs_Kwolo:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=GYBxrf0svAk:isubs_Kwolo:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/GYBxrf0svAk" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2011/03/liferay-multidevice-extension.html</feedburner:origLink></entry>

<entry>
    <title>Liferay GWT portlet - how to make it "instanceable" and use GWT RPC</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/K8pe8ENazW0/liferay-gwt-portlet-how-to-make-it-instanceable-and-use-gwt-rpc.html" />
    <id>tag:milen.commsen.com,2011://1.17</id>

    <published>2011-01-29T14:46:35Z</published>
    <updated>2011-01-29T23:44:37Z</updated>

    <summary>Every once in a while somebody asks about writing Liferay portlets in GWT. It seems a lot of people are successfully using GWT with Liferay but surprisingly I couldn't find any complete tutorial on the subject. There are a of...</summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="tips and tricks" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="gwt" label="GWT" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="java" label="java" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="javascript" label="javascript" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="servicebuilder" label="service builder" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;Every once in a while somebody asks about writing &lt;a href="http://liferay.com"&gt;Liferay&lt;/a&gt; portlets in &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt;. It seems a lot of people are successfully using &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt; with &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://liferay.com"&gt;Liferay&lt;/a&gt; but surprisingly I couldn't find any complete tutorial on the subject. There are a of course tutorials explaining the basics but what they concentrate on, is how to build &lt;i&gt;single-instance&lt;/i&gt; and &lt;i&gt;client-side-only&lt;/i&gt; portlets. This is good enough to get you started but chances are sooner or later you'll need to place two instances of the same &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt; portlet on the same page and/or implement &lt;a href="http://code.google.com/intl/pl/webtoolkit/doc/latest/tutorial/RPC.html"&gt;GWT RPC&lt;/a&gt; to make use of the &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://liferay.com"&gt;Liferay&lt;/a&gt;&amp;nbsp;services.&lt;/p&gt; &lt;p&gt;I've reached that point myself sometime ago and unfortunately had to solve the problem myself. Then I wrote sample portlet called &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet"&gt;gwt-chatrooms-portlet&lt;/a&gt; to demonstrate the solution and hopefully save you some time. So here is a step by step tutorial how to create GWT portlet for &lt;a href="http://www.liferay.com/downloads/liferay-portal/available-releases"&gt;Liferay 6.0.5&lt;/a&gt; which:&lt;/p&gt; &lt;ul&gt;     &lt;li&gt;allows many instances to be placed on the same page&lt;/li&gt;     &lt;li&gt;uses &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://code.google.com/intl/pl/webtoolkit/doc/latest/tutorial/RPC.html"&gt;GWT RPC&lt;/a&gt; for client-server communication&lt;/li&gt; &lt;/ul&gt;
        &lt;p&gt;The gwt-chatrooms-portlet is very simple portlet allowing users to enter chat room &lt;i&gt;(by typing in it's name)&lt;/i&gt; and then chat with other users. Here is screenshot :&lt;/p&gt; &lt;p&gt;&lt;img alt="screenshot of chatrooms GWT portlet" width="710" src="http://milen.commsen.com/screenshots/chatrooms-gwt-portlet.png" /&gt; &lt;br /&gt; As you can see, multiple instances can be added on the same page allowing users to chat in more than one room at a time. Message persistence API is generated using Liferay's &lt;a href="http://www.liferay.com/documentation/liferay-portal/6.0/development/-/ai/service-builder"&gt;ServiceBuilder&lt;/a&gt;. The &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt;&amp;nbsp;client code uses &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://code.google.com/intl/pl/webtoolkit/doc/latest/tutorial/RPC.html"&gt;GWT RPC&lt;/a&gt;&amp;nbsp;to receive room messages from the server and store new ones. Here is how to build it.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;span style="font-size: large; "&gt;&lt;u&gt;&lt;b&gt;Generate the portlet in Liferay SDK&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;u&gt; &lt;/u&gt;&lt;/h2&gt; &lt;p&gt;OK first things first. Make sure you have &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://www.liferay.com/downloads/liferay-portal/available-releases"&gt;Liferay 6.0.5&lt;/a&gt;&amp;nbsp;and &lt;a href="http://www.liferay.com/downloads/liferay-portal/additional-files"&gt;Liferay plugins SDK-6.0.5&lt;/a&gt; installed and configured. Then create new portlet by tying :&lt;br /&gt; &lt;code class="block"&gt;create.sh gwt-chatrooms &amp;quot;Chatrooms - Sample GWT portlet&amp;quot; &lt;/code&gt;  &lt;br /&gt; in &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;LIFERAY_SDK_HOME&amp;gt;/portlets&lt;/span&gt;&lt;/b&gt;. This will create &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;gwt-chatrooms-portlet&lt;/span&gt;&lt;/b&gt;&amp;nbsp;folder and the standard set of files.&amp;nbsp;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/7c65913dca9d18df440831c39fb76b897570834a"&gt;This is in my first commit&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-size: 13px; font-weight: normal; "&gt;&lt;span style="font-size: large; "&gt;&lt;u&gt;&lt;b&gt;Add GWT compile task to the build&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;Before you continue with actual development, you have to add an ant task to &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;LIFERAY_SDK_HOME&amp;gt;/portlets/gwt-chatrooms-portlet/build.xml&lt;/span&gt;&lt;/b&gt; responsible for compiling GWT code.   The code is available &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/57c4c010c7aad160bb84e4ecbae02df94119c29e/build.xml"&gt;here&lt;/a&gt;. You have probably noticed my task uses &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;${gwt.sdk}&lt;/span&gt;&lt;/b&gt; variable. To use it as is you have to set it's value in  &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;LIFERAY_SDK_HOME&amp;gt;/build.&amp;lt;USER_NAME&amp;gt;.properties&lt;/span&gt;&lt;/b&gt;&amp;nbsp;file :&lt;br /&gt; &lt;code class="blockWhite"&gt;gwt.sdk=&amp;lt;GWT_HOME&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;h2 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-size: 13px; font-weight: normal; "&gt;&lt;span style="font-size: large; "&gt;&lt;u&gt;&lt;b&gt;Create GWT module and entry point class&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;Now you are ready for GWT portlet development. Create GWT module file &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;gwt-chatrooms-portlet/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/Chatrooms.gwt.xml&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt; &lt;pre style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font: normal normal normal 12px/normal Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; "&gt;&lt;code class="blockWhite"&gt;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;&amp;lt;module&lt;/span&gt; &lt;span class="na" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 128, 128); "&gt;rename-to=&lt;/span&gt;&lt;span class="s" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(221, 17, 68); "&gt;'Chatrooms'&lt;/span&gt;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;&amp;lt;inherits&lt;/span&gt; &lt;span class="na" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 128, 128); "&gt;name=&lt;/span&gt;&lt;span class="s" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(221, 17, 68); "&gt;'com.google.gwt.user.User'&lt;/span&gt;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;&amp;lt;inherits&lt;/span&gt; &lt;span class="na" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 128, 128); "&gt;name=&lt;/span&gt;&lt;span class="s" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(221, 17, 68); "&gt;'com.google.gwt.user.theme.standard.Standard'&lt;/span&gt;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;&amp;lt;entry-point&lt;/span&gt; &lt;span class="na" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 128, 128); "&gt;class=&lt;/span&gt;&lt;span class="s" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(221, 17, 68); "&gt;'com.commsen.sample.portlet.chatrooms.client.GWTEntryPoint'&lt;/span&gt;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 128, 128); "&gt;path=&lt;/span&gt;&lt;span class="s" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(221, 17, 68); "&gt;'client'&lt;/span&gt;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 128, 128); "&gt;path=&lt;/span&gt;&lt;span class="s" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(221, 17, 68); "&gt;'shared'&lt;/span&gt;&lt;span class="nt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 0, 128); "&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="line-height: 14px; color: rgb(0, 0, 128); "&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;and GWT entry point  class &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;LIFERAY_SDK_HOME&amp;gt;/portlets/gwt-chatrooms-portlet/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/GWTEntryPoint.java&lt;/span&gt;&lt;/b&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;pre style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font: normal normal normal 12px/normal Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; "&gt;&lt;code class="blockWhite"&gt;&lt;span style="font-family: 'Courier New'; "&gt;&lt;span class="kd" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;public&lt;/span&gt; &lt;span class="kd" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;class&lt;/span&gt; &lt;span class="nc" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(68, 85, 136); font-weight: bold; "&gt;GWTEntryPoint&lt;/span&gt; &lt;span class="kd" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;implements&lt;/span&gt; &lt;span class="n" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; "&gt;EntryPoint&lt;/span&gt; &lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;{&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="line-height: 14px; "&gt;   @Override&lt;br /&gt;&lt;/span&gt;&lt;span class="kd" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;   public&lt;/span&gt; &lt;span class="kt" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(68, 85, 136); font-weight: bold; "&gt;void&lt;/span&gt; &lt;span class="nf" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(153, 0, 0); font-weight: bold; "&gt;onModuleLoad&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;()&lt;/span&gt; &lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;{&lt;br /&gt;&lt;/span&gt;&lt;span class="n" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; "&gt;      RootPanel&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;.&lt;/span&gt;&lt;span class="na" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 128, 128); "&gt;get&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;(&lt;/span&gt;&lt;span class="s" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(221, 17, 68); "&gt;&amp;quot;chatrooms-portlet&amp;quot;&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;).&lt;/span&gt;&lt;span class="na" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(0, 128, 128); "&gt;add&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;(&lt;/span&gt;&lt;span class="k" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;new&lt;/span&gt; &lt;span class="n" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; "&gt;HTML&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;(&lt;/span&gt;&lt;span class="s" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(221, 17, 68); "&gt;&amp;quot;This is the &amp;lt;b&amp;gt;GWT chat rooms&amp;lt;/b&amp;gt; portlet.&amp;quot;&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;));&lt;br /&gt;&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;   }&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="line-height: 14px; font-weight: bold; "&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;In &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;view.jsp&lt;/b&gt;&lt;/span&gt;  remove the default message and add &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;div&lt;/span&gt;&lt;/b&gt; element with id &amp;quot;&lt;span style="color: rgb(51, 51, 0); "&gt;&lt;b&gt;chatrooms-portlet&lt;/b&gt;&lt;/span&gt;&amp;quot; - this is the container for GWT code. Next replace default value of &amp;quot;&lt;span style="color: rgb(51, 51, 0); "&gt;&lt;b&gt;footer-portlet-javascript&lt;/b&gt;&lt;/span&gt;&amp;quot; in &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;LIFERAY_SDK_HOME&amp;gt;/portlets/gwt-chatrooms-portletdocroot/WEB-INF/liferay-portlet.xml&lt;/span&gt;&lt;/b&gt; with &amp;quot;&lt;span style="color: rgb(51, 51, 0); "&gt;&lt;b&gt;/Chatrooms/Chatrooms.nocache.js&lt;/b&gt;&lt;/span&gt;&amp;quot; &lt;i&gt;(assuming &amp;quot;&lt;b&gt;&lt;span style="color: rgb(51, 51, 0); "&gt;Chatrooms&lt;/span&gt;&lt;/b&gt;&amp;quot; is the name of your GWT module)&lt;/i&gt;. &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/9623586fc32433a11bdadf6298d40e66b680c661"&gt;Here are my changes&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Before you deploy and see your portlet in action you need to also add&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt;&amp;lt;ajaxable&amp;gt;false&amp;lt;/ajaxable&amp;gt;&amp;nbsp;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;into portlet's configuration in&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;liferay-portlet.xml&lt;/b&gt;&lt;/span&gt; file to make sure Liferay will not use AJAX to load portlet's content . However if you try to place 2 instance of the portlet on the same page you'll be surprised that one of them (or even both in some browsers) shows up empty. This is because the HTML page now has more than one &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;div&lt;/b&gt;&lt;/span&gt; element with the same id&amp;nbsp;&amp;quot;&lt;span style="color: rgb(51, 51, 0); "&gt;&lt;b&gt;chatrooms-portlet&lt;/b&gt;&lt;/span&gt;&amp;quot;.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;h2 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-size: 13px; font-weight: normal; "&gt;&lt;span style="font-size: large; "&gt;&lt;u&gt;&lt;b&gt;Make GWT code recognize portlet instances&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;To overcome the problem you can make use of portlet's instance id and add it to the id of the &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;div&lt;/b&gt;&lt;/span&gt; element in every portlet. To prepare for this change, create a javascript array (say &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;chatroomPortletInstances&lt;/b&gt;&lt;/span&gt;) to hold portlet instance ids. &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/6cd49209efb204be0876fa4713daeb5e3b9575c7"&gt;Here is how I did it&lt;/a&gt;. Then modify &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;view.jsp&lt;/b&gt;&lt;/span&gt; &amp;nbsp;so that it adds the portlet id into&amp;nbsp; &lt;span class="Apple-style-span" style="font-family: 'Courier New'; "&gt;&lt;b&gt;chatroomPortletInstances&lt;/b&gt;&lt;/span&gt;&amp;nbsp;and make the &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;div&lt;/span&gt;&lt;/b&gt; id contain the portlet id. See &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/bf7e759dbe5c6ca6f83ee2ad437af56fef5def21"&gt;my code&lt;/a&gt; for example.&lt;/p&gt; &lt;p&gt;Now you need to let the GWT code &amp;quot;know&amp;quot; about portlet instances. So instead of doing all initialization in the entry point class &lt;i&gt;(which I consider bad practice anyway)&lt;/i&gt; create a dedicated class (say &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt;&lt;/b&gt;) with constructor accepting portlet id as parameter. This way you can create dedicated&amp;nbsp;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;Chatroom&lt;/span&gt;&lt;/b&gt;&amp;nbsp;instance for every portlet instance. In order to do that you need to know the ids of all portlet instances available on the page and this is where &lt;span class="Apple-style-span" style="font-family: 'Courier New'; "&gt;&lt;b&gt;chatroomPortletInstances&lt;/b&gt;&lt;/span&gt;&amp;nbsp;array comes in. Thanks to GWT's &lt;a href="http://code.google.com/intl/pl/webtoolkit/doc/latest/DevGuideCodingBasicsJSNI.html"&gt;JSNI&lt;/a&gt; is as easy as&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; white-space: pre; "&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="kd" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;public&lt;/span&gt; &lt;span class="kd" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;static&lt;/span&gt; &lt;span class="kd" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;native&lt;/span&gt; &lt;span class="n" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; "&gt;JsArrayString&lt;/span&gt; &lt;span class="nf" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; color: rgb(153, 0, 0); font-weight: bold; "&gt;getPortletInstances&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;()&lt;br /&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px; white-space: pre; "&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: rgb(0, 0, 0); "&gt;&lt;span class="cm" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-style: italic; "&gt;/*-{&lt;br /&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic; line-height: 14px; white-space: pre; "&gt;        return $wnd.chatroomPortletInstances;&lt;br /&gt; &lt;/span&gt;&lt;span class="Apple-style-span" style="line-height: 16px; white-space: pre; "&gt;&lt;span style="color: rgb(0, 0, 0); "&gt;&lt;span class="cm" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-style: italic; "&gt;    }-*/&lt;/span&gt;&lt;/span&gt;&lt;span class="o" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 1.4em; font-weight: bold; "&gt;;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;Now all that's left is to iterate over portlet instances and create&amp;nbsp;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;Chatroom&amp;nbsp;&lt;/span&gt;&lt;/b&gt;instance for each. Of course feel free to use&amp;nbsp;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/4bc17ce9e8f9e23af5f49f7e9561be17e73f2efc"&gt;my code&lt;/a&gt;&amp;nbsp;as example.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;span style="color: rgb(51, 51, 0); "&gt;&lt;b&gt;Now you can place as many GWT portlet instances as you wish&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 0); "&gt;&lt;b&gt;on the same portal page&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 0); "&gt;&lt;b&gt;!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;If you want to test it, go to portlet's folder ant type&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;code class="block"&gt;ant clean gwtc deploy&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-size: 13px; font-weight: normal; "&gt;&lt;span style="font-size: large; "&gt;&lt;u&gt;&lt;b&gt;Generate Liferay services with ServiceBuilder&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;The portlet needs to persist the chatrooms' messages in Liferay's database. Thus you need to have at least some services and persitence API on the server side. Fortunately with Liferay's &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://www.liferay.com/documentation/liferay-portal/6.0/development/-/ai/service-builder"&gt;ServiceBuilder&lt;/a&gt;&amp;nbsp;almost everything can be generated by providing a single XML file. &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/63b77b5960a1f68e05f1bc602c3a9573a92aa3d7/docroot/WEB-INF/service.xml"&gt;Here is the one I used&lt;/a&gt;. I'm not going to explain in details how &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://www.liferay.com/documentation/liferay-portal/6.0/development/-/ai/service-builder"&gt;ServiceBuilder&lt;/a&gt;&amp;nbsp;works&lt;i&gt; (please see Liferay's documentation)&lt;/i&gt;. In case you are not really trying to learn but simply follow the instructions, here is the one-liner: Place the XML file in &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;WEB-INF &lt;/span&gt;&lt;/b&gt;folder and then do&lt;code class="block"&gt;ant build-service&lt;/code&gt;it will generate everything you need.&lt;/p&gt; &lt;p&gt;The most important things to notice are the&amp;nbsp;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;Message&lt;/span&gt;&lt;/b&gt;&amp;nbsp;interface (represents chatroom message) and the&amp;nbsp;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;MessageLocalServiceUtil&lt;/span&gt;&lt;/b&gt; class which provides convenient static methods for creating, storing and retrieving&amp;nbsp; &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;Message&amp;nbsp;&lt;/span&gt;&lt;/b&gt;objects. By the way&amp;nbsp;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/63b77b5960a1f68e05f1bc602c3a9573a92aa3d7"&gt;this commit&lt;/a&gt; contains all the files generated by&amp;nbsp;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://www.liferay.com/documentation/liferay-portal/6.0/development/-/ai/service-builder"&gt;ServiceBuilder&lt;/a&gt;&amp;nbsp;in case you are curious.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h2 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;span style="font-size: large; "&gt;&lt;font class="Apple-style-span"&gt;&lt;b&gt;&lt;u&gt;Implement the view and&amp;nbsp;&lt;/u&gt;&lt;/b&gt;&lt;/font&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;&lt;u&gt;GWT&amp;nbsp;&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;&lt;u&gt;RPC&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;Finally it is time to get your hands dirty with some real GWT stuff. &amp;nbsp;First you need to create standard &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://code.google.com/intl/pl/webtoolkit/doc/latest/tutorial/RPC.html"&gt;GWT RPC&lt;/a&gt;&amp;nbsp;service to save and receive messages. So create the&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;ChatroomService&lt;/b&gt;&lt;/span&gt; and&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;ChatroomServiceAsync&lt;/b&gt;&lt;/span&gt; interfaces in client code and&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;ChatroomServiceImpl&lt;/b&gt;&lt;/span&gt; in server side code. They need to have 2 methods &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;saveMessage&lt;/b&gt;&lt;/span&gt; and &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;getMessages&lt;/b&gt;&lt;/span&gt;. &amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;In the implementation code of those methods in&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New'; "&gt;&lt;b&gt;ChatroomServiceImpl &lt;/b&gt;&lt;/span&gt;you can call appropriate methods form&amp;nbsp;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;MessageLocalServiceUtil&amp;nbsp;&lt;/span&gt;&lt;/b&gt;or use Liferay's utility class&amp;nbsp;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;PortalUtil&lt;/span&gt;&lt;/b&gt;&amp;nbsp;to get access to other Liferay services &lt;i&gt;(for example to get the current user).&lt;/i&gt; &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/9a084048e203bbf3c6642c522ceb60c51e8a480b/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/server/ChatroomServiceImpl.java"&gt;Here is what I did&lt;/a&gt;.&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;Then you need to code the view. It's really up to you how you design the front end but&amp;nbsp;of course I'll use&amp;nbsp;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/9a084048e203bbf3c6642c522ceb60c51e8a480b/docroot/WEB-INF/src/com/commsen/sample/portlet/chatrooms/client/Chatroom.java"&gt;my version of&amp;nbsp;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;Chatroom &lt;/span&gt;&lt;/b&gt;class&lt;/a&gt;&amp;nbsp;to point out the key elements&lt;i&gt;:&amp;nbsp;&lt;/i&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt;     &lt;li&gt;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;sendMessageToServer&lt;/span&gt;&lt;/b&gt; method uses &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;ChatroomService&lt;/b&gt;&lt;/span&gt; to send user's message&amp;nbsp;&lt;/li&gt;     &lt;li&gt;&lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;getMessages&lt;/span&gt;&lt;/b&gt; method is continuously called by GWT timer to refresh the chatroom view&lt;/li&gt;     &lt;li&gt;somewhat mysterious code at line 52&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;By now you may think that you are ready. Simply configure&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New'; "&gt;&lt;b&gt;ChatroomServiceImpl&lt;/b&gt;&lt;/span&gt;&amp;nbsp;servlet in &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;web.xml&lt;/b&gt;&lt;/span&gt;, compile, deploy and enjoy. In fact if you do so, there will be unpleasant surprise. &amp;nbsp;The problem with this standard GWT approach is that you will be calling the&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New'; "&gt;&lt;b&gt;ChatroomServiceImpl&lt;/b&gt;&lt;/span&gt;&amp;nbsp;servlet directly and not through the portal. This means the portal will never have a chance to do it's magic. This means non of it's service classes will be available for the servlet. This means you'll see a nice&amp;nbsp;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: monospace; font-size: medium; white-space: pre; "&gt;&lt;b&gt;NoClassDefFoundError&lt;/b&gt;&lt;/span&gt;&amp;nbsp;in your server's logs.&lt;/p&gt; &lt;p&gt;Luckily since version&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif; line-height: 19px; "&gt;4.3.x&amp;nbsp;&lt;/span&gt;Liferay has built in solution for this problem. It's called&amp;nbsp;&lt;a href="http://longgoldenears.blogspot.com/2008/03/portaldelegateservlet-servlet-session.html"&gt;PortalDelegateServlet&lt;/a&gt;. I'm&amp;nbsp;oversimplifying the concept here but basically it allows you to define a servlet in portal's context. There is special delegate servlet, mapped at &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;/delegate&lt;/span&gt;&lt;/b&gt;&amp;nbsp;location. Liferay extensions can configure sub-contexts to redirect to their own servlets after the portal is done with the magic. Having this in mind there are 2 more things you need to do:&lt;/p&gt; &lt;ul&gt;     &lt;li&gt;configure your portlet to use &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;PortalDelegateServlet&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;     &lt;li&gt;change the address of your servlet in GWT's front-end code&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;For the first one have a look at &lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/blob/9a084048e203bbf3c6642c522ceb60c51e8a480b/docroot/WEB-INF/web.xml"&gt;how I have done it&lt;/a&gt; &amp;nbsp;and for the second one ... well that is the &amp;quot;&lt;i&gt;somewhat mysterious code at line 52&lt;/i&gt;&amp;quot; mentioned above.&amp;nbsp;Of course complete list of changes described in this section is in my&amp;nbsp;&lt;a href="https://github.com/azzazzel/gwt-chatrooms-portlet/commit/9a084048e203bbf3c6642c522ceb60c51e8a480b"&gt;final commit&lt;/a&gt;. &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p&gt;And this is it. Compile, deploy, enjoy!&amp;nbsp;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/W-W1gjf5EFuWB71G2DtiMf7im1k/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/W-W1gjf5EFuWB71G2DtiMf7im1k/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/W-W1gjf5EFuWB71G2DtiMf7im1k/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/W-W1gjf5EFuWB71G2DtiMf7im1k/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=K8pe8ENazW0:e4-piRTaJzc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=K8pe8ENazW0:e4-piRTaJzc:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=K8pe8ENazW0:e4-piRTaJzc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=K8pe8ENazW0:e4-piRTaJzc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=K8pe8ENazW0:e4-piRTaJzc:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=K8pe8ENazW0:e4-piRTaJzc:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/K8pe8ENazW0" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2011/01/liferay-gwt-portlet-how-to-make-it-instanceable-and-use-gwt-rpc.html</feedburner:origLink></entry>

<entry>
    <title>Liferay User Interface Development</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/xFtIPkzl6pU/liferay-user-interface-development.html" />
    <id>tag:milen.commsen.com,2010://1.16</id>

    <published>2010-12-11T15:56:00Z</published>
    <updated>2010-12-11T16:35:10Z</updated>

    <summary><![CDATA[ The last 6 months were extremely busy for me. &nbsp;A lot had happened in both private and professional aspects. Having that in mind I'm quite happy I manged to deal with completely new experience - being a technical reviewer...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="book" label="book" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;&lt;img alt="" align="right" src="https://www.packtpub.com/sites/default/files/imagecache/productview/2626OS_Mockup%20cover_0.jpg" /&gt;&lt;/p&gt; &lt;p&gt;The last 6 months were extremely busy for me. &amp;nbsp;A lot had happened in both private and professional aspects. Having that in mind I'm quite happy I manged to deal with completely new experience - being a technical reviewer of &amp;quot;&lt;a href="http://www.packtpub.com/liferay-user-interface-development/book"&gt;Liferay User Interface Development&lt;/a&gt;&amp;quot; - a new book published recently by &lt;a href="http://www.packtpub.com"&gt;Packt Publishing&lt;/a&gt;. Despite the lack of spare time I was somehow able to read and comment on drafts of 10 chapters covering things like theme development, layout templates, &lt;a href="http://velocity.apache.org/"&gt;velocity templates&lt;/a&gt;, tag libraries, &lt;a href="http://alloy.liferay.com/"&gt;AlloyUI&lt;/a&gt;, and much more. Hopefully my comments and opinions ware useful for the authors and help them improve the book.&amp;nbsp;&lt;/p&gt;
        &lt;div&gt;I still don't have the published book &lt;i&gt;(I'm about to receive my copy soon)&lt;/i&gt; but based on what I have read in the drafts I can say it's worth recommendation. The book puts together most of the peaces related to UI development in &lt;a href="http://www.liferay.com"&gt;Liferay&lt;/a&gt;. Of course it does not cover all the details &lt;i&gt;(no book can do this)&lt;/i&gt; but it often goes beyond the basics. In fact one of the chapters I found very informative and well organized is freely available on-line (&lt;a href="http://www.packtpub.com/sites/default/files/2626OS-Chapter-5-Advanced-Theme.pdf"&gt;http://www.packtpub.com/sites/default/files/2626OS-Chapter-5-Advanced-Theme.pdf&lt;/a&gt;) so you can check for yourself. There is also quite good chapter about &lt;a href="http://alloy.liferay.com"&gt;AlloyUI&lt;/a&gt; - especially useful if you have to move form &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;Liferay&lt;/span&gt;&lt;span style="font-family: 'Courier New'; "&gt; 5.2&lt;/span&gt;&lt;/b&gt; to &lt;b&gt;&lt;span style="font-family: 'Courier New'; "&gt;Liferay 6.0&lt;/span&gt;&lt;/b&gt; and replace &lt;a href="http://jquery.com/"&gt;JQuery&lt;/a&gt; with &lt;a href="http://alloy.liferay.com"&gt;AlloyUI&lt;/a&gt;. &amp;nbsp;The migration and upgrade process is also one of the subjects in the final chapter &amp;quot;&lt;i&gt;&lt;b&gt;User Interface in Production&lt;/b&gt;&lt;/i&gt;&amp;quot; which among others covers things like workflows, social UI and friendly URLs.&lt;/div&gt; &lt;div&gt;&amp;nbsp;&lt;/div&gt;  &lt;div&gt;Of course, there are too many options when it comes to UI development (&lt;a href="http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html"&gt;JSF&lt;/a&gt;, &lt;a href="http://struts.apache.org/"&gt;Struts&lt;/a&gt; &amp;amp; &lt;a href="http://struts.apache.org/1.x/struts-tiles/index.html"&gt;Tiles&lt;/a&gt;, &lt;a href="http://vaadin.com/home"&gt;Vaadin&lt;/a&gt;, &lt;a href="http://jquery.com/"&gt;JQuery&lt;/a&gt;, &lt;a href="http://alloy.liferay.com"&gt;AlloyUI&lt;/a&gt;, Liferay UI taglib, &lt;a href="http://velocity.apache.org/"&gt;Velocity&lt;/a&gt;, &lt;a href="http://freemarker.sourceforge.net/"&gt;Freemarker&lt;/a&gt; &amp;nbsp;to mention just a few) &amp;nbsp;and it's not possible to describe them all in details. &amp;nbsp;This book concentrates on Liferay's approach to UI development which &lt;i&gt;(in version 6)&lt;/i&gt; is a powerful mix of &lt;a href="http://velocity.apache.org/"&gt;Velocity templates&lt;/a&gt;, tag libraries and &lt;a href="http://alloy.liferay.com"&gt;AlloyUI&lt;/a&gt;. And yes, if you use&amp;nbsp;&lt;a href="http://vaadin.com/home"&gt;Vaadin&lt;/a&gt;&amp;nbsp;or&amp;nbsp;&lt;a href="http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html"&gt;JSF&lt;/a&gt;&amp;nbsp;or&amp;nbsp;&lt;a href="http://freemarker.sourceforge.net/"&gt;Freemarker&lt;/a&gt; &amp;nbsp;for your day to day work, it may not be a book for you as all you'll find in it about this technologies is references to online recourses. &amp;nbsp;But going back back to &amp;quot;standard&amp;quot; UI approach, the authors really try to teach the reader by providing many examples, mini tutorials and references to portal's and portlet's source code.&amp;nbsp;&lt;/div&gt; &lt;div&gt;&amp;nbsp;&lt;/div&gt; &lt;div&gt;One thing I was pointing out while reviewing the book was the lack of good reference documentation in two areas: tag libraries and &lt;a href="http://velocity.apache.org/"&gt;Velocity&lt;/a&gt; variables and macros . One may argue whether such a book is the best place to provide such documentation. Maybe not, I'm not sure. On the other hand comparing the number of questions posted on Liferay's forums about what tags are available and what their parameters mean with briefness of documentation available at &lt;a href="http://docs.liferay.com/portal/6.0/taglibs"&gt;http://docs.liferay.com/portal/6.0/taglibs&lt;/a&gt;, makes me thing that more in depth information on the subject would make this book more attractive for wider group of Liferay users. Same thing about &lt;a href="http://velocity.apache.org/"&gt;Velocity&lt;/a&gt; macros and variables. Event the most advanced reference about velocity variables in Liferay I know about - &lt;a href="http://www.myoffice24x7.com/web/manual/howto/explore-velocity-variables/-/velocity-explorer/journal"&gt;http://www.myoffice24x7.com/web/manual/howto/explore-velocity-variables/-/velocity-explorer/journal&lt;/a&gt; - seems to be &amp;nbsp;incomplete and sometimes inaccurate. &amp;nbsp;I don't know if my suggestions were taken into account. Honestly, I doubt the authors had enough time and room to be able to dig deeply into those subjects. But hopefully at least those tags, variables and macros used in the examples and better described. &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/div&gt; &lt;div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/div&gt; &lt;div&gt;But please don't get me wrong. The fact that I will always point out something that in my opinion can be done better does not mean the book is bad. Assuming one don't need to get deeply into Liferay's internals and do not worry too much about what exactly any particular line in the sample code does, this book provides complete information about Liferay UI development. I personally learned a lot of new things although I've been using Liferay for a few years. The bottom line is: &lt;b&gt;whether you have been mastering Liferay portal for a while or just entering the world of Liferay, this book will help you understand how to develop complex and user friendly user interfaces in Liferay Portal 6.0&lt;/b&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/div&gt; &lt;div&gt;&amp;nbsp;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Ezt3OtsyBHkW5DH1UQoIJpwt0ZM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Ezt3OtsyBHkW5DH1UQoIJpwt0ZM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Ezt3OtsyBHkW5DH1UQoIJpwt0ZM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Ezt3OtsyBHkW5DH1UQoIJpwt0ZM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=xFtIPkzl6pU:VLSywPEFKt4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=xFtIPkzl6pU:VLSywPEFKt4:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=xFtIPkzl6pU:VLSywPEFKt4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=xFtIPkzl6pU:VLSywPEFKt4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=xFtIPkzl6pU:VLSywPEFKt4:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=xFtIPkzl6pU:VLSywPEFKt4:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/xFtIPkzl6pU" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2010/12/liferay-user-interface-development.html</feedburner:origLink></entry>

<entry>
    <title>Liferay plug-ins adapted to work with Liferay 6.0.5</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/Eyy6z2b1VHs/liferay-plug-ins-adapted-to-work-with-liferay-6-0-5.html" />
    <id>tag:milen.commsen.com,2010://1.15</id>

    <published>2010-11-08T21:12:16Z</published>
    <updated>2010-11-08T23:32:11Z</updated>

    <summary><![CDATA[As soon as Liferay 6.0.5 was released I decided to&nbsp;adapt my plug-ins to the newest framework version. But as we all know, being determined to do something is not the same as having the time to do it. The good...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="maven" label="Maven" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plugin" label="plug-in" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="video" label="video" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;As soon as Liferay 6.0.5 was released I decided to&amp;nbsp;adapt my plug-ins to the newest framework version.  But as we all know, being determined to do something is not the same as having the time to do it. The good news is, a few days ago I finally quit saying myself &lt;i&gt;&amp;quot;never mind, you'll do it tomorrow&amp;quot;&lt;/i&gt; and started getting things done. And now I'm happy to announce that  &lt;a href="http://www.liferay.com/downloads/liferay-portal/community-plugins/-/software_catalog/products/4846919"&gt;Custom Global Markup&lt;/a&gt;, &lt;a href="http://www.liferay.com/downloads/liferay-portal/community-plugins/-/software_catalog/products/4924578"&gt;Tailgate&lt;/a&gt; and &lt;a href="http://www.liferay.com/downloads/liferay-portal/community-plugins/-/software_catalog/products/4906953"&gt;Liferay-UI Taglib Demo&lt;/a&gt; are already upgraded to work with Liferay 6.0.5.&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;Please read my previous posts &amp;quot;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://milen.commsen.com/2010/04/custom-global-markup-portlet.html"&gt;Custom global markup portlet&lt;/a&gt;&amp;quot; and &amp;quot;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://milen.commsen.com/2010/05/writing-liferay-portlet-to-display-a-file-in-a-way-tail--f-does.html"&gt;Writing Liferay portlet to display a file in a way &amp;quot;tail -f&amp;quot; does&lt;/a&gt;&amp;quot; for more information about&amp;nbsp;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://www.liferay.com/downloads/liferay-portal/community-plugins/-/software_catalog/products/4846919"&gt;Custom Global Markup&lt;/a&gt; and &lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://www.liferay.com/downloads/liferay-portal/community-plugins/-/software_catalog/products/4924578"&gt;Tailgate&lt;/a&gt; respectively.&lt;/p&gt;
        &lt;h3&gt;The plugins for 5.2.3 versions ware build by &lt;a href="https://github.com/azzazzel/liferay-maven-sdk"&gt;liferay-maven-sdk&lt;/a&gt;&amp;nbsp;and this was one of my biggest concerns. &amp;nbsp;I was a bit warred about how difficult will be to move to the native Maven support in Liferay 6.&amp;nbsp;However, not trusting my own experience and struggling to think logically, I realized it should be only a matter of modifying the POM. And indeed it was. I simply removed 5.2.3 dependencies and maven plugins and added 6.0.5 ones (&lt;a href="https://github.com/azzazzel/Liferay-plugins/commit/6476d09685ba47559d860aa30eb3bb48caa42df4#diff-0"&gt;here is the diff&lt;/a&gt;) and I was able to build my plugins using Liferay's 6 maven artifacts. Even ServiceBuilder worked without problems and additional configurations.&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/h3&gt; &lt;p&gt;Apart from adapting the code there is one more significant change.&amp;nbsp;While version control and issue tracker remain on GitHub,&amp;nbsp;binary files were moved to new SourceForge project called &amp;quot;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://sourceforge.net/projects/liferay-plugins/"&gt;liferay-plugins&lt;/a&gt;&amp;quot;. You are welcome to visit it and download, comment, rate, review, ....&amp;nbsp;There are also some &lt;a href="http://sourceforge.net/project/screenshots.php?group_id=368520"&gt;screenshots&lt;/a&gt;&amp;nbsp;of the plug-ins.&lt;/p&gt; &lt;p&gt;While I thought having screenshots is cool, a (much younger) collegue of mine, pointed out that these days every self respecting project has instructional videos on YouTube. Well, my generation didn't spend their whole childhood in front of the TV so please excuse my ignorance. Not to give anyone another reason to complain here are the videos:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;object width="640" height="505"&gt;&lt;param name="movie" value="http://www.youtube.com/v/hN4JbLx0vNo?fs=1&amp;amp;hl=pl_PL&amp;amp;rel=0&amp;amp;hd=1&amp;amp;color1=0x234900&amp;amp;color2=0x4e9e00"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/hN4JbLx0vNo?fs=1&amp;amp;hl=pl_PL&amp;amp;rel=0&amp;amp;hd=1&amp;amp;color1=0x234900&amp;amp;color2=0x4e9e00" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"&gt;&lt;/embed&gt;&lt;/object&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;object width="640" height="505"&gt;&lt;param name="movie" value="http://www.youtube.com/v/5e5Ucw434SA?fs=1&amp;amp;hl=pl_PL&amp;amp;rel=0&amp;amp;hd=1&amp;amp;color1=0x234900&amp;amp;color2=0x4e9e00"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/5e5Ucw434SA?fs=1&amp;amp;hl=pl_PL&amp;amp;rel=0&amp;amp;hd=1&amp;amp;color1=0x234900&amp;amp;color2=0x4e9e00" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"&gt;&lt;/embed&gt;&lt;/object&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/stGvPVF_MRvewMF3mbWZQamVlcg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/stGvPVF_MRvewMF3mbWZQamVlcg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/stGvPVF_MRvewMF3mbWZQamVlcg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/stGvPVF_MRvewMF3mbWZQamVlcg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=Eyy6z2b1VHs:piHgNqNw8lw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=Eyy6z2b1VHs:piHgNqNw8lw:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=Eyy6z2b1VHs:piHgNqNw8lw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=Eyy6z2b1VHs:piHgNqNw8lw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=Eyy6z2b1VHs:piHgNqNw8lw:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=Eyy6z2b1VHs:piHgNqNw8lw:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/Eyy6z2b1VHs" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2010/11/liferay-plug-ins-adapted-to-work-with-liferay-6-0-5.html</feedburner:origLink></entry>

<entry>
    <title>Just added 'J' in front of WebThumb</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/ckkW2ZKE06U/just-added-j-in-front-of-webthumb.html" />
    <id>tag:milen.commsen.com,2010://1.14</id>

    <published>2010-07-22T22:21:42Z</published>
    <updated>2010-07-22T22:41:59Z</updated>

    <summary>Yep, good guess, a Java API to bluga.net webthumb in now available. Making your Java application display website thumbnails is now something really easy to implement. Get your API KEY form bluga.net webthumb, download JWebThumb and start requesting and fetching...</summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Software" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="api" label="API" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="gae" label="GAE" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="simple" label="Simple" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="thumbnail" label="thumbnail" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="xstream" label="XStream" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;Yep, good guess, a Java API to &lt;a href="http://webthumb.bluga.net"&gt;bluga.net webthumb&lt;/a&gt; in now available. Making your Java application display website thumbnails is now something really easy to implement. Get your API KEY form &lt;a style="text-decoration: none; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://webthumb.bluga.net"&gt;bluga.net webthumb&lt;/a&gt;, download &lt;a href="http://sourceforge.net/projects/jwebthumb/files/"&gt;JWebThumb&lt;/a&gt; and start requesting and fetching thumbnails with just a few lines of code. &amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;div&gt;&amp;nbsp;&lt;/div&gt; &lt;div&gt;Why&amp;nbsp;&lt;a style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://webthumb.bluga.net"&gt;bluga.net webthumb&lt;/a&gt;? Nope, I'm not gonna tell you it's the best tool out there, having unique features, ... or any of this marketing bla bla. The truth is, it was the first tool I found, that met my requirements&lt;/div&gt;     &lt;ul&gt;&lt;li&gt;custom size thumbnails&lt;/li&gt;&lt;li&gt;support for both JPG an PNG&lt;/li&gt;&lt;li&gt;web services or REST based API&lt;/li&gt;&lt;li&gt;either creates thumbnail instantly or sends notification when done&lt;/li&gt;&lt;li&gt;free version&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;
        &lt;p&gt;I gave it a try and it turned out it's quite fast and reliable. Not that I have been heavily using it, but so far I haven't had any problems with it. Most of the time when I request a thumbnail it estimates it will take about 20 second but in fact my servlet receives notification in less than 2 seconds.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;So, after a few days of playing with webthumb's API I had a pile of Java snippets testing different aspects of it. Organizing the chaos resulted in version 0.1 of &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;JWebThumb&lt;/b&gt;&lt;/span&gt; project. Added data model and error handling on the top of that and 0.2 version was ready to go public (under LGPL). As usual Maven helped create a &lt;a href="http://jwebthumb.sourceforge.net/"&gt;project site&lt;/a&gt; from where you can learn how to use &lt;span style="font-family: 'Courier New'; "&gt;&lt;b&gt;JWebThumb&lt;/b&gt;&lt;/span&gt;, the &lt;a href="http://github.com/azzazzel/JWebThumb"&gt;source code&lt;/a&gt; is on GitHub and &lt;a href="http://sourceforge.net/projects/jwebthumb/files/"&gt;downloads&lt;/a&gt; are available on SourceForge. &amp;nbsp;If you find a bug or missing feature don't hesitate to &lt;a href="http://github.com/azzazzel/JWebThumb/issues"&gt;create an issue&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;I consider 0.2 an early beta version. It works but it's not extensively tested and may have bugs. It uses &lt;a href="http://xstream.codehaus.org/"&gt;XStream&lt;/a&gt; for XML serialization and deserialization thus you can not yet use it on &lt;a href="http://appengine.google.com/"&gt;GAE&lt;/a&gt;. So version 0.3 is already underway having&amp;nbsp;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;a style="text-decoration: none; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://xstream.codehaus.org/"&gt;XStream&lt;/a&gt;&amp;nbsp;replaced by &lt;a href="http://simple.sourceforge.net/"&gt;Simple&lt;/a&gt; so it works on&amp;nbsp;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;a style="text-decoration: none; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://appengine.google.com/"&gt;GAE&lt;/a&gt;. But before I release it I would like to test it a bit more and perhaps add support for &lt;a href="http://webthumb.bluga.net/apidoc#status"&gt;'status' requests&lt;/a&gt; missing in 0.2. So stay tuned, it shouldn't &amp;nbsp;take too long.&lt;/meta&gt;&lt;/meta&gt;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/x5dQs5O7Y4ElxKoOxr-ujsFYtdE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/x5dQs5O7Y4ElxKoOxr-ujsFYtdE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/x5dQs5O7Y4ElxKoOxr-ujsFYtdE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/x5dQs5O7Y4ElxKoOxr-ujsFYtdE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=ckkW2ZKE06U:qSAiaZFOB8A:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=ckkW2ZKE06U:qSAiaZFOB8A:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=ckkW2ZKE06U:qSAiaZFOB8A:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=ckkW2ZKE06U:qSAiaZFOB8A:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=ckkW2ZKE06U:qSAiaZFOB8A:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=ckkW2ZKE06U:qSAiaZFOB8A:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/ckkW2ZKE06U" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2010/07/just-added-j-in-front-of-webthumb.html</feedburner:origLink></entry>

<entry>
    <title>More "Simple" than "XStream"</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/A-UxBugy3E8/more-simple-than-xstream.html" />
    <id>tag:milen.commsen.com,2010://1.13</id>

    <published>2010-07-19T22:56:21Z</published>
    <updated>2010-07-19T23:44:52Z</updated>

    <summary><![CDATA[I guess every Java developer dealing with JAVA/XML serialization/deserialization&nbsp;knows about XStream. I was using it for years until yesterday. What happened yesterday? I found out XStream dos not work out of the box with GAE. Well is's not exactly XStream's...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Miscellaneous" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="tips and tricks" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="gae" label="GAE" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="simple" label="Simple" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="xml" label="XML" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="xstream" label="XStream" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;I guess every Java developer dealing with JAVA/XML serialization/deserialization&amp;nbsp;knows about &lt;a href="http://xstream.codehaus.org"&gt;XStream&lt;/a&gt;. I was using it for years until yesterday. What happened yesterday? I found out XStream dos not work out of the box with &lt;a href="http://code.google.com/appengine/"&gt;GAE&lt;/a&gt;. Well is's not exactly XStream's fault. A lot of stuff does not work properly with GAE due to its limitations and odd security restrictions. But my hope to quickly find patch/workaround, went away as soon as I realized the problem was reported to XStream over an year ago&amp;nbsp;(&lt;a class="moz-txt-link-freetext" style="text-decoration: underline; outline-style: none; outline-width: initial; outline-color: initial; color: rgb(61, 123, 34); " href="http://jira.codehaus.org/browse/XSTR-566"&gt;http://jira.codehaus.org/browse/XSTR-566&lt;/a&gt;) and there is still no good solution.&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;This way I was forced to look for alternatives. And I found &lt;a href="http://simple.sourceforge.net/"&gt;Simple&lt;/a&gt;! Conceptually it's a very similar to XStream. Serialization is really simple to use and revolves around several annotations and a single persister object. I got the impression it's noticeably faster than XStream. It's feature list is quite long (it even claims to be bean version tolerant) but so far I've used the standard stuff like converters, transformers, persister, etc.&lt;/p&gt;  &lt;p&gt;However since &amp;quot;Simple&amp;quot;&lt;/p&gt; &lt;ul&gt;     &lt;li&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: verdana, geneva, arial, sans-serif; font-size: 12px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "&gt;does not depend on 3rd party libraries&lt;/span&gt;&lt;/li&gt;     &lt;li&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: verdana, geneva, arial, sans-serif; font-size: 12px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "&gt;is available in central Maven repository&lt;/span&gt;&lt;/li&gt;     &lt;li&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: verdana, geneva, arial, sans-serif; font-size: 12px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "&gt;works out of the box with GAE&lt;/span&gt;&lt;/li&gt;     &lt;li&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: verdana, geneva, arial, sans-serif; font-size: 12px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "&gt;is capable of doing everything XStream is doing &amp;nbsp;&lt;/span&gt;&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;it's about to become my number one XML serialization/deserialization tool. At least until I discover it's dark sides.&lt;/p&gt;
        
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/24ct3kdqMSh9-C2FK9I6ItGnSQc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/24ct3kdqMSh9-C2FK9I6ItGnSQc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/24ct3kdqMSh9-C2FK9I6ItGnSQc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/24ct3kdqMSh9-C2FK9I6ItGnSQc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=A-UxBugy3E8:AxEoK83vEAI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=A-UxBugy3E8:AxEoK83vEAI:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=A-UxBugy3E8:AxEoK83vEAI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=A-UxBugy3E8:AxEoK83vEAI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=A-UxBugy3E8:AxEoK83vEAI:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=A-UxBugy3E8:AxEoK83vEAI:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/A-UxBugy3E8" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2010/07/more-simple-than-xstream.html</feedburner:origLink></entry>

<entry>
    <title>Liferay Portal 6 Enterprise Intranets review</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/0kAto-BStNg/liferay-portal-6-enterprise-intranets-review.html" />
    <id>tag:milen.commsen.com,2010://1.12</id>

    <published>2010-07-04T07:56:19Z</published>
    <updated>2010-07-04T08:22:28Z</updated>

    <summary><![CDATA[ A few weeks ago I was asked by Packt publishing to review the new Liferay Portal 6 Enterprise Intranets book. Going through over 650 pages took me some time but finally I'm ready to share my thought about it.&nbsp;...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="book" label="book" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;&lt;img alt="" align="right" src="https://www.packtpub.com/sites/default/files/imagecache/productview/0387_Liferay%20Portal%206%20Enterprise%20Intranets.jpg" /&gt;&lt;/p&gt; &lt;p&gt;A few weeks ago I was asked by &lt;a href="http://www.packtpub.com"&gt;Packt publishing&lt;/a&gt; to review the new &lt;a href="https://www.packtpub.com/liferay-portal-6-enterprise-intranets/book"&gt;Liferay Portal 6 Enterprise Intranets&lt;/a&gt; book. Going through over 650 pages took me some time but finally I'm ready to share my thought about it.&amp;nbsp;&lt;/p&gt; &lt;p&gt;By now you are probably scanning the text for something like &amp;quot;In general this is ____ book&amp;quot;. Don't bother, I'm not going to generalize in this post. In fact, what you put in place of ____ &amp;nbsp;depends on who you are, what is your Liferay background, and what you expect to learn.&lt;/p&gt; &lt;div&gt;&amp;nbsp;&lt;/div&gt;
        &lt;p&gt;I'm a software developer and I have been using Liferay for a few years now. When I heard about the book, my imagination draw a visions of me learning &amp;quot;how Liferay internal mechanisms work&amp;quot; or &amp;quot;what some of those strange configuration parameters are used for&amp;quot; or &amp;quot;how to tweak portlets' functionality and performance&amp;quot; or ... Of course, none of this had happened! This does not mean the book is bad, it only means I had too big expectations. If you are like me, then you may even get bored trying to read it form side to side.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;b&gt;One thing that I really miss in this book is pointing out what's new in Liferay 6&lt;/b&gt;. I know well 5.2.x version and I would appreciate a special style or sign indicating new&amp;nbsp;&lt;i&gt;(or updated)&lt;/i&gt;&amp;nbsp;feature in Liferay 6. This way more advanced readers could concentrate on things that are potentially of their interest and skip the part they are already familiar with. &amp;nbsp;If it wasn't for the review I would probably scan through the first few chapters for things I don't know &lt;i&gt;(and yes there are some interesting features to learn even if you already know Liferay)&lt;/i&gt; and then pay more attention at the last ones.&amp;nbsp;&amp;nbsp;The good news is the &lt;b&gt;chapter 11 called &amp;quot;&lt;/b&gt;&lt;a href="https://docs.google.com/viewer?url=https%3A%2F%2Fwww.packtpub.com%2Fsites%2Fdefault%2Ffiles%2F0387-Chapter-11-Ongoing-Admin-Tasks.pdf"&gt;&lt;b&gt;Ongoing Admin Tasks&lt;/b&gt;&lt;/a&gt;&lt;b&gt;&amp;quot; is freely available online&lt;/b&gt; &amp;nbsp;so you can have a look and see how it compares to the level of your knowledge. &amp;nbsp;&lt;/meta&gt;&lt;/p&gt;&lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;But since&amp;nbsp;&lt;u&gt;&lt;i&gt;&amp;quot;This book is for system administrators or experienced users (not necessarily programmers) who want to install and use Liferay in their teams or businesses without dealing with complex code. Prior knowledge of Liferay is not expected for this book.&amp;quot;&lt;/i&gt;&lt;/u&gt;&lt;i&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/i&gt;I decided to pretend I know almost nothing about Liferay and simply followed the instructions in the book &lt;i&gt;(I wish I had the PDF version, it would save me some typing)&lt;/i&gt;. When I got rid of &lt;i&gt;&amp;quot;come on, I already know all this&amp;quot;&lt;/i&gt; attitude, I had to admit the book is quite well organized.&lt;b&gt; Each chapter typically starts with explaining the basic functionality then goes through some configuration options and ends up instructing the reader how to define appropriate permissions.&lt;/b&gt; Sure, after the first two chapters you already know the pattern for defining permissions and there is no need to repeat it over and over again. But on the other hand if you intend to later one use the book as a quick reference or cheat-sheet, it may come handy. &amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;The book will explain almost &lt;/b&gt;&lt;i&gt;(as with every book the thing you are particularly interested in, will be probably missing)&lt;/i&gt;&lt;b&gt; every intranet feature you may need.&lt;/b&gt; Moreover it sometimes goes a bit off topic as I can hardly imagine configuring WAP or SEO for intranet site. It will not give too much details though, only enough to get you started and sometimes make small customizations. For example, it will not tell you how exactly portlet properties affect Liferay, but will give you a list of all properties related to current component with short explanation.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Being frequent reader of Liferay forums I'm convinced there is need for such book.&lt;/b&gt; The number of questions starting with &amp;quot;How can I ...&amp;quot; speaks for itself and from what I've noticed people are already referring to this book for answers. &lt;b&gt;But even if you are more advanced Liferay user, you may still find in the book valuable information about open search, clustering, reporting and audit logging, integration with Alfresco, CMIS and many others.&lt;/b&gt; Just remember, don't expect too much details. &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&amp;nbsp;&lt;/div&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/2vzgsi20hb7CugmsbxBBQT2D7U8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2vzgsi20hb7CugmsbxBBQT2D7U8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/2vzgsi20hb7CugmsbxBBQT2D7U8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2vzgsi20hb7CugmsbxBBQT2D7U8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=0kAto-BStNg:ivcksgvgbFQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=0kAto-BStNg:ivcksgvgbFQ:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=0kAto-BStNg:ivcksgvgbFQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=0kAto-BStNg:ivcksgvgbFQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=0kAto-BStNg:ivcksgvgbFQ:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=0kAto-BStNg:ivcksgvgbFQ:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/0kAto-BStNg" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2010/07/liferay-portal-6-enterprise-intranets-review.html</feedburner:origLink></entry>

<entry>
    <title>Writing Liferay portlet to display a file in a way "tail -f" does  </title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/H07Z296FgOs/writing-liferay-portlet-to-display-a-file-in-a-way-tail--f-does.html" />
    <id>tag:milen.commsen.com,2010://1.11</id>

    <published>2010-05-03T22:10:42Z</published>
    <updated>2010-07-04T08:27:10Z</updated>

    <summary><![CDATA[ Don't know about you but I can't imagine debugging enterprise class applications without having &quot;tail -f /path/to/log.file&quot; running in dedicated console window. During development and testing phases (assuming work is done &quot;in house&quot;) there is usually no problem with...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="tips and tricks" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="java" label="Java" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="javascript" label="javascript" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="jquery" label="jquery" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="portlet" label="portlet" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="weakreferences" label="weak references" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;Don't know about you but I can't imagine debugging enterprise class applications without having &amp;quot;&lt;span style="font-family: 'Courier New'; "&gt;tail -f /path/to/log.file&lt;/span&gt;&amp;quot; running in dedicated console window. During development and testing phases (assuming work is done &amp;quot;in house&amp;quot;) there is usually no problem with this approach as the whole team have access to servers' log files. This is not always the case with staging and production environments though. These days a lot of companies execute strong security policies which sometimes means that application is only accessible via HTTP. In such case, depending on how you SLA looks like, &amp;quot;&lt;i&gt;log files provided on demand via e-mail or FTP&lt;/i&gt;&amp;quot; may not be an option.&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;Facing this kind of problem in recent Liferay based project, made me think about creating a portlet capable of displaying log files. Something like WWW based version of &amp;quot;tail -f&amp;quot;. This is how Tailgate was born (for those of you looking for solution here is &lt;a href="http://github.com/azzazzel/Liferay-plugins/downloads"&gt;download page&lt;/a&gt;). The rest of this post will concentrate on explaining why it was not &amp;quot;&lt;i&gt;a max 2h of coding&lt;/i&gt;&amp;quot; as I thought in the begging.&lt;/p&gt;
        &lt;p style="text-align: justify; "&gt;Tailgate portlet needs to dynamically show new lines as they are written to the file without reloading the whole portal page. Assuming one portlet instance is configured to display only one file, the solution appears to be straightforward and rather simple: &lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;&lt;code class="blockWhite"&gt;while page is displayed {&lt;br /&gt; &amp;nbsp;browser sends AJAX request&lt;br /&gt; &amp;nbsp;server checks if there are new lines in given file &amp;nbsp;&lt;br /&gt; &amp;nbsp;server responds with list of new lines&lt;br /&gt; &amp;nbsp;browser adds lines to appropriate DOM element&lt;br /&gt; }&lt;/code&gt;While this is in general the whole functionality, there are a few things to consider on both front-end (client) and back-end (server) side. &amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;b&gt;&lt;span style="font-size: large; "&gt;front-end&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;As far as front-end is concern there are 2 main things to consider:&amp;nbsp;&lt;/p&gt; &lt;h3&gt;&lt;span style="font-size: small; "&gt;&lt;u&gt;&lt;b&gt;Multiple instances on the same page&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h3&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;This is a bit tricky and requires good understanding of how portals work. When a portlet is developed it contains common code for all instances. So if multiple instance can be placed on the same portal page then the common code should be able to distinguish instances. This is even more important with AJAX requests. &amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;In this case we have a common logic for sending and receiving AJAX requests and updating DOM model. However when portlet instance sends AJAX requests it needs to provide instance specific set of parameters as part of the URL. Also when response is received only DOM elements belonging to this particular instance need to be updated.&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;The common JavaScript code is provided in &lt;span style="font-family: 'Courier New'; "&gt;tailgate.js&lt;/span&gt; file. The portlet uses also &lt;a href="http://plugins.jquery.com/project/timers"&gt;jQuery timers module&lt;/a&gt; (&lt;span style="font-family: 'Courier New'; "&gt;jquery.timers.js&lt;/span&gt;) which provides high level abstraction of setTimeout and setInterval. These files are part of the portlet code. Including them in &lt;span style="font-family: 'Courier New'; "&gt;HTML&lt;/span&gt; page is done by adding&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;code class="blockWhite"&gt;&amp;lt;header-portlet-javascript&amp;gt;/js/jquery.timers.js&amp;lt;/header-portlet-javascript&amp;gt;&lt;br /&gt; &amp;lt;header-portlet-javascript&amp;gt;/js/tailgate.js&amp;lt;/header-portlet-javascript&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;to &lt;span style="font-family: 'Courier New'; "&gt;WEB-INF/liferay-portlet.xml&lt;/span&gt;. This way Liferay will add appropriate links in &lt;span style="font-family: 'Courier New'; "&gt;HEAD&lt;/span&gt; section of &lt;span style="font-family: 'Courier New'; "&gt;HTML&lt;/span&gt; page and will do this only once regardless of how many portlet instances page contains.&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;The &lt;span style="font-family: 'Courier New'; "&gt;tailgate.js&lt;/span&gt;&amp;nbsp;defines the Tailgate object and&amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;tailgateInstances&lt;/span&gt;&amp;nbsp;map for holding information about Tailgate instances:&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;code class="blockWhite"&gt;var tailgateInstances = new Array();&amp;nbsp;&lt;br /&gt; function Tailgate(lines, url) {&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;this.lines=lines&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;this.url=url&lt;br /&gt; }&lt;/code&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;When portlet instance is rendered it takes care to prefix DOM element ids with it's namespace&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;code class="blockWhite"&gt;&amp;lt;button id=&amp;quot;&amp;lt;portlet:namespace /&amp;gt;_start&amp;quot;&amp;gt;Start&amp;lt;/button&amp;gt;&lt;br /&gt; &amp;lt;button id=&amp;quot;&amp;lt;portlet:namespace /&amp;gt;_stop&amp;quot;&amp;gt;Stop&amp;lt;/button&amp;gt;&lt;br /&gt; ...&lt;br /&gt; &amp;lt;ul id=&amp;quot;&amp;lt;portlet:namespace /&amp;gt;list&amp;quot; class=&amp;quot;tailgate&amp;quot;&amp;gt;&amp;nbsp;&lt;/code&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;, add itself to &lt;span style="font-family: 'Courier New'; "&gt;tailgateInstances&lt;/span&gt;&amp;nbsp;map &amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;code class="blockWhite"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;tailgateInstances[&amp;quot;&amp;lt;portlet:namespace /&amp;gt;&amp;quot;] =&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; new Tailgate(&amp;lt;%=prefs.getValue(&amp;quot;lines&amp;quot;,&amp;quot;100&amp;quot;)%&amp;gt;, &amp;quot;&amp;lt;liferay-portlet:resourceURL /&amp;gt;&amp;quot;);&amp;nbsp;&lt;/code&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&amp;nbsp;and pass the namespace to called functions&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;code class="blockWhite"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;jQuery(&amp;quot;#&amp;lt;portlet:namespace /&amp;gt;_start&amp;quot;).click(function(){&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;		&lt;/span&gt;startReading(&amp;quot;&amp;lt;portlet:namespace /&amp;gt;&amp;quot;);&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;})&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;jQuery(&amp;quot;#&amp;lt;portlet:namespace /&amp;gt;_stop&amp;quot;).click(function(){&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;		&lt;/span&gt;stopReading(&amp;quot;&amp;lt;portlet:namespace /&amp;gt;&amp;quot;);&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;})&lt;br /&gt; &amp;lt;/script&amp;gt;&amp;nbsp;&lt;/code&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;Note that all functions in &lt;span style="font-family: 'Courier New'; "&gt;tailgate.js&lt;/span&gt; are designed to accept namespace as parameter. This way when called they can either get appropriate Tailgate instance from &lt;span style="font-family: 'Courier New'; "&gt;tailgateInstances&lt;/span&gt; map and then check for given property (for example url), or find and update DOM elements prefixed with this namespace.&amp;nbsp;&lt;/p&gt; &lt;h3&gt;&lt;u&gt;&lt;b&gt;Control the CPU and memory usage&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;Monitored file can change very fast (application could add few megabytes is just a second) therefore at first it seems to be very important to query back-end as often as possible. &amp;nbsp;This however results in very high CPU usage. In fact going down below 10ms may force you to kill your browser in order to recover your system. Experimenting with different values I finally decided that refresh rate of one second is a reasonable compromise.&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;Another thing is memory. If lines are only added but never deleted then after a while the browser will be trying to display a tens of megabytes of &lt;span style="font-family: 'Courier New'; "&gt;HTML&lt;/span&gt; code. Therefore Tailgate is configured to only display last &lt;span style="font-family: 'Courier New'; "&gt;X&lt;/span&gt; lines. It renders each line as &lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;li&amp;gt;&lt;/span&gt; element and when new line is added, a new &lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;li&amp;gt;&lt;/span&gt; element is added to the parent &lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;. Then it checks the size of &lt;span style="font-family: 'Courier New'; "&gt;&amp;lt;ul&amp;gt;&lt;/span&gt; and if it's bigger than &lt;span style="font-family: 'Courier New'; "&gt;X&lt;/span&gt;, old lines are deleted from DOM model. Luckily &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; comes with convenient methods so this is really easy to implement:&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;code class="blockWhite"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;jQuery('#'+namespace+'list').append(data);&lt;br /&gt; &amp;nbsp;&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;var maxLines = tailgateInstances[namespace].lines;&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;var lines = jQuery('#' + namespace + 'list li').length;&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;if (lines &amp;gt; maxLines) {&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;		&lt;/span&gt;jQuery('#' + namespace + 'list li').slice(0, lines - maxLines).remove();&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;}&lt;/code&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;b&gt;&lt;span style="font-size: large; "&gt;back-end&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;The line &lt;i&gt;&amp;quot;server checks if there are new lines in given file&amp;quot;&lt;/i&gt; in the above pseudo algorithm is also way oversimplified.&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;The &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/io/RandomAccessFile.html"&gt;RandomAccessFile&lt;/a&gt;&amp;nbsp;class provides the functionality to position at specific place in file and start reading. However creating a new instance on every request is not a very smart thing to do. Even if it is somehow cached per portlet instance, there still could be many instances monitoring the same file &lt;i&gt;(in the future each may provide different filtering, highlighting, etc.)&lt;/i&gt; Also, depending on what file system is used &lt;i&gt;(for example old versions of NFS)&lt;/i&gt;, there may be some locking issues when multiple threads try to access the given file at the same time. Therefore it looks like the optimal solution would be to have one thread continuously reading the file and updating in memory buffers provided by specific instances. Here is the activity diagram: &amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img alt="Tailgate activity diagram" width="700" src="http://milen.commsen.com/TailgateActivityDiagram.png" /&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;This looks simple enough but again there are a couple of things to think about:&lt;/p&gt; &lt;h3&gt;&lt;u&gt;&lt;b&gt;synchronization&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;Since there are two thread operating on the same buffer (one writing and one reading) the buffer's read and write operations need to be synchronized. Otherwise a typical &lt;a href="http://java.sun.com/docs/books/tutorial/essential/concurrency/memconsist.html"&gt;Memory Consistency Errors&lt;/a&gt;&amp;nbsp;may occur. &amp;nbsp;&lt;/p&gt; &lt;h3&gt;&lt;u&gt;&lt;b&gt;buffer size&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;Buffers need to have fixed size in order to avoid memory leaks! Since the front-end also displays a limited amount of data, the same configuration parameter can be used to define both the number of lines displayed and buffered. Then every time a new line is added to the the oldest one is removed if buffer the size is reached:&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;code class="blockWhite"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;public boolean addLine(final String line) {&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;		&lt;/span&gt;boolean result;&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;		&lt;/span&gt;synchronized (buffer) {&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;			&lt;/span&gt;result = buffer.add(line);&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;			&lt;/span&gt;if (buffer.size() &amp;gt; maxSize) {&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;				&lt;/span&gt;buffer.remove();&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;			&lt;/span&gt;}&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;		&lt;/span&gt;}&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;		&lt;/span&gt;return result;&lt;br /&gt; &lt;span class="Apple-tab-span" style="white-space: pre; "&gt;	&lt;/span&gt;}&amp;nbsp;&lt;/code&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;&lt;u&gt;&lt;b&gt;when to stop reading&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;If you have carefully examined the activity diagram above you may have noticed that buffers are never unregistered. This is not an error, it is simply impossible to tell when a buffer is no longer needed. One may argue that user could send us appropriate message by clicking on something saying &lt;i&gt;&amp;quot;I'm done watching, please stop the buffer!&amp;quot;&lt;/i&gt;. My experience shows such approach is often misunderstood and misused &lt;i&gt;(by that I mean used too often or not at all)&lt;/i&gt;. So how can one prevent &lt;span style="font-family: 'Courier New'; "&gt;FileMonitor&lt;/span&gt; thread from running forever&lt;i&gt; (it will run as long as there are buffers)&lt;/i&gt;? Let the garbage collector do it's job!&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;Buffers are stored in portlet sessions, so instead of relaying on user interaction, Tailgate relays on buffers being garbage collected once portlet session is closed. As you probably know an object becomes eligible for garbage collection when there are no hard references to it. Is this the case with buffers? As the diagram shows, buffers are referenced in 2 other places (marked in red) - &lt;span style="font-family: 'Courier New'; "&gt;FileMonitoringEngine&lt;/span&gt; needs to keep track of which buffer is assigned to which monitor and &lt;span style="font-family: 'Courier New'; "&gt;FileMonitor&lt;/span&gt; needs to maintain a list of buffers to write to. But here is the difference, in order to leverage the garbage collector's ability to determine buffers' reachability, both &lt;span style="font-family: 'Courier New'; "&gt;FileMonitoringEngine&lt;/span&gt; and &lt;span style="font-family: 'Courier New'; "&gt;FileMonitor&lt;/span&gt; use weak references. &lt;span style="font-family: 'Courier New'; "&gt;FileMonitoringEngine&lt;/span&gt; uses in fact standard WeakHashMap to store the mapping. &amp;nbsp;&lt;span style="font-family: 'Courier New'; "&gt;FileMonitor&lt;/span&gt; only needs a Set of weak references but there is no WeakHashSet class. In JDK 6 there is a convenient &amp;quot;&lt;span style="font-family: 'Courier New'; "&gt;newSetFromMap(Map&amp;lt;E,Boolean&amp;gt; map)&lt;/span&gt;&amp;quot; method available in &lt;span style="font-family: 'Courier New'; "&gt;java.util.Collections&lt;/span&gt; class. In order to be compatible with JDK 5 the behavior of this the JDK 6 method had to be implemented as part of Tailgate portlet.&amp;nbsp;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;This way as soon as portlet session gets garbage collected there are no hard references to the buffer and it is collected as well. When all buffers are garbage collected the &lt;span style="font-family: 'Courier New'; "&gt;FileMonitor&lt;/span&gt; thread ends. The first request instantiating new buffer will start new &lt;span style="font-family: 'Courier New'; "&gt;FileMonitor&lt;/span&gt; thread which will again run as long as there is someone interested in receiving results.&amp;nbsp;&lt;/p&gt; &lt;h2&gt;&lt;b&gt;&lt;span style="font-size: medium; "&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0.75em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; text-align: justify; "&gt;I'm well aware I'm not writing anything really revealing here. But after spending some hours on Tailgate portlet I thought I would write about the problems and solutions. Hopefully you at least learned a little something from this experience. In case you are interested,&amp;nbsp;&lt;a href="http://github.com/azzazzel/Liferay-plugins/tree/master/tailgate/"&gt;Tailgate's source code is available at GitHub.&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Y8RwURhqOopZu8CjYypxFQQ87l8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Y8RwURhqOopZu8CjYypxFQQ87l8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Y8RwURhqOopZu8CjYypxFQQ87l8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Y8RwURhqOopZu8CjYypxFQQ87l8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=H07Z296FgOs:6Ib-1RLgJHA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=H07Z296FgOs:6Ib-1RLgJHA:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=H07Z296FgOs:6Ib-1RLgJHA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=H07Z296FgOs:6Ib-1RLgJHA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=H07Z296FgOs:6Ib-1RLgJHA:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=H07Z296FgOs:6Ib-1RLgJHA:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/H07Z296FgOs" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2010/05/writing-liferay-portlet-to-display-a-file-in-a-way-tail--f-does.html</feedburner:origLink></entry>

<entry>
    <title>Custom global markup portlet</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/h5u45gyE1vM/custom-global-markup-portlet.html" />
    <id>tag:milen.commsen.com,2010://1.10</id>

    <published>2010-04-05T22:40:01Z</published>
    <updated>2010-07-04T08:27:55Z</updated>

    <summary><![CDATA[What would you do if a customer demands to &quot;integrate&quot; his Liferay based corporate portal with Google Analytics, Geminus, ClickTale, Crazy Egg,&nbsp; and whole bunch of other analytics tools available out there?As you probably know, such services typically provide some...]]></summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="tips and tricks" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="css" label="css" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="html" label="html" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="javascript" label="javascript" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="portlet" label="portlet" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;What would you do if a customer demands to &amp;quot;integrate&amp;quot; his Liferay based corporate portal with &lt;a href="http://www.google.com/analytics"&gt;Google Analytics&lt;/a&gt;, &lt;a href="http://www.gemius.com/"&gt;Geminus&lt;/a&gt;, &lt;a href="http://www.clicktale.com/"&gt;ClickTale&lt;/a&gt;, &lt;a href="http://www.crazyegg.com/"&gt;Crazy Egg&lt;/a&gt;,&amp;nbsp; and whole bunch of other analytics tools available out there?&lt;/p&gt;&lt;p&gt;As you probably know, such services typically provide some piece of javascript (code or file) which needs to be added to every page of monitored web site. Each service also provides unique customer code/key (which is either already part of the javascript provided or needs to be placed in specific place). Regardless of whether using all of them at the same time is a smart thing to do, there are a few technical problems to solve:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;How to add custom code to every portal page&lt;/li&gt;&lt;li&gt;How to deal with unique codes/keys through development, testing, staging, production phases&lt;/li&gt;&lt;li&gt;How to minimize the impact of changing/removing custom code in production environment&lt;/li&gt;&lt;/ul&gt;
        &lt;p&gt;There are few ways to solve the first case&lt;/p&gt; &lt;p&gt;&lt;u&gt;&lt;b&gt;Make the code part of the theme. &lt;/b&gt;&lt;/u&gt;&lt;br /&gt; &lt;br /&gt; This is easy to do but it has some drawbacks. First of all, depending on how theme is applied, the code may end up on every page in every community or only in few rarely visited pages. Also if your portal uses a number of themes than you need to either make a common theme and make the rest extend it, or you need to add it to each theme. This approach may be a serious maintenance challenge. &lt;br /&gt; &lt;br /&gt; You may solve the problem with unique codes/keys by using portal properties but you'll not be able to easily modify or remove the java script code if you have disabled (and you should) hot deployment on production servers.&amp;nbsp; &lt;br /&gt; &lt;br /&gt; &lt;u&gt;&lt;b&gt;&lt;br /&gt; Create custom portlet and add it to every page. &lt;/b&gt;&lt;/u&gt;&lt;br /&gt; &lt;br /&gt; Samuel Kong's excellent post &lt;a href="http://www.liferay.com/web/samuel.kong/blog/-/blogs/adding-a-javascript-to-every-page"&gt;http://www.liferay.com/web/samuel.kong/blog/-/blogs/adding-a-javascript-to-every-page&lt;/a&gt;&amp;nbsp; explains how to add javascript to every page. However be aware that if you blindly follow the example you'll add the code to EVERY page (not every page in given community). Following this approach you'll have to choose between two options&lt;/p&gt; &lt;ul&gt;     &lt;li&gt;one portlet having all javascript codes&lt;/li&gt;     &lt;li&gt;separate portlet per javascript code (or group of codes)&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;The first one is only acceptable if all javascript codes can ALWAYS be placed together and it kind of violates the &amp;quot;design by responsibility&amp;quot; concept. The second approach on the other hand deploys a lot of boilerplate code which in some cases may have&amp;nbsp; impact on performance. &lt;br /&gt; Unique codes/keys may be provided in portlet preferences but still it's not very convenient when portlets are automatically added via &lt;code&gt;layout.static.portlets.all&lt;/code&gt; property. Also, as you have probably guessed, this approach does not solve the problem with modifying/removing javascript code in production environment.&lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;u&gt;&lt;b&gt;Use custom-global-markup-portlet&lt;br /&gt; &lt;/b&gt;&lt;/u&gt;&lt;br /&gt; custom-global-markup-portlet was written to solve all of the problems described above. The portlet is based on Samuel Kong's example, but it also provides convenient management interface in Liferay's control panel:&lt;/p&gt; &lt;p&gt;&lt;a href="http://milen.commsen.com/customglobalmarkup/CustomGlobalMarkupConfig.png"&gt;&lt;img width="700" alt="Custom Global Markup Portlet Configuration" src="http://milen.commsen.com/customglobalmarkup/CustomGlobalMarkupConfig.png" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;As you can see from the above screenshot&amp;nbsp;portal administrator can easly add/modify/delete any markup (javascript, CSS, HTML, ...). Here is how the portal look like after you save the above markups:&lt;/p&gt; &lt;p&gt;&lt;a href="http://milen.commsen.com/customglobalmarkup/CustomGlobalMarkupResult.png"&gt;&lt;img alt="Portal changed via Custom Global Markup Portlet" width="700" src="http://milen.commsen.com/customglobalmarkup/CustomGlobalMarkupResult.png" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;As you may have already noticed there are a few important features. First of all the markup can be divided into multiple entries and each entry can be enabled/disabled and placed on top (in &amp;lt;head&amp;gt; section) or bottom (before &amp;lt;/html&amp;gt;) of the page. All entries are persisted into database which eliminates potential problems with maintaining different portlet preferences in different environments (development, staging, production). Also note that custom-global-markup-portlet is community scoped, which allows adding markup to pages of specific community.&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt; You can download the latest version of custom-global-markup-portlet here: &lt;a href="http://github.com/azzazzel/Liferay-plugins/downloads"&gt;http://github.com/azzazzel/Liferay-plugins/downloads&lt;/a&gt;.&amp;nbsp;It is part of &lt;a href="http://github.com/azzazzel/Liferay-plugins"&gt;Commsen Lifery plugins&lt;/a&gt; which is free and open source project hosted at &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt; and released under &lt;a href="http://www.gnu.org/licenses/lgpl-2.1.html"&gt;LGPL license&lt;/a&gt;. It is developed with &lt;a href="http://github.com/azzazzel/liferay-maven-sdk"&gt;liferay-maven-sdk&lt;/a&gt; and uses &lt;a href="http://git-scm.com/"&gt;Git SCM&lt;/a&gt;&lt;br /&gt; &amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/_-V36_PH7BqVdU_9vfbjHP6M0mo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_-V36_PH7BqVdU_9vfbjHP6M0mo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/_-V36_PH7BqVdU_9vfbjHP6M0mo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_-V36_PH7BqVdU_9vfbjHP6M0mo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=h5u45gyE1vM:PjWib2k_58c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=h5u45gyE1vM:PjWib2k_58c:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=h5u45gyE1vM:PjWib2k_58c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=h5u45gyE1vM:PjWib2k_58c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=h5u45gyE1vM:PjWib2k_58c:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=h5u45gyE1vM:PjWib2k_58c:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/h5u45gyE1vM" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2010/04/custom-global-markup-portlet.html</feedburner:origLink></entry>

<entry>
    <title>Creating Liferay portlet with liferay-maven-sdk</title>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/MilenDyankov/~3/gYlMrk_spuw/creating-liferay-portlet-with-liferay-maven-sdk.html" />
    <id>tag:milen.commsen.com,2009://1.9</id>

    <published>2009-10-09T21:47:50Z</published>
    <updated>2010-07-04T08:36:09Z</updated>

    <summary>This post will demonstrate how liferay-maven-sdk can be employed to build a Liferay portlet using Liferay's Service Builder feature. For this purpose we will create service-builder-portlet which is capable of displaying a list of players and adding a new player...</summary>
    <author>
        <name>Milen Dyankov</name>
        
    </author>
    
        <category term="Liferay" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="liferay" label="Liferay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="maven" label="Maven" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="portlet" label="portlet" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="servicebuilder" label="service builder" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://milen.commsen.com/">
        &lt;p&gt;This post will demonstrate how &lt;a href="http://github.com/azzazzel/liferay-maven-sdk"&gt;liferay-maven-sdk&lt;/a&gt; can be employed to build a Liferay portlet using Liferay's Service Builder feature. For this purpose we will create service-builder-portlet which is capable of displaying a list of players and adding a new player to this list. The model, persistence layer and data access services will be generated by &lt;code&gt;Service Builder&lt;/code&gt;.&lt;br /&gt; But first things first. Download and install&amp;nbsp; &lt;code&gt;liferay-maven-sdk&lt;/code&gt; if you haven't done so already (have a look at&amp;nbsp; &amp;quot;&lt;a href="http://wiki.github.com/azzazzel/liferay-maven-sdk/download-and-install"&gt;Download and Install&lt;/a&gt;&amp;quot; page for instructions). Once &lt;code&gt;liferay-maven-sdk&lt;/code&gt; is installed in your local repository, you can create the portlet.&lt;/p&gt;
        &lt;p&gt;So enter the folder (or create one) where you keep your portlets and execute&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt; mvn archetype:generate &lt;/code&gt;&lt;/p&gt; &lt;p&gt;you should see a list of available archetypes starting with&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt;  Choose archetype:&lt;br /&gt; 1: local -&amp;gt; liferay-portlet-archetype (Liferay portlet archetype)&lt;br /&gt; 2: local -&amp;gt; liferay-theme-archetype (Liferay theme archetype)&lt;br /&gt; 3: internal -&amp;gt; appfuse-basic-jsf (AppFuse archetype for creating a web application with Hibernate, Spring and JSF)&lt;br /&gt; 4: internal -&amp;gt; appfuse-basic-spring (AppFuse archetype for creating a web application with Hibernate, Spring and Spring MVC)&lt;br /&gt; ...&lt;br /&gt; Choose a number:&amp;nbsp; (1/2/3/4/...)&amp;nbsp; :1&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Type &lt;code&gt;1&lt;/code&gt; and press enter to choose &lt;code&gt;liferay-portlet-archetype. Then provide &lt;code&gt;groupId&lt;/code&gt;, &lt;code&gt;artifactID&lt;/code&gt;, &lt;code&gt;package&lt;/code&gt; and &lt;code&gt;version&lt;/code&gt;. For example:&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt;  Define value for groupId: : com.commsen.liferay.examples.portlet.servicebuilder&lt;br /&gt; Define value for artifactId: : service-builder-portlet&lt;br /&gt; Define value for version:&amp;nbsp; 1.0-SNAPSHOT: : 1.0 &lt;br /&gt; Define value for package:&amp;nbsp; com.commsen.liferay.examples.portlet.servicebuilder: :&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Additionally you may execute&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt; mvn eclipse:eclipse &lt;/code&gt;&lt;/p&gt; &lt;p&gt;to setup Eclipse IDE if, that is what you are using! At this time your portlet skeleton is ready and you may compile it and even create WAR, but it of course does nothig special.&lt;/p&gt; &lt;p&gt;Let's now add data model and services. Create file &lt;code&gt;service-builder-portlet/src/main/webapp/WEB-INF/service.xml&lt;/code&gt; :&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt;  &amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;br /&gt; &amp;lt;!DOCTYPE service-builder PUBLIC &amp;quot;-//Liferay//DTD Service Builder 5.2.0//EN&amp;quot; &amp;quot;http://www.liferay.com/dtd/liferay-service-builder_5_2_0.dtd&amp;quot;&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;service-builder package-path=&amp;quot;com.commsen.liferay.examples.portlet.servicebuilder&amp;quot;&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;namespace&amp;gt;SB&amp;lt;/namespace&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;entity name=&amp;quot;Player&amp;quot; local-service=&amp;quot;true&amp;quot; remote-service=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;!-- PK fields --&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;column name=&amp;quot;playerId&amp;quot; type=&amp;quot;long&amp;quot; primary=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;!-- Other fields --&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;column name=&amp;quot;name&amp;quot; type=&amp;quot;String&amp;quot; /&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;column name=&amp;quot;active&amp;quot; type=&amp;quot;boolean&amp;quot; /&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;column name=&amp;quot;score&amp;quot; type=&amp;quot;int&amp;quot; /&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;column name=&amp;quot;birthday&amp;quot; type=&amp;quot;Date&amp;quot; /&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;column name=&amp;quot;description&amp;quot; type=&amp;quot;String&amp;quot; /&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;!-- Order --&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;order by=&amp;quot;asc&amp;quot;&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;order-column name=&amp;quot;name&amp;quot; /&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;/order&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;!-- Finder methods --&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;finder name=&amp;quot;ActivePlayers&amp;quot; return-type=&amp;quot;Collection&amp;quot;&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;finder-column name=&amp;quot;active&amp;quot; /&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;/finder&amp;gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;/entity&amp;gt;&lt;br /&gt; &amp;lt;/service-builder&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;The portlet projects created by liferay-portlet-archetype contain maven profile with lifray-maven-plugin&amp;rsquo;s &lt;code&gt;build-service&lt;/code&gt; goal attached to &lt;code&gt;generate-sources&lt;/code&gt; phase. To run ServiceBuilder you need to activate the profile:&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt; mvn -P build-service package&lt;/code&gt;&lt;/p&gt; &lt;p&gt;If you read carefully the messages you will realize that service and persistence classes were generated in &lt;code&gt;service-builder-portlet/src/main/java-service-api/&lt;/code&gt; folder. Also there should be a few implementation files in &lt;code&gt;service-builder-portlet/src/main/java/&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;Now we'll add custom methods. Open the following file &lt;code&gt; service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerLocalServiceImpl.java&lt;/code&gt; and paste this code:&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt; public void addPlayer(String name, boolean active, int score, Date birthday, String desc) throws PortalException, SystemException {&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;long playerId = CounterLocalServiceUtil.increment();&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;Player player = PlayerUtil.create(playerId);&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;player.setName(name);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;player.setActive(active);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;player.setScore(score);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;player.setBirthday(birthday);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;player.setDescription(desc);&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;PlayerUtil.update(player, false);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;public List&amp;lt;Player&amp;gt; getAllPlayers() throws PortalException, SystemException {&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;return PlayerUtil.findAll();&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &lt;/code&gt;&lt;/p&gt; &lt;p&gt;We added methods to the implementation class. The next time we compile the code we need to activate the &lt;code&gt;build-service&lt;/code&gt; profile again in order for &lt;code&gt;Service Builder&lt;/code&gt; to react on the change and regenerate the API and interfaces. If you want to try it now simply execute&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt; mvn -P build-service compile&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Now we can start using these services in our portlet. Open&lt;code&gt; service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/JSPPortlet.java&lt;/code&gt; and add this method&lt;/p&gt; &lt;p&gt;&lt;code class="blockWhite"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; @ProcessAction(name = Constants.ADD)&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;public void addPlayer(ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException, IOException {&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;String name = ParamUtil.getString(actionRequest, &amp;quot;name&amp;quot;);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;boolean active = ParamUtil.getBoolean(actionRequest, &amp;quot;active&amp;quot;);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;int score = ParamUtil.getInteger(actionRequest, &amp;quot;score&amp;quot;);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;String description = ParamUtil.getString(actionRequest, &amp;quot;description&amp;quot;);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;int year = ParamUtil.getInteger(actionRequest, &amp;quot;birthday_year&amp;quot;);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;int month = ParamUtil.getInteger(actionRequest, &amp;quot;birthday_month&amp;quot;);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;int day = ParamUtil.getInteger(actionRequest, &amp;quot;birthday_day&amp;quot;);&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;Calendar calendar = Calendar.getInstance();&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;calendar.set(Calendar.YEAR, year);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;calendar.set(Calendar.MONTH, month);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;calendar.set(Calendar.DAY_OF_MONTH, day);&lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;try {&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;PlayerLocalServiceUtil.addPlayer(name, active, score, calendar.getTime(), description);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;} catch (Exception e) {&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;throw new PortletException(&amp;quot;Failed to add player&amp;quot;, e);&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt; &amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;/code&gt;&lt;/p&gt; &lt;p&gt;This method handles adding players to database by calling the method we created earliar. To complete the portlet we only need the JSP page which displays the list and render HTML form to add users. The page source code is available &lt;a href="http://github.com/azzazzel/liferay-maven-sdk/blob/master/examples/service-builder-portlet/src/main/webapp/view.jsp"&gt;here&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;That's all! We can now create WAR file (&lt;code&gt;mvn package&lt;/code&gt;) deploy it and add some players to our database!&amp;nbsp; For more details have a look at portlet's source code available in &lt;a href="http://github.com/azzazzel/liferay-maven-sdk/tree/master/examples/service-builder-portlet"&gt;examples/service-builder-portlet&lt;/a&gt;      folder of &lt;code&gt;liferay-maven-sdk&lt;/code&gt;.&lt;/p&gt;
    
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xIWCHBgFJCWRVqs-48XM7pqK7O0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xIWCHBgFJCWRVqs-48XM7pqK7O0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xIWCHBgFJCWRVqs-48XM7pqK7O0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xIWCHBgFJCWRVqs-48XM7pqK7O0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=gYlMrk_spuw:PjsKF1UYGoc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:l6gmwiTKsz0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=l6gmwiTKsz0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:KwTdNBX3Jqk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=gYlMrk_spuw:PjsKF1UYGoc:KwTdNBX3Jqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=gYlMrk_spuw:PjsKF1UYGoc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=gYlMrk_spuw:PjsKF1UYGoc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?i=gYlMrk_spuw:PjsKF1UYGoc:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MilenDyankov?a=gYlMrk_spuw:PjsKF1UYGoc:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MilenDyankov?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MilenDyankov/~4/gYlMrk_spuw" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://milen.commsen.com/2009/10/creating-liferay-portlet-with-liferay-maven-sdk.html</feedburner:origLink></entry>

</feed>

