Liferay-6

89
Liferay Installation How to install Liferay ? First download the community version with tomcat server from the liferay website or Click Here Unzip the contents to a suitable location. Open the bin directory And click on the startup.bat file to start and shutdown.bat file to shutdown. To change the server standard time. Open the setenv.bat in an editor and change the –Duser.timezone -Duser.timezone=Asia/Calcutta Restart the Server . Reference link: http://liferaydemystified.blogspot.com/2011/08/table- relationships.html

Transcript of Liferay-6

Page 1: Liferay-6

Liferay Installation

How to install Liferay ?

First download the community version with tomcat server from the liferay websiteor Click Here

Unzip the contents to a suitable location.

Open the bin directory

And click on the startup.bat file to start and shutdown.bat file to shutdown.

To change the server standard time.

Open the setenv.bat in an editor and change the –Duser.timezone

-Duser.timezone=Asia/Calcutta

Restart the Server .

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 2: Liferay-6

For Database Settings

log into the MySql command line editor.

mysql> create database `lportal` CHARACTER SET utf8 COLLATE utf8_general_ci;

create a portal-ext.properties file in \liferay-portal-6.0.6

Add the following Lines to connect to MySql Database.

## MySQL #jdbc.default.driverClassName=com.mysql.jdbc.Driver jdbc.default.url=jdbc:mysql://localhost/lportal?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=falsejdbc.default.username=rootjdbc.default.password=root

save and restart.

Check installation success in MySql

mysql>use lportal ;mysql>show tables ;

A total of 185 rows indicating 185 tables must be shown.

There is another way to connect Tomcat to the database. Here is how it is done. Assuming that lportal schema is available in MySQL.

goto this path ${TOMCAT_HOME}\conf\Catalina\localhostOpen the root.xml and add the following lines in it.

<Context path="" crossContext="true">

<Resourcename="jdbc/LiferayPool"auth="Container"

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 3: Liferay-6

type="javax.sql.DataSource"driverClassName="com.mysql.jdbc.Driver"url="jdbc:mysql://localhost:3306/lportal?useUnicode=true&amp;amp;characterEncoding=UTF-8"username="root"password="root"maxActive="20"/></Context>

while configuring your database do make sure the corresponding jar file of the database is present in the lib directory of tomcat. Liferay Bundled wit tomcat has mysql.jar in it by default in the lib/ext folder.More Liferay 6.0.5 Properties.

Now ,some fine tuning must be done if you are going to start development in liferay , so that everything runs faster and smoother , without much of ui customization.

Here is what you've got to do.

Open setenv.bat again , and add the following lines to it

-Dexternal-properties=portal-developer.properties

Thats it, You are done and now you can start development on Liferay !!!

MVC Portlet Development : Eclipse Installation

Liferay Installation

Before jumping on the Liferay Bandwagon , lets talk in brief about the Portal Technology.

A Portal is simply an aggregation of portlets and takes up the job of placement of portlets and handling the requests and rendering them back. Like Yahoo , It’s a portal , or iGoogle it’s a portal . and on the Home page of yahoo you can see different sections Like entertainment ,games etc these are nothing but portlets.

A Portlet is more or less like a servlet with the few main differences

1) A servlet URL can be chosen by the Developer , in Portlets the URLs are dynamically generated by the Portal Container

2) Every Portlet may or may not share the same real-estate on the screen.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 4: Liferay-6

3) In Servlets request and response handling happens in the same lifecycle. Portlets have a different mechanism for handling requests and generating responses.

For rendering even a Portlet uses a jsp page.

Liferay is using the latest Java Portlet Specification JSR-286.

I would advise you to read the following links, before you jump on to Liferay.

Read the Introductory Chapter 1 of Portlet Faces

Portlet Faces

http://editorial.mcpressonline.com/web/mcpdf.nsf/wdocs/5232/$FILE/5232_EXP.pdf

http://java.sys-con.com/node/46966

Difference between Servlets and Portlets :

http://www.coderanch.com/t/203209/Portals-Portlets/java/portlet-servlet

http://fanatech.wordpress.com/servlets-vs-portlets/

MVC Portlet is a design pattern built by liferay to make portlets faster,easier and scalable. It is advised to use MVCPortlet for a 2-20 action requests.If more than that , then its best to create an action class I.e. making a normal class with Action extended.

In order to learn how to create MVC Portlets we shall take an example of User Registration , where we shall learn how to create a database table using the liferay services ,how to make use of built in liferay apis , the MVC portlet structure , the flow of request and response,the jsp coding , the permissioning system and practically all you need to start making your own portlets.

Project Creation

We’ll be using eclipse as our development platform.

Help => Eclipse Market Place=> type liferay in the search box

Screen Shot :

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 5: Liferay-6

Click on install and follow the general procedure of installing a plug-in .

In the Meanwhile download the liferay-sdk from here

Linking SDK to eclipse.

Window => Preferences

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 6: Liferay-6

Click on Add => Browse to the sdk location and then restart your eclipse.

Creating a new Liferay Project.

1) Enter the Name of the Project.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 7: Liferay-6

=> Connect the project with the liferay tomcat folder on your computer.The SDK directory should show u by default. If it doesn’t then browse and plug it in.

=> Click on Next

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 8: Liferay-6

Select MVCPortlet and check “create custom portlet”

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 9: Liferay-6

=> Enter the Desired name and package of the Portlet.

Select an appropriate Display Name and Name of the Portlet. These entries shall go directly in the liferay-portlet.xml , and portlet.xml

Also check the

=> create jsp Files

=> create resource bundles.

If you want to store the jsps in a custom folder then just enter

/customfoldername

Ex : /jsps

Click Finish to complete the Process.

MVC Portlet Development : Directory Structure

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 10: Liferay-6

MVC Portlet Development Eclipse Installation

While deploying the application, everything is folded up into the docroot folder. All the source class files and jsp files are folded up or wrapped up in the docroot folder.

There are 3 Most Important xml files viz. :

1) liferay-display.xml : specifies where your portlet should displayed , under which category. Also specifies the portlet id.

NOTE : Every Portlet is assigned a unique name using the following template portletname_WAR_applicationname. In our Case : it will be booksportlet_WAR_books-portlet

Eclipse by default adds ‘-portlet’after the application name , but this can be refactored

?12<?xml version="1.0"?><!DOCTYPE display PUBLIC "-//Liferay//DTD Display 6.0.0//

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 11: Liferay-6

345678910111213

EN" "http://www.liferay.com/dtd/liferay-display_6_0_0.dtd">

<display><category name="category.sample">

</category><category name="Books"> <portlet id="booksportlet"></portlet></category></display>

2) liferay-portlet.xml : Defines liferay specific features of the portlet.

?12345678910111213141516

<?xml version="1.0"?><!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 6.0.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_0_0.dtd"> <liferay-portlet-app>

<portlet> <portlet-name>booksportlet</portlet-name> <icon>/icon.png</icon> <instanceable>false</instanceable> <header-portlet-css>/css/portlet.css</header-portlet-css> <footer-portlet-javascript> /js/javascript.js </footer-portlet-javascript> <css-class-wrapper>booksportlet-portlet</css-class-wrapper></portlet><role-mapper> <role-name>administrator</role-name> <role-link>Administrator</role-link></role-mapper><role-mapper> <role-name>guest</role-name> <role-link>Guest</role-link></role-mapper><role-mapper> <role-name>power-user</role-name> <role-link>Power User</role-link></role-mapper>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 12: Liferay-6

171819202122232425262728293031323334

<role-mapper> <role-name>user</role-name> <role-link>User</role-link></role-mapper></liferay-portlet-app>

The instanceable tag allows to configure the number of instances of that portlet on a particular page. If set to false means you cannot have the same portlet on the same page.If you want a custom icon for your portlet then , you can specify its location within the tag.3) portlet.xml : Follows the jsr-286 specifications of defining portlets and their activities.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 13: Liferay-6

?123456789101112131415161718192021222324252627

<?xml version="1.0"?>

<portlet-appversion="2.0"xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">

<portlet> <portlet-name>booksportlet</portlet-name> <display-name>Books Catalog</display-name> <portlet-class>com.books.portlet.BooksPortlet</portlet-class> <init-param> <name>view-jsp</name> <value>/jsps/view.jsp</value> </init-param> <expiration-cache>0</expiration-cache> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW</portlet-mode> </supports> <resource-bundle>content/Language</resource-bundle> <portlet-info> <title>Books Portlet</title> <short-title>BooksPortlet</short-title> <keywords></keywords> </portlet-info> <security-role-ref> <role-name>administrator</role-name> </security-role-ref> <security-role-ref> <role-name>guest</role-name> </security-role-ref> <security-role-ref> <role-name>power-user</role-name> </security-role-ref> <security-role-ref> <role-name>user</role-name> </security-role-ref></portlet></portlet-app>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 14: Liferay-6

28293031323334353637383940414243

Most of the tags are self-explanatory , Attention needs to be paid at init-parameter tag. The init-parameter tag holds the initial parameters needed to launch an MVCPortlet application. In this case we are having the init-parameter as view-jsp which has been defined in the MVCPortlet specification as the home page or the page that shall be loaded first or by default for this particular portlet. If you define a different folder for your jsps then you need to specify it here.

