Error: java.lang.ClassNotFoundException: org.apache.jsp.html.portlet.dockbar.view_jsp

No Comments »

After restarting your Server you might get a:

ClassNotFoundException: org.apache.jsp.html.portlet.dockbar.view_jsp

This is a known issue in Liferay 6.2. The solution is quite simple.

Create a empty file view_user_account.portal.jspf in /webapps/ROOT/html/portlet/dockbar/.

Animated Loading Icon (Spinner / Progress Bar)

1 Comment »

I just tried to show an animated loading icon (like a spinner or progress bar) while my portlet was loading.

 A very simple way is to use the css-class "loading-animation", which is delivered with Alloy-Ui, I guess.

 Adding a single div:
<div class="loading-animation" />

 You will get an animated logo like this:


How to get and modify Portal-URL

2 Comments »

import com.liferay.portal.kernel.util.HttpUtil; 
import com.liferay.portal.kernel.util.ParamUtil; 
import com.liferay.portal.util.PortalUtil;
 
// delivers url-path including parameters
String currentUrlPathWithParamters = PortalUtil.getCurrentURL( request );
// --> Example: /group/guest/home?foo=test

// delivers url-path without parameters
String currentUrlPath = HttpUtil.getPath(currentUrlPathWithParamters);
// --> Example: /group/guest/home

// delivers complete url
String currentUrl = PortalUtil.getPortalURL( request ) + currentUrlPath;
// --> Example: http://localhost:8080/group/guest/home

// adding parameters to url
String urlWithCustomParameter= HttpUtil.addParameter(currentUrl,"foo", "faa");
// --> Example: http://localhost:8080/group/guest/home?foo=faa

portal-setup-wizard

No Comments »

After starting a clean liferay instance, you will see the portal-setup-wizard helping you to configure your portal. It provides help concerning your database-connection, default user,...

After you finished configuration portal-setup-wizard will not show up again. To enable portal-setup-wizard again, you can set the following property inside portal-setup-wizard.properties:

portal.setup.wizard.enabled=true

Hook- vs Ext-plugin

No Comments »

Using Hooks you can:

  • provide a portal configuration (portal-ext.properties)
  • define new or modify existing language key (language.properties)
  • modify portal JSPs
  • define servlet filters
  • implement post indexers
  • override Liferay-Services (especially by implementing a ServiceWrapper, like for example UserServiceWrapper)


Using an ext-Plugin it is possible to:

  • override any class inside Liferay (classes inside portal-iml.jar or portal-util)
  • modify Liferay's core portlet's desciptors and configurations (like portelt.xml, liferay-portlet.xml,...)

Ext-plugins are more powerful than hook-plugins BUT ext-plugins are not hot-deployable, an can not be undeployed! If you want to undeploy an ext-plugin, it is recommended to start with a clean liferay instance!

Get PortletPreferences

No Comments »

import javax.portlet.PortletPreferences;
import com.liferay.portlet.PortletPreferencesFactoryUtil;

PortletPreferences portletSetup = PortletPreferencesFactoryUtil.getLayoutPortletSetup( layout , portletId); 
String foo = portletSetup.getValue("foo", "defaultValue");

Get all portlets placed on a page (layout)

No Comments »

To get all portlets placed on a page (layout) you can use the following lines of code:

import com.liferay.portal.model.LayoutTypePortlet;
import com.liferay.portal.model.Portlet;

LayoutTypePortlet layoutTypePortlet = (LayoutTypePortlet) l.getLayoutType();
List< Portlet > portlets = layoutTypePortlet.getAllPortlets();

Liferay WebServices

No Comments »

Liferay offers the potential to use it's services via WebServices. If you need an overview over all available WebServices just take a look at: http://*your.portal.url*/api/jsonws. Your custom Services created with Liferay's ServiceBuilder will also be listed here.

import com.liferay.portlet.asset.model.AssetEntrySoap;
import com.liferay.portlet.asset.model.AssetVocabularySoap;
import com.liferay.portlet.asset.service.persistence.AssetEntryQuery;
import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import org.json.JSONException;
import org.json.JSONObject;

