Service Builder

No Comments »

In this post you will find a collection of informations concerning the service builder.

Maximum size of a database columns

For each model entity you define in service.xml a seperate database table will be created. By default service builder will set the maximum size of a database column for each of a model's fields to 75 characters. To configure the maximum size take a look at docroot/WEB-INF/src/META-INF/portlet-model-hints.xml. For example if you want to set the maximum size of a field called "name" to 1000 characters you can change:


to

 1000


Force ServiceBuilder to recreate database tables

ServiceBuilder uses the table "servicecomponents" to memorize if certain database tables have already been created. If you want to force ServiceBuilder to recreate database tables for some reason just remove the rows referencing your portlet from database table "servicecomponents".

Add custom portlet to control panel

No Comments »

In order to place your custom portlet to the control panel just add the following lines to your liferay-portlet.xml:



Liferay-Blog
/icon.png
apps
100
de.blogspot.blog.liferay.ControlPanelEntryHandler
...



Here are the explanations taken from liferay-portlet-app_6_2_0.dtd:

control-panel-entry-category: Set the control-panel-entry-category value to "my" to make this portlet available within the My Account administration of the user. Set the value to "apps", "configuration", "sites", or "users" to make it available in the Control Panel under that category. Set the value to "site_administration.configuration", "site_administration.content", "site_administration.pages" or "site_administration.users" to make it available in the Site Administration under that category. Legacy values from previous versions of Liferay will be automatically mapped to the new values: "content" to "site_administration.content", "portal" to "users", and "server" to "apps". [Source]

control-panel-entry-weight: Set the control-panel-entry-weight value to a double number to control the position of the entry within its Control Panel category. Higher values mean that the entry will appear lower in the Control Panel menu. [Source]

control-panel-entry-class: The control-panel-entry-class value must be a class that implements com.liferay.portlet.ControlPanelEntry and is called by the Control Panel to decide whether the portlet should be shown to a specific user in a specific context. [Source]

In your control-panel-entry-class you might for example check whether the user has a certain regular role or not. Here is a example where I check if the user has a regular role called "Liferay-Blog":

package de.blogspot.blog.liferay;

import com.liferay.portal.model.Group;
import com.liferay.portal.model.Portlet;
import com.liferay.portal.model.Role;
import com.liferay.portal.model.User;
import com.liferay.portal.security.permission.PermissionChecker;
import com.liferay.portal.service.RoleLocalServiceUtil;
import com.liferay.portal.util.PortalUtil;
import com.liferay.portlet.BaseControlPanelEntry;

public class ControlPanelEntryHandler extends BaseControlPanelEntry{
 @Override
 public boolean hasAccessPermission(PermissionChecker permissionChecker, Group group, Portlet portlet) throws Exception {
 User user = permissionChecker.getUser();
 Role liferayBlogRole = RoleLocalServiceUtil.getRole(PortalUtil.getDefaultCompanyId(), "Liferay-Blog");
 
 boolean hasAccessPermission = RoleLocalServiceUtil.hasUserRole(user.getUserId(), liferayBlogRole.getRoleId());
 
 return hasAccessPermission;
 }
}

This site is inactive Please contact the administrator

No Comments »

When you try to access your portal and get the following message:


You probably deactivated your default guest site (group). Just run this query on your database ans restart your portal server:

UPDATE group_ SET active = 1 WHERE name = "group_name"

Setting portlet preferences in configuration mode

No Comments »

There two cases when the following post becomes interesting:

1. You hook some liferay portlet and want to modify a the portlets configuration jsp without hooking the appropriate struts action.

2. Creating a configuration view for your custom portlet by implementing a ConfigurationAction that extends com.liferay.portal.kernel.portlet.DefaultConfigurationAction and adding the following line to yoor liferay-portlet.xml:


 ...
 /icon.png
 
 de.blogspot.blog.liferay.ConfigurationAction
  
 true
 ...