security-role-ref : The security-role-ref element contains the declaration of a security role reference in the code of the web application. Specifically in Liferay, the role-name references which role’s can access the portlet. (A

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 15: Liferay-6

Power User can personalize the portal, whereas a User cannot .

In the resource-bundle tag we have

?12<resource-bundle>content/Language</resource-bundle>

This tag is used for having language resources. We can have different Language.properties file of different languages by including them under content/All the above coding has been generated by eclipse by default.

?1234

<security-role-ref> <role-name>administrator</role-name> </security-role-ref>

The security-role tag creates the default roles of this portlet. Default Roles means , these roles will be present in this portlet , and will the permissions of these roles shall be mapped to the respective portal default roles.

Liferay Groups Mystery Untangled

Liferay , has 4 types of aggregation

1) Company : Company basically means a standalone portal. Like if we have one single portal then there will be only one single companyId. But if we have more than one portals then there will be different companyIds.

For Ex Google will have one headquarter and different branches , so every branch including the headquarter will be different company id and the users will be grouped into those portals . So , if you want to retrieve the users from a particular branch , you just need to fire a query by giving the companyid. This companyID can easily be obtained from the ActionRequest object and the themeDisplay object as we shall see later.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 16: Liferay-6

2) Communities : Now , CMS or content management systems , on which liferay is based is all about sharing data or knowledge. How easy it would be if we were to segregate the interests of different users so that data sharing can be streamlined. This has been taken care of by introducing the concept of Communities. Each liferay portal instance can have different communities, and users can join these communities if their interested align with the objectives of the communities. For Example , there may be a Student community or a professors community and so on. Each community has a unique communityID within that portal instance.

There are 3 types of communities :

a) Restricted : Membership and visibility of the content on this community is controlled only by the admin.

b) Public : Membership is free and all the contents are visible to everyone in the organization

c) Private : Same as restricted but its existence is kept confidential.

3) UserGroups : This aggregation is done by admin to give cross functionality to specific members like we create a global resource Like a Technical Architect who can contribute by writing in both Java and .NET communities.

So instead of having a separate community for Technical Architects we can have a Team or a UserGroup of TAs.

4) Roles : Users are aggregated on the basis of the functions assigned to them by the admin. Like we can have a Role of Reviewer , who has the permission of reviewing the blogs content.

There are 3 types of roles or scope of Roles more precisely

a) Portal Roles : here we define access permissions to different portlets throughout the portal instances .

There are a few pre-defined default Portal Level Roles which cannot be deleted.

i) Admin : is Omnipotent.

ii) User : Is a member of an organization

iii) Power User : inherits all the powers of the user , but also gets his/her custom public/private page.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 17: Liferay-6

By default a registered member is granted a power user and user roles.

b) Community Roles : A Community role would grant that access only within a single community.

For Example we can have an Invigilator Role assigned to the Education Community , and a Student Role assigned to the same community. The invigilator would have the permissions to create tests , but the student cannot create tests

c) Organization Roles : Similarly , we have Organization Role which defines access to different portlets in a particular portal instance. Like a Role of reviewer assigned to Mumbai Portal , will not necessarily have the same role assigned to him for the Delhi Branch Portal.

New roles can be created and assigned permissions by the Admin.

Now the Obvious question , what is the difference between a community and an organization ?

In an Organization or Company , the users are aggregated in a hierarchical manner by assigning them different organization level roles.

In a community , all users are at the same level , but certain permissions related to deleting or creating a blog etc are restricted to certain users.

Pages can be assigned to a Community,Organization or a UserGroup , but not to roles. A Power User Role is assigned to all registered members by default , and by assigning them to a particular UserGroup can enable us to have a custom public/private page for that User. For Example , a group of Student we can have a certain set of Pub/Pri pages where as a group of Teachers we can have a different set of Pub/Pri pages.Just create a particular UserGroup and define its public/private pages and assign the users to those respective usergroups.

By Default there is a Guest UserGroup , who is just a guest or a visitor the website, with the guest role.So if a guest logins in or is registered , he is by default assigned a Guest UserGroup and Guest Role .

For more information on the Portal Structure in Liferay , read The Liferay Administrators Guide page 67.

MVC Portlet Development : Service Builder-I

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 18: Liferay-6

Liferay Eclipse Installation

MVC Portlet Development : Directory Structure

In the previous post , we saw the directory structure inherently created by eclipse and the liferay-sdk. Here we shall be introduced to a new concept of service builder.

Liferay sdk has service builder which abstracts all the database building,connecting code from the developer. We just need to create a small xml file and we’ll be done with it.Service builder abstracts all the information by making certain classes on the spring-hibernate framework.It does a lot of things most which might go tangential for us. So while learning service builder its best to focus on whatever is in our hands to code and try not to delve deeper into the service builder codes.There is only one class where we have to do the coding and another which we shall use for communication with the database.

So , opening eclipse again .

Create a new liferay-service.

After clicking on that add the name,package and the namespace as shown.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 19: Liferay-6

Click on finish and then check your directory structure.

You can see that a service.xml file has opened up in the eclipse editor.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 20: Liferay-6

We shall follow a Bottom-Up Approach to make our portlets.

So lets make our Table Design first.

Now each entity specifies the structure of a database table.Entity name will be the name of the table and also of the class which is mapped to that table.

So lets populate the service.xml file. Before that we need to know what all do we require for having a Books Catalog.

1) Title2) Pages3) Date Of Purchase4) Author

Along with these we shall require 3 more fields , userid,groupid and companyid.What is this ?Please Read the following blog before you go ahead.

Liferay Groups Mystery Untangled

Coming back to our earlier discussion of the userId,groupId and companyId, we can now map their relevance with the portal architecture in the background.

UserID: Unique ID assigned to every Registered User.

GroupID : ID of a particular Community on a particular portal instance

CompanyID : ID of a particular portal instance.

UserGroupID : ID of a particular UserGroup.

So Our service.xml would look something like this

?123456789

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.0.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_0_0.dtd"><service-builder package-path="com.books.database"><author>Rohit</author><namespace>B</namespace>

<entity name="Books" local-service="true" remote-service="false"> <column name="bookId" type="long" primary="true"></column> <column name="title" type="String"></column> <column name="author" type="String"></column>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 21: Liferay-6

1011121314151617181920212223242526272829303132

<column name="dateOfPurchase" type="Date"></column> <column name="pages" type="int"></column> <column name="userId" type="long"></column> <column name="companyId" type="long"></column> <column name="groupId" type="long"></column> <order by="asc"> <order-column name="bookId"></order-column> </order> <finder return-type="Collection" name="GroupId"> <finder-column name="groupId"></finder-column> </finder> <finder return-type="Collection" name="CompanyId"> <finder-column name="companyId"></finder-column> </finder> <finder return-type="Collection" name="UserId"> <finder-column name="userId"></finder-column> </finder> <finder return-type="Collection" name="Group_Title"> <finder-column name="groupId"></finder-column> <finder-column name="title"></finder-column> </finder> <finder return-type="Collection" name="Group_Author"> <finder-column name="groupId"></finder-column> <finder-column name="author"></finder-column> </finder></entity></service-builder>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 22: Liferay-6

33343536373839

I’ll try to analyze the entire document line by line.

?1<entity name="Books" local-service="true" remote-service="false">

Defines the Entity name which also assigns the name for the Model Class , which we shall see later.

The table name however shall be assigned as NamespaceEntityname in this case it’ll be BBooks

local-service=true shall create a utility class that can be used on the same jvm , by putting remote-service=true we can create a utility class which can be used inter-jvms.It creates stubs skeletons and handles all the network related connections.

?1<column name="bookId" type="long" primary="true"></column>

Defines the name and type of the column. Primary shud be set only one per entity.

Type can be any primitive datatype or a java Object.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 23: Liferay-6

?123

<order by="asc"> <order-column name="bookId"></order-column></order>

Assigning ascending order on firstname column

?123

<finder return-type="Collection" name="GroupId"> <finder-column name="groupId"></finder-column></finder>

This finder column is another beauty of the Liferay Service Builder. It generates a function , which shall accept groupId as the parameter/argument and return a Collection or a List of Books Objects matching that particular groupId. We can also assign multiple arguments like we have in the above finder groups Group_LastName. Its advisable to have the companyId ,groupId and userId in all entities for implementing the permissioning system in liferay.I shall explain that later.

There is no need to write a finder method for primary key column , as liferay sdk ceates one by default.Inface you do attempt to write a finder element on stand-alone primary key column , it would throw an error. I told you I am here to share my experience :PThe finder methods named as findByFinderName Ex : we have above GroupId so the method signature would be like this List findByGroupId(long arg0) ;

More on Finder Tags

NOTE : Before you go to the next step of building services and generating the code , make sure you are confident about your table structure and that you have entered in all the data well.It Is advisable to have the table design in place, before you go for the service.xml. Once you build the service , you cannot add rename any of the components. Also you cannot add more finder methods.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 24: Liferay-6

Click on Build Services button on top-right corner of the screen.

Then open the console and see the services being build. If you get a Build Succesful as shown in the image above , means you are ready to move on.

If your Build Fails then check for the jre installation. The Build Services shall work only if you have a jdk 1.6 and above. Another source of error would be from spelling mistakes in the finder and order tags. Its also case-sensitive.

If you get runtime exception then , check for spellings or naming and run the build service again.

Also after every build make sure you clean and build your project workspace.Now , when you see the directory structure you’ll say a lot of addditonal files eill be generated.

Here is how it should like.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 25: Liferay-6

The service Builder is working on a spring-hibernate framework.So it generates all these files from somewhere. Don’t bother to understand from where.Its a waste of time unless you are more interested in learning Spring and Hibernate.

The only Class that we shall open here is RegistrationLocalServiceImpl.class and BookLocalServiceImpl.class or in general EntityLocalServiceImpl.