public class WebServicesClient 
{
    private Client client;
    private WebTarget target;
    
    public WebServicesClient( final String portalUrl, final String username, final String password )
    {
        client = ClientBuilder.newClient();       
        client.register( new Authenticator( username, password ) );  
        client.register( GensonProvider.class );
        target = client.target( portalUrl + "api/jsonws" );        
    }

 public AssetEntrySoap requestAssetEntry( final String entryId ) 
    { 
        Form form = new Form();
        form.param( "entryId", entryId );

        AssetEntrySoap assetEntry = target.path( "/assetentry/get-entry" )
            .request( MediaType.APPLICATION_JSON_TYPE )
            .post( Entity.entity( form, MediaType.APPLICATION_FORM_URLENCODED_TYPE ), AssetEntrySoap.class );

        return assetEntry;
    }
 
    public List getAssetEntries(final String companyId ) 
    { 
        Form form = new Form();
        form.param( "companyId", companyId );
        form.param( "start", "-1" );
        form.param( "end", "-1" );

        List< AssetEntrySoap > assetEntries = target.path( "/assetentry/get-company-entries" )
            .request( MediaType.APPLICATION_JSON_TYPE )
            .post( Entity.entity( form, MediaType.APPLICATION_FORM_URLENCODED_TYPE ), new GenericType< List< AssetEntrySoap > >() { } );
   
        return assetEntries;
    }
}

To perform a valid authentication you can implement an authenticator like this:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.xml.bind.DatatypeConverter;

public class Authenticator implements ClientRequestFilter 
{ 
 private final String username;
    private final String password;

    public Authenticator( final String username, final String password ) 
    {
        this.username = username;
        this.password = password;
    }

    public void filter( final ClientRequestContext requestContext ) throws IOException 
    {
        MultivaluedMap headers = requestContext.getHeaders();
        final String basicAuthentication = getBasicAuthentication();
        headers.add( "Authorization", basicAuthentication );
    }

    private String getBasicAuthentication() 
    {
        String token = this.username + ":" + this.password;
        try{
            return "BASIC " + DatatypeConverter.printBase64Binary( token.getBytes( "UTF-8" ) );
        }catch ( UnsupportedEncodingException ex ){
            throw new IllegalStateException( );
        }
    } 
}

If you use Genson for Building your json String, you will have to set useDateAsTimestamp as true in your GensonBuilder, since Liferay uses timestamps as date-fields.

import com.owlike.genson.Genson;
import com.owlike.genson.GensonBuilder;
import javax.ws.rs.ext.ContextResolver;

public class GensonProvider implements ContextResolver< Genson > 
{
    private final Genson genson = new GensonBuilder().useDateAsTimestamp( true ).create();

    @Override
    public Genson getContext( final Class< ? > arg0 ){
        return genson;
    }
}

Testing with JUnit

No Comments »

If you want to write JUnit tests for your application, you can use the following TestRunner which will initialize a liferay context such that you are able to use for example liferay services. However this approach makes it necessary to add portal-impl.jar as a dependency.

public class LiferayJUnitTestRunner
extends BlockJUnit4ClassRunner {

public LiferayIntegrationJUnitTestRunner(Class clazz)
throws InitializationError {

super(clazz);

if (System.getProperty("external-properties") == null) {
System.setProperty("external-properties", "portal-test.properties");
}

InitUtil.initWithSpring();

_testContextHandler = new TestContextHandler(clazz);
}

@Override
protected Statement withAfters(
FrameworkMethod frameworkMethod, Object instance, Statement statement) {

Statement withAftersStatement = super.withAfters(frameworkMethod, instance, statement);

return new RunAfterTestMethodCallback(
instance, frameworkMethod.getMethod(), withAftersStatement,
_testContextHandler);
}

@Override
protected Statement withBefores(
FrameworkMethod frameworkMethod, Object instance, Statement statement) {

Statement withBeforesStatement = super.withBefores(frameworkMethod, instance, statement);

return new RunBeforeTestMethodCallback(
instance, frameworkMethod.getMethod(), withBeforesStatement,
_testContextHandler);
}

public static void run(Class clazz){
Request request=Request.classWithoutSuiteMethod(clazz);
Runner runner=request.getRunner();
RunNotifier notifier=new RunNotifier();
runner.run(notifier);
}

private TestContextHandler _testContextHandler;
}
A sample TestCase looks like that:
@RunWith(LiferayIntegrationJUnitTestRunner.class)
public class SampleTestCase{
@Test
public void testSample() throws Exception {
List users = UserLocalServiceUtil.getUsers(-1, -1);
Assert.assertNotNull(users);
}
}