When using AUI input fields just choose their names according the pattern "preferences--paramName--" and the DefaultConfigurationAction class will handle all parameters and store them in portlet preferences. There is no need to implement any line of code. Example input field:
< aui:input 
name="preferences--hideToolbar--" 
type="checkbox" value="<%= hideToolbar %>" />
Choosing the name "preferences--hideToolbar--" for your input field, the DefaultConfigurationAction will store the "hideToolbar" value in your portlet preferences when the user submits the configuration form.

Custom startup actions

No Comments »

It is often necessary to define a startup action. For example to verify whether the portal is correctly configured. The following portal properties offer the chance to define custom startup actions which will be executed during portal startup and each deployment of your startup action.

global.startup.events
application.startup.events
Using global.startup.events you can define a action running once while actions defined using application.startup.events run for every portal instance. Since global.startup.events describes an event, intercepting Liferay statup, you will need to define your class in an ext-plugin. Whereas application.startup.events can be defined in a hook-plugin. Your custom startup action has to extend com.liferay.portal.kernel.events.SimpleAction and override a run-method. Example: In portal.properties:
application.startup.events=de.blogspot.blog.liferay.StartupEvent
The appropriate startup class:
package de.blogspot.blog.liferay;

import com.liferay.portal.kernel.events.ActionException;
import com.liferay.portal.kernel.events.SimpleAction;

public class StartupEvent extends SimpleAction{
    @Override
    public void run(String[] ids) throws ActionException {
     System.out.println("Liferay-Blog.blogspot.de");
    }
}

Asset Publisher: Custom Display Style

1 Comment »

You can add custom display styles to the asset publisher. Let's say you want to add a display style called "MyDisplayTemplate". First of all you add your style's name to the following portal property:

asset.publisher.display.styles=
table,title-list,abstracts,full-content,MyDisplayTemplate
Now you have to create a hook for the asset publisher. Add a jsp called "MyDisplayTemplate.jsp" in "docroot\custom_jsps\html\portlet\asset_publisher\display". Consider that the jsp file's name has to be exact the same as you defined it in portal.properties.

That's it!

Portal properties

No Comments »

In this post you will find a collection of frequently used portal properties.

Remove password reset on first login

passwords.default.policy.change.required=false
Remove terms of use on first login
terms.of.use.required=false
Remove Password reminder question on first login
users.reminder.queries.enabled=false
users.reminder.queries.custom.question.enabled=false

Display styles for the asset publisher (HowTo:Add custom style):
asset.publisher.display.styles=
table,title-list,abstracts,full-content

Expandos

No Comments »

Necessary classes:

com.liferay.portlet.expando.model.ExpandoTable
com.liferay.portlet.expando.model.ExpandoValue
com.liferay.portal.service.ClassNameLocalServiceUtil
com.liferay.portlet.expando.service.ExpandoColumnLocalServiceUtil
com.liferay.portlet.expando.service.ExpandoTableLocalServiceUtil
com.liferay.portlet.expando.service.ExpandoValueLocalServiceUtil
Here is a example how you get a expando-value programmatically. Lets say you have a expando named "foo" for User class. You can get a user's value like this:
long userClassNameId = 
ClassNameLocalServiceUtil.getClassNameId(User.class.getName());
ExpandoTable userExpandoTable = 
ExpandoTableLocalServiceUtil.getDefaultTable(PortalUtil.getDefaultCompanyId(), userClassNameId);
ExpandoColumn userExpandoTableColumn = 
ExpandoColumnLocalServiceUtil.getColumn(userExpandoTable.getTableId(), "foo");
ExpandoValue expandoValue = 
ExpandoValueLocalServiceUtil.getValue(userExpandoTable.getTableId(),userExpandoTableColumn.getColumnId(), user.getUserId());
String foo= expandoValue.getString();
There is also a shorter way based on ExpandoBridge. What you have to consider when using this approach, is that permission checking is enabled when using ExpandoBridge. For example when you try to access some expando value as a non-logged in user you will get some exception because of missing permissions to access expando-values.
String education = 
(String)user.getExpandoBridge().getAttribute("foo");
Setting value by using ExpandoValueLocalServiceUtil
ExpandoValueLocalServiceUtil.addValue(userClassNameId, userExpandoTable.getTableId(), 
userExpandoTableColumn.getColumnId(), user.getUserId(), "some value");
Setting the same value by using ExpandoBridge
user.getExpandoBridge().setAttribute("foo", "some value");

