Thursday, December 4, 2014

Kaleo Workflow Limitations and Considerations.

Limitations w.r.t liferay 6.1.20

  • Can not have multiple terminal (end) states.
  • Can not send notifications in the terminal state for the roles though it can send the notifications to users specified.
  • There is no scripted assignment for notifications separately. In other words, <recipients> tag in the <notifications> does not have a provision for scripted assignment. 


Things to be considered while developing the Kaleo workflows.


  • When ever there is a script error, workflow engine does not give/throw the exception and swallows the exception silently.
  • The only way to check whether the script executes perfectly or not is not copy the script and run that script in the Control Panel --> Server Administration --> Scripts console and debug there.
  • Scripted assignment is present at <Task> level. If the notification does not have < recipients> tag, then the notification uses the assignment tag specified at the task level. Thus, task assignment and notifications are sent to the same set of users.





Monday, August 4, 2014

Override annotation compilation problem - Liferay 6.1 Plugins SDK

You have classes implementing interface methods, which in Java 1.6 can be annotated with @Override; however, in Java 1.5, @override could only be applied to methods overriding a superclass method.

So while using liferay 6.1 plugins SDK, if you use @override annotations for implementing interface methods, though the server JDK is at 1.6, it still complains, resulting in not compiling the class with that annotation. Here is the example:

When creating a model listener hook, you need to implement all of the methods present in the ModelListener interface. If the implemented class has annotation "override", while building using the ant, it gives compilation error. 

Temporary fix

Remove @override annotation and build the project using ant.

Permanent Fix

To solve this issue the compiler compliance level should be set to 1.6. As we are building from ant, we have to set the compiler compliance level of ant. This can be set in build.properties file present in the plugins SDK root directory. All you need to do is change the following properties to 1.6

ant.build.javac.source=1.6

ant.build.javac.target=1.6

Thursday, November 7, 2013

WAR file built Using Liferay Plugins SDK contains java source files

The standard Liferay SDK build process includes all java sources to the deployment units (war file).

As Liferay is Open Source, it makes sense to include the code also in the war, if someone just download the plugin war and installs it. This holds good for the plugins developed to be shared among the community. But it is not acceptable while building it for any enterprise project.

It is possible to override the war target in individual build.xml of the portlet or you could just replace the target with your own in the build-common-plugin.xml so it applies to all portlets in your SDK. Below is the snippet.

<target name="war" depends="compile">
<mkdir dir="${sdk.dir}/dist" />

<if>
<available file="tmp" />
<then>
<property name="docroot.dir" value="tmp" />
</then>
<else>
<property name="docroot.dir" value="docroot" />
</else>
</if>

<delete file="${plugin.file}" />

<antcall target="clean-portal-dependencies" />

<if>
<available file="docroot/WEB-INF/liferay-hook.xml.processed" />
<then>
<property name="liferay-hook.xml.excludes" value="WEB-INF/liferay-hook.xml*" />
</then>
<else>
<property name="liferay-hook.xml.excludes" value="" />
</else>
</if>

<if>
<contains string="${app.server.dir}" substring="glassfish" />
<then>
<zip
basedir="${docroot.dir}"
destfile="${plugin.file}"
excludes="**/META-INF/context.xml,${liferay-hook.xml.excludes},${plugins.war.excludes}, WEB-INF/src/**"
>
<zipfileset
dir="${docroot.dir}"
fullpath="WEB-INF/liferay-hook.xml"
includes="WEB-INF/liferay-hook.xml.processed"
/>
</zip>
</then>
<else>
<zip
basedir="${docroot.dir}"
destfile="${plugin.file}"
excludes="${liferay-hook.xml.excludes},${plugins.war.excludes}, WEB-INF/src/**"
>
<zipfileset
dir="${docroot.dir}"
fullpath="WEB-INF/liferay-hook.xml"
includes="WEB-INF/liferay-hook.xml.processed"
/>
</zip>
</else>
</if>

<if>
<and>
<equals arg1="${plugins.src.zip.enabled}" arg2="true" />
</and>
<then>
<zip destfile="${plugin.src.file}">
<zipfileset
dir="${docroot.dir}"
excludes="${liferay-hook.xml.excludes}"
prefix="${plugin.name}-src-${plugin.full.version}"
/>
<zipfileset
dir="${docroot.dir}"
fullpath="${plugin.name}-src-${plugin.full.version}/WEB-INF/liferay-hook.xml"
includes="WEB-INF/liferay-hook.xml.processed"
/>
</zip>
</then>
</if>
</target>

Adding Documents to liferay Document Library through API

While adding documents to documents library there are two ways of doing it using the liferay API,  DLFileEntryLocalServiceUtil or DLAppLocalServiceUtil


Difference between DLFileEntryLocalServiceUtil and DLAppLocalServiceUtil