For more info on Service Builder and The class relationships check out this link.

Here we got only LocalServiceImpl classes, but if you were to keep remote-service=true in service.xml

entity name="Book" local-service="true" remote-service="true"

then we would have got EntityServiceImpl , separately . Because you might want to restrict external applications from using some of the functionality .

I shall continue , in my next blog MVC Portlet Development - Service Builder - II

MVC Portlet Development : Service Builder -II

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 26: Liferay-6

MVC Portlet Development : Service Builder -I

Also you can see , that the service builder created a small books-portlet-service.jar file in the WEB-INF/lib directory. This jar file is packaged with all the files in the WEB-INF/service folder.

You can access the Books Database in 2 ways

1) First , by leaving this jar file as it is in the lib folder

2) Secondly , you can just copy this file and paste it in the lib/ext folder of your tomcat .

Basically you are adding the jar file to the global path of tomcat , and you can give access to BBooks table in your database to any portlet. But if you are following the 2nd step , then make sure that you delete this jar file from the lib folder before you deploy the portlet. This is a very common mistake.

Now , in the BooksLocalServiceImpl .class we need to include all the code required to access data.In BooksLocalServiceImpl , similar functions will be included.

Note all the finder methods can be called only by a entityPersistence in this case productPersistence Object inside the BookLocalServiceImpl.class its not availible otherwise.Hence we first need to make wrapper functions for the same.

?12345678910111213141516171819

package com.books.database.service.impl; import com.books.database.NoSuchooksException;import com.books.database.model.Books;import com.books.database.service.base.BooksLocalServiceBaseImpl;import java.util.Collections;import java.util.List;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import com.liferay.portal.kernel.exception.PortalException;import com.liferay.portal.kernel.exception.SystemException;import com.liferay.portal.model.ResourceConstants; /*** The implementation of the books local service.** <p>* All custom service methods should be put in this class. Whenever methods are* added, rerun ServiceBuilder to copy their definitions into the* {@link com.books.database.service.BooksLocalService} interface.* </p>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 27: Liferay-6

20212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465

** <p>* Never reference this interface directly. Always use* {@link com.books.database.service.BooksLocalServiceUtil} to access the books* local service.* </p>** <p>* This is a local service. Methods of this service will not have security* checks based on the propagated JAAS credentials because this service can only* be accessed from within the same VM.* </p>** @author Rohit* @see com.books.database.service.base.BooksLocalServiceBaseImpl* @see com.books.database.service.BooksLocalServiceUtil*/public class BooksLocalServiceImpl extends BooksLocalServiceBaseImpl { public Books addBooks(Books booksParam) { Books booksVar;

try { booksVar = booksPersistence.create(counterLocalService .increment(Books.class.toString())); } catch (SystemException e) { e.printStackTrace(); return booksVar = null; }

try { resourceLocalService.addResources(booksParam.getCompanyId(), booksParam.getGroupId(), booksParam.getUserId(), Books.class.getName(), booksParam.getPrimaryKey(),false, true, true); } catch (PortalException e) { e.printStackTrace(); return booksVar = null; } catch (SystemException e) { e.printStackTrace(); return booksVar = null; }

booksVar.setAuthor(booksParam.getAuthor()); booksVar.setCompanyId(booksParam.getCompanyId()); booksVar.setPages(booksParam.getPages()); booksVar.setDateOfPurchase(booksParam.getDateOfPurchase()); booksVar.setGroupId(booksParam.getGroupId()); booksVar.setTitle(booksParam.getTitle()); booksVar.setUserId(booksParam.getUserId());

try { return booksPersistence.update(booksVar, false); } catch (SystemException e) {

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 28: Liferay-6

66676869707172737475767778798081828384858687888990919293949596979899100101102103104105

e.printStackTrace(); return booksVar = null; }}

public Books getBooksInstance() { try { return booksPersistence.create(counterLocalService .increment(Books.class.getName())); } catch (SystemException e) { e.printStackTrace(); return null; }}

public List<books> getAllBooks(long companyId) { try { return booksPersistence.findByCompanyId(companyId); } catch (SystemException e) { e.printStackTrace(); return Collections.emptyList(); }}

public List<books> getAllBooks() { try { return booksPersistence.findAll(); } catch (SystemException e) { e.printStackTrace(); return Collections.emptyList(); }}

public List<books> getAllBooks(long groupId, String title) { try { return booksPersistence.findByGroup_Title(groupId, title); } catch (SystemException e) { e.printStackTrace(); return Collections.emptyList(); }}

public List<books> getBooksByUserId(long userId) { try { return booksPersistence.findByUserId(userId); } catch (SystemException e) { e.printStackTrace(); return null; }}

public void deleteBooks(long booksId, long companyId) { Books books; try {

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 29: Liferay-6

106107108109110111112113114115116117118119120121122123124125126127128

books = booksPersistence.findByPrimaryKey(booksId); } catch (SystemException e) { e.printStackTrace(); return; } catch (NoSuchooksException e) { e.printStackTrace(); return; } deleteBooks(books, companyId);}

public void deleteBooks(Books books, long companyId) { try { resourceLocalService.deleteResource(companyId, Books.class.getName(), ResourceConstants.SCOPE_INDIVIDUAL, books.getPrimaryKey()); } catch (PortalException e) { e.printStackTrace(); return; } catch (SystemException e) { e.printStackTrace(); return; } try { booksPersistence.remove(books); } catch (SystemException e) { e.printStackTrace(); return; }}

}</books></books></books></books>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 30: Liferay-6

129130131132133134135136137138139140141142143144145146147148149150151

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 31: Liferay-6

152153154155156157158159160161162163164

That’s a lot a of coding. But we should include only that code which we require to communicate with the database.

Note : After writing the code , we must run the Service Builder again and clean the project.Service Builder runs in a reverse way with respect to java specifications i.e.As per the Java Specs , we should first create the interfaces and then implement the functions.But Service Builder does a full u-turn .

It asks us to implement the functions here in the LocalServiceImpl classes and then generates an Interface or an Abstract class with LocalServiceUtil as the postfix.If you read the comment above the class code , it clearly states

* Never reference this interface directly. Always use* {@link com.books.database.service.BooksLocalServiceUtil} to access the

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 32: Liferay-6

books* local service.

i.e. we should use BookLocalServiceUtil always in all the coding. Example if you need to addBook then the call would beBookLocalServiceUtil.addBook() ;

If we had remote-service=true then it would be BookServiceUtil.

In the background , service builder does all the hardwork of creating all Model and Bean classes . We need only to classes . viz ..

1) LocalServiceImpl : for writing implementing all the code

2) LocalServiceUtil : for UTILising the code.

?12345678910

try {bookVar = bookPersistence.create(counterLocalService .increment(Book.class.toString()));} catch (SystemException e) {log.error(e);return bookVar = null;}

bookPersistence is the Object of BookPersistenceIImpl Class in service.impl package. It has implementation of all the basic methods of adding , updating , deleting and finding an entity.Basically implementing all the CRUD operations on databases. Just use shift+space to see all the functions in eclipse.

counterLocalService is an object provided for incrementing primary keys of an entity.To avoid overflowing of the inbuilt 32 bit counter ,we need to specify the class so that it increments only for the particular object.

The above code, just creates an entity or a row in the table , by auto-incrementing its primary key.

It’s a best practice followed by liferay and must be followed.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 33: Liferay-6

?123456

resourceLocalService.addResources(bookParam.getCompanyId(), bookParam.getGroupId(), bookParam.getUserId(), Book.class.getName(), bookParam.getPrimaryKey(), false, true, true);

Liferay is a CMS , and it is resource driven.Every object,blog,wiki,image etc is defined as a resource.

But why ? Why everything needs to be defined as a resource ? to implement Permissioning systems.

Using the above code , we are actually informing the permissioning systems of liferay that we are going to implement certain permissions on the above entity.resourceLocalService is an object of ResourceLocalServiceUtil in liferay.

To define the permission , we require the groupId,companyId and the userId. Hence I had commented while beginning with the liferay service builder that we need to include all 3 of these ids.

Liferay also uses the same approach for making its own entities and tables.They also use Service Builder.

Along with this , we also need to include an xml file , informing liferay what kind of permissions do we need to implement and on whom should we implement.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 34: Liferay-6

As you can see we have added 2 files and a folder.

In the portlet.properties file we have included the path for the permissioning file default.xml , to inform liferay that permissioning system has been implemented in this application.

The contents of portlet.properties is as follows

resource.actions.configs=resource-actions/default.xml

default.xml

?123456789101

<?xml version="1.0" encoding="UTF-8"?> <resource-action-mapping>

<portlet-resource><portlet-name>booksportlet</portlet-name><permissions><supports> <action-key>ADD_BOOKS</action-key> <action-key>VIEW</action-key></supports><community-defaults> <action-key>VIEW</action-key></community-defaults>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 35: Liferay-6

1121314151617181920212223242526272829303132333

<guest-defaults> <action-key>VIEW</action-key></guest-defaults>

<guest-unsupported> <action-key>ADD_BOOKS</action-key></guest-unsupported></permissions></portlet-resource>

<model-resource><model-name>com.books.database.model.Books</model-name><portlet-ref><portlet-name>booksportlet</portlet-name></portlet-ref><permissions><supports> <action-key>DELETE</action-key> <action-key>UPDATE</action-key> <action-key>VIEW</action-key></supports><community-defaults> <action-key>VIEW</action-key></community-defaults><guest-defaults> <action-key>VIEW</action-key></guest-defaults><guest-unsupported> <action-key>UPDATE</action-key> <action-key>DELETE</action-key></guest-unsupported></permissions></model-resource>