Checking if a certain expando exists. For example an expando "hobby" for Users:
user.getExpandoBridge().hasAttribute("hobby")

Avoiding multiple submits

No Comments »

To prevent repeated invocation of the action-phase of a portlet by pressing the F5 button, add the following entry to liferay-portlet.xml, right after the “<icon>” Tag:

true 

PortalClassInvoker

No Comments »

Necessary classes:

com.liferay.portal.kernel.util.PortalClassInvoker
com.liferay.portal.kernel.util.ClassResolverUtil
com.liferay.portal.kernel.util.MethodKey
If you want to invoke classes that are not directly accessible because they are contained in the portal-impl, you can use the PortalClassInvoker. For example if you want to encrypt a password you can use the class PasswordEncryptorUtil. Here is a example how to invoke the method encrypt in PasswordEncryptorUtil:
MethodKey methodKey = 
new MethodKey(ClassResolverUtil.resolveByPortalClassLoader
("com.liferay.portal.security.pwd.PasswordEncryptorUtil"), "encrypt", String.class);
String result = 
(String)PortalClassInvoker.invoke( false, methodKey, "test");

Language properties

No Comments »

Necessary utility classes:

com.liferay.portal.kernel.language.LanguageUtil
To get some value from language.properties programmatically use:
LanguageUtil.get(Locale locale, String key);

URLs

No Comments »

Necessary utility classes:

com.liferay.portal.util.PortalUtil
Get your portal URL programmatically:
public String getPortalUrl() 
throws PortalException, SystemException {
Company defaultCompany = 
CompanyLocalServiceUtil.getCompany(PortalUtil.getDefaultCompanyId());
portalUrl = 
defaultCompany.getPortalURL(defaultCompany.getGroupId());
   
return portalUrl;
}

Company

No Comments »

Necessary utility classes:

com.liferay.portal.util.PortalUtil
Get default companyId programmatically:
PortalUtil.getDefaultCompanyId()

Mails

No Comments »

Necessary classes

com.liferay.portal.util.SubscriptionSender
You can send mails programmatically using Liferay-Services. Here is one example:
private void sendMail( long fromUserId, long toUserId, String comment) throws SystemException, PortalException {
User fromUser = UserLocalServiceUtil.getUser(fromUserId);
User toUser = UserLocalServiceUtil.getUser(toUserId);

String fromName = fromUser.getFullName();
String fromAddress = fromUser.getEmailAddress()

String toName = toUser.getFullName();
String toAddress = toUser.getEmailAddress();

String subject = "Example mail-subject";
String body = "Example mail-body. Here is some comment: [$COMMENTS$]";

SubscriptionSender subscriptionSender = new SubscriptionSender();

subscriptionSender.setBody(body);
subscriptionSender.setCompanyId(toUser .getCompanyId());
subscriptionSender.setContextAttributes( "[$COMMENTS$]", comment);
subscriptionSender.setFrom(fromAddress, fromName);
subscriptionSender.setHtmlFormat(true);
subscriptionSender.setMailId("userId", toUserId);
subscriptionSender.setServiceContext(serviceContext);
subscriptionSender.setSubject(subject);
subscriptionSender.setUserId(userId);
subscriptionSender.addRuntimeSubscribers(toAddress, toName);
subscriptionSender.flushNotificationsAsync();
}
As you can see you can use
subscriptionSender.setContextAttributes(Obect...values);
to replace placeholders in your mail content.

Users

No Comments »

Necessary utility classes:

com.liferay.portal.util.PortalUtil
Get current logged-in user:
PortalUtil.getUser(PortletRequest request);
Avoid password reset on first login programmatically(can also be achieved by setting portal.properties [klick]):
user.setPasswordReset(false);
UserLocalServiceUtil.updateUser(user);
Avoid terms of use on first login programmatically(can also be achieved by setting portal.properties [klick]):
UserLocalServiceUtil.updateAgreedToTermsOfUse(User user, true);

Roles and Permissions

No Comments »

Necessary classes:

com.liferay.portal.service.UserGroupRoleLocalServiceUtil
com.liferay.portal.service.RoleLocalServiceUtil
Add Site-Role to user:
UserGroupRoleLocalServiceUtil.
addUserGroupRoles(userId, groupId, roleIds);
Get all users with a specific site-role:
List userIds = new ArrayList<>();
Role role = 
RoleLocalServiceUtil.getRole(long companyId, String roleName);

List userGroupRoles = 
UserGroupRoleLocalServiceUtil.getUserGroupRolesByGroupAndRole(long groupId, long roleId);

for(UserGroupRole u:userGroupRoles){
userIds.add(u.getUserId());
}
Check if user has regular role:
RoleLocalServiceUtil.hasUserRole(long userId, long roleId);
Check if user has site role:
UserGroupRoleLocalServiceUtil.hasUserGroupRole(long userId, long groupId, String roleName);

Sites

No Comments »

Necessary Liferay-Service:

com.liferay.portal.service.GroupLocalServiceUtil
com.liferay.portal.service.MembershipRequestLocalServiceUtil
Add Site programmatically:
ServiceContext serviceContext = 
ServiceContextFactory.getInstance(ActionRequest request);

GroupLocalServiceUtil.
addGroup(userId, className, classPK, name, description, type, 
friendlyURL, site, active, serviceContext);
You can use the serviceContext to set more properties like:
serviceContext.
setAddGroupPermissions(boolean addGroupPermissions);
serviceContext.
setAddGuestPermissions(boolean addGuestPermissions);
The possible types can be found in com.liferay.portal.model.GroupConstants. Often used values are:
GroupConstants.TYPE_SITE_RESTRICTED
GroupConstants.TYPE_SITE_PRIVATE
GroupConstants.TYPE_SITE_OPEN
For Sites with restricted access you can add a Site-Membership request programmatically:
ServiceContext serviceContext = ServiceContextFactory.getInstance(Group.class.getName(), ActionRequest request);
MembershipRequestLocalServiceUtil.addMembershipRequest(userId, groupId, comments, serviceContext);

Application Adapters

No Comments »

An application Application Adapter is a hook that does not affect the whole portal but just specific sites. Liferay-Wiki In order to define a Application Adapter you have to add the following line to liferay-hook.xml:

false
Afterwards you can activate the Application Adapter in 'Site Administration / Configuration / Application Adapter'.

Important note: If there are any includes in your hooked jsp Liferay will furthermore include the original and unmodified jsps. If you would like to included your hooked jsps you have to add your hook-project name to the filename. For example:
<%@ include file="/html/taglib/ui/asset_links/init.jsp" %>
becomes
<%@ include 
file="/html/taglib/ui/asset_links/init.BlogsPortlet-hook.jsp" %>

Blog domains

No Comments »

I registered the following free domains for this blog:

  1. liferay-blog.de.vu @ NIC
  2. liferay.de.ms @ Cydots
You can also just use my Blogger-URL http://liferay-blog.blogspot.de/

The code of method is exceeding bytes limit exception

No Comments »

When hooking/extending some liferay jsp and exceeding the 65535 bytes limit you will get following exception:

The code of method _jspService(HttpServletRequest, 
HttpServletResponse) is exceeding the 65535 bytes limit

Stacktrace:
at org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:103)
at org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:366)
at org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:468)
...
To solve this issue follow this steps:

1. change from static include to dynamic include:

 static:
<%@include file="test.jspf"%>
 dynamic:
<jsp:include page="test.jsp" />
2. rename included *.jspf to *.jsp

3. redeclare variables necessary in the included *.jsp