DLFileEntry services and DLFolderEntry services are specifically for storing file and folder entries in liferay's database and are totally unaware of the new repository concept introduced in 6.1. The user-guide & this wiki explains how to add a new repository.

Where as DLApp (DLAppService & DLAppLocalService) services take into account these things i.e. to say that they take care of syncing documents between liferay database and other repositories, and not just store entries in Liferay database.

Adding documents to Documents Library

1. Get the File object (using input stream) of the file which is being inserting to the document library.

2. Get the FileInputStream 

InputStream inputStream = new FileInputStream( file );

3. Get the ThemeDisplay from the request. This is used for retrieving the user id and group id while adding the documents which is depicted in the further steps down.

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

4. Get the Service Context object

ServiceContext serviceContext = ServiceContextFactory.getInstance( actionRequest );

5. Get the access folder in which the document would be placed.

Folder folder = DLAppLocalServiceUtil.getFolder( themeDisplay.getScopeGroupId(), 0, "<<Name of the folder>>" );

Here the first argument is the repository ID,  If the repository is a default Liferay repository, the repositoryId is the groupId or scopeGroupId. Otherwise, the repositoryId will correspond to values obtained from RepositoryLocalServiceUtil.

6. Now finally the inserting to the document library using DLAppLocalServiceUtil

FileEntry fileEntry = DLAppLocalServiceUtil.addFileEntry( themeDisplay.getUserId(), folder.getRepositoryId(), folder.getFolderId(), fileName,
contentType, fileName, fileName, "changeLog", inputStream, file.length(), serviceContext );


That is all we need to do, document is now inserted in the document library.

Monday, November 4, 2013

Defining custom Velocity Variables for Liferay Themes

There are number of predefined variables that can be accessed from with in the liferay theme. For elaborated list of those, below is the url

http://www.liferay.com/community/wiki/-/wiki/Main/Access+Objects+from+Velocity?_36_pageResourcePrimKey=2905717

Apart from those variables, if at all we end up needing a custom variable, which define a custom functionality/value as per the specific business need, we can define them in two places.

1. init_custom.vm. 

init.vm file, which is present in the liferay theme, contains all the liferay defined velocity variables. As a best practice, all the custom variables should be defined in the init_custom.vm file. 
This file allows you to override and define new Velocity variables.

#set($background_url = $theme_display.getThemeSetting('background-url'))

In the above example we are reading the background-url value provided by the user, while configuring the themes.

2. Setting the variables in request scope under attribute WebKeys.VM_VARIABLES

Create a hook, either Service Pre action or Login Post Action hook and inside your extended pre or post Action class, create a Map object with the key and value of the vm variables you want to insert, and then set that into the attribute under the key WebKeys.VM_VARIABLES. The variables added to the map are directly accessible in the Theme. This method provide more flexibility than the earlier one as there are no restrictions for defining the variables in this method.

Here is the code snippet for the same


Map< String, Object > vmVariables = ( Map< String, Object > ) request.getAttribute( WebKeys.VM_VARIABLES );

if ( vmVariables == null ) {
         vmVariables = new HashMap< String, Object >();
}
vmVariables.put("someVariable", "someValue");


request.setAttribute( WebKeys.VM_VARIABLES, vmVariables );

Now the variable added to the Map is directly accessible from with in the velocity template file in the theme.

For example it can be directly accessible from portal_normal.vm as below

<a id="siteLogo" class="logo $logo_css_class" href="$someVariable" title="#language("go-to") $site_name"/>


Thursday, August 8, 2013

Deploying the liferay war to non root context

There might be situations where you need to deploy liferay on to the different context than the default root("/") context.

One classic use case is - let us say you have a application that is deployed to the context "/app" and liferay reserves this context for json webservices. In this case you will have a context conflict thus making the liferay json ws not work properly.

For deploying liferay in non root context is two step process.

1. Add the property to portal-ext.properties
        portal-ctx="/whatevercontext"
2. Change the context path of liferay where it is deployed,  from root to whatevercontext context.


Wednesday, March 6, 2013

Customizing the Control Panel sections in liferay

Customizing the sections that are present in the control panel are flexible in liferay. You can control these sections from portal-ext.properties.

For customizing My Account, input a list of sections that will be included as part of the user form when updating a user in the My Account portlet.


#users.form.my.account.main=password,organizations,sites,user-groups,roles,categorization
#users.form.my.account.identification=addresses,phone-numbers,additional-email-addresses,websites,instant-messenger,social-network,sms,open-id
#users.form.my.account.miscellaneous=announcements,display-settings,comments,custom-fields


For customizing Users under Users and Organization, input a list of sections that will be included as part of the user form when updating a user.

#users.form.update.main=details,password,organizations,sites,user-groups,roles,personal-site,categorization
#users.form.update.identification=addresses,phone-numbers,additional-email-addresses,websites,instant-messenger,social-network,sms,open-id
#users.form.update.miscellaneous=announcements,display-settings,comments,custom-fields