</resource-action-mapping>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 36: Liferay-6

43536373839404142434445464748495051

So , now here we are actually having two types of permissions.One on the Portlet another on the Model or the entity.

These permissions can either be defined by the admin by assigning roles and defining permissions for that role , orCan be used programmatically , as we shall see later.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 37: Liferay-6

?123456

<supports> <action-key>DELETE</action-key> <action-key>UPDATE</action-key> <action-key>VIEW</action-key></supports>

In the Supports tag , we need to define all the sort of permissions that need to be implemented on the model or the portlet.Delete,Add,Update,View are all the Possible Permissions defined for this particular Portlet.We can have more such permissions like Scroll , Move etc..

?1234

<community-defaults> <action-key>VIEW</action-key></community-defaults>

Specifies that , these particular permissions will be available to all members of a particular community by default.

For Ex : above community-default VIEW permission has been given ,hence the portlet and the data displayed by the portlet can be viewed by all the members of the community.

Update,Delete permissions can only be assigned by the Admin.

Similarly we have guest-defaults.

?12345

<guest-unsupported> <action-key>UPDATE</action-key> <action-key>DELETE</action-key></guest-unsupported>

All the permissions declared under this tag , will be unavailable for the guest.Even the admin cannot change this.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 38: Liferay-6

A guest would be a non-member of a community or an unregistered member.

You would get an error , in LocalServiceImpl class if you try to use addBook without including the default.xml file.

If you donot want to assign any permissions , then donot use

?123456789

resourceLocalService.addResources(bookParam.getCompanyId(), bookParam.getGroupId(), bookParam.getUserId(), Book.class.getName(), bookParam.getPrimaryKey(), false, true, true);

ResourceLocalServiceUtil.addResources(entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),BlogsEntry.class.getName(), entry.getPrimaryKey().toString(),false,addCommunityPermissions, addGuestPermissions);

The last three are Boolean variables , specifying whether we are supposed to add the permissions or not.

False means that portlet level permissions should be omitted.

For More on Security framework , read Page 56 of Liferay Developers Guide

MVC Portlet Development : MVC Framework and AlloyUI

What we have done so far ,

Eclipse Installation

Directory Structure

Service Builder - I

Service Builder - II

and continuing to the last part . The MVC Framework and Alloy UI

Every Portlet on a portal page , will have a different render and request cycle.

In servlet we either implement a doGet or a doPost method which handle the response and the request in the same cycle. But here in the Portlet

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 39: Liferay-6

specification jsr-286 , the request and rendering or response is handled separately.

In the Portlet cycle , we have two main methods processAction and render.

processAction handles all the requests and render handles the response.When the portlet is loaded for the first time , render is called to load the default view lets say a form.When you fill the form and send it across processAction will be called to get all the form data.Once the processAction is executed you can specify a jsp page where the next event has to be handlded. By default it will go to the home page.

But in the MVCPorrlet interface , all these things have been abstracted for us. We donot need to implement any of these render or processAction methods.

In portlet.xml we specified view-jsp as n initial parameter.This is nothing but the location of the default page that loads when the portlet is loaded for the first time or whenever no action is called.

In MVC Portlet , there is a simple way of sending a request and rendering the response.

Below is the code of a JSP file and its corresponding MVC portlet.?1234567891011121314151

<%@ include file="/init.jsp"%><%Books book = (Books) request.getAttribute("book");if (book == null) {book = new BooksImpl();Calendar now = CalendarFactoryUtil.getCalendar();now.set(1970, 1, 1);book.setDateOfPurchase(now.getTime());}

%><liferay-portlet:actionURL name="addBook" var="addBookURL"></liferay-portlet:actionURL><liferay-ui:success key="book-added" message="book-added" /><liferay-ui:success key="book-deleted" message="book-deleted" /><liferay-ui:error key="error-deleting" message="error-deleting" /><liferay-ui:error key="error-while-adding" message="error-while-adding" /><aui:form action="<%=addBookURL.toString() %>" method="post" name="fm"> <aui:fieldset><liferay-ui:error key="title-required" message="title-required" /><p><aui:input name="title" label="Title" type="text"value="<%=book.getTitle() %>"></aui:input></p><liferay-ui:error key="author-required" message="author-required" /><p>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 40: Liferay-6

6171819202122232425262728293031323334353637383

<aui:input name="author" label="Author" type="text"value="<%=book.getAuthor() %>"></aui:input></p><liferay-ui:error key="pages-required" message="pages-required" /><liferay-ui:error key="pages-cannot-be-zero"message="pages-cannot-be-zero" /><p><aui:input name="pages" label="Pages" type="text"value="<%=String.valueOf(book.getPages()) %>"></aui:input></p><liferay-ui:error key="dop-required" message="dop-required" /><p><%Calendar dop = CalendarFactoryUtil.getCalendar(); dop.setTime(book.getDateOfPurchase());%><aui:input model="<%=Books.class %>" bean="<%=book%>"label="Date of Purchase" name="dateOfPurchase" value="<%= dop %>" /> </p><aui:button-row><p><aui:button class="aui-button-input" type="submit" value="Submit" /><aui:button class="aui-button-input" type="reset" value="Reset" /></p></aui:button-row></aui:fieldset></aui:form>

<liferay-ui:search-container emptyResultsMessage="no-books" delta="5"><liferay-ui:search-container-results><%List<Books> tempResults = (List<Books>) BooksActionUtil .getAllBooks(themeDisplay.getCompanyId());

results = ListUtil.subList(tempResults, searchContainer.getStart(), searchContainer.getEnd()); total = tempResults.size();

pageContext.setAttribute("results", results); pageContext.setAttribute("total", total);%></liferay-ui:search-container-results>

<liferay-ui:search-container-rowclassName="com.books.database.model.Books" keyProperty="bookId"modelVar="book1">

<liferay-ui:search-container-column-text name="Title" property="title" /><liferay-ui:search-container-column-text name="Author"property="author" /><liferay-ui:search-container-column-text name="Pages" property="pages" /><liferay-ui:search-container-column-text name="Date of Purchase"property="dateOfPurchase" />

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 41: Liferay-6

9404142434445464748495051525354555657585960616

<% long groupId = themeDisplay.getLayout().getGroupId(); String name = Books.class.getName(); String bookId = String.valueOf(book.getPrimaryKey());%><c:iftest="<%= permissionChecker.hasPermission(groupId, name,bookId,"DELETE") %>"><liferay-ui:search-container-column-jsp name="Delete"path="/jsps/display_actions.jsp" align="right" /></c:if></liferay-ui:search-container-row>

<liferay-ui:search-iterator />

</liferay-ui:search-container>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 42: Liferay-6

2636465666768697071727374757677787980818283848

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 43: Liferay-6

58687888990919293949596979899

?123456789101112

import java.util.ArrayList;import java.util.List; import javax.portlet.ActionRequest;import javax.portlet.ActionResponse; import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory; import com.books.database.model.Books;import com.books.database.service.BooksLocalServiceUtil;import com.books.util.BooksActionUtil;import com.books.util.BooksValidator;import com.liferay.portal.kernel.exception.SystemException;import com.liferay.portal.kernel.servlet.SessionErrors;import com.liferay.portal.kernel.servlet.SessionMessages;import com.liferay.portal.kernel.util.ParamUtil;

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 44: Liferay-6

1314151617181920212223242526272829303132333435

import com.liferay.portal.kernel.util.Validator;import com.liferay.portal.kernel.util.WebKeys;import com.liferay.portal.theme.ThemeDisplay;import com.liferay.util.bridges.mvc.MVCPortlet; /*** Portlet implementation class BooksPortlet*/public class BooksPortlet extends MVCPortlet { private static Log log = LogFactory.getLog(BooksPortlet.class);private static String errorJSP="/jsps/error.jsp" ; public void addBook(ActionRequest request, ActionResponse response) { log.info("Inside addBooks");List<String> errors=new ArrayList<String>();Books book=BooksActionUtil.getBookFromRequest(request);boolean bookValid=BooksValidator.validateBook(book,errors);if(bookValid) {try {log.info(book);Books test=BooksLocalServiceUtil.addBooks(book);if(test==null) { log.error("Book was Found Null"); response.setRenderParameter("jspPage", errorJSP); return ;}} catch (SystemException e) {log.error(e);/*If there is an error then divert the control to the error page.*/response.setRenderParameter("jspPage", errorJSP);return ;}SessionMessages.add(request,"book-added");return ;}else {for (String error : errors) { SessionErrors.add(request, error);}SessionErrors.add(request, "error-while-adding");request.setAttribute("book",book);return ;}

}

public void deleteBooks(ActionRequest request, ActionResponse response) { long bookId = ParamUtil.getLong(request, "bookId");ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 45: Liferay-6

3637383940414243444546474849505152535455565758

if (Validator.isNotNull(bookId)) {BooksLocalServiceUtil.deleteBooks(bookId, themeDisplay.getCompanyId());SessionMessages.add(request, "book-deleted");

} else {SessionErrors.add(request, "error-deleting");

}

}}

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 46: Liferay-6

5960616263646566676869707172737475767778798081

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 47: Liferay-6

82838485

<liferay-portlet:actionURL name="addBook" var="addBookURL"></liferay-portlet:actionURL>

In Portlet , we cannot create our own links, the way we do it in servlets . We need to create URLs to submit a form or to perform some action.

The above code , maps the to the function

