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

<channel>
	<title>Dev @ Work &#187; Bert Willems</title>
	<atom:link href="http://www.devatwork.nl/author/admin/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.devatwork.nl</link>
	<description>A day in the life of a developer</description>
	<lastBuildDate>Tue, 18 Oct 2011 16:32:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Liferay: Embedding Portlets in your Portlet</title>
		<link>http://www.devatwork.nl/2011/07/liferay-embedding-portlets-in-your-portlet/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=liferay-embedding-portlets-in-your-portlet</link>
		<comments>http://www.devatwork.nl/2011/07/liferay-embedding-portlets-in-your-portlet/#comments</comments>
		<pubDate>Fri, 01 Jul 2011 14:32:45 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Liones]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=894</guid>
		<description><![CDATA[In this article I will show you how you can embed an existing Liferay portlet into your own plug-in portlet without using Ext. This might be useful in several scenarios, for example: building your own &#8216;nested portlet&#8217; portlet or include the web form portlet in your own portlet. The solutions works in Liferay 6.0 EE [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.devatwork.nl/wp-content/uploads/2010/01/liferay-logo-block.jpg" rel="lightbox[894]"><img class="alignright size-full wp-image-656" title="Liferay" src="http://www.devatwork.nl/wp-content/uploads/2010/01/liferay-logo-block.jpg" alt="" width="99" height="96" /></a>In this article I will show you how you can embed an existing Liferay portlet into your own plug-in portlet without using Ext. This might be useful in several scenarios, for example: building your own &#8216;nested portlet&#8217; portlet or include the web form portlet in your own portlet.</p>
<p>The solutions works in Liferay 6.0 EE SP1 and can include portlets from Liferay itself as well as portlets coming from other plug-ins. Other versions of Liferay have not been tested yet.</p>
<p>I hope this snippet is as useful to you as it is to me!</p>
<pre class="brush: java; title: ; notranslate">package nl.liones.liferay;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.portlet.PortletBag;
import com.liferay.portal.kernel.portlet.PortletBagPool;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.service.PortletLocalServiceUtil;
import com.liferay.portal.theme.PortletDisplay;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.portal.util.PortalUtil;
import com.liferay.portal.util.PortletKeys;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.ValidatorException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
 * Portlet embed utility method.
 *
 * @author Stef Busking (Liones), Bert Willems (Liones)
 */
public class RuntimePortletEmbedUtil {
    /**
     * Renders the given portlet as a runtime portlet and returns the portlet's HTML.
     *
     * @param request     The {@link PortletRequest}.
     * @param response    The {@link PortletResponse}.
     * @param portletId   The ID of the portlet to render, includes instance ID for instance portlets.
     * @param queryString The query string to use for the portlet.
     * @return The HTML for the given portlet.
     * @throws SystemException    on error.
     * @throws IOException        on error.
     * @throws ServletException   on error.
     * @throws ValidatorException on error.
     */
    public static String renderPortlet(final PortletRequest request, final PortletResponse response, final String portletId, final String queryString) throws SystemException, IOException, ServletException, ValidatorException {
        // Get servlet request / response
        HttpServletRequest servletRequest = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(request));
        HttpServletResponse servletResponse = PortalUtil.getHttpServletResponse(response);
        // Get theme display
        final ThemeDisplay themeDisplay = (ThemeDisplay) servletRequest.getAttribute(WebKeys.THEME_DISPLAY);
        // Backup current state
        PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
        PortletDisplay portletDisplayClone = new PortletDisplay();
        portletDisplay.copyTo(portletDisplayClone);
        final Map&lt;String, Object&gt; requestAttributeBackup = new HashMap&lt;String, Object&gt;();
        for (final String key : Collections.list((Enumeration&lt;String&gt;) servletRequest.getAttributeNames())) {
            requestAttributeBackup.put(key, servletRequest.getAttribute(key));
        }
        // Render the portlet as a runtime portlet
        String result;
        try {
            PortletBag implPortletBag = PortletBagPool.get(PortletKeys.JOURNAL);
            com.liferay.portal.model.Portlet portlet = PortletLocalServiceUtil.getPortletById(PortalUtil.getCompanyId(request), portletId);
            servletRequest.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
            result = PortalUtil.renderPortlet(implPortletBag.getServletContext(), servletRequest, servletResponse, portlet, queryString, false);
        } finally {
            // Restore the state
            portletDisplay.copyFrom(portletDisplayClone);
            portletDisplayClone.recycle();
            for (final String key : Collections.list((Enumeration&lt;String&gt;) servletRequest.getAttributeNames())) {
                if (!requestAttributeBackup.containsKey(key)) {
                    servletRequest.removeAttribute(key);
                }
            }
            for (final Map.Entry&lt;String, Object&gt; entry : requestAttributeBackup.entrySet()) {
                servletRequest.setAttribute(entry.getKey(), entry.getValue());
            }
        }
        return result;
    }
}</pre>
<p><strong>Using this code</strong><br />
The snippet below demos how to embed the Liferay Web Form portlet and how to set a preference for this embedded portlet.</p>
<pre class="brush: java; title: ; notranslate">final String portletId = &quot;1_WAR_webformportlet_INSTANCE_abcd&quot;;
final ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
// get the preferences
final PortletPreferences prefs = PortletPreferencesUtilityLocalServiceUtil.getWrappedPortletPreferences(themeDisplay, portletId);
// set a preference
prefs.setValue(&quot;successURL&quot;, &quot;some url&quot;);
// dont forget to store the preferences
formPrefs.store();
// get the HTML from the portlet
final String portletHtml = RuntimePortletEmbedUtil.renderPortlet(request, response, portletId, &quot;&quot;);</pre>

	Tags: <a href="http://www.devatwork.nl/tag/liferay/" title="Liferay" rel="tag">Liferay</a>, <a href="http://www.devatwork.nl/tag/liones/" title="Liones" rel="tag">Liones</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2011/07/liferay-embedding-portlets-in-your-portlet/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Software Complexity &#8211; Decomposing an Application</title>
		<link>http://www.devatwork.nl/2011/01/software-complexity-decomposing-an-application/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=software-complexity-decomposing-an-application</link>
		<comments>http://www.devatwork.nl/2011/01/software-complexity-decomposing-an-application/#comments</comments>
		<pubDate>Fri, 14 Jan 2011 08:56:43 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=865</guid>
		<description><![CDATA[Inspired by a talk from Thomas Thwaites about the complexity of creating a simple toaster from scratch, I thought it would be a nice idea to decompose an application I recently build to give you an indication of the complexity. But first let&#8217;s watch Thomas&#8217;s talk: I will use the Kluwer Support portal I recently [...]]]></description>
			<content:encoded><![CDATA[<p>Inspired by a talk from <a title="Thomas Thwaites" href="http://www.ted.com/speakers/thomas_thwaites.html">Thomas Thwaites</a> about the complexity of creating a simple toaster from scratch, I thought it would be a nice idea to decompose an application I recently build to give you an indication of the complexity.</p>
<p>But first let&#8217;s watch Thomas&#8217;s talk:<br />
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="446" height="326" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="wmode" value="transparent" /><param name="bgColor" value="#ffffff" /><param name="flashvars" value="vu=http://video.ted.com/talks/dynamic/ThomasThwaites_2010S-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/ThomasThwaites-2010S.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=1051&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=thomas_thwaites_how_i_built_a_toaster_from_scratch;year=2010;theme=tales_of_invention;theme=new_on_ted_com;theme=the_creative_spark;event=TEDSalon+London+2010;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" /><param name="src" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" /><param name="bgcolor" value="#ffffff" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="446" height="326" src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" flashvars="vu=http://video.ted.com/talks/dynamic/ThomasThwaites_2010S-medium.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/ThomasThwaites-2010S.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=1051&amp;introDuration=15330&amp;adDuration=4000&amp;postAdDuration=830&amp;adKeys=talk=thomas_thwaites_how_i_built_a_toaster_from_scratch;year=2010;theme=tales_of_invention;theme=new_on_ted_com;theme=the_creative_spark;event=TEDSalon+London+2010;&amp;preAdTag=tconf.ted/embed;tile=1;sz=512x288;" bgcolor="#ffffff" wmode="transparent" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>I will use the <a title="Building Kluwer Support Portal – a Developers Perspective" href="http://www.devatwork.nl/2010/12/building-kluwer-support-portal-a-developers-perspective/">Kluwer Support portal I recently built</a> as an example. I created a new <a title="Portlet- Wikipedia" href="http://en.wikipedia.org/wiki/Portlet" target="_blank">portlet </a>which was deployed into <a title="Liferay - Wikipedia" href="http://en.wikipedia.org/wiki/Liferay" target="_blank">Liferay</a>, an enterprise portal, which runs on top of the <a title="JBoss AS - Wikipedia" href="http://en.wikipedia.org/wiki/JBoss_Application_Server" target="_blank">JBoss Application Server</a> which is programmed in <a title="Java Programming Language - Wikipedia" href="http://en.wikipedia.org/wiki/Java_(programming_language)" target="_blank">Java </a>running on the <a title="Java Virtual Machine - Wikipedia" href="http://en.wikipedia.org/wiki/Java_Virtual_Machine" target="_blank">Java Virtual Machine</a> running on top of the <a title="CentOS - Wikipedia" href="http://en.wikipedia.org/wiki/CentOS" target="_blank">CentOS </a>operating system running on top of an <a title="Hardware Abstraction Layer - Wikipedia" href="http://en.wikipedia.org/wiki/Hardware_Abstraction_Layer" target="_blank">Hardware Abstraction Layer</a> running on top of <a title="Computer hardware - Wikipedia" href="http://en.wikipedia.org/wiki/Computer_hardware" target="_blank">hardware</a>. Liferay uses <a title="Spring framework - Wikipedia" href="http://en.wikipedia.org/wiki/Spring_Framework" target="_blank">Spring</a> to inject services  in my portlet which retrieve data through <a title="Hibernate ORM - Wikipedia" href="http://en.wikipedia.org/wiki/Hibernate_(Java)" target="_blank">Hibernate</a> from <a title="MySQL - Wikipedia" href="http://en.wikipedia.org/wiki/MySQL" target="_blank">MySQL</a>.</p>
<p>In order to implement the customer requirements the portlet had to use Spring to separate presentation from business logic which connect to a <a title="Simple Object Access Protocol - Wikipedia" href="http://en.wikipedia.org/wiki/SOAP" target="_blank">SOAP web service</a> through <a title="Hypertext Transfer Protocol - Wikipedia" href="http://en.wikipedia.org/wiki/Http" target="_blank">HTTP</a> using <a title="Apache Axis - Wikipedia" href="http://en.wikipedia.org/wiki/Apache_Axis" target="_blank">Axis</a> in order to retrieve data which was index by <a title="Apache Solr - Wikipedia" href="http://en.wikipedia.org/wiki/Solr" target="_blank">Solr</a>, a <a title="Apache Lucene - Wikipedia" href="http://en.wikipedia.org/wiki/Lucene" target="_blank">Lucene</a> based search server in order to be able to render a search form using <a title="JavaServer Pages" href="http://en.wikipedia.org/wiki/Javaserver_pages" target="_blank">JavaServer Pages</a> and <a title="Apache Velocity - Wikipedia" href="http://en.wikipedia.org/wiki/Apache_Velocity" target="_blank">Velocity</a> as <a title="HyperText Markup Language - Wikipedia" href="http://en.wikipedia.org/wiki/Html" target="_blank">HTML</a> which is styled using <a title="Cascading Style Sheets - Wikipedia" href="http://en.wikipedia.org/wiki/Css" target="_blank">CSS</a> and made interactively using <a title="JavaScript - Wikipedia" href="http://en.wikipedia.org/wiki/JavaScript" target="_blank">JavaScript</a>.</p>
<p>If this technological enumeration (a total of 21) makes your head spin you got another thing coming because I only scratched the surface. I estimate it took an army of a million computer scientists over a billion man-hours to make this application work. A small miracle in my opinion!</p>
No tag for this post.]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2011/01/software-complexity-decomposing-an-application/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Solving the Portlet Design Problem</title>
		<link>http://www.devatwork.nl/2010/12/solving-the-portlet-design-problem/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=solving-the-portlet-design-problem</link>
		<comments>http://www.devatwork.nl/2010/12/solving-the-portlet-design-problem/#comments</comments>
		<pubDate>Wed, 22 Dec 2010 07:34:08 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Liones]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=828</guid>
		<description><![CDATA[In my previous post I told you about the problem we encountered while implementing the Kluwer Support portal in Liferay. In this post I will explain the solution we came up with. But first lets have a quick look at the problem again: We needed to support different styles per portlet and ‘read more’ links [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a title="Building Kluwer Support Portal – a Developers Perspective" href="http://www.devatwork.nl/2010/12/building-kluwer-support-portal-a-developers-perspective/">previous post</a> I told you about the problem we encountered while implementing the <a title="Kluwer Support" href="http://support.kluwer.nl/" target="_blank">Kluwer Support</a> portal in <a title="Enterprise open source portal and collaboration software - Liferay.com" href="http://www.liferay.com/" target="_blank">Liferay</a>. In this post I will explain the solution we came up with.</p>
<p>But first lets have a quick look at the problem again: We needed to support different styles per portlet and ‘read more’ links which needed to work for both custom and out-of-the-box potlets. Let have a look at some of the different ‘web-content display portlet’ styles used in the portal:</p>
<table>
<tbody>
<tr>
<td><img class="size-full wp-image-836" style="width: 172px; height: 120px;" title="web content display portlet 1" src="http://www.devatwork.nl/wp-content/uploads/2010/12/web-content-display-portlet-1.png" alt="" width="206" height="142" /></td>
<td><img class="size-full wp-image-837" style="width: 172px; height: 120px;" title="web content display portlet 2" src="http://www.devatwork.nl/wp-content/uploads/2010/12/web-content-display-portlet-2.png" alt="" width="244" height="144" /></td>
<td><img class="size-full wp-image-838" style="width: 172px; height: 120px;" title="web content display portlet 3" src="http://www.devatwork.nl/wp-content/uploads/2010/12/web-content-display-portlet-3.png" alt="" width="211" height="246" /></td>
</tr>
</tbody>
</table>
<p>Liferay, at least not version 5.2.8 EE, does not support these requirements out of the box (Not entirely true: Liferay does allow you to specify custom CSS rules per portlet instance, but you would need a front-end specialist to maintain the website which IMHO is not acceptable).</p>
<p>To make it even more difficult we were not allowed to use Liferay Ext or place many hooks or have impact on existing communities in the portal instance.</p>
<p><span id="more-828"></span></p>
<p>The solution that we came up with was to use an JSP hook to replace Liferays ‘look and feel’ page. We wrote some code which would add a new tab displaying theme specific properties to the page if the theme had a specific setting specifying the path to a velocity template which in turn would render the theme specific settings.</p>
<p>Some of the settings we included are:</p>
<ul>
<li>Custom CSS classes</li>
<li>Display mode</li>
<li>Read more link URL &amp; label</li>
</ul>
<p>However, we can easily add more, or less, properties depending on the requirements without having to touch the implementation code or break the theme for Kluwer Support.</p>
<p>Next we implemented a servlet which handles the storage of our custom properties. The servlet simple updates the portlet preferences with the custom properties. The properties are read by the theme and used to determine how to render the portlet.</p>
<p>We all implemented this in a separate deployment package except for the mentioned velocity template which resided in the theme package. By doing this, we solved the problem not only for this project but for upcoming projects as well: We will just implement a theme and the velocity template containing the custom properties for that particular project! I am willing to share some code, let met know if you want it.</p>
<p>I am very curious about the way you would have solved this problem and what you think of this solution so please write a comment.</p>

	Tags: <a href="http://www.devatwork.nl/tag/liferay/" title="Liferay" rel="tag">Liferay</a>, <a href="http://www.devatwork.nl/tag/liones/" title="Liones" rel="tag">Liones</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2010/12/solving-the-portlet-design-problem/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Building Kluwer Support Portal &#8211; a Developers Perspective</title>
		<link>http://www.devatwork.nl/2010/12/building-kluwer-support-portal-a-developers-perspective/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=building-kluwer-support-portal-a-developers-perspective</link>
		<comments>http://www.devatwork.nl/2010/12/building-kluwer-support-portal-a-developers-perspective/#comments</comments>
		<pubDate>Fri, 17 Dec 2010 13:14:09 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[<Liferay]]></category>
		<category><![CDATA[Liones]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=824</guid>
		<description><![CDATA[In the past two months we (Liones) build a new Liferay based portal for Kluwer (a major Dutch publisher), one of our clients. The purpose of this portal is to help the customers of Kluwer online products to understand and use their products better. This week the Kluwer Support portal was launched with success and [...]]]></description>
			<content:encoded><![CDATA[<p>In the past two months we (<a title="Liones, Internetbureau voor uitgevers" href="http://www.liones.nl/" target="_blank">Liones</a>) build a new <a title="Enterprise open source portal and collaboration software - Liferay.com" href="http://www.liferay.com/" target="_blank">Liferay</a> based portal for <a title="Kluwer - a Wolters Kluwer business" href="http://www.kluwer.nl" target="_blank">Kluwer</a> (a major Dutch publisher), one of our clients. The purpose of this portal is to help the customers of Kluwer online products to understand and use their products better. This week the <a title="Kluwer Support" href="http://www.kluwer.nl/support/" target="_blank">Kluwer Support</a> portal was launched with success and I reckoned this was a good moment to share some insight in how we developed that particular portal and what problems we encountered during the development.</p>
<p>But let’s have a look at the result first:</p>
<p style="text-align: center;"><a href="http://www.devatwork.nl/wp-content/uploads/2010/12/kluwer-support.png" rel="lightbox[824]"><img class="size-medium wp-image-832 aligncenter" title="Kluwer Support screenshot" src="http://www.devatwork.nl/wp-content/uploads/2010/12/kluwer-support-278x300.png" alt="" width="278" height="300" /></a></p>
<p>I hope you agree with me when I say that it looks great, I know for a fact a lot of people do. You can find the actual portal at <a title="Kluwer Support" href="http://www.kluwer.nl/support" target="_blank">http://www.kluwer.nl/support</a>, although the portal is in Dutch, feel free to look around.</p>
<p>In the next few paragraphs I will share some challenges we faced and the lessons we learned while implementing the Kluwer Support portal.</p>
<p><span id="more-824"></span></p>
<h3>Design</h3>
<p>One of the challenges for us in this project was to transform the graphical design, created by Evident, into HTML and then into a Liferay theme. Our front-end specialist, <a title="Vincent Smedinga" href="http://nl.linkedin.com/in/vincentsmedinga" target="_blank">Vincent Smedinga</a>, first transformed the PSD into HMTL using the latest versions of HTML 5, CSS 3 and other best front-end practices like Modernizr en Selectivzr. These technologies enabled him to create the HTML semantically correct, let it display correctly in older, less compliant browsers while staying true to the graphical design.</p>
<p>The now finished HTML needed to be transformed into Liferay components like themes, layouts and the actual portlets. That task proofed to be quiet challenging for <a title="Stef Busking" href="http://nl.linkedin.com/in/stefbusking" target="_blank">Stef Busking</a> (one of our Liferay software engineers) and me. The reason why this task was challenging is that fact that we needed to reuse as much standard Liferay components as possible. The two things that it so difficult and almost impossible were the different styles per portlet and the ‘read more’ links. Let have a look at some of the different ‘web-content display portlet’ styles used in the portal:</p>
<table>
<tbody>
<tr>
<td><img class="size-full wp-image-836" style="width: 172px; height: 120px;" title="web content display portlet 1" src="http://www.devatwork.nl/wp-content/uploads/2010/12/web-content-display-portlet-1.png" alt="" width="206" height="142" /></td>
<td><img class="size-full wp-image-837" style="width: 172px; height: 120px;" title="web content display portlet 2" src="http://www.devatwork.nl/wp-content/uploads/2010/12/web-content-display-portlet-2.png" alt="" width="244" height="144" /></td>
<td><img class="size-full wp-image-838" style="width: 172px; height: 120px;" title="web content display portlet 3" src="http://www.devatwork.nl/wp-content/uploads/2010/12/web-content-display-portlet-3.png" alt="" width="211" height="246" /></td>
</tr>
</tbody>
</table>
<p>Liferay, at least not version 5.2.8 EE, does not support these requirements out of the box (Not entirely true: Liferay does allow you to specify custom CSS rules per portlet instance, but you would need a front-end specialist to maintain the website which IMHO is not acceptable).</p>
<p>To make it even more difficult we were not allowed to use Liferay Ext or place many hooks or have impact on existing communities in the portal instance,  which, in my opinion, is a good thing. However, that forced us to think hard and we (although I should have said Stef here because he is the one who came up with the idea) found a clever solution to solve both problems with the use of one JSP hook.</p>
<p>I want you think about how you would have solved this problem in these fairly strict conditions. You can find <a title="Solving the Portlet Design Problem" href="http://www.devatwork.nl/2010/12/solving-the-portlet-design-problem/">the solution here</a>.</p>
<h3>Search</h3>
<p>Another problem we faced were the search requirements like ‘auto complete’ and sorting web content (FAQ entries and videos) according to their structure. We decided that the default Liferay search option would not be sufficient because we would not be able to implement the ‘auto complete’.</p>
<p>After researching several alternatives we choose to use one of the most powerful open-source enterprise search engines available: <a title="Apache Solr" href="http://lucene.apache.org/solr/" target="_blank">Apache Solr</a>. We implemented a client for it which uses the Liferay service bus to swap out the default Liferay search engine.</p>
<p>Now we had the proper infrastructure at our disposal it was a ‘trivial’ task to implement two custom portlets (search box in navigation bar and a result portlet). I quoted ‘trivial’ because it was not quiet trivial. We encountered a very annoying issue in the default web-content indexer Liferay provides:  it does not specify the structure ID nor the template ID in the document to be indexed.</p>
<p>I won’t go into specific how we solved this problem. It is sufficient to say that we are working on a robust solution which will ‘unpack’ the document  we receive from the indexer and enrich it with those fields before sending it to Solr for indexing.</p>
<h3>Wrap up</h3>
<p>Like always there is always more to share but that is really it for this post. Don’t forget to think about the ‘portlet design problem’ and stay tuned for our solution! As always: comments are most welcome.</p>

	Tags: <a href="http://www.devatwork.nl/tag/liferay-34/" title="&lt;Liferay" rel="tag">&lt;Liferay</a>, <a href="http://www.devatwork.nl/tag/liones/" title="Liones" rel="tag">Liones</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2010/12/building-kluwer-support-portal-a-developers-perspective/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Securing your Liferay Service using PermissionChecker</title>
		<link>http://www.devatwork.nl/2010/05/securing-your-liferay-service-using-permissionchecker/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=securing-your-liferay-service-using-permissionchecker</link>
		<comments>http://www.devatwork.nl/2010/05/securing-your-liferay-service-using-permissionchecker/#comments</comments>
		<pubDate>Mon, 03 May 2010 06:42:08 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=798</guid>
		<description><![CDATA[Welcome to 3rd article in this series of articles showing you how you can develop custom Liferay services. In the previous article I showed you how you can implement a custom Liferay service and expose it as a web service. In this article I will show you how you can secure your service using Liferay&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-656" title="Liferay" src="http://www.devatwork.nl/wp-content/uploads/2010/01/liferay-logo-block.jpg" alt="" width="99" height="96" />Welcome to 3rd article in this series of articles showing you how you can develop custom Liferay services. In the previous article I showed you how you can <a title="Implementing a reusable Liferay Service Without Ext or Service Builder" href="http://www.devatwork.nl/2010/04/implementing-a-reusable-liferay-service-without-ext-or-service-builder/">implement a custom Liferay service</a> and <a title="Expose a Liferay Service as a Web Service" href="http://www.devatwork.nl/2010/04/expose-a-liferay-service-as-a-web-service/">expose it as a web service</a>. In this article I will show you how you can secure your service using Liferay&#8217;s build-in permission model.</p>
<p>The permission system in Liferay is pretty powerful: you configure permissions on roles or teams. Next you apply roles to either groups (communities, organizations) or individual users. In this article we will define a new permission: the permission to access our &#8220;very exiting business logic&#8221; sayHello. After all, we have invested countless hours in developing it; we don&#8217;t want everybody to use it without us knowing <img src='http://www.devatwork.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<p>I hope this article is useful to you. Please let me know if you have any questions or comments; just drop me a message and I will get back to you as soon as I can.<br />
<span id="more-798"></span></p>
<h3>0. Project Setup</h3>
<p>I have made some modifications to the code since my last article, so please <a href="http://www.devatwork.nl/wp-content/uploads/2010/04/hello-world-remote-security-start.zip">download and unzip</a> the starting point of our application. Please familiarize yourself with the project structure. I have refactored the view of the SayHelloPortlet to render using a JSP called sayHello.jsp, this will help us further along in this article.</p>
<p>Please note that I have modified the service contract specified in HelloWorldService.java. I have added the groupId parameter which we will use later in this article. Here is the new service contract:</p>
<pre class="brush: java; light: true; title: ; notranslate">String sayHello(long groupId, String name);</pre>
<p>I have updated all the service implementation files as well to reflect changes in the contract.</p>
<h3>1. Implement the permission check on the service</h3>
<p>The first step is to implement the actual check on permission in our service implementation. Replace the sayHello method in HelloWorldServiceImpl.java with the following code (note the marked lines are new lines):</p>
<pre class="brush: java; highlight: [2,3,4,5,6,7]; title: ; wrap-lines: false; notranslate">public String sayHello(long groupId, String name) {
    try {
        if (!getPermissionChecker().hasPermission(groupId, &quot;nl.devatwork.hello.world.service&quot;, groupId, &quot;SAY_HELLO&quot;))
            return &quot;Hah, I don't think you can use my service. You don't have permission&quot;;
    } catch (PrincipalException ex) {
        return &quot;security blew up&quot;;
    }

    return &quot;Hello, &quot; + name;
}</pre>
<p>Lets dissect this code: The first thing we do is to get the instance of the <strong><em>PermissionChecker </em></strong>from our base class <strong><em>PrincipalBean</em></strong>. The <strong><em>PermissionChecker </em></strong>will do the heavy lifting for us, that is convenient isn&#8217;t it?</p>
<p>The second step is the call to the method hasPermission. This method performs the actual check for us. The method has the following signature:</p>
<pre class="brush: java; light: true; title: ; notranslate">public boolean hasPermission(long groupId, String name, long primKey, String actionId);</pre>
<p>The first argument, groupId, determines the scope of the check. Remember I told you that you can apply roles to communities and organizations? Those things are groups with and ID. In the next step I will show you how we will get the value for groupId.</p>
<p>The second argument, name, is the name of our permission. The convention is we pass a String representation of our package in which the service lives.</p>
<p>The third argument, primKey, is the primary key of the resource we are protecting. Our service is a so-called top level resource which do not have a primary key that is why we will use the value of groupId. If we would have a model stored in the database we would specify the ID of the model here.</p>
<p>The final argument, actionId, is the identifier of the action. We will use a capitalized version of the method name here.</p>
<p>I think that is enough info about these few lines of code.</p>
<h3>2. Getting the scope</h3>
<p>Now that our service checks for permission we need to modify our portlet to provide the correct groupId in order for Liferay to scope the authorization properly. Please add the highlighted lines to SayHelloPortlet.java:</p>
<pre class="brush: java; highlight: [2,3]; title: ; wrap-lines: false; notranslate">public void doView(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException {
    ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
    long groupId = themeDisplay.getScopeGroupId();

    String msg = HelloWorldServiceUtil.sayHello(groupId, &quot;Liferay Dev&quot;);
    request.setAttribute(&quot;msg&quot;, msg);
    request.setAttribute(&quot;groupId&quot;, groupId);

    getPortletContext().getRequestDispatcher(&quot;/WEB-INF/jsp/sayHello.jsp&quot;).include(request, response);
}</pre>
<p>As you can see Liferay provides a nice utility called ThemeDisplay from which we can get the scope groupId.</p>
<h3>3. Telling Liferay about our new permission</h3>
<p>So far we have implemented the necessary code to check for permission. Now we have to inform Liferay that there is a new permission, otherwise you won&#8217;t be able to configure it and that would be a waste of effort, wouldn&#8217;t it? Create a new file called portlet.properties in the resource folder of the portlet application and paste the following content into it:</p>
<pre class="brush: plain; light: true; title: ; notranslate">resource.actions.configs=resource-actions/default.xml</pre>
<p>This properties file tells Liferay to look for resource actions (permissions) in default.xml in the folder resource-actions. Lets create that file now and paste the following content into it:</p>
<pre class="brush: xml; highlight: [4,6,10]; title: ; wrap-lines: false; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;resource-action-mapping&gt;
    &lt;model-resource&gt;
        &lt;model-name&gt;nl.devatwork.hello.world.service&lt;/model-name&gt;
        &lt;portlet-ref&gt;
            &lt;portlet-name&gt;SayHelloPortlet&lt;/portlet-name&gt;
        &lt;/portlet-ref&gt;

        &lt;supports&gt;
            &lt;action-key&gt;SAY_HELLO&lt;/action-key&gt;
        &lt;/supports&gt;

        &lt;community-defaults/&gt;
        &lt;guest-defaults/&gt;
        &lt;guest-unsupported/&gt;

    &lt;/model-resource&gt;
&lt;/resource-action-mapping&gt;</pre>
<p>I have highlighted the important lines. Please take a look at the first highlighted line. Does it look familiar to you? Yes, it is the same as the value of the name argument of the <strong><em>hasPermission </em></strong>method.</p>
<p>The second highlighted line tells Liferay that the SayHelloPortlet can configure this permission, I will show you how in the next step.</p>
<p>The final highlighted line should also look familiar to you. It is the same as the value of the actionId argument of the <strong><em>hasPermission </em></strong>method.</p>
<h3>4. Create configure permissions link</h3>
<p>This is the final step, we implemented the check, we told Liferay about our new permission. Now we need a place to configure it. Modify sayHello.jsp:</p>
<pre class="brush: java; highlight: [3,4,5,6,7,11,12,13]; title: ; wrap-lines: false; notranslate">&lt;%@ page contentType=&quot;text/html&quot; isELIgnored=&quot;false&quot; %&gt;
&lt;%@ include file=&quot;/WEB-INF/jsp/include.jsp&quot; %&gt;
&lt;liferay-security:permissionsURL
        modelResource=&quot;nl.devatwork.hello.world.service&quot;
        modelResourceDescription=&quot;Hello Service Permissions&quot;
        resourcePrimKey=&quot;${groupId}&quot;
        var=&quot;permissionURL&quot;/&gt;

&lt;p&gt;the msg was: ${msg}&lt;/p&gt;

&lt;div&gt;
    &lt;p&gt;lets &lt;a href=&quot;${permissionURL}&quot;&gt;configure&lt;/a&gt; the permission for our service&lt;/p&gt;
&lt;/div&gt;</pre>
<p>We have added a link to configure permission to our service. Notice that modelResource is again the same as the value of the name argument of the <strong><em>hasPermission </em></strong>method.</p>
<p>Now that we have implemented all the necessary changes we can compile and deploy the new JAR&#8217;s and WAR&#8217;s and start our application. Go ahead and add permissions, remove them, login and logout under different accounts. Our permission is working like a charm. If you haven&#8217;t followed all the steps above you can <a href="http://www.devatwork.nl/wp-content/uploads/2010/04/hello-world-remote-security-result.zip">download the finished project</a>.</p>
<p>That is it for now,I hope you have learned something. Let me know if you have any questions or comments. Bye.</p>

	Tags: <a href="http://www.devatwork.nl/tag/java/" title="Java" rel="tag">Java</a>, <a href="http://www.devatwork.nl/tag/liferay/" title="Liferay" rel="tag">Liferay</a>, <a href="http://www.devatwork.nl/tag/security/" title="Security" rel="tag">Security</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2010/05/securing-your-liferay-service-using-permissionchecker/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Expose a Liferay Service as a Web Service</title>
		<link>http://www.devatwork.nl/2010/04/expose-a-liferay-service-as-a-web-service/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=expose-a-liferay-service-as-a-web-service</link>
		<comments>http://www.devatwork.nl/2010/04/expose-a-liferay-service-as-a-web-service/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 06:39:50 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Web Services]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=729</guid>
		<description><![CDATA[In my previous article I showed you how you can implement a reusable Liferay Service without using Ext or  the Service Builder utility. In this article we will take it one step further and expose the service we have created as web service again without using Ext or the Service Builder. Liferay exposes the services [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-656" title="Liferay" src="http://www.devatwork.nl/wp-content/uploads/2010/01/liferay-logo-block.jpg" alt="" width="99" height="96" />In my previous article I showed you how you can implement a reusable Liferay Service without using Ext or  the Service Builder utility. In this article we will take it one step further and expose the service we have created as web service again without using Ext or the Service Builder.</p>
<p>Liferay exposes the services based on Axis using a separate web application called tunnel-web. We will hook into tunnel-web so our service will be exposed in exactly the same way Liferay services are externalized. Let&#8217;s get started.<br />
<span id="more-729"></span></p>
<h3>0. Project Setup</h3>
<p>We will pick up from where we ended in the previous article. I have you haven&#8217;t followed the previous article you can <a href="http://www.devatwork.nl/wp-content/uploads/2010/04/hello-world-result.zip">download the initial project setup here</a>. Please take a minute to familiarize yourself with the project structure.</p>
<p>We need to add a new dependencies to the pom of the service contract library:</p>
<pre class="brush: xml; title: ; wrap-lines: false; notranslate">&lt;dependency&gt;
    &lt;groupId&gt;com.liferay.portal&lt;/groupId&gt;
    &lt;artifactId&gt;portal-service&lt;/artifactId&gt;
    &lt;version&gt;${liferay.version}&lt;/version&gt;
    &lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;com.liferay.portal&lt;/groupId&gt;
    &lt;artifactId&gt;portal-kernel&lt;/artifactId&gt;
    &lt;version&gt;${liferay.version}&lt;/version&gt;
    &lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;com.liferay.portal&lt;/groupId&gt;
    &lt;artifactId&gt;portal-impl&lt;/artifactId&gt;
    &lt;version&gt;${liferay.version}&lt;/version&gt;
    &lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;</pre>
<h3>1. Prepare the portal</h3>
<p>Make sure tunnel-web is installed in your application server. See the Liferay administration guide for details. The access to the web-service is restricted based on IP address. Open your portal-ext.properties and add the following lines to allow specified IP addresses to access to the web-services.</p>
<pre class="brush: plain; title: ; notranslate">axis.servlet.hosts.allowed=127.0.0.1,SERVER_IP
axis.servlet.https.required=false</pre>
<h3>2. Add the Service Classes</h3>
<p>Ok lets get down to business. The first step is to create the web service class in the service contract library. Create a new class called HelloWorldServiceSoap in the package nl.devatwork.hello.world.service.http and copy the following code into it:</p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">package nl.devatwork.hello.world.service.http;

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import nl.devatwork.hello.world.service.HelloWorldServiceUtil;

import java.rmi.RemoteException;

public class HelloWorldServiceSoap {
    private static Log _log = LogFactoryUtil.getLog(HelloWorldServiceSoap.class);

    public static String sayHello(String name)
            throws RemoteException {
        String result;
        try {
            result = HelloWorldServiceUtil.sayHello(name);
        } catch (Exception e) {
            _log.error(e, e);

            throw new RemoteException(e.getMessage());
        }

        return result;
    }
}</pre>
<p>This class wraps SOAP calls and maps them to the appropriate service call.</p>
<p>You can now build the service contract library by executing the following command in the /hello-world-service/ folder:</p>
<pre class="brush: bash; light: true; title: ; notranslate">mvn clean package</pre>
<p>Copy the resulting JAR file (/hello-world-service/target/hello-world-service-1.0.0-SNAPSHOT.jar) to the /lib/ext folder of your application server.</p>
<h3>3. Apply Glue</h3>
<p>The final step is a bit of handwork. We need to manually register the new service to the tunnel-web application. Open the server-config.wsdd located in the deploy directory/tunnel-web/WEB-INF folder of your application server. Add the following code just above the end of the XML:</p>
<pre class="brush: xml; title: ; wrap-lines: false; notranslate">&lt;service name=&quot;Portlet_DevAtWork_HelloWorldService&quot; provider=&quot;java:RPC&quot; style=&quot;rpc&quot; use=&quot;encoded&quot;&gt;
	&lt;parameter name=&quot;wsdlTargetNamespace&quot; value=&quot;urn:http.service.world.hello.devatwork.nl&quot;/&gt;
	&lt;parameter name=&quot;wsdlServiceElement&quot; value=&quot;HelloWorldServiceSoapService&quot;/&gt;
	&lt;parameter name=&quot;wsdlServicePort&quot; value=&quot;Portlet_DevAtWork_HelloWorldService&quot;/&gt;
	&lt;parameter name=&quot;className&quot; value=&quot;nl.devatwork.hello.world.service.http.HelloWorldServiceSoap&quot;/&gt;
	&lt;parameter name=&quot;wsdlPortType&quot; value=&quot;HelloWorldServiceSoap&quot;/&gt;
	&lt;parameter name=&quot;typeMappingVersion&quot; value=&quot;1.2&quot;/&gt;
	&lt;operation xmlns:operNS=&quot;urn:http.service.world.hello.devatwork.nl&quot; name=&quot;sayHello&quot; qname=&quot;operNS:sayHello&quot; soapAction=&quot;&quot;&gt;
		&lt;parameter xmlns:tns=&quot;http://www.w3.org/2001/XMLSchema&quot; qname=&quot;name&quot; type=&quot;tns:string&quot;&gt;&lt;/parameter&gt;
	&lt;/operation&gt;
	&lt;parameter name=&quot;allowedMethods&quot; value=&quot;sayHello&quot;/&gt;
&lt;/service&gt;</pre>
<p>This will register our service within tunnel-web.</p>
<p>Start your application server and navigate to <a href="http://127.0.0.1:8080/tunnel-web/axis">http://127.0.0.1:8080/tunnel-web/axis</a>. Here you will find a list of all the services currently exposed by Liferay. In the list you will find our service (Portlet_DevAtWork_HelloWorldService). You can view the WSDL by clicking on the link behind the service.</p>
<p>That wasn&#8217;t to bad now was it? If you are to lazy to copy the code you can <a href="http://www.devatwork.nl/wp-content/uploads/2010/04/hello-world-remote-result.zip">download the complete project here</a>.</p>
<p>I hope you learned how you can expose services as web services in Liferay. In the upcoming article I will show you how you can add security to the web service.</p>
<p>That is it for now. Let me know if you have any comments or questions.</p>

	Tags: <a href="http://www.devatwork.nl/tag/java/" title="Java" rel="tag">Java</a>, <a href="http://www.devatwork.nl/tag/liferay/" title="Liferay" rel="tag">Liferay</a>, <a href="http://www.devatwork.nl/tag/spring/" title="Spring" rel="tag">Spring</a>, <a href="http://www.devatwork.nl/tag/web-services/" title="Web Services" rel="tag">Web Services</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2010/04/expose-a-liferay-service-as-a-web-service/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Implementing a reusable Liferay Service Without Ext or Service Builder</title>
		<link>http://www.devatwork.nl/2010/04/implementing-a-reusable-liferay-service-without-ext-or-service-builder/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=implementing-a-reusable-liferay-service-without-ext-or-service-builder</link>
		<comments>http://www.devatwork.nl/2010/04/implementing-a-reusable-liferay-service-without-ext-or-service-builder/#comments</comments>
		<pubDate>Mon, 19 Apr 2010 10:38:01 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Spring]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=728</guid>
		<description><![CDATA[In Liferay you can split your application logic vertically exposing each component as a separate independent service. This service can be consumed by your portlet applications and any other applications. Liferay itself exposes several services to you: GroupService (for managing communities) and UserService (for managing users) for example. In this article I will show you how you [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-656" title="Liferay" src="http://www.devatwork.nl/wp-content/uploads/2010/01/liferay-logo-block.jpg" alt="" width="99" height="96" />In Liferay you can split your application logic vertically exposing each component as a separate independent service. This service can be consumed by your portlet applications and any other applications. Liferay itself exposes several services to you: GroupService (for managing communities) and UserService (for managing users) for example. In this article I will show you how you can create a reusable service yourself and host it in Liferay.</p>
<p>In this article we will build a simple hello world service, nothing to fancy (I want to leave something for you to do yourself <img src='http://www.devatwork.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ). We will code the service from scratch without using tools like service builder.</p>
<p>The project will contain 3 modules:</p>
<ol>
<li>A library containing the service contract</li>
<li>A web application implementing the service contract</li>
<li>A web application consuming the service</li>
</ol>
<p>I hope you like this article, please let me know if you have any questions or comments. Lets get started. I assume you have read my <a title="Setting up Maven for Liferay Development" href="http://www.devatwork.nl/2010/04/setting-up-maven-for-liferay-development/">previous article about using Maven to build Liferay applications</a>. If not please read it first.<br />
<span id="more-728"></span></p>
<h3>0. Project Setup</h3>
<p>Please <a href="http://www.devatwork.nl/wp-content/uploads/2010/04/hello-world-start.zip">download and unzip</a> the empty project and load it into an IDE of choice or use the command shell if you want. The project contains empty files. Please familiarizes yourself with the project structure and notice the dependencies in the different pom.xml files. Nothing special going on though.</p>
<h3>1. Service Contract</h3>
<p>This library contains the code contract of our HelloWorld service and a utility class which will provide easy access for non Spring portlets. Lets first set up our service contract, copy he following code into HelloWorldService.java:</p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">package nl.devatwork.hello.world.service;

public interface HelloWorldService {
    String sayHello(String name);
}</pre>
<p>That wasn&#8217;t so bad now was it? I think you have written more complex service contracts <img src='http://www.devatwork.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<p>Lets implement the access utility class. Copy the following code into HelloWorldServiceUtil.java:</p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">package nl.devatwork.hello.world.service;

public class HelloWorldServiceUtil {
    private static HelloWorldService _service;

    public static HelloWorldService getService() {
        if (_service == null) {
            throw new RuntimeException(&quot;HelloWorldService is not set&quot;);
        }

        return _service;
    }

    public void setService(HelloWorldService service) {
        _service = service;
    }

    public static String sayHello(String name) {
        return getService().sayHello(name);
    }
}</pre>
<p>Again a really simple class. It has a getter and a setter which will be used to inject our service instance into this utility class. The static sayHello method is a proxies the service method.</p>
<p>You can build the service contract library by executing the following command in the /hello-world-service/ folder:</p>
<pre class="brush: bash; light: true; title: ; notranslate">mvn clean package</pre>
<p>Copy the resulting JAR file (/hello-world-service/target/hello-world-service-1.0.0-SNAPSHOT.jar) to the /lib/ext folder of your application server. You have to do this in order to avoid class loader issues. We will use this library later.</p>
<h3>2. Service Implementation</h3>
<p>Now we will implement the service in a self contained web application.  This application can be deployed using the auto deploy mechanism of your application server.</p>
<p>Lets implement the base class for our service implementation which implements the required plumbing. Copy the following code into HelloWorldServiceBaseImpl.java:</p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">package nl.devatwork.hello.world.service.base;

import com.liferay.portal.SystemException;
import com.liferay.portal.kernel.annotation.BeanReference;
import com.liferay.portal.service.base.PrincipalBean;
import com.liferay.portal.util.PortalUtil;
import nl.devatwork.hello.world.service.HelloWorldService;

public abstract class HelloWorldServiceBaseImpl extends PrincipalBean implements HelloWorldService {
    @BeanReference(name = &quot;nl.devatwork.hello.world.service.HelloWorldService.impl&quot;)
    protected HelloWorldService helloWorldService;

    public HelloWorldService getHelloWorldService() {
        return helloWorldService;
    }

    public void setHelloWorldService(HelloWorldService helloWorldService) {
        this.helloWorldService = helloWorldService;
    }

    protected void runSQL(String sql) throws SystemException {
        try {
            PortalUtil.runSQL(sql);
        } catch (Exception e) {
            throw new SystemException(e);
        }
    }
}</pre>
<p>Now that we have the plumbing in place lets concentrate on our state of the art business logic. Copy the following code into HelloWorldServiceImpl.java:</p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">package nl.devatwork.hello.world.service.impl;

import nl.devatwork.hello.world.service.base.HelloWorldServiceBaseImpl;

public class HelloWorldServiceImpl extends HelloWorldServiceBaseImpl {
    public String sayHello(String name) {
        return &quot;Hello, &quot; + name;
    }
}</pre>
<p>Very exiting business logic isn&#8217;t it? <img src='http://www.devatwork.nl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<p>Ok, now that we have our code in place lets apply some glue to make it all work. Copy the following content to service.properties:</p>
<pre class="brush: plain; highlight: [29,30]; title: ; wrap-lines: false; notranslate">##
## Properties Override
##

    #
    # Specify where to get the overridden properties. Updates should not be made
    # on this file but on the overridden version of this file.
    #
    include-and-override=service-ext.properties

##
## Build
##

    build.namespace=DevAtWork
    build.number=1
    build.date=1269952033689
    build.auto.upgrade=true

##
## Spring
##

    #
    # Input a list of comma delimited Spring configurations. These will be
    # loaded after the bean definitions specified in the
	# portalContextConfigLocation parameter in web.xml.
    #
    spring.configs=\
        WEB-INF/classes/META-INF/portlet-spring.xml</pre>
<p>Notice the last two lines. This tells Liferay to load our Spring configuration.</p>
<p>Lets create our Spring configuration now. Copy the following code to portlet-spring.xml:</p>
<pre class="brush: xml; title: ; wrap-lines: false; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;

&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; default-init-method=&quot;afterPropertiesSet&quot; xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&quot;&gt;
    &lt;bean id=&quot;nl.devatwork.hello.world.service.HelloWorldService.impl&quot; class=&quot;nl.devatwork.hello.world.service.impl.HelloWorldServiceImpl&quot;/&gt;
    &lt;bean id=&quot;nl.devatwork.hello.world.service.HelloWorldServiceUtil&quot; class=&quot;nl.devatwork.hello.world.service.HelloWorldServiceUtil&quot;&gt;
        &lt;property name=&quot;service&quot; ref=&quot;nl.devatwork.hello.world.service.HelloWorldService.impl&quot;/&gt;
    &lt;/bean&gt;
&lt;/beans&gt;</pre>
<p>We register two beans into the Spring container. One for our service implementation instance and one for our service util.</p>
<p>Lets add the following code to web.xml:</p>
<pre class="brush: xml; highlight: [4,5,6]; title: ; wrap-lines: false; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&quot; version=&quot;2.4&quot;&gt;

    &lt;listener&gt;
        &lt;listener-class&gt;com.liferay.portal.kernel.spring.context.PortletContextLoaderListener&lt;/listener-class&gt;
    &lt;/listener&gt;

&lt;/web-app&gt;</pre>
<p>This will load the Spring configuration for us.</p>
<p>Add the following code to liferay-plugin-package.properties:</p>
<pre class="brush: plain; highlight: [10]; title: ; wrap-lines: false; notranslate">name=Hello World Service Implementation
module-group-id=nl.devatwork.service.impl
module-incremental-version=1
short-description=
change-log=
page-url=http://www.devatwork.nl
author=Dev @ Work
licenses=Free

portal-dependency-jars=hello-world-service-1.0.0-SNAPSHOT.jar</pre>
<p>Notice that we declare a dependency on the library we deployed earlier. Liferay will load the library on our class path.</p>
<p>We are ready with the service implementation now. You can build the service implementation by executing the following command in the /hello-world-service-impl/ folder:</p>
<pre class="brush: bash; light: true; title: ; notranslate">mvn clean package</pre>
<p>Copy the resulting WAR file (/hello-world-service-impl/target/hello-world-service-impl-1.0.0-SNAPSHOT.war to the auto deploy folder of your application server. The service implementation will be installed now.</p>
<h3>3. Consumer Implementation</h3>
<p>Now that we have the service contract and implementation in place lets create a portlet which consumes the service.</p>
<p>Copy the following code into SayHelloPortlet.java:</p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">package nl.devatwork.hello.world.portlets;

import nl.devatwork.hello.world.service.HelloWorldServiceUtil;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class SayHelloPortlet extends GenericPortlet {
    public void doView(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException {
        String msg = HelloWorldServiceUtil.sayHello(&quot;Liferay Dev&quot;);
        response.setContentType(&quot;text/html&quot;);
        response.getWriter().print(msg);
    }
}</pre>
<p>Copy the following code to portlet.xml:</p>
<pre class="brush: xml; title: ; wrap-lines: false; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;portlet-app xmlns=&quot;http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; version=&quot;2.0&quot;
             xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd&quot;&gt;

    &lt;portlet&gt;
        &lt;portlet-name&gt;SayHelloPortlet&lt;/portlet-name&gt;
        &lt;display-name&gt;Say Hello Portlet&lt;/display-name&gt;
        &lt;portlet-class&gt;nl.devatwork.hello.world.portlets.SayHelloPortlet&lt;/portlet-class&gt;
        &lt;expiration-cache&gt;0&lt;/expiration-cache&gt;
        &lt;supports&gt;
            &lt;mime-type&gt;text/html&lt;/mime-type&gt;
            &lt;portlet-mode&gt;view&lt;/portlet-mode&gt;
        &lt;/supports&gt;
        &lt;portlet-info&gt;
            &lt;title&gt;Say Hello Portlet&lt;/title&gt;
            &lt;short-title&gt;Say Hello Portlet&lt;/short-title&gt;
            &lt;keywords&gt;DevAtWork&lt;/keywords&gt;
        &lt;/portlet-info&gt;
    &lt;/portlet&gt;

&lt;/portlet-app&gt;</pre>
<p>Copy the following code to liferay-plugin-package.properties:</p>
<pre class="brush: plain; highlight: [10]; title: ; wrap-lines: false; notranslate">name=Hello World Portlets
module-group-id=nl.devatwork.portlets
module-incremental-version=1
short-description=
change-log=
page-url=http://www.devatwork.nl
author=Dev @ Work
licenses=Free

portal-dependency-jars=hello-world-service-1.0.0-SNAPSHOT.jar</pre>
<p>Copy the following code to web.xml:</p>
<pre class="brush: xml; title: ; wrap-lines: false; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&quot; version=&quot;2.4&quot;&gt;
&lt;/web-app&gt;</pre>
<p>We are ready with the consumer implementation now. You can build the portlet by executing the following command in the /hello-world-portlets/ folder:</p>
<pre class="brush: bash; light: true; title: ; notranslate">mvn clean package</pre>
<p>Copy the resulting WAR file (/hello-world-portlets/target/hello-world-portlets-1.0.0-SNAPSHOT.war to the auto deploy folder of your application server. The portlet will be installed now. Add the new portlet to a page and if everything works well then it should display the message: &#8216;Hello, Liferay Dev&#8217;.</p>
<p>You can <a href="http://www.devatwork.nl/wp-content/uploads/2010/04/hello-world-result.zip">download the complete project here</a>.</p>
<p>That is it for this article, I hope you enjoyed reading it and that you learned something. If you have any questions or comments please post a comment and I will get back to you as soon as I can. In the next article I will show you how you can expose the HelloWorld service as a web service so it can be consumed by external applications.</p>

	Tags: <a href="http://www.devatwork.nl/tag/java/" title="Java" rel="tag">Java</a>, <a href="http://www.devatwork.nl/tag/liferay/" title="Liferay" rel="tag">Liferay</a>, <a href="http://www.devatwork.nl/tag/spring/" title="Spring" rel="tag">Spring</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2010/04/implementing-a-reusable-liferay-service-without-ext-or-service-builder/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Setting up Maven for Liferay Development</title>
		<link>http://www.devatwork.nl/2010/04/setting-up-maven-for-liferay-development/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=setting-up-maven-for-liferay-development</link>
		<comments>http://www.devatwork.nl/2010/04/setting-up-maven-for-liferay-development/#comments</comments>
		<pubDate>Sat, 17 Apr 2010 13:08:03 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Maven]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=635</guid>
		<description><![CDATA[Welcome to the third article in these series about Liferay usage, maintenance and development. In this post I will show you how to set up your Liferay development enviroment using Apaches Maven2 build tool. We will develop a really simple JSR-168 portlet which can be deployed into Liferay. I assume you have read my previous [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-656" title="Liferay" src="http://www.devatwork.nl/wp-content/uploads/2010/01/liferay-logo-block.jpg" alt="" width="99" height="96" />Welcome to the third article in these series about Liferay usage, maintenance and development. In this post I will show you how to set up your Liferay development enviroment using Apaches Maven2 build tool. We will develop a really simple JSR-168 portlet which can be deployed into Liferay. I assume you have read my <a title="Setting up Liferay 5.2.3 on JBoss 5.1" href="http://www.devatwork.nl/2010/01/setting-up-liferay-in-jboss-5-1/">previous</a> <a title="Setting up Liferay 5.2.3 on Liferay" href="http://www.devatwork.nl/2010/01/setting-up-liferay-with-mysql/">articles</a> and that you are using Liferay 5.2.3 on JBoss 5.1. I hope you like this post as much as the previous ones, if you have any feedback feel free to contact me or post a response.</p>
<p>The next version of Liferay, release date end Q1 begin Q2, will have complete support for maven including custom archetypes. Some of the steps described in this article will be obsolete then, but lets get started.<span id="more-635"></span></p>
<h3>Installing Maven</h3>
<p>The first step is to actually install Maven. You can find the download and installation instructions on the Maven website <a href="http://maven.apache.org/">http://maven.apache.org/</a>. Confirm that Maven is installed properly by executing the following command:</p>
<pre class="brush: bash; light: true; title: ; notranslate">mvn --version</pre>
<p>You should see the Maven version number.</p>
<h3>Installing the Liferay dependencies into your local Maven repository</h3>
<p>The next step is to install the Liferay portal-kernel and portal-service into your local repository. This manual step is required in order for Maven to resolve the Liferay portal dependencies. Navigate the ‘%JBOSS_HOME%/server/default/lib/ext&#8217; folder where the JARs are located. Execute the following commands:</p>
<pre class="brush: bash; light: true; title: ; notranslate">mvn install:install-file -Dfile=&quot;portal-kernel.jar&quot; -DgroupId=&quot;com.liferay.portal&quot; -DartifactId=&quot;portal-kernel&quot; -Dversion=&quot;5.2.3-RELEASE&quot; -Dpackaging=jar
mvn install:install-file -Dfile=&quot;portal-service.jar&quot; -DgroupId=&quot;com.liferay.portal&quot; -DartifactId=&quot;portal-service&quot; -Dversion=&quot;5.2.3-RELEASE&quot; -Dpackaging=jar</pre>
<p>Now that you have installed the required dependencies let set up a quick Hello World portlet using Maven.</p>
<h3>Setting up the Hello World Portlet</h3>
<p>Now that we have all the required dependencies installed in our local Maven repository we can start building an application. <a href="http://www.devatwork.nl/wp-content/uploads/2010/04/maven-hello-world-portlet.zip">Download the complete source here</a>. Create the following folder structure:</p>
<pre class="brush: plain; light: true; title: ; notranslate">/pom.xml
/src/main/java/nl/devatwork/HelloWorldPortlet.java
/src/main/webapp/WEB-INF/portlet.xml
/src/main/webapp/WEB-INF/web.xml</pre>
<p>First let set up the POM so our dependencies can be loaded. Notice that I have set the Liferay dependencies as being provided. Add the following code to the pom.xml file you have just created:</p>
<pre class="brush: xml; collapse: true; highlight: [15,22]; light: false; title: ; toolbar: true; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;groupId&gt;devatwork&lt;/groupId&gt;
    &lt;version&gt;1.0.0-SNAPSHOT&lt;/version&gt;
    &lt;artifactId&gt;maven-hello-world&lt;/artifactId&gt;
    &lt;packaging&gt;war&lt;/packaging&gt;
    &lt;name&gt;Maven Hello World Portlet&lt;/name&gt;
    &lt;dependencies&gt;
        &lt;!-- Java dependencies --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax.portlet&lt;/groupId&gt;
            &lt;artifactId&gt;portlet-api&lt;/artifactId&gt;
            &lt;version&gt;2.0&lt;/version&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;!-- liferay dependencies --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.liferay.portal&lt;/groupId&gt;
            &lt;artifactId&gt;portal-service&lt;/artifactId&gt;
            &lt;version&gt;5.2.3-RELEASE&lt;/version&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.liferay.portal&lt;/groupId&gt;
            &lt;artifactId&gt;portal-kernel&lt;/artifactId&gt;
            &lt;version&gt;5.2.3-RELEASE&lt;/version&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
&lt;/project&gt;</pre>
<p>The portlet will be a very simple portlet. It will  print a string and the name of the current theme. Add the following code to the HelloWorldPortlet.java file:</p>
<pre class="brush: java; collapse: true; light: false; title: ; toolbar: true; notranslate">package nl.devatwork;

import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.theme.ThemeDisplay;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class HelloWorldPortlet extends GenericPortlet {
    protected void doView(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException {
        ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
        response.setContentType(&quot;text/html&quot;);
        response.getWriter().print(&quot;Hello World, &quot; + themeDisplay.getTheme().getName());
    }
}</pre>
<p>The next step is to set up the web.xml file, just copy the following code into it:</p>
<pre class="brush: xml; collapse: true; light: false; title: ; toolbar: true; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&quot; version=&quot;2.4&quot;&gt;
&lt;/web-app&gt;</pre>
<p>The final step of this sample portlet is the portlet.xml, again really straight forward. Just copy in the following code:</p>
<pre class="brush: xml; collapse: true; light: false; title: ; toolbar: true; notranslate">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;portlet-app xmlns=&quot;http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; version=&quot;2.0&quot; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd&quot;&gt;
    &lt;portlet&gt;
        &lt;portlet-name&gt;HelloWorldPortlet&lt;/portlet-name&gt;
        &lt;display-name&gt;Maven Hello World Portlet&lt;/display-name&gt;
        &lt;portlet-class&gt;nl.devatwork.HelloWorldPortlet&lt;/portlet-class&gt;
        &lt;expiration-cache&gt;0&lt;/expiration-cache&gt;
        &lt;supports&gt;
            &lt;mime-type&gt;text/html&lt;/mime-type&gt;
            &lt;portlet-mode&gt;view&lt;/portlet-mode&gt;
        &lt;/supports&gt;
    &lt;/portlet&gt;
&lt;/portlet-app&gt;</pre>
<p>Now that the application is finished you can package it by executing the following command in the root of your application:</p>
<pre class="brush: bash; light: true; title: ; notranslate">mvn clean package</pre>
<p>Deploy the WAR to your application server and test it. <a href="http://www.devatwork.nl/wp-content/uploads/2010/04/maven-hello-world-portlet.zip">Download the complete source here</a>.</p>
<p>Now you are able to build Liferay plug-ins using Maven. I hope you liked this article. Please let me know if you have any questions or comments. Bye for now!</p>

	Tags: <a href="http://www.devatwork.nl/tag/java/" title="Java" rel="tag">Java</a>, <a href="http://www.devatwork.nl/tag/liferay/" title="Liferay" rel="tag">Liferay</a>, <a href="http://www.devatwork.nl/tag/maven/" title="Maven" rel="tag">Maven</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2010/04/setting-up-maven-for-liferay-development/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>SEO Friendly URLs for Liferay Portlets</title>
		<link>http://www.devatwork.nl/2010/04/seo-friendly-urls-for-liferay-portlets/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=seo-friendly-urls-for-liferay-portlets</link>
		<comments>http://www.devatwork.nl/2010/04/seo-friendly-urls-for-liferay-portlets/#comments</comments>
		<pubDate>Sun, 04 Apr 2010 10:40:31 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[SEO]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=679</guid>
		<description><![CDATA[In my previous article I showed you how you can optimize SEO from within a portlet. Today we will take it one step further: I will show you how you can optimize portlet URLs. By default the URLs generate by Liferay are quite messy; it contains the portlet ID, the state and several other options. [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-656" title="Liferay" src="http://www.devatwork.nl/wp-content/uploads/2010/01/liferay-logo-block.jpg" alt="" width="99" height="96" />In my <a title="SEO optimize a Liferay portlet – Title, Description, Keywords" href="http://www.devatwork.nl/2010/03/seo-optimize-a-liferay-portlet-title-description-keywords/">previous article</a> I showed you how you can optimize SEO from within a portlet. Today we will take it one step further: I will show you how you can optimize portlet URLs. By default the URLs generate by Liferay are quite messy; it contains the portlet ID, the state and several other options. This doesn&#8217;t really look nice for Google.</p>
<p>However, Liferay has a nice method of controlling the URL the portal generates for a portlet, the &#8216;<em>FriendlyURLMapper</em>&#8216;. You can implement this interface, registerd it in the liferay-portlet.xml and you will have nice URLs. In the following example I will show how to implement it and what each individual method does.</p>
<p><span id="more-679"></span>I assume you have installed Liferay and the plugin SDK and that you know how to develop Liferay portlets.</p>
<p>The first step is to create a new class which will implement the &#8216;<em>FriendlyURLMapper</em>&#8216; interface. To make things easies we will derive that class from &#8216;<em>BaseFriendlyURLMapper</em>&#8216;. You have to implement several methods yourself but don&#8217;t worry I will show you how.</p>
<h3>The getMapping method</h3>
<p>The &#8216;<em>getMapping</em>&#8216; method must return an identifier for the mapping. The mapping identifier is used by Liferay to map URLs to instances of the &#8216;<em>FriendlyURLMapper</em>&#8216;. For example Liferay will resolve the following URL &#8216;/seoPortlet/123/view&#8217; to a &#8216;<em>FriendlyURLMapper</em>&#8216; instance with mapping &#8216;<em>seoPortlet</em>&#8216;. You can choose whatever mapping you want, just make sure your custom URLs always start with the mapping identifier.</p>
<p>To implement the &#8216;<em>getMapping</em>&#8216; method just return an unique identifier for the URL mapper.</p>
<pre class="brush: java; title: ; notranslate">public String getMapping() {
    return &quot;seoPortlet&quot;;
}</pre>
<h3>The buildPath method</h3>
<p>The &#8216;<em>buildPath</em>&#8216; method builds the actual URL. Here you implement the URL generation logic. You have access to the &#8216;<em>LiferayPortletURL</em>&#8216; object for which the URL is generated. You can extract the portletId, parameters, window state, etc. from it. The method should return a string containing the friendly URL for that particular portletURL, when the method returns <em>null</em> the default portletURL is used.</p>
<p>For each parameter (p_p_id for example) you move from the query string to the URL, you need to call &#8216;<em>portletURL.addParameterIncludedInPath(&#8220;p_p_id&#8221;)</em>&#8216;. This will tell Liferay to not include the parameter in the query string. Parameters who are not marked as &#8216;included in path&#8217; will be added to the query string automatically by Liferay.</p>
<p>Here is an example which maps URLs with a parameter named event to a friendly URL.</p>
<pre class="brush: java; title: ; notranslate">public String buildPath(final LiferayPortletURL portletURL) {
    String friendlyURLPath = null;

    // get the value
    final String portletId = portletURL.getPortletId();
    final String eventName = GetterUtil.getString(portletURL.getParameter(&quot;event&quot;));

    if (Validator.isNotNull(portletId) &amp;&amp; Validator.isNotNull(eventName)) {
        friendlyURLPath = StringPool.FORWARD_SLASH + &quot;seoPortlet&quot;+ StringPool.FORWARD_SLASH + portletId + StringPool.FORWARD_SLASH + eventName;
        portletURL.addParameterIncludedInPath(&quot;event&quot;);
    }

    // add other pararmeters
    if (Validator.isNotNull(friendlyURLPath)) {
        portletURL.addParameterIncludedInPath(&quot;p_p_id&quot;);
    }

    return friendlyURLPath;
}</pre>
<p>Notice that we are including the mapping prefix &#8216;seoPortlet&#8217; and that we are excluding the &#8216;p_p_id&#8217; and &#8216;event&#8217;  parameters from the URL.</p>
<h3>The getPortletId method</h3>
<p>This method is used by the &#8216;<em>BaseFriendlyURLMapper</em>&#8216; super class to retrieve the portlet id. This will be used by <em>&#8216;populateParams</em>&#8216; method.</p>
<p>To implement the &#8216;<em>getPortletId</em>&#8216; method just return the value of a backing field with the name portletId. See example:</p>
<pre class="brush: java; title: ; notranslate">private String portletId;
public String getPortletId() {
    return portletId;
}</pre>
<h3>The populateParams method</h3>
<p>This method will be called by Liferay each time a request is made with the mapping identifier in the URL. This method is responsible for mapping the parameters we removed from the query string and added to the path back to parameters: reversing the work we did in the &#8216;buildPath&#8217; method.</p>
<p>Here is an example implementation.</p>
<pre class="brush: java; title: ; notranslate">public void populateParams(final String friendlyURLPath, final Map&lt;String, String[]&gt; params) {
    // get the values
    final String[] parts = StringUtil.split(friendlyURLPath, StringPool.SLASH);
    portletId = parts[2];
    final String event = parts[3];
    final String namespace = getNamespace();

    params.put(&quot;p_p_id&quot;, new String[]{portletId});
    params.put(&quot;p_p_state&quot;, new String[]{WindowState.NORMAL.toString()});
    params.put(namespace + &quot;event&quot;, new String[]{event});
}</pre>
<p>The method takes apart the &#8216;<em>friendlyURLPath</em>&#8216; and assembles parameters from it&#8217;s parts. Notice that in order to avoid parameter clashes between portlets the event parameter is prefixed with the portlet namespace, generated by the &#8216;<em>BaseFriendlyURLMapper</em>&#8221;s &#8216;<em>getNamespace</em>&#8216; method. The &#8216;<em>getNamespace</em>&#8216; method consumes the portletId using the &#8216;<em>getPortletId</em>&#8216; method.</p>
<h3>liferay-portlet.xml</h3>
<p>Now that the mapper is finished we need to tell Liferay to start using it. Add the friendly-url-mapper-class declaration to the portlet declaration and set its content to point to the class you just wrote:</p>
<pre class="brush: xml; title: ; notranslate">&lt;friendly-url-mapper-class&gt;com.sample.FriendlyURLMapper&lt;/friendly-url-mapper-class&gt;</pre>
<p>That is it, know you can assemble your own FriendlyURLMapper now. I hope this article was useful to you. Please let me know if you have any questions or comments.</p>

	Tags: <a href="http://www.devatwork.nl/tag/liferay/" title="Liferay" rel="tag">Liferay</a>, <a href="http://www.devatwork.nl/tag/seo/" title="SEO" rel="tag">SEO</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2010/04/seo-friendly-urls-for-liferay-portlets/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Liferay Training @ Frankfurt, part 4</title>
		<link>http://www.devatwork.nl/2010/03/liferay-training-frankfurt-part-4/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=liferay-training-frankfurt-part-4</link>
		<comments>http://www.devatwork.nl/2010/03/liferay-training-frankfurt-part-4/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 13:37:02 +0000</pubDate>
		<dc:creator>Bert Willems</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Liferay]]></category>

		<guid isPermaLink="false">http://www.devatwork.nl/?p=709</guid>
		<description><![CDATA[Today is the last day of the Liferay development training in Frankfurt, which is too bad because there is so much more to discover about Liferay. A quick summary of what we have learned during this course: Setting up Liferay, the plugin SDK and the Ext environment (allows you to customize the Liferay core) Setting up MySQL [...]]]></description>
			<content:encoded><![CDATA[<p>Today is the last day of the Liferay development training in Frankfurt, which is too bad because there is so much more to discover about Liferay.</p>
<p>A quick summary of what we have learned during this course:</p>
<ul>
<li>Setting up Liferay, the plugin SDK and the Ext environment (allows you to customize the Liferay core)</li>
<li>Setting up MySQL for Liferay</li>
<li>Setting up a basic portlet</li>
<li>Setting up a Liferay entity &amp; service, a portlet which consumes it and hook those two up including validation and localization</li>
<li>Creating a hook</li>
<li>Creating a theme</li>
<li>And a lot more&#8230;</li>
</ul>
<p>I think this will be the last update regarding the Frankfurt training.</p>

	Tags: <a href="http://www.devatwork.nl/tag/liferay/" title="Liferay" rel="tag">Liferay</a><br />
]]></content:encoded>
			<wfw:commentRss>http://www.devatwork.nl/2010/03/liferay-training-frankfurt-part-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

