tag:blogger.com,1999:blog-3223501623837928992024-03-08T18:02:30.331+01:00Liferay made easy!Anonymoushttp://www.blogger.com/profile/05319972493304519634noreply@blogger.comBlogger6125tag:blogger.com,1999:blog-322350162383792899.post-87449635530632749412014-09-07T20:40:00.002+02:002014-09-07T20:40:14.586+02:00Use third party authentication service in Liferay<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
Hi,<br />
<br />
This blog quickly describe, how to hook the third party authentication services to use Liferay standard auhentication.<br />
<br />
Liferay provides very rich set of connections for authentication, still many times we come across situations where we have to use some third party non standard (like proprietary solution) for authentication.<br />
<br />
The following shows how to do that quickly.<br />
<br />
1. Create a liferay hook<br />
<br />
Create a new liferay hook to hook UserLocalService for custom authentication. Follow this link on <a href="https://www.liferay.com/documentation/liferay-portal/6.1/development/-/ai/creating-a-ho-4" target="_blank">how to create a liferay hook</a><br />
<br />
In this hook, implement a UserLocalServiceWrapperImpl class which implements <u style="font-weight: bold;">com.liferay.portal.service.UserLocalServiceWrapper. </u>This class will have the implementation of your desired authentication method.<br />
<br />
Let say, you are using authentication by email address in Liferay, so in that case, please override method authenticationByEmailAddess(). in the method implementation, you can call you custom service or third party authentication service for the authentication. You have the user provided email address and password as method parameter, so you can easily send them.<br />
<br />
Based on the result of you authentication process, you can return the com.liferay.portal.security.auth.Authenticator.SUCCESS or FAILURE.<br />
<br />
@Override<br />
public int authenticateByEmailAddress(long companyId, String emailAddress, String password,<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>Map<string tring=""> headerMap, Map<string tring=""> parameterMap, Map<string bject=""> resultsMap)</string></string></string><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>throws SystemException, PortalException {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>LOG.info("Calling authenticateByEmailAddress"); <br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>try {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>//call your custom authentication service<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>boolean result = CustomAuthenticationServiceUtil.authenticate(emailAddress, password);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>if(result) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return Authenticator.SUCCESS;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return Authenticator.FAILURE;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>} catch (Exception e) {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>LOG.error("authentication failed by :",e);<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>return Authenticator.FAILURE;<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br />
}<br />
<br />
2. Hook the service<br />
<br />
Open the liferay-hook.xml and add the below code<br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><service><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><service-type>com.liferay.portal.service.UserLocalService</service-type><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><service-impl>com.felixchristy.login.UserLocalServiceWrapperImpl</service-impl><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span></service><br />
<br />
3. Now, deploy the hook. Whenever you will use the Liferay login portlet, Liferay will call the hooked service and there you go<br />
<br />
Happy coding!</div>
Anonymoushttp://www.blogger.com/profile/05319972493304519634noreply@blogger.com3tag:blogger.com,1999:blog-322350162383792899.post-35485232460269794742014-09-07T20:39:00.007+02:002014-09-07T20:39:55.129+02:00Components and code-base management in Liferay<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<br />
Hi Friends!<br />
<br />
Here, I will be sharing my experience and thoughts on the component and the code-base management for a Liferay project.<br />
<br />
You can use either ANT or Maven for the code base management. I would say Maven is a good choice for modular architecture.<br />
<br />
Lets get back to the topic.<br />
<br />
In Liferay, a portlet, hook, web, theme, layout template, all are web applications. When you create them and deploy, it will be deployed as a separate web application in an application server. Considering this fact, more number of components will create more number of web apps and at the later stage will require more maintenance.<br />
<br />
You can actually create many portlets, themes, layouts, hooks in a single web app. Also, you can mix and match. Meaning, a single web application can contain a portlet and a theme also or any other components.<br />
<br />
Lets say, we are creating a web application for a brand called "Epic". And like any other web application, this has various features like user authentication, user profile management, content management, payment gateway integration, look and feel components, document management, third party service integration etc.<br />
<br />
So, how should we start? Well.. lets start then<br />
<br />
<h3>
List down the components</h3>
<br />
In our case, I am listing down some components<br />
<ol>
<li>user authentication hook (our backend uses some third party authentication)</li>
<li>user my profile portlet</li>
<li>liferay-hook (for liferay jsp modification and language properties)</li>
<li>epic theme (a new theme for look and feel)</li>
<li>1-2-2-1 layout (assuming we need some new liferay page layout template)</li>
<li>order-processing portlet</li>
<li>marketing-portlet</li>
<li>reporting-portlet</li>
</ol>
<div>
aah.. that is enough.. we can scale that later. Lets move on.</div>
<div>
</div>
<br />
<h3>
Logically divide and combine components</h3>
<div>
How? Let us say that our features user authentication, user my profile portlet and liferay-hook (containing login.jsp of Liferay) contain the component and features that are related with user .authentication and management process.</div>
<div>
<br /></div>
<div>
So create a component called "epic-user-management-component". You can create this by using <u><a href="http://www.liferay.com/documentation/liferay-portal/6.1/development/-/ai/liferay-plugin-types-to-develop-with-maven" target="_blank">maven commands of Liferay</a>. </u>Give a name ending with "component" and not "portlet". Maven has created a portlet for you, but we can make this as a component. </div>
<div>
<br /></div>
<div>
Since, this is maven module is a type of "portlet", it has a standard <b>portlet.xml</b> and <b>liferay-portlet.xml</b> and etc. In a nutshell, it has a project nature "portlet". the portlet.xml and liferay-portlet.xml can have multiple "portlet" tags and thus it can contain more than one portlets.</div>
<div>
<br /></div>
<div>
So, any portlet that has a logical / business nature of "user-management" should go here. Now, let say, that you have also modified the liferay "login.jsp" for the same. So, you need a hook. Simple add the "liferay-hook.xml" in the <b>"epic-user-management-component"</b> and also, copy the customized jsp into webapps and also configure the path of that.</div>
<div>
<br /></div>
<div>
Your component has now 2 project natures. A portlet and a hook. Let say that you have also modified the liferay user services for the same, or you have created a new services for authentication Simple add the <b>"service.xml" </b>of your new components and build the liferay service. Your "epic-user-management-component" can now serve the new services as well. Same can be done for theme and layouts. By adding <b>liferay-look-and-feel.xml</b> or by <b>liferay-layout-templates.xml</b> will make the component with a nature of theme and layout-template.</div>
<div>
<br /></div>
<div>
So, you component is now acting as a portlet, a service provider, a hook and so on. Also, defining the dependency for this component is easy and simple, the <b>pom.xml</b> of this component will have all the dependencies that you require for user management.</div>
<div>
<br /></div>
<div>
The second component can be an "epic-look-and-feel-component". This component can contain all the custom themes, layouts, any Liferay jsps that you have modified for look and feel, some custom images that you want to inject directly to /ROOT (liferay portal web app) and etc.</div>
<div>
<br /></div>
<div>
The third component can be an "epic-localization-component" this component can contain all your language properties, custom language properties, Liferay jsps that you have modified for internationalization, and third party service components that you want to use for internationalization.</div>
<div>
<br /></div>
<div>
And all other components can be divided based on the use case or feature.</div>
<div>
<br /></div>
<div>
So, if you divide your features or components like this, it will have less web applications, the related components are together and they can share the same dependencies on the same class path.</div>
<div>
<br /></div>
<div>
Your code base will look like </div>
<div>
<br /></div>
<div>
<ol>
<li>epic-user-management-component</li>
<li>epic-look-and-feel-component</li>
<li>epic-internationalization-component</li>
<li>epic-reporting-component</li>
<li>epic-marketing-component</li>
<li>epic-web-analysis-component</li>
<li>epic-...</li>
</ol>
<div>
instead of</div>
</div>
<div>
<br /></div>
<div>
<ol>
<li>epic-user-profile-portlet</li>
<li>epic-public-theme</li>
<li>epic-private-theme</li>
<li>epic-1-2-2-1-layout</li>
<li>epic-2-2-2-layout</li>
<li>epic-hook</li>
<li>epic-marketing-display-portlet</li>
<li>epic-hr-support-portlet</li>
<li>epic-leave-balance-portlet</li>
<li>epic-bla-bla-bla</li>
</ol>
<div>
<br /></div>
</div>
<div>
Happy coding!</div>
</div>
Anonymoushttp://www.blogger.com/profile/05319972493304519634noreply@blogger.com0tag:blogger.com,1999:blog-322350162383792899.post-83299887233389490272014-09-07T20:39:00.001+02:002014-09-07T20:39:06.768+02:00SimpleDateFormat in web technology<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<br />
<br />
Hi,<br />
<br />
Many of times we are using java <a href="http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html" target="_blank">SimpleDateFormat </a>class to format the date and convert the date into String and vice verse.<br />
<br />
Sometimes, by mistake we are creating a static instance of the SimpleDateFormat object, as either it is used in many of other classes or used many times in same class. This is the example of the same<br />
<br />
private static final SimpleDateFormat ENGLISH_DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy");<br />
<br />
And we put this in some constant class and as and when required, we use this with the static reference.<br />
<br />
This will work perfectly fine, but other part is that the SimpleDateFormat is not synchronized. So, let say, if we are working in Struts (Action classes) or say some Portlets (Portlet classes) and we make use of this static reference, then chances are higher that we get false values for the dates.<br />
<br />
While converting and formatting dates, SimpleDateFormat stores the provided date value into its instance variable and start the converting process.<br />
<br />
Since we have made it as a static reference, 2 web request running on different threads may access this at a same time and we get stale data.<br />
<br />
<br />
Hope this will help!<br />
<br />
keep coding!</div>
Anonymoushttp://www.blogger.com/profile/05319972493304519634noreply@blogger.com0tag:blogger.com,1999:blog-322350162383792899.post-37784772704920687912014-09-07T20:38:00.005+02:002014-09-07T20:38:48.426+02:00Creating custom navigation in Liferay<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<br />
<br />
Hi Friends,<br />
<br />
Liferay provides the menu (root navigation). But it always shows from the current community. Sometimes, there is a need of creating a navigation from base community and not from the current community.<br />
<br />
For e.g., In your Liferay portal, there are lot of communities and a single base community (with name BASE) which is common for all users and we need the root navigation based on that community only.<br />
<br />
To achieve this, we need to create a ServicePreAction, which will create a new custom NavItem object and a change in navigation.vm of the theme, which will show the custom navigation.<br />
<br />
Here are the steps to create the custom navigation<br />
<br />
1) Create a new ServicePreAction say CustomServicePreAction using hook ( Refer <a href="http://www.liferay.com/community/wiki/-/wiki/Main/Portal+Hook+Plugins">http://www.liferay.com/community/wiki/-/wiki/Main/Portal+Hook+Plugins</a> on creating ServicePre hook)<br />
<br />
2) In the run() method of CusomServicePreAction, retrieve the BASE community group object<br />
<br />
Group baseCommunity = GroupLocalServiceUtil.getGroup( themeDisplay.getCompanyId(), "BASE");<br />
<br />
3) After that, retrieve the default layout and layout set of the base community. If you need to show private pages, then pass "true" in the getLayouts() method, else pass "false" to retrieve the public pages.<br />
<br />
<br />
long defaultLayoutId = LayoutLocalServiceUtil .getDefaultPlid(baseCommunity.getGroupId());<br />
<br />
Layout defaultLayout = LayoutLocalServiceUtil .getLayout(defaultLayoutId);<br />
<br />
List<layout> layoutSet = LayoutLocalServiceUtil.getLayouts(<br />baseCommunity.getGroupId, true);<br /><br /><br />4) Create the RequestVars object from the defaultLayout and layoutSet<br /><br />RequestVars requestVars = new RequestVars(req,themeDisplay, defaultLayout.getAncestorPlid(),<br />defaultLayout.getAncestorLayoutId());<br /><br />5) finally, create the List of NavItems using RequestVars and layoutSet<br /><br />List<navitem> navItems = NavItem.fromLayouts(requestVars,layoutSet);<br /><br />6) Now, create a new HashMap like<br /><br />Map<string object=""> vmVariables = new HashMap<string object="">();<br /><br />7) Save the NavItems into that<br /><br />vmVariables.put("baseNavItems", navItems);<br /><br />8). Save the HashMap into the request<br /><br />req.setAttribute(WebKeys.VM_VARIABLES, vmVariables);<br /><br />---------------------------------------------------------------------------------------<br /><br />Now, in the navigation.vm of the Theme,<br /><br />replace<br /><br />#foreach ($nav_item in $nav_items) with #foreach ($nav_item in $baseNavItems)<br /><br />---------------------------------------------------------------------------------------<br /><br />Deploy the theme and the hook.<br /><br />Now your top navigation will show the menu items from the BASE community and not from the current community.<br /><br />Enjoy!</string></string></navitem></layout></div>
Anonymoushttp://www.blogger.com/profile/05319972493304519634noreply@blogger.com0tag:blogger.com,1999:blog-322350162383792899.post-57416743568367907712014-09-07T20:38:00.001+02:002014-09-07T20:38:05.781+02:00Liferay Search with multiple portlets<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<br />
<br />
<br />
Hi!!!!!<br />
<br />
Greetings from Felix!!!!<br />
<br />
This is about Liferay Search, it is tricky and one of the most complex part of the Liferay Portal!<br />
<br />
Till today I was thinking that Liferay didn't provide any way to search content for selective portlets, but it is not true.<br />
<br />
For e.g., if I want to search only for Document Library and Journal Content in a single service call, it is possible with Liferay.<br />
<br />
Just follow CompanyLocalServiceImpl.search() method (Liferay Version 6.0.4 Community Edition) <a href="http://sourceforge.net/projects/lportal/files/Liferay%20Portal/6.0.4/liferay-portal-src-6.0.4.zip/download">Liferay Portal src</a><br />
<br />
There is a code which sets the PORTLET_ID in the Query.<br />
<br />
<blockquote>
if (Validator.isNotNull(portletId)) {<br />
contextQuery.addRequiredTerm(Field.PORTLET_ID, portletId);<br />
}</blockquote>
<br />
Just comment out this part and add the following part<br />
<br />
<blockquote>
BooleanQuery portletQuery = BooleanQueryFactoryUtil.create();<br />
portletQuery.addTerm(Field.PORTLET_ID, portletId);</blockquote>
<br />
And once, fullQuery is created, add this portletQuery to the fullQuery.<br />
<br />
<blockquote>
fullQuery.add(portletQuery, BooleanClauseOccur.MUST);</blockquote>
<br />
Now, comes the real part!<br />
<br />
If you want to search for multiple portlets, just create a String of portletIds and put "OR" operator in between.<br />
<br />
For e.g., if you want to search only for JournalArticle and Document Library, create a portletId value as "15 OR 20",where "15" is a portletId of Journal and "20" is a portletId of Document Library.<br />
<br />
<br />
This will return search Hits for given portletIds.<br />
<br />
This is very useful, as developer does not have to worry about the custom pagination and custom search containers.<br />
<br />
Do send me your comments!</div>
Anonymoushttp://www.blogger.com/profile/05319972493304519634noreply@blogger.com0tag:blogger.com,1999:blog-322350162383792899.post-52377633075534097822014-09-07T20:37:00.001+02:002014-09-07T20:37:34.905+02:00Modifying PDFs using iText api<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<br />
Hi there!!!<br />
<br />
Using iText, one can create a copy of existing pdf file with desired modification. Also, iText allows us to add acrobat reader javascripts into PDF, which is very useful to add custom command buttons, hiding menubars, toolbars and invoking dialog boxes.<br />
<br />
Following java code shows to invoke a print dialog box on opening a pdf file.<br />
<br />
<span style="font-size: 14px;"><span style="font-family: courier new;">import com.lowagie.text.Document;</span> <span style="font-family: courier new;"><br />import com.lowagie.text.pdf.PdfCopy;</span> <span style="font-family: courier new;"><br />import com.lowagie.text.pdf.PdfImportedPage;</span><br /><span style="font-family: courier new;">import com.lowagie.text.pdf.PdfReader;</span><br /><br /><br /><span style="font-family: courier new;">Document document = new Document();</span><br /><span style="font-family: courier new;">PdfReader pdfReader = new PdfReader(fileData);</span> // fileData is a byte[] of existing pdf<br /><span style="font-family: courier new;">pdfReader.consolidateNamedDestinations();</span><br /><span style="font-family: courier new;">PdfCopy writer = new PdfCopy(document, </span><span style="font-family: courier new;"><br />new FileOutputStream(writeFile)); // create a pdf copy.</span><br /><span style="font-family: courier new;">document.open();</span><br /><span style="font-family: courier new;">writer.addJavaScript("this.print();"); //adding javascript //for the print dialog.</span><br /><span style="font-family: courier new;">int pages = pdfReader.getNumberOfPages();</span><br /><span style="font-family: courier new;">if(pages > 0) {</span> <span style="font-family: courier new;"><br /> PdfImportedPage page;</span><span style="font-family: courier new;"> for(int i=1;i<=pages;i++) { </span><span style="font-family: courier new;"><br /> page = writer.getImportedPage(pdfReader, i); //get page //from the pdf</span><br /><span style="font-family: courier new;"> writer.addPage(page); // add to the new pdf.</span> <span style="font-family: courier new;"><br /> }<br />}</span> <span style="font-family: courier new;"><br />document.close();</span> <span style="font-family: courier new;"><br /></span></span><br />
"writeFile" is a new file which contains a java script to open a print dialog.<br />
<br />
Similarly you can import the pdf bookmarks and annotations.</div>
Anonymoushttp://www.blogger.com/profile/05319972493304519634noreply@blogger.com0