public void addBook(ActionRequest request, ActionResponse response) {in the BooksPortlet class.

The name in actionURL tag is the name of the function that is implemented in the portlet class. The var is just a variable holding the link.

So while creating a form , we specify it in the following manner .?12<aui:form action="<%=addBookURL.toString() %>" method="post" name="fm">

Just like actionURL , we also have renderURL .?12345

<liferay-portlet:renderURL var=”successURL”><portlet:param name=”jspPage” value=”success.jsp” /><liferay-portlet:renderURL><a href=”<%=successURL.toString()%>”>Success</a>

It basically renders a jsp or an HTML page.

?12portlet:param name=”jspPage” value=”success.jsp” />

For rendering any JSP , MVCPortlet framework , has the above syntax.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 48: Liferay-6

For rendering after completing an action , we have

?12response.setRenderParameter(“jspPage”,”jspLocation”) ;

Calls to these functions , are followed by execution of thePublic void render(RenderRequest request,RenderResponse response) function internally.

BooksActionUtil.class

As you have seen in the BooksPortlet , we have called two functions ,?123

Books book=BooksActionUtil.getBookFromRequest(request);boolean bookValid=BooksValidator.validateBook(book,errors);

This is a standard procedure followed by Liferay , to reduce concentrating all the code in one class itself. Like common , it follows more out of practise and common sense. So here , are the two classes , BooksActionUtil.class and BooksValidator.class

?123456789101112131

package com.books.util; import java.util.*; import javax.portlet.ActionRequest; import com.books.database.model.Books;import com.books.database.model.impl.BooksImpl;import com.books.database.service.BooksLocalServiceUtil;import com.liferay.portal.kernel.exception.PortalException;import com.liferay.portal.kernel.util.ParamUtil;import com.liferay.portal.kernel.util.Validator;import com.liferay.portal.kernel.util.WebKeys;import com.liferay.portal.theme.ThemeDisplay;import com.liferay.portal.util.PortalUtil; public class BooksActionUtil { public static Books getBookFromRequest(ActionRequest request) {ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 49: Liferay-6

4151617181920212223242526272829303132333435363

String title = ParamUtil.getString(request, "title","Title Not Availible");String author = ParamUtil.getString(request, "author","Author Not Availible");String pageStr = ParamUtil.getString(request, "pages", "0");int pages = 0;if (Validator.isDigit(pageStr)) {pages = Integer.parseInt(pageStr);}// Month ,Day and Year are a prefix which must be givenint dopMonth = ParamUtil.getInteger(request, "dateOfPurchaseMonth");int dopDay = ParamUtil.getInteger(request, "dateOfPurchaseDay");int dopYear = ParamUtil.getInteger(request, "dateOfPurchaseYear"); Books book = new BooksImpl();book.setAuthor(author);book.setPages(pages);book.setTitle(title);book.setCompanyId(themeDisplay.getCompanyId());book.setGroupId(themeDisplay.getLayout().getGroupId());book.setUserId(themeDisplay.getUserId());if (Validator.isDate(dopMonth, dopDay, dopYear)) {try { book.setDateOfPurchase(PortalUtil.getDate(dopMonth, dopDay,dopYear, new PortalException())); } catch (PortalException ex) {//Setting to Null Will enable us to catch it in the Validatorbook.setDateOfPurchase(null);}} else {book.setDateOfPurchase(null);}return book;}

public static List<books> getAllBooks(long companyId) { return BooksLocalServiceUtil.getAllBooks(companyId);}

}</books>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 50: Liferay-6

7383940414243444546474849505152535455565758596

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 51: Liferay-6

06162636465

BooksVaildator.class

?1234567891011121314151617181920

package com.books.util;import java.util.* ; import com.books.database.model.Books;import com.liferay.portal.kernel.util.Validator; public class BooksValidator { public static boolean validateBook(Books book, List<string> errors) { boolean valid=true ;if (Validator.isNull(book.getTitle())) { errors.add("title-required"); valid = false;}

if (Validator.isNull(book.getAuthor())) { errors.add("author-required"); valid = false;}

if (Validator.isNull(book.getDateOfPurchase())) { errors.add("dop-required"); valid = false;}

if (Validator.isNull(book.getPages())) { errors.add("pages-required"); valid = false;}if(book.getPages()==0) {errors.add("pages-cannot-be-zero"); valid = false;}return valid ;}

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 52: Liferay-6

21222324252627282930313233343536373839

}

ThemeDisplay

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 53: Liferay-6

?123

ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);

themeDisplay is an object containing all the information about the page, its layout, about the user whether he is logged in or not , certain fixed urls like create account , sign in etc. from themeDisplay we can get information about the company,group,user the particular page is associated with. It’s a very important object.

Here is the documentation of the ThemeDisplay Object and its functions.

Here is the Screen Shot of the portlet that we have created.

DatePicker

The date picker object Is very simple to implement. Here is the implementation code.

?123456789101

<p><%Calendar dop = CalendarFactoryUtil.getCalendar();dop.setTime(book.getDateOfPurchase());%><aui:input model="<%=Books.class %>" bean="<%=book%>"label="Date of Purchase" name="dateOfPurchase" value="<%= dop %>" /> </p>

//And here is how you would retrieve the Date object,

nt dopMonth = ParamUtil.getInteger(request, "dateOfPurchaseMonth");int dopDay = ParamUtil.getInteger(request, "dateOfPurchaseDay");

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 54: Liferay-6

112131415161718192021222324252627282930

int dopYear = ParamUtil.getInteger(request, "dateOfPurchaseYear"); if (Validator.isDate(dopMonth, dopDay, dopYear)) {try { book.setDateOfPurchase(PortalUtil.getDate(dopMonth, dopDay, dopYear, new PortalException()));} catch (PortalException ex) {/* Setting to Null Will enable us to catch it in the Validator */book.setDateOfPurchase(null);}} else {book.setDateOfPurchase(null);}

For the date picker , it is necessary to provide the Model and the bean attributes to the input tag.In the src/META-INF folder , we have a n xml file where we can set restrictions on the datatypesportlet-model-hints.xml

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 55: Liferay-6

?1234567891011121314151617181920

<?xml version="1.0" encoding="UTF-8"?> <model-hints><model name="com.books.database.model.Books"><field name="bookId" type="long" /><field name="title" type="String" /><field name="author" type="String" /><field name="dateOfPurchase" type="Date"><hint name="year-range-delta">90</hint><hint name="year-range-future">true</hint><hint name="show-time">false</hint></field><field name="pages" type="int" /><field name="userId" type="long" /><field name="companyId" type="long" /><field name="groupId" type="long" /></model></model-hints>

We can also restrict the lenth of certain fields using?12<hint name=”max-length”>4000</hint>

For more info on model-hints , take a look at the liferay source code ,portal-impl/src/META-INF/portal-modelt-hints.xml file.

Model-Hints

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 56: Liferay-6

NOTE : While using the date field , the name attribute of the input tage should match with the name attribute of the field tag in portlet-model-hint.

ParamUtil and PortalUtil.

ParamUtil is a utility class provided by liferay to extract the parameters from the query strings with a lot of added functionality.For Example :?12String title = ParamUtil.getString(request, "title","Title Not Availible");

Here the getString method is having 3 parameters, request object ,the parameter name , and the default parameter if in case there is an error in the connection or the session is timed out.

ParamUtil Documentation .

PortalUtil is also a utility class having some portal related functions

Liferay Also provides a Validator class , which we can use to validate all predefined java primitives and objects.Life email address,phonenumber , street address , null check etc.Validator Documentation

Liferay-Search Container

Liferay provides yet another awesome feature of generating a tabular container , with navigation capabilities.Its also pretty simple to implement. You just needs the list of Object that needs to be displayed.That object can either be Model class or our Own bean class.

?1 <liferay-ui:search-container emptyResultsMessage="no-books" delta="5">

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 57: Liferay-6

2345678910111213141516171819202122232425262728

<liferay-ui:search-container-results><%List<Books> tempResults = (List<Books>) BooksActionUtil .getAllBooks(themeDisplay.getCompanyId());

results = ListUtil.subList(tempResults, searchContainer.getStart(), searchContainer.getEnd()); total = tempResults.size();

%></liferay-ui:search-container-results>

<liferay-ui:search-container-rowclassName="com.books.database.model.Books" keyProperty="bookId"modelVar="book1">

<liferay-ui:search-container-column-text name="Title" property="title" /><liferay-ui:search-container-column-text name="Author"property="author" /><liferay-ui:search-container-column-text name="Pages" property="pages" /><liferay-ui:search-container-column-text name="Date of Purchase"property="dateOfPurchase" /><% long groupId = themeDisplay.getLayout().getGroupId(); String name = Books.class.getName(); String bookId = String.valueOf(book.getPrimaryKey());%><c:iftest="<%= permissionChecker.hasPermission(groupId, name,bookId,"DELETE") %>"><liferay-ui:search-container-column-jsp name="Delete"path="/jsps/display_actions.jsp" align="right" /></c:if></liferay-ui:search-container-row>

<liferay-ui:search-iterator />

</liferay-ui:search-container>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 58: Liferay-6

293031323334353637383940

In the <liferay-ui:search-container-results> tag , we first populate the list . It counts the number of elements.

<liferay-ui:search-container-row> this tag , is used to display the all the information , But we must make sure to give the correct class name and the primary key

Note : Make sure you specify your "className", "keyProperty" name exactly the way you have written in service.xml, It is case-sensitive , and the "modelVar" is just a variable name, You can name it whatever you want just make sure that name doesnt repeat throughout the entire jsp document.

?123

<liferay-ui:search-container-column-text name="Title" property="title" />Note : Make sure that the property matches the exact property name given in service.xml

You might come across a situation where the data in your column is not matching the UI requirement , Like for Example , you store the date in 1970,11,11 and now you want to format this date before you put it up on search-container , how to go about that ?

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 59: Liferay-6

Simple , Just create a new Class , and just to follow proper naming convention , post-fix the class name with "Bean"Then create instance variables , of the class same as that in service.xml , you can also give them different namesFor Example , for the books portlet ,

?12345678910111213141516171819202122232

package com.books.util;import java.util.* ; public class BooksBean { private long bookId ;private String title ;private String author ;private Date dop ;private int pages ;private long userId ;private long companyId ;private long groupId ;public long getBookId() {return bookId;}public void setBookId(long bookId) {this.bookId = bookId;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public Date getDop() {//Write your Own Simple Date Formatter Code Herereturn dop;}public void setDop(Date dop) {this.dop = dop;}public int getPages() {return pages;}public void setPages(int pages) {this.pages = pages;}public long getUserId() {return userId;

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 60: Liferay-6

4252627282930313233343536373839404142434445464

}public void setUserId(long userId) {this.userId = userId;}public long getCompanyId() {return companyId;}public void setCompanyId(long companyId) {this.companyId = companyId;}public long getGroupId() {return groupId;}public void setGroupId(long groupId) {this.groupId = groupId;}

}

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 61: Liferay-6

748495051525354555657585960616263646566

then refer modelClass=com.package.name.BooksBean and the keyProperty=bookId or whatever you have chosen in your beanClass.

Also while populating the List donot forget to map each property of Bean to the Actual Class

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 62: Liferay-6

?123456789101112

List<booksbean> list= new ArrayList<booksbean>();List<books> originalList=getAllBooks(companyId) ;

for(Books b:originalList){BooksBean bean= new BooksBean(); bean.setCompanyId(b.getCompanyID);and so ...

}

</books></booksbean></booksbean>

More on Search Container

Liferay-Permission Checker

Checking permission in liferay is just a matter of calling a function .?12permissionChecker.hasPermission(groupId, name,bookId,"DELETE") ;

This function , is given the groupId , the name of the class , the primary key of the class and the type of Action supported.

We have defined all this in the default.xml file under the resource-actions folder.

The above permissionChecker , simply passes on these parameters and checks it against the permissions given to the particular user . If the user has permission it will return true , else false.

We have used the permission checker to toggle the Delete functionality for different users . Any user having role for which delete functionality has been granted permission . will see the delete icon , else wont.

Here is a screen shot displaying the permissionChecker in action , with 2 images of the portlet on before log-in and one after log-in.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 63: Liferay-6

Pre-Login .

Post-Login

PermissionChecker API

Liferay Messages

?1234567

SessionMessages.add(request,"book-added");<liferay-ui:success key="book-added" message="book-added" /> SessionErrors.add(request, "error-while-adding");<liferay-ui:error key="error-while-adding" message="error-while-adding" />

SessionMessages and SessionErrors , are two classes which ease out sending out messages to the users or while debugging.

Few Uses of the liferay-error :

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 64: Liferay-6

?123456

<liferay-ui:error message="this-is-an-error" key="key" /> SessionErrors.add(actionRequest, e.getClass().getName(), e);

<liferay-ui:error exception="<%=SomeException.class%>" message="your-message" />

The message attribute contains the key to the key-value pair store in the Language.properties file.

Language.properties :book-added=Books have been Added Successfully !error-while-adding=Some Error has Occured While Adding, Please Try Again

If you click on Submit with all the fields empty , it will show you the above messages.

Some More Useful Links :

Liferay-UI TagLib :

Liferay Freak :

Minesweeper Portlet Game

Main Page of Development Articles in Liferay

From DB to simple UI

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 65: Liferay-6

Liferay MVC Framework :

Liferays Permissioning System :

Portal Properties Liferay 6.0.5

Alloy UI Forms :

Alloy-UI Scripting basics :

Alloy-ui Working with widgets :

Alloy-ui Working with Ajax :

and plug-ins :

Liferay : Default Landing Page

import java.util.HashMap;

We have seen in liferay that , when we login , we get directed to the Welcome Page of Liferay.An interesting questions would be how to change that default functionality ?Its simple. Liferay provides certain events1) Start-up Events 2) Shut-Down Events 3) Portal Events

Now we are interested in Portal Event which have 4 Types1) Pre Login2) Post Login3) Pre Logout4) Post Logout

1) Open your portlet-ext.properties file and insert the following lines

login.events.post=com.liferay.portal.events.LoginPostAction,com..defaultlandingpage.CustomLandingPageActionauth.forward.by.last.path=truedefault.landing.page.path=

So Basically , the format islogin.events.post=com.liferay.portal.events.LoginPostAction,your.package.cl

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 66: Liferay-6

ass.name

By inputting this line you are informing liferay that , the default functionality of LoginPostAction class has been overriden by your custom class.

Now how to achieve this overriding behavior ? Thats a multi-million dollar question !

import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import com.liferay.portal.kernel.events.Action;import com.liferay.portal.kernel.exception.PortalException;import com.liferay.portal.kernel.exception.SystemException;import com.liferay.portal.kernel.log.Log;import com.liferay.portal.kernel.log.LogFactoryUtil;import com.liferay.portal.kernel.struts.LastPath;import com.liferay.portal.kernel.util.PropsKeys;import com.liferay.portal.kernel.util.StringPool;import com.liferay.portal.kernel.util.Validator;import com.liferay.portal.kernel.util.WebKeys;import com.liferay.portal.model.User;import com.liferay.portal.util.PortalUtil;

public class CustomLandingPageAction extends Action {private static Log _log = LogFactoryUtil.getLog(CustomLandingPageAction.class);

public void run(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); String path = null; User user = null;

if( session != null ){ try { user = PortalUtil.getUser(request); path = user.getScreenName(); _log.debug("path = " + path); } catch (PortalException e) { _log.error("Error: " + e.getMessage()); } catch (SystemException e) { _log.error("Error: " + e.getMessage()); } }

if (Validator.isNotNull(path) && user != null){ //login user with its default page LastPath lastPath = new LastPath(StringPool.BLANK, "/user/"+path, new HashMap()); _log.info("Use Default User Path: " + lastPath.toString()); session.setAttribute(WebKeys.LAST_PATH, lastPath); } else{ //use the default landing page from config. _log.info("Using the default landing page from config");

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 67: Liferay-6

setDefaultLandingPagePath(session); }}

private void setDefaultLandingPagePath(HttpSession session) {String path=PropsKeys.DEFAULT_LANDING_PAGE_PATH;if (Validator.isNotNull(path)) { LastPath lastPath = new LastPath(StringPool.BLANK, path, new HashMap()); session.setAttribute(WebKeys.LAST_PATH, lastPath); _log.debug("Use System Config LastPath URL: "+ lastPath.toString()); System.out.println("Use System Config LastPath URL: "+ lastPath.toString()); }else {_log.error("Default Landing Page is Null");}}}

The Run Method will be called the moment the user Logs In.

user = PortalUtil.getUser(request);path = user.getScreenName();

Using the above method we get all the details of the user , like the screen name.

Now , when you start liferay , form your tomcat machine , you specify the path ashttp://localhost:8080

This path is basically your domain name. When the user logs in , Liferay by Default, appends "/web/group/home". This basically is the address of the Default Public Community of liferay called liferay.com.You can always go to the communities and check.There will be a liferay.com community which is public and has no private pages.It has only one public Page.

layout.friendly.url.private.group.servlet.mapping=/grouplayout.friendly.url.private.user.servlet.mapping=/userlayout.friendly.url.public.servlet.mapping=/web

Now these are the layout friendly URLs , which map to specific pages of liferay.

The first one "/group" maps to the private page of a community."/user" Maps to the private page of the user.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 68: Liferay-6

"/web" Maps to the public page of a public community.

Now, we know how the mapping takes place.But how to actually Map the page in the code ?

if (Validator.isNotNull(path) && user != null){ //login user with its default page LastPath lastPath = new LastPath(StringPool.BLANK, "/user/"+path, new HashMap()); _log.info("Use Default User Path: " + lastPath.toString()); session.setAttribute(WebKeys.LAST_PATH, lastPath); } else{ //use the default landing page from config. _log.info("Using the default landing page from config"); setDefaultLandingPagePath(session); }

Here , the variable "path" is actually holding the screenname of the user.So first we check , whether the user logged in is a registered user or Not. If he is not then forward him to "web/guest/home" page which is the default page set with the property

company.default.home.url=/web/guest

Then notice that, in the lastPath variable declaration we are setting the path as"user"+path This basically means we shall have something like this when lets say you sign in as Test Test

http://localhost:8080/user/joebloggs/home

"home" is the first page of the private layout of Joe Bloggs.

Keeping all the code same , we can in this way modify the default Landing page of the user PostLogin.

similary we can have a user directed directly to the private page of his community , by simply appending the "group"+path , path being the name of the community.

Now , what if , you want to have a particular Private Page for particular group of users , like you may have a different customization for different users , For Ex : If you have a College Portal , there might be students of Arts,Commerce and Science, And for each you might want to have a different page. What to do ?

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 69: Liferay-6

Simple, just create differerent UserGroups and design the public/private pages according to the requirement. It Works ! and its very Simple !

Now , about deployment. This is a bit tricky.y

In eclipse , you"ll need to create a new liferay project. And since with every project you always get a portlet , this time you will have to ingore that portlet.Just create a different package , a new class , and then simply paste the code above in that class. Modify it as per your requirement , but now i am sure you know what you really need to modify. just the lastPath Object.Nothing else. Keep everything the same.Once that is done , just export that package , as a jar file and put that jar file in the lib directory of tomcat.

Also , donot forget to add the following lines to portal-ext.properties file

login.events.post=com.liferay.portal.events.LoginPostAction,com..defaultlandingpage.CustomLandingPageActionauth.forward.by.last.path=truedefault.landing.page.path=

Enjoy !!!

Liferay HOWTOs - I

There are a lot of places where liferay can tuned and tweaked . I shall discus some of them.Most of these tweaks can be done by looking at Portal Properties 6.0.5

1) How to change the domain name from liferay.com to example.com