Creating a service without service-builder

No Comments »

Create your service-project:
1) Create new Liferay-Portlet project
2) clear porlet.xml.

<portlet-app version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" 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-app>

2) create a service.xml file in docroot/WEB-INF



< ?xml version="1.0" encoding="UTF-8"? >
< !DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd" >
< service-builder package-path="test" >
 < author >test< /author >
 < namespace >test< /namespace >
 
 < exceptions >

 < /exceptions >
< /service-builder >




3) Right click on service.xml and choose „Liferay - build services“. Service-Builder will create a directory „service“
4)Open project-properties ans choose the „service“-directory as additional source directory
5) All your service-packages and classes should now be created in this directory. choose „Liferay à build services“ or run ant-task „build-service“ and you will get your service-jar in „EB-INF\lib

Deploy your Service:
Choose among three options:
A) Modify your Portlets liferay-plugin-package.properties and declare your service-project as required-deployment-context. When building your service-jar and afterwars building your portel, a copy of service-jar will be copied to your portlets WEB-INF/lib folder. In addition you have to deploy your service  to Liferay.

Advantages:
1.You can modify your service and rebuilt service and portlet without restarting your application server.
Disadvantages:
1. You also have to deploy vour service, otherweise your portlet will not be deployed because of a missing deployment-context
2.Each portlet using your your service will have a seperate service-instance

B) Copy your service.jar to tomcat-x.x.xx\lib\ext

Advantages:
1. All  portlets using your your service will share one service-instance
Disadvantages:
2. When modifying your service you have to copy a new service-jar to your application server and restart it

C) Copy your service.jar to tomcat-x.x.xx\webapps\ROOT\WEB-INF\lib and modify your liferay-plugin-package.properties by adding your service.jar as portal-dependency-jar

Disadvantages:
1.When modifying your service you have to copy a new service-jar to your application server and restart it
2. Each portlet using your your service will have a seperate service-instance

Download sample:
Mirror 0
Mirror 1
Mirror 2

Create Liferay Portlet URLs

No Comments »

You will often have to built a URL leading to a specific portlet without knowing on which page it was placed. In order to find the page (layout) containing your portlet and building a valid LiferayPortletURL you can use the following code:

ThemeDisplay themeDisplay = (ThemeDisplay)liferayPortletRequest.getAttribute(WebKeys.THEME_DISPLAY);
Layout targetLayout = themeDisplay.getLayout(); 
List allLayouts = LayoutLocalServiceUtil.getLayouts(-1, -1);
        
layoutloop:
for(Layout l:allLayouts){
   LayoutTypePortlet layoutTypePortlet = (LayoutTypePortlet)l.getLayoutType();
   List portletIdList = layoutTypePortlet.getPortletIds();
            
   for(String portletId: portletIdList ){
      if(portletId.equalsIgnoreCase(*your portletId*)){
          targetLayout = l;
          break layoutloop;
      }
   }
}
        
LiferayPortletURL targetUrl = 
PortletURLFactoryUtil.create(liferayPortletRequest, *your portletId*, targetLayout .getPlid(), PortletRequest.RENDER_PHASE);

Format file size

No Comments »

Liferay provides

com.liferay.portal.kernel.util.TextFormatter
, which can be used to format the size of a file given in bytes and thus make it human readable. The relevant method is given with two different signatures;
static String  formatStorageSize(double size, Locale locale)
           
static String  formatStorageSize(int size, Locale locale) 

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")