Company Properties

company.default.web.id=liferay.com

change it to example.com

2) How to change my login ? If i want to use screen name instead of emailAddress

company.security.auth.type=emailAddress#company.security.auth.type=screenName#company.security.auth.type=userId

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 70: Liferay-6

In the above case , screenName and userId are commented out using #

3) Password Related

• Set this to true to allow users to ask the portal to send them their password.company.security.send.password=true

• Set this to true to allow users to ask the portal to send them a password reset link.company.security.send.password.reset.link=true

• Set the following encryption algorithm to encrypt passwords. The defaultalgorithm is SHA (SHA-1). If set to NONE, passwords are stored in thedatabase as plain text. The SHA-512 algorithm is currently unsupported.

#passwords.encryption.algorithm=CRYPT#passwords.encryption.algorithm=MD2#passwords.encryption.algorithm=MD5#passwords.encryption.algorithm=NONEpasswords.encryption.algorithm=SHA#passwords.encryption.algorithm=SHA-256#passwords.encryption.algorithm=SHA-384#passwords.encryption.algorithm=SSHA

Uncomment whichever password encryption algo you would like http://www.blogger.com/img/blank.gifto use

• Set your own regex pattern for your Passwordpasswords.regexptoolkit.pattern=(?=.{4})(?:[a-zA-Z0-9]*)

• Set this to true to allow the user to choose a password during account creation.login.create.account.allow.custom.password=false

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 71: Liferay-6

More On Passwords

4) I want to have my own Login portlet , what to do ?

Change the following properties with your own login Portlet id

auth.login.portlet.name=58

here 58 is the portletId or the portlet name of Login Portlet used in Liferay.

In your Portlet , use the following functions to add users and depending on your requirement add them to their respective groupshttp://www.blogger.com/img/blank.gif

?1234567

User user = UserLocalServiceUtil.addUser(0, companyId, autoPassword,password1, password2, autoScreenName,screenName, emailAddress,facebookId, openId, locale,, middleName, lastName,prefixId, suffixId, male,birthdayMonth, birthdayDay,birthdayYear, jobTitle,groupIds, organizationIds, roleIds,userGroupIds, sendEmail, serviceContext);

UserLocalServiceUtil

GroupLocalServiceUtil

UserGroupLocalServiceUtil

RoleLocalServiceUtil

4) Get Rid of the remind queries while Registration

To enable them set both to true.

users.reminder.queries.enabled=falseusers.reminder.queries.custom.question.enabled=false

5) Static Portlets

Set the static portlets that will appear for every layout. See /html/portal/layout/view/portlet.jspfor the logic of when these portlets will be shown. For example, these portlets will only show for layouts that can contain portlets and are not in a pop up state.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 72: Liferay-6

layout.static.portlets.all=1_WAR_chatportlet

6) If you want to remove the wrench-shaped icon for Look and Feel and Configuration, you can add the following code to your portlet JSP file:

?123456

<%ThemeDisplay themeDisplay= (ThemeDisplay)renderRequest.getAttribute(WebKeys.THEME_DISPLAY);PortletDisplay portletDisplay= themeDisplay.getPortletDisplay();portletDisplay.setShowConfigurationIcon(false); %>

7) SignIn , CreateAccount Links in themeDisplay

?123456789101112

//Check Whether the user is signed in or notthemeDisplay.isSignedIn();// Liferay Defined URLs in themeDusplay

themeDisplay.getURLAddContent();themeDisplay.getURLControlPanel();themeDisplay.getURLCreateAccount();themeDisplay.getURLHome();themeDisplay.getURLSignIn();themeDisplay.getURLSignOut();

8) How can I give all my users the ability to Maxmize and Minimize portlets abilities only?

For guest we can do in portal-ext.properties while for users u need to customize portlet.vm file of your theme. it can be done like this #if ($permissionChecker.isCompanyAdmin($company_id)) $theme.iconOptions() $theme.iconClose()#end so admin only can see all icon . and all other users will get only maximize and minimized icon. Don't forget to stop and start the server after modifying vm files...

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 73: Liferay-6

9) What are some suggestions on improving start up time under a VM?

It may take several (five-plus) minutes to reboot Liferay. We are running 4.1 Liferay Enterprise in a virtual web server. I've removed unused portlets to try to cut down the booting speed, but that doesn't help much. What are other ways available to speed up? Of course, a physical server rather than a virtual server will help. What else? Adding more memory to the JVM via the argument of: -Xmx1024m will help.Depending on what you are using Liferay for, you can remove uneeded webapps under /webapps (for Tomcat). Another thing that will help is to set:

index.on.startup=false

in portal-ext.properties. This property tells Lucene not to reindex content that is part of the portal.

10) How do you completely hide portlets with borders that users don’t have permission to see?

To change this feature for all the portlets in the portal, set the following parameter in portal.properties to "false": layout.show.portlet.access.denied=false To change this feature on a per portlet level, set the "show-portlet-access-denied" parameter in liferay-portlet.xml to "false" for a particular portlet. The setting in liferay-portlet.xml will override the setting in portal.properties.

11) How do you completely hide portlets with borders that are inactive?

To change this feature for all the portlets in the portal, set the following parameter in portal.properties to "false":

layout.show.portlet.inactive=false

To change this feature on a per portlet level, set the "show-portlet-inactive" parameter in liferay-portlet.xml to "false" for a particular portlet. The setting in liferay-portlet.xml will override the setting in portal.properties.

12) How do you display/store images in Liferay?

There are 2 ways to display images in Liferay:

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 74: Liferay-6

1) There is a portlet called "Image Gallery" that can be used to upload images to the portal. These images can then be accessed in your HTML in the following way:

?12<img src="/image/image_gallery?img_id=1001">

Obviously, this may not be the optimal way to access images because you would have to know each image's ID in order to display it. However, this is probably the quickest and least intrusive way to do it.

2) Images can be put into the theme of your page. Each theme has the same directory structure, and one of those directories is the "images" directory. Within the images directory, we've further divided the image files into more granular directories (e.g., blogs, document_library, message_boards, etc.). You can create your own directory and place any image files that you may need here. You would then access the files in the following way:

?12<img src="<%= themeDisplay.getPathThemeImage() %>/your_portlet/some_image.gif">

Reference for Questions 8-12

13) How Do i Associate new Users with a Default community or a default landing page ?

14) How to add Expression Language EL in JSPs in Liferay ?

add the following lines in your init.jsp or your jsp page using the EL?12<%@ page contentType="text/html" isELIgnored="false" %>

Will Keep Adding as and when i come across new thing

Liferay UI Taglib

Here are a few UI TagLibs defined by liferay which can be used in your jsps. For a few of the tags i have also displayed the code of how to retrieve it in the your Portlet.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 75: Liferay-6

1) Displaying the Users Pictures and Name , with link into the MyAccount Page

?12345678

<c:if test="<%=themeDisplay.isSignedIn()%>" > <liferay-ui:user-displaydisplayStyle="0"userId="<%= themeDisplay.getUser().getUserId() %>"/></c:if>

2) Displaying Option for Selecting Languages with Flags?12345

//Shows Flags<liferay-ui:language displayStyle="0" languageIds='<%= new String[]{"en_US","en_GB","en_AU"} %>' />// Shows as a drop down list<liferay-ui:language displayStyle="3" languageIds='<%= new String[]{"en_US","en_GB","en_AU"} %>' />

3) Liferay UI Tabs

4) Date Picker

The date picker object Is very simple to implement. Here is the implementation code.

?123456789

<p><%Calendar dop = CalendarFactoryUtil.getCalendar();dop.setTime(book.getDateOfPurchase());%><aui:input model="<%=Books.class %>" bean="<%=book%>"label="Date of Purchase" name="dateOfPurchase" value="<%= dop %>" /> </p>

//And here is how you would retrieve the Date object,

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 76: Liferay-6

1011121314151617181920212223242526272829

nt dopMonth = ParamUtil.getInteger(request, "dateOfPurchaseMonth");int dopDay = ParamUtil.getInteger(request, "dateOfPurchaseDay");int dopYear = ParamUtil.getInteger(request, "dateOfPurchaseYear"); if (Validator.isDate(dopMonth, dopDay, dopYear)) {try { book.setDateOfPurchase(PortalUtil.getDate(dopMonth, dopDay,dopYear, new PortalException()));} catch (PortalException ex) {/* Setting to Null Will enable us to catch it in the Validator */book.setDateOfPurchase(null);}} else {book.setDateOfPurchase(null);}

For the date picker , it is necessary to provide the Model and the bean attributes to the input tag.In the src/META-INF folder , we have a n xml file where we can set

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 77: Liferay-6

restrictions on the datatypesportlet-model-hints.xml

?12345678910111213141516171819

<?xml version="1.0" encoding="UTF-8"?> <model-hints><model name="com.books.database.model.Books"><field name="bookId" type="long" /><field name="title" type="String" /><field name="author" type="String" /><field name="dateOfPurchase" type="Date"><hint name="year-range-delta">90</hint><hint name="year-range-future">true</hint><hint name="show-time">false</hint></field><field name="pages" type="int" /><field name="userId" type="long" /><field name="companyId" type="long" /><field name="groupId" type="long" /></model></model-hints>

We can also restrict the length of certain fields using?12<hint name=”max-length”>4000</hint>

For more info on model-hints , take a look at the liferay source code ,portal-impl/src/META-INF/portal-modelt-hints.xml file.

Model-Hints

NOTE : While using the date field , the name attribute of the input tage should match with the name attribute of the field tag in portlet-model-hint.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 78: Liferay-6

5) Liferay-UI Panel

?1234567

<liferay-ui:panel-container ><liferay-ui:panel id="panelId" title="Any Title" collapsible="true" extended="true" >Any Content here<liferay-ui:</liferay-ui:panel></liferay-ui:panel-container >

7) Liferay Text Area

?12<liferay-ui:input-textarea param="aoi" defaultValue="Your Areas of Interest" />

8) Liferay Time Select

?1234567

<liferay-ui:input-timeamPmParam="ampm"hourParam="hour"minuteParam="min"minuteInterval="10"/>

9) Liferay Text Editor

?12<liferay-ui:input-editor />

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 79: Liferay-6

More on Liferay Editor Soon...

Liferay UI Tabs

Creating Tabs is a really Cool feature and Liferay has an inbuilt functionality to do so.

Here is how it can be done.

1) In your Project , first create the following files under the following path/docroot/jsps by creating a new folder called jsps

view.jspsunday.jspmonday.jsptuesday.jspadmin.jsp

code for view.jsp

?12345678

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %><%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %><%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %><%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %><%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %><%@page import="com.liferay.portal.kernel.util.ParamUtil" %><%@page import="java.util.ArrayList"%><%@page import="java.util.List"%><liferay-theme:defineObjects />

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 80: Liferay-6

9101112131415161718192021222324252627282930313

//A renderURL is created because we need to render a jsp page you need to use //renderURL we can also pass parameters if required

<liferay-portlet:renderURL var="portletURL"/>

<%//We must Specify a default value for tabs. In this example it is sunday. Else it //will throw an error.String tabValue = ParamUtil.getString(request, "tab", "sunday");String tabsURL = "/jsps/" + tabValue.trim() + ".jsp";String tabNames="Sunday,Monday,Tuesday" ;String tabVal="sunday,monday,tuesday" ;if(permissionChecker.isCompanyAdmin(themeDisplay.getCompanyId())){tabNames+=",Admin" ;tabVal+=",admin" ;}%>

<liferay-ui:tabsnames="<%=tabNames%>"tabsValues="<%=tabVal%>"param="tab"url="<%= portletURL %>"/>

//this wud render the tab page<c:import url="<%= tabsURL %>"></c:import>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 81: Liferay-6

233343536

Here is how it would Look Like

The Admin Page Will be Visible only if an Admin Logs in.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 82: Liferay-6

To Download the Project click here

Liferay HOWTOs - II

Liferay HOWTOs Part-I

Continued from the first Part ,

15) How to programmatically get file content from document library?

?1234567891011121314

long scopedGroupId = themeDisplay.getScopeGroupId(); DLFolder root = null;try { root = DLFolderServiceUtil.getFolder(DLFolderConstants.DEFAULT_PARENT_FOLDER_ID); List<DLFolder> sub = DLFolderServiceUtil.getFolders(scopedGroupId, root.getFolderId());

} catch (PortalException e) { e.printStackTrace(); } catch (SystemException e) { e.printStackTrace();}

Now you can perform various operations by going through the code below on how to deal with files

DLFolderServiceUtil Documentation

Adding Users to Groups,Communities,UserGroups Programmatically

This post shows how to programatically add a user to UserGroups,Communities,Groups etc.

For an indepth understanding of what are the above notions click here.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 83: Liferay-6

Here is the code snippet to do the same.

?1234567891011121314151617181920212223242526

long[] groupIds = new long[1]; long[] organizationIds = new long[1]; long[] roleIds = new long[1]; long[] userGroupIds = new long[1]; UserGroup userGroup = null; userGroup = UserGroupLocalServiceUtil.getUserGroup(companyId,"userGroupName"); log.info("User GRoup " + userGroup.getName()); Group group = GroupLocalServiceUtil.getGroup(companyId, "groupName"); log.info("Community " + group.getName()); Role role = RoleLocalServiceUtil.getRole(companyId, "roleName"); log.info("Role Name " + role.getName()); if (userGroup.getUserGroupId() > 0) { userGroupIds[0] = userGroup.getUserGroupId(); } else { userGroupIds = null; } if (role.getRoleId() > 0) { roleIds[0] = role.getRoleId(); log.info("Role Id" + roleIds[0]); } else { roleIds = null; } if (group.getGroupId() > 0) { groupIds[0] = group.getGroupId(); log.info("Group Id" + groupIds[0]); } else { groupIds = null; }

Locale locale = Locale.ENGLISH;

ServiceContext serviceContext = ServiceContextFactory.getInstance( User.class.getName(), actionRequest);

User user = UserLocalServiceUtil.addUser(0, companyId, autoPassword,password1, password2, autoScreenName, screenName,emailAddress,facebookId, openId, locale, firstName, middleName, lastName,prefixId, suffixId, male,birthdayMonth, birthdayDay,birthdayYear, jobTitle, groupIds, organizationIds, roleIds,userGroupIds, sendEmail, serviceContext);

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 84: Liferay-6

272829303132333435363738394041

UserLocalServiceUtil

GroupLocalServiceUtil

UserGroupLocalServiceUtil

RoleLocalServiceUtil

Liferay Refresh Bug

If you have downloaded myBooks-portlet example , and deployed it in your liferay server , you would observe that there is a small bug in the application.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 85: Liferay-6

After you add a book , and click on refresh it creates a duplicate copy of the same book

Like Here in the picture below , i first add a book. (on the Side note , its a really awesome Book !)

Now , after i click on refresh , magically the same book gets added :P.

Well , there is nothing like magic (dont wana disappoint you if you are a big fan of harry porter) but the thing is that , when we click on refresh , the same portletURL gets executed once again. Means the entire lifecycle of the Portlet repeats from action-render. To avoid that , there are 2 ways

1) in the liferay-portlet.xml add the following line?1234567

<portlet> <portlet-name>booksportlet</portlet-name> <icon>/icon.png</icon> <action-url-redirect>true</action-url-redirect> <instanceable>false</instanceable>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 86: Liferay-6

pay close attention to the line

<action-url-redirect>true</action-url-redirect>

The value of this tag is by default false.

2) to transfer control to another jsp page or to the same jsp page we traditionally use sendRedirect("jspPage",jspPage) ; This method is highly inefficient as it merely renders the page. We also need to update the content in the page. so we need to have a different approach. Here is what you need to do. Just call the function below whenever you need to forward to another jsp.

?1234567891011121314151617181920

public boolean forwardToJsp(String jspPage, ActionResponse response, ActionRequest request) { boolean success =true ; ThemeDisplay themeDisplay = (ThemeDisplay) request .getAttribute(WebKeys.THEME_DISPLAY); portletName=(String) request.getAttribute(WebKeys.PORTLET_ID); PortletURL portletURL = PortletURLFactoryUtil .create(PortalUtil.getHttpServletRequest(request), portletName, themeDisplay.getLayout().getPlid(), PortletRequest.RENDER_PHASE);

try { portletURL.setWindowState(WindowState.NORMAL); } catch (WindowStateException e) { log.error(e); return success=false ; } portletURL.setParameter("jspPage",jspPage); try { response.sendRedirect(portletURL.toString()); } catch (IOException e) { log.error(e); return success=false ; } return success ; }

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 87: Liferay-6

2122232425262728

One interesting parameter here is "PortletRequest.RENDER_PHASE" Basically this parameter informs the Portal that the jspPage just needs to be rendered. What will happen in this case is that the portlet request and response will be of the type RenderRequest and RenderResponse

If you are trying to transfer control to another portlet , then in that case you need to have "PortletRequest.EVENT_PHASE" , so the PortletRequest interface shall produce EventRequest and EventResponse type of Portlet Request.

Cannot comment which one is better as i still have to look in passing parameters via request using the above methods.

Table Relationships

Lets Say there is a Parent Table and a Child Table. Now One Parent may have one ore more than one Children. So in your service.xml file should look something like this

?12345678

<entity name="Parent" local-service="true" remote-service="false"> <column name="parentId" type="long" primary="true" /> .

.

.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 88: Liferay-6

9101112131415161718192021222324252627282930313

.

.

</entity>

<entity name="Child" local-service="true" remote-service="false"> <column name="childId" type="long" primary="true" /> <column name="parentId" type="Collections" entity="Parent" mapping-key="parentId" /> .

.

.

</entity>

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html

Page 89: Liferay-6

233

So basically , you are informing service.xml that parentId is the foreign key of the Child Table.

Since, internally Liferay is using Spring and Hibernate , it injects an instance of Parent Object with all the Parent Functions into the ChildLocalServiceUtil.

if you want to sepcify many to many relationship then in the above mentioned way use the relationship in the both entities.

Reference link: http://liferaydemystified.blogspot.com/2011/08/table-relationships.html