Auto Vaadin Theme Deployment

General Blogs February 10, 2015 By David H Nebinger

Introduction

So in two previous blogs I introduced Auto Vaadin Add On Deployment and Vaadin 7 Theming.  At the end of the Vaadin 7 Theming blog I said that there was a similar mechanism for handling the deployment of your themes using the Vaadin 7 Control Panel, the mechanism introduced in the Auto Vaadin Add On Deployment blog.

So this blog is going to cover that mechanism by showing how to handle Auto Vaadin Theme Deployment.

Preparation

Follow the instructions from the Auto Vaadin Add On Deployment blog through the addition of the required-deployment-contexts entry in the liferay-plugin-package.properties file, then come back here...

Implementation

We also need to add a startup action class that extends one of the classes from the Vaadin 7 Control Panel.  The class is below:

package com.dnebinger.liferay.vaadin.sample;

import com.dnebinger.liferay.vaadin.startup.AbstractVaadinThemeDeployStartupAction;
import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * SampleThemeDeployStartupAction: A sample class to demonstrate how to do automatic theme deployment.
 * @author dnebinger 
 */
public class SampleThemeDeployStartupAction extends AbstractVaadinThemeDeployStartupAction {
   private static final String SAMPLE_THEME = "sample.zip";
   
   /**
    * getThemeNames: Returns the names of the theme zip files from the WEB-INF/vaadin/themes directory that should be deployed.
    * @return List The list of theme names.
    */
   @Override
   protected List<String> getThemeNames() {
      List<String> names = new ArrayList<String>(1);

      names.add(SAMPLE_THEME);

      return names;
   }

   /**
    * getThemeVersion: Returns the version number to associate with the theme.
    * @param themeName Name of the theme file to get the version number for.
    * @return int The version number for the theme file.
    */
   @Override
   protected int getThemeVersion(String themeName) {
      if (StringUtils.isBlank(themeName))
      return 0;

      if (SAMPLE_THEME.equals(themeName)) {
         return 100;
      }

      return 0;
   }
}

This class does two things:

  1. It returns the list of themes to be deployed.
  2. It provides the version number to use for the theme.

To get the theme zip file, create and test your theme using the Vaadin 7 Control Panel.  When you are satisfied with the theme, use the Export button to export the theme as a zip file on your desktop.

The zip file must be added to your project in the src/main/webapp/WEB-INF/vaadin/themes folder.

The theme version number is used to determine if the theme has already been deployed.  If you are shipping an updated version of the theme, be sure to increment the version number.

We also need to add the src/webapp/WEB-INF/liferay-hook.xml file to add the hook to the portlet:

<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd">

<hook>
    <portal-properties>vaadin-sample-portlet-hook.properties</portal-properties>
</hook>

We also need to create the src/resources/vaadin-sample-portlet-hook.properties file:

#
# vaadin-sample-portlet-hook.properties - Properties for the hook to add the app startup action.
#

application.startup.events=com.dnebinger.liferay.vaadin.sample.SampleThemeDeployStartupAction

That's it!

Conclusion

With these changes in place, when you build and deploy the portlet, when it is started in the application container the startup action will process the sample.zip theme file.

If it has either not been deployed before or if the version is greater than the currently installed version (considered a theme upgrade), the theme will be copied to the portal's html/VAADIN/themes directory and compiled to be ready for immediate use.

If it has already been deployed or the version is less than or equal to the deployed version, nothing happens (since it's already included).

So this eliminates the prework involved with deploying and compiling the themes, so you're back to just deploying your snazzy new Vaadin 7 portlet.

Just as with the automatic Add On deployment, you can include your theme with your project instead of treating them as separate deployments.

Updating Vaadin 7 Shared Environment

General Blogs February 8, 2015 By David H Nebinger

Introduction

Vaadin 7 is an active project still in development.  New releases come out regularly with bug fixes (mostly browser compatibility).  New versions come out with new functionality, etc.

When using the Vaadin 7 shared environment, the version of Vaadin must be the same across the portal.

The reason is the compiled WidgetSets.  When you compile the WidgetSet, the compiled JavaScript is for the version of Vaadin that is being compiled against.  If you compile the WidgetSet using Vaadin 7.2.7, the code will not work so well against 7.2.6 or 7.3.

Keeping the version of Vaadin in sync in your portal has been difficult, but you have a tool to help you complete this task, the Vaadin 7 Control Panel.

Upgrading Vaadin

So upgrading the Vaadin 7 shared environment takes a couple of steps:

  1. Download the new version of Vaadin.
  2. Replace the existing Vaadin theme/widgetset currently in the portal with the new files from the new distribution.
  3. Recompile the custom themes and the widgetset using the deployed Add Ons.
  4. Replace the Vaadin jars for all Vaadin portlets with the version from the distribution.
  5. Restart the portal so the new jars take effect.

Except for the last step, The Vaadin 7 Control Panel will take care of all of these things automatically, you just have to enable a setting and then follow the upgrade procedure.

Enabling the Portlet Auto Update Feature

The portlet Auto Update feature is enabled/disabled in the Settings page of the Vaadin 7 Control Panel:

Settings

Check the "Update Portlets during version change." to enable the Auto Update feature.

NOTE: I recommend checking the "Automatically Compile WidgetSet on version change." checkbox.  Otherwise you must update and then manually compile the widgetset.  Since both must be done, why not save yourself some clicks and do it all at once?

Choosing The Version

The Overview page shows the currently installed Vaadin 7 version as well as the current stable version.  Note that to get this information, your server makes an HTTP request to vaadin.com; if your firewall does not allow this outbound traffic, you will not see a value for the stable version.

Click the Change Version link to change the version.

Again to populate this list, your server will open an HTTP connection to vaadin.com.  If your firewall will not allow this connection, you will not get a list to display from.

That's okay, though, just follow the directions in the note to download the Vaadin 7 archive from vaadin.com manually and upload it using the form at the bottom.

Select the version from the list that you want to install:

After selecting your version, click the Change Version button to go to the next page.

NOTE: There are alpha, beta, pre-release and nightly builds of Vaadin available for download, but the Vaadin 7 Control Panel does not show these for installation.  You can use the manual approach to install one of these versions if you'd like.  Personally I don't believe that you should be trying to use non-stable versions of Vaadin in your portal (you will have enough to worry about using the stable versions).

You have one more chance to reconsider the upgrade.  Click Cancel to return to the Overview page or Change Version to start the upgrade process.

The upgrade process will update the status message at the top and the progress bar so you know what is going on during the upgrade.  A detailed log window appears below to provide all information relative to the upgrade steps.

When the upgrade process is done, you can click Done to return to the Overview page, but if you haven't enabled automatic WidgetSet compilation, click on the Compile Widgetset button and complete the widgetset compile.

Conclusion

When you are done with the upgrade process, the Overview page will reflect the upgraded version of Vaadin:

Note that after upgrading Vaadin 7, you should restart the application server.  This ensures that the correct version of Vaadin is being used by all Vaadin portlets.

As you can see, upgrading Vaadin 7 using the Vaadin 7 Control Panel just couldn't be easier.  And this is something you're going to want to do to keep up with all of the fixes for supported browsers.

 

Vaadin 7 HighCharts Portlet

General Blogs February 8, 2015 By David H Nebinger

Introduction

So the last few Vaadin posts were on some basic introductory stuff, but not a whole lot of fun.  I thought I'd do a blog post on a quick and fun little Vaadin 7 portlet, one that uses HighCharts.

So I'm creating a portlet to show a pie chart of registered user ages (based on birthdate).  The fun part about this portlet is that it will use the Liferay API to access the user birthdates, but will use a DynamicQuery to check the birthdates, and we'll break it up into seven groups and display as a pie chart using HighCharts.  And the whole thing will be written for the Vaadin framework.

Project Setup

So first thing you need is the HighCharts for Vaadin 7 Add On.  You can use the Vaadin 7 Control Panel to deploy the Add On to your environment.  This Add On includes the Vaadin 7 widget for integrating with HighCharts in your Vaadin application, but you also need the HighCharts JavaScript file.

Initially I tried to use the version that comes with the Add On but quickly found that it was not going to work.  The JavaScript shipped with the Add On uses jQuery, but not jQuery in no conflict mode.  So that version of the HighCharts JavaScript won't work in the portal.

Fortunately, however, there is a viable alternative.  From the HighCharts Download page, one of the adapter options includes "Standalone framework" mode.  This adapter option does not rely on jQuery or any other JavaScript framework.

HighCharts Download

Select the Standalone Framework option and any other portions to include in the download you want.  The portlet being built in this blog uses the Pie Chart, so be sure to include that chart type.  I would selecting everything, that way you'll have a complete HighCharts JavaScript file to use in future charting portlets.

If you do not want the minified JavaScript, uncheck the "Compile code" checkbox before downloading.

Download the JavaScript file and save it for later.

Creating the Project

Since I'm using Intellij, I started a Maven project using the "liferay-portlet-archetype", similarly to the project I did for the "vaadin-sample-portlet" project.  I called the portlet and the project "vaadin-user-age-chart-portlet".

To create the portlet, there will be four classes:

  • UsersChartUI - This is the UI class for the portlet, it extends com.vaadin.ui.UI class.
  • DateRange - This is a utility class that calculates and keeps track of a date range.
  • UserAgeData - This is a utility class which retrieves the age data from the Liferay API.
  • UserPieChart - This is the extension class responsible for rendering the pie chart.

DateRange

Let's start with the DateRange class.  It basically has the following:

package com.dnebinger.liferay.vaadin.userchart;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;

/**
 * DateRange: A container for a date range.
 * Created by dnebinger on 2/6/15.
 */
public class DateRange implements Serializable{
   private static final long serialVersionUID = 58547944852615871L;
   private Calendar startDate;
   private Calendar endDate;

   /**
    * DateRange: Constructor for the instance.
    * @param type
    */
   public DateRange(final int type) {
      super();

      endDate = Calendar.getInstance();
      startDate = Calendar.getInstance();

      switch (type) {
         case UserAgeData.AGE_0_10:
            // end date is now

            // start date is just shy of 11 years ago.
            startDate.add(Calendar.YEAR, -11);
            break;
         case UserAgeData.AGE_11_20:
            endDate.add(Calendar.YEAR, -11);

            startDate.add(Calendar.YEAR, -21);
            break;
         case UserAgeData.AGE_21_30:
            endDate.add(Calendar.YEAR, -21);

            startDate.add(Calendar.YEAR, -31);
            break;
         case UserAgeData.AGE_31_40:
            endDate.add(Calendar.YEAR, -31);

            startDate.add(Calendar.YEAR, -41);
            break;
         case UserAgeData.AGE_41_50:
            endDate.add(Calendar.YEAR, -41);

            startDate.add(Calendar.YEAR, -51);
            break;
         case UserAgeData.AGE_51_60:
            endDate.add(Calendar.YEAR, -51);

            startDate.add(Calendar.YEAR, -61);
            break;
         case UserAgeData.AGE_60_PLUS:
            endDate.add(Calendar.YEAR, -61);

            startDate.add(Calendar.YEAR, -121);
            break;
      }

      startDate.add(Calendar.DATE, 1);
   }

   /**
    * getEndDate: Returns the end date in the range.
    * @return Date The end date.
    */
   public Date getEndDate() {
      // start by verifying the day of year comparisons
      Calendar cal = Calendar.getInstance();

      if (cal.get(Calendar.DAY_OF_YEAR) != endDate.get(Calendar.DAY_OF_YEAR)) {
         // update start and end days
         endDate.add(Calendar.DATE, 1);
         startDate.add(Calendar.DATE, 1);
      }

      return endDate.getTime();
   }

   /**
    * getStartDate: Returns the start date in the range.
    * @return Date The start date.
    */
   public Date getStartDate() {
      getEndDate();

      return startDate.getTime();
   }
}

So the class is initialized for a type code and, given the type code, it sets up the start and end dates to cover the appropriate range.  Each time the starting and end dates are retrieved, the dates will be checked for possible increment (to keep the ranges intact).

UserAgeData

The UserAgeData class uses the DynamicQuery API to count users that fall between the start and end date ranges.

package com.dnebinger.liferay.vaadin.userchart;

import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
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.util.PortalClassLoaderUtil;
import com.liferay.portal.model.Contact;
import com.liferay.portal.service.UserLocalServiceUtil;

/**
 * class UserAgeData: A class that contains or determines the user age data percentages.
 */
public class UserAgeData {
   private static final Log logger = LogFactoryUtil.getLog(UserAgeData.class);

   // okay, we need to know when the data was retrieved
   private long timestamp;

   // and we need a container for the data
   private double[] percentages;

   private static final long ONE_DAY_MILLIS = 1000 * 1 * 60 * 60 * 24;

   public static final int AGE_0_10 = 0;
   public static final int AGE_11_20 = 1;
   public static final int AGE_21_30 = 2;
   public static final int AGE_31_40 = 3;
   public static final int AGE_41_50 = 4;
   public static final int AGE_51_60 = 5;
   public static final int AGE_60_PLUS = 6;

   private DateRange[] ranges = new DateRange[7];

   /**
    * UserAgeData: Constructor.
    */
   public UserAgeData() {
      super();

      percentages = new double[7];
      timestamp = 0;

      for (int idx = 0; idx < 7; idx++) {
         ranges[idx] = new DateRange(idx);
      }
   }

   /**
    * getPercentages: Returns either the cached percentages or pulls the count.
    * @return double[] An array of 7 doubles with the age ranges.
    */
   public double[] getPercentages() {
      // if we already have cached users
      if (timestamp > 0) {
         // need to check the timestamp
         long current = System.currentTimeMillis();

         if (current <= (timestamp + ONE_DAY_MILLIS)) {
            // we have values and they are still valid for caching

            if (logger.isDebugEnabled()) logger.debug("Found user data in cache, returning it.");

            return percentages;
         }
      }

      // if we get here then either we have no info or the info is stale.

      long[] counts = new long[7];
      long totalUsers = 0;

      // get the count of users
      for (int idx = 0; idx < 7; idx++) {
         counts[idx] = countUsers(ranges[idx]);
         if (logger.isDebugEnabled()) logger.debug("  " + idx + " has count " + counts[idx]);
         totalUsers += counts[idx];
      }

      // now we can do the math...
      double total = Double.valueOf(totalUsers);

      for (int idx = 0; idx < 7; idx ++) {
         percentages[idx] = 100.0 * (Double.valueOf(counts[idx]) / total);

         if (logger.isDebugEnabled()) logger.debug("Percentage " + idx + " is " + percentages[idx] + "%");
      }

      timestamp = System.currentTimeMillis();

      return percentages;
   }

   /**
    * countUsers: Counts the number of users for the given date range.
    * @param range The date range to use for the query.
    * @return long The number of users
    */
   protected long countUsers(DateRange range) {
      if (logger.isDebugEnabled()) logger.debug("Looking for birthday from " + range.getStartDate() + " to " + range.getEndDate() + ".");

      // create a new dynamic query for the Contact class (it has the birth dates).
      DynamicQuery dq = DynamicQueryFactoryUtil.forClass(Contact.class, PortalClassLoaderUtil.getClassLoader());

      // restrict the count so the birthday falls between the start and end date.
      dq.add(RestrictionsFactoryUtil.between("birthday", range.getStartDate(), range.getEndDate()));

      long count = -1;

      try {
         // count the users that satisfy the query.
         count =  UserLocalServiceUtil.dynamicQueryCount(dq);
      } catch (SystemException e) {
         logger.error("Error getting user count: " + e.getMessage(), e);
      }

      if (logger.isDebugEnabled()) logger.debug("Found " + count + " users.");

      return count;
   }
}

This class will keep a cache of counts that will apply for one day.  After 24 hours the cached values are discarded and the queries will be performed again.

Probably not the best implementation, but I'm not shooting for realtime accuracy, just mostly accurate data suitable for a chart on say a dashboard page.

UsersChartsUI

Next comes the UserChartsUI class that implements the UI for the portlet.

package com.dnebinger.liferay.vaadin.userchart;

import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.dnebinger.vaadin.highcharts.UserPieChart;

/**
 * Created by dnebinger on 2/6/15.
 */
@Theme("sample")
public class UsersChartUI extends UI {
   private VerticalLayout mainLayout;

   private UserPieChart pieChart;

   private static final UserAgeData userAgeData = new UserAgeData();

   @Override
   protected void init(VaadinRequest vaadinRequest) {
      // create the main vertical layout
      mainLayout = new VerticalLayout();

      // give it a margin and space the internal components.
      mainLayout.setMargin(true);
      mainLayout.setSpacing(true);
      mainLayout.setWidth("100%");
      mainLayout.setHeight("100%");

      // set the layout as the content area.
      setContent(mainLayout);

      setStyleName("ui-users-chart");

      setHeight("400px");

      pieChart = new UserPieChart();
      pieChart.setImmediate(true);
      pieChart.setHeight("100%");
      pieChart.setWidth("100%");

      mainLayout.addComponent(pieChart);
      mainLayout.setComponentAlignment(pieChart, Alignment.TOP_CENTER);

      double[] percentages = userAgeData.getPercentages();

      pieChart.updateUsers(percentages[0], percentages[1],percentages[2],percentages[3],percentages[4],percentages[5],percentages[6]);
   }
}

Nothing special in the UI, it creates a UserPieChart instance and places it in the layout.

UserPieChart

The final class is the com.dnebinger.vaadin.highcharts.UserPieChart class.  This is the special integration class joining Vaadin 7 and HighCharts.

package com.dnebinger.vaadin.highcharts;

import com.dnebinger.liferay.vaadin.userchart.UserAgeData;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.vaadin.annotations.JavaScript;

/**
 * Created by dnebinger on 2/6/15.
 */
@JavaScript({"highcharts-custom.js", "highcharts-connector-nojq.js"})
public class UserPieChart extends AbstractHighChart {
   private static final Log logger = LogFactoryUtil.getLog(UserAgeData.class);
   private static final long serialVersionUID = 7380693815312826144L;

   /**
    * updateUsers: Updates the pie chart using the given percentages.
    * @param age_0_10
    * @param age_11_20
    * @param age_21_30
    * @param age_31_40
    * @param age_41_50
    * @param age_51_60
    * @param age_60_plus
    */
   public void updateUsers(final double age_0_10, final double age_11_20, final double age_21_30, final double age_31_40, final double age_41_50, final double age_51_60, final double age_60_plus) {

      StringBuilder sb = new StringBuilder("var options = { ");

      sb.append("chart: {");
      sb.append("plotBackgroundColor: null,");
      sb.append("plotBorderWidth: null,");
      sb.append("plotShadow: false");
      sb.append("},");
      sb.append("title: {");
      sb.append("text: 'Age Breakdown for Registered Users'");
      sb.append("},");
      sb.append("plotOptions: {");
      sb.append("pie: {");
      sb.append("allowPointSelect: true,");
      sb.append("cursor: 'pointer',");
      sb.append("dataLabels: {");
      sb.append("enabled: false");
      sb.append("},");
      sb.append("showInLegend: true");
      sb.append("}");
      sb.append("},");
      sb.append("series: [{");
      sb.append("type: 'pie',");
      sb.append("name: 'Age Breakdown',");
      sb.append("data: [");
      sb.append("['Zero to 10', ").append(format(age_0_10)).append("],");
      sb.append("['11 to 20', ").append(format(age_11_20)).append("],");
      sb.append("['21 to 30', ").append(format(age_21_30)).append("],");
      sb.append("['31 to 40', ").append(format(age_31_40)).append("],");
      sb.append("['41 to 50', ").append(format(age_41_50)).append("],");
      sb.append("['51 to 60', ").append(format(age_51_60)).append("],");
      sb.append("['Over 60', ").append(format(age_60_plus)).append(']');
      sb.append("]");

      sb.append("}]");

      // close the options
      sb.append(" };");

      String chart = sb.toString();

      if (logger.isDebugEnabled()) logger.debug(chart);

      setHcjs(chart);
   }

   protected String format(final double val) {
      String s = String.format("%s", val);

      int pos = s.indexOf('.');

      if (pos < 0) return s + ".0";

      double x = Double.valueOf(Double.valueOf((val * 10.0) + 0.5).longValue()) / 10.0;

      return s.substring(0, pos+2);
   }
}

This class requires the most explanation, so here we go.

The first thing is the @JavaScript annotation.  This is a Vaadin 7 annotation that is used to inject JavaScript files into the response stream for the portlet.  For this portlet we need the highcharts-custom.js file (this will be the one that you downloaded earlier) as well as a highcharts-connector-nojq.js file which we will add later.

The updateUsers() method takes the 7 percentage values and outputs JavaScript to create and populate an options object, this object will be used by the HighCharts library to render the chart.  I used a simple StringBuilder to build the JavaScript, but a better way would have been to use the org.json.JSONObject class to construct an object and output it as a string (that way you don't have to worry about syntax, quoting, etc.).

The last method, the format() method, is a simple method to output a double as a string to a single decimal place.  Nothing fancy, but it will work.

Adding the JavaScript Files

As previously stated, we need to add two javascript files to the project, but these do not go in the normal places.  Since we used the @JavaScript annotation in the UserPieChart class, we have to put them into the project's src/main/resources folder as the JavaScript files need to be in the class path.

Since our Java class is com.dnebinger.vaadin.highcharts.UserPieChart that has the @JavaScript annotation, our JavaScript files have to be in src/main/resources/com/dnebinger/vaadin/highcharts.  The HighCharts JavaScript file that we downloaded earlier must be copied to this directory named "highcharts-custom.js" (to match the value we used in the @JavaScript annotation).

The second javascript file we will create in this directory is "highcharts-connector-nojq.js".  The contents of this file should be:

window.com_dnebinger_vaadin_highcharts_UserPieChart = function () {

   this.onStateChange = function () {
      // read state
      var domId = this.getState().domId;
      var hcjs = this.getState().hcjs;

      // evaluate highcharts JS which needs to define var "options"
      eval(hcjs);

        // update the renderTo to point at the dom element for the chart.
        if (options.chart === undefined) {
            options.chart = {renderTo: domId};
        } else {
            options.chart.renderTo = domId;
        }
        
        // create the new highcharts object to render the chart.
        var chart1 = new Highcharts.Chart(options);
   };
};

This is a connector JavaScript function to bridge Vaadin 7 and HighCharts.  Note the name of the function matches the package path and class for the function name, except the periods are replaced with underscores.

Since the current HighCharts Add On relies on jQuery, the connector function that comes with the Add On will just not work in our new implementation for the portal.  This function does not rely on jQuery and will ensure the correct stuff happens.

Conclusion

So far I've presented some code, but it's not all that much.  Some utility classes for date calculations, a wrapper class encapsulating the DynamicQuery access, our necessary UI class for the portlet and a UserPieChart class to encapsulate the HighCharts access.

The results of this code can be seen below:

User Ages Pie Chart

Had I taken a little time to create some users with suitable dates, I could make the chart take on any sort of view.  Since I'm using a stock Liferay bundle with my own extra user account, I have 3 users that must be broken down and displayed.

I think you must agree, however, that all in all this is an extremely simple portlet.  It should be easy to see how you could leverage a number of small Vaadin 7 portlets to create a dashboard page with quite a few graphs on it.

If I were asked to do something like that, I'd make a few changes:

If there were more than say 4 or 5 graphs on the page, I'd put the highcharts-custom.js JavaScript file into the theme.  I'd then remove it from the @JavaScript annotation.  The connector JavaScript would remain, but it is so small and is bound to the chart package/class anyway.

If there are more than two on the page but less than 5, I would at least put the highcharts-custom.js into the portlet javascript resources and pull in using the <header-portlet-javascript /> tag in liferay-portlet.xml.  That would at least allow the portal to import a single copy of the JavaScript rather than multiple copies.  Again it would be removed from the @JavaScript annotation, but the connector JavaScript would remain.

Note: Before anyone asks, I'm not going to be putting the code for this portlet online.  Without the HighCharts JavaScript, it's not really complete and I can't distribute the HighCharts JavaScript myself.  However, all of the code for the portlet is here in the blog and I've left nothing out.  If you have any problems reconstituting the portlet, feel free to ask.

Enjoy!

Vaadin 7 Theming

General Blogs February 5, 2015 By David H Nebinger

Introduction

Wow, been staying up late cranking out some Vaadin blogs.  It's starting to catch up with me, but I have one more to add to the pile - Theming.

Vaadin Themes in Liferay

Vaadin in the portal is challenging because of theming.  In a Liferay portal window, well the surrounding frame is all managed and styled by the Liferay theme.  This poses a special problem for Vaadin because Vaadin portlets, like Vaadin servlets, want to be styled exclusively by a separate Vaadin theme.

In a Vaadin servlet this isn't a problem because there is no surrounding styling to worry about, but in the portal the Vaadin theme is styling a portlet within the context of the portal's theme, and these two are typically not aware of the impact they can have on each other.

I'll wager that any Vaadin theme you try, from the standard Vaadin themes to those available from http://www.vaadin.com, every one of these will end up rendering differently within the portal than from a servlet.

Some of the rendering differences will be minor, some will not.

Usually it comes down to this - Vaadin themes always assume they are starting from a blank slate, a totally unstyled starting point that the Vaadin styling can build off of.

In Liferay, however, this is never the case.  When Vaadin gets to start styling tags there's a whole mountain of CSS styling already in place, styling that the Vaadin theme doesn't think it has to undo.  For example, a Vaadin theme can style a tag by giving a "margin-left: 20px" style because it will assume that the tag has no margin styling from Vaadin; the problems arise when the Liferay theme applies generic margins to an element that Vaadin isn't undoing.  The correct Vaadin styling that should apply is a left margin of 20px but a top, right, and bottom margin of 0px if it doesn't want or need them.

So as you move forward creating Vaadin themes, keep in mind that you are probably not just styling Vaadin elements, you are also undoing or mixing in the styling from your Liferay theme.

Keep in mind a few key points to use in Vaadin theming:

  • You can specifically undo a style.  For example, setting a margin to 0px when you don't want a margin rather than assuming there just isn't one.
  • You can use !important to force a rule, but as always the more you use it the harder it is to work around it.
  • Higher specificity always rules.  So if you can match on a path or on multiple classes, writing a rule that results in higher specificity will give your rules precedence over inherited styling from the Liferay theme.

When to Theme in Vaadin

You create themes in Vaadin for the same reasons you create themes in Liferay - to package a set of styling rules that can be reused and applied to multiple portlets.

But you will also finding yourself creating themes because it's the only effective way to style your Vaadin portlets.

Many aspects of your Liferay theme that you hope would apply to your Vaadin elements simply won't because the Vaadin theme is in play.  The liferay-portlet.xml file way of defining CSS to include in the portlet, well even that starts breaking down within the Vaadin portlet where the Vaadin theme is getting in the way.

By creating and maintaining a Vaadin theme for your Vaadin portlets, you get a theme which will style the Vaadin widgets just the way you need every time.

How to Theme Vaadin Portlets

So you theme your Vaadin portlets in two ways.  The first is to add style classes to your widgets in the Java code and the second is to write CSS (usually from SCSS) that define the style rules for the classes.

Every Vaadin widget, from the UI class all the way down to a caption on a label, every widget can be assigned style classes.  You decorate your Vaadin widgets with classes when you need to style them differently from the norm.

For example, we're going to be taking the vaadin-sample-portlet project and modifying the look and feel of the user detail page.  We have these requirements to:

  • Change the caption for required elements red.
  • Increase the font size for the displayed values.
  • Indent the displayed values from their captions.
  • Adjust some margins so the elements are not all cramped together.

As a reminder, here's how the user details panel looks before styling is applied:

Existing User Detail Panel

Not very pretty, I think we'd all agree on that.

Adding Style Names to Vaadin Widgets

Now based upon our requirements we know that we are going to be indenting all of the values from the captions and we're also going to change the "required" caption to red.  We'll assume that the Name is our only required field (hey, this is just an example, I know email and screen name are also required, but how fun is that to make them all the same?).

So we'll use two classes, "indented" and "required-cap".  We'll be using two methods on the widgets, the setStyleName() and addStyleName() method.  The set method does that, it sets a single value, the add method adds additional style classes beyond the first.

Below is the code we'll use to style the widgets:

// add some classes to the widgets, we'll sort them out in the theme
name.setStyleName("indented");
userId.setStyleName("indented");
emailAddress.setStyleName("indented");
screenName.setStyleName("indented");
userPortrait.setStyleName("indented");

name.addStyleName("required-cap");

Just a quick word on style names.  Vaadin actually does some weird things with the class names that get applied, you will actually end up with one or two classes for each style name.  For example, the userId widget is a Label instance.  The HTML that results for this widget is:

Generated HTML

The userId element is the outer div for the "v-widget" and two inner divs.  The first inner div is the caption, the "User ID:" string.  The second inner div is the label, the "11005" value.

Note the classes on the second inner div, the "v-label" div.  It has both the "indented" and "v-label-indented" classes.  The first inner div, the "v-caption" div, that only has a manufactured class of "v-caption-indented".

So your simple assignment of "indented" as a style name results in classes that match the name but also classes prefixed with the widget type.

Although this may seem odd at first, it is actually kind of useful.  You can style using the generic "indented" class that would apply to all widgets or you can provide specific and different styling for indented captions vs indented labels.  The user portrait is an instance of an Embedded object; it's unique class is "v-embedded-indented".  When we create our theme we'll be taking advantage of these differences.

Creating a Vaadin Theme

So creating a Vaadin theme is pretty easy when using the Vaadin 7 Control Panel.

The Vaadin Theme panel lists the current themes available in your Vaadin shared environment:

Current Themes

In the window above, all of the listed themes are the standard themes.  These are handled differently than custom themes in that they cannot be edited, compiled or deleted.  Your custom themes can be edited, compiled or deleted.

Click the "Create Theme" button to create a theme.  We'll name our new theme "sample".  Note that theme names become part of the URL, so some characters will be invalid.

Creating a Theme

With our new theme created, it will be in the theme list.  We'll be selecting it so we can edit the theme.

When editing a theme, you begin from the Theme Structure panel with a tree view on the left showing all files included in the theme and a preview area on the right.  The preview area is read-only.

Viewing Theme Files

On the left is a tree view of the files that are in the theme.  All new themes will start with two files, the styles.scss file is the main one used to compile the theme and the second file is an SCSS file named from the theme.

You can actually right-click on the folder to create new subfolders, upload assets (such as images) or delete files.  There is no limit to what you can build into your theme.

The right side is a preview panel to view the current contents of the file (it will also preview image files).  The preview control is based on the Ace Editor Vaadin Add On and it is a syntax-aware code viewing/editing control.  

At the bottom of the panel is an Edit button, click the button to open the edit dialog.

By default, every custom theme inherits from the Liferay Vaadin theme.  Remember the Liferay Vaadin theme is not your Liferay theme, it's actually an adaptation of the Liferay Classic theme as a Vaadin theme.  You can change your theme inheritance to any other installed theme.  The Vaadin 7 Control Panel uses the Liferay theme as the default base theme because this has the least amount of conflict with the Liferay themes (well, the Liferay Classic theme, your Liferay theme can have it's own incompatibilities).

So, given our requirements we will add our own style definitions to handle our recently added classes:

Note how we've handled the v-label-indented and v-embedded-indented differently.  Also note the overlap in the margin-left and margin-top values.  We could have used a rule for the "indented" class that had the two margin settings and a rule for "v-label-indented" to have the margin-bottom and font-size changes.

Anyway, we would continue editing this file, adding other files, adding assets that we needed such as background images or sprites, whatever was needed to flush out the theme.  When finished, we click on the Back link from the top right of the Theme Structure panel to return to the theme list page.

On the theme list page, we have to choose the "Compile Theme" button to compile our theme (compiling the theme converts the SCSS into standard CSS for serving to the browser).

When we return to the theme list, we will see our theme with a corresponding compile date.

Like Vaadin Add Ons, when you are working in a cluster the theme needs to be copied to each node and compiled separately.  Fortunately the "Export Theme" and "Import Theme" buttons can help with this.

The Export Theme function bundles the theme file into a zip and uses the browser to download the theme to your desktop.  The Import Theme function lets you browse for a theme zip file on your desktop to upload to the server.

After importing the theme, you should compile the theme so it is ready on the node.  Repeat this step for all nodes in the cluster.

The Vaadin 7 Control Panel also supports automated theme deployment similar to the automated Add On deployment discussed in a previous blog entry.  A future blog entry will cover the automated theme deployment functionality of the Vaadin 7 Control Panel.

So our new sample theme is done and ready for use in our portlets, but our vaadin-sample-portlet project needs one more change to use the theme.

Assigning the Vaadin Theme for a Vaadin Portlet

We have one minor change we must make so the vaadin-sample-portlet uses the new sample theme.

In the com.dnebinger.liferay.vaadin.sample.UsersUI class we had an annotation indicating we wanted to use the liferay theme:

// Use the standard Liferay theme for the widgets.
@Theme("liferay")
public class UsersUI extends UI implements Page.BrowserWindowResizeListener {

We need to change the annotation for our sample theme:

// Use our own theme
@Theme("sample")
public class UsersUI extends UI implements Page.BrowserWindowResizeListener {

Through this annotation our portlet will always use the sample theme.  If the sample theme is not available, Vaadin will fall back to a standard theme (the Liferay theme).

Beginning with Vaadin 7.3.0, you can call the UI's setTheme() method with a theme name, allowing for a runtime theme change.

Page Resizing

If you were closely following the previous blog posting, the addition of the "implements Page.BrowserWindowResizeListener" would stand out as a new addition.

Although this isn't necessary Vaadin Theme related, it does affect the view presentation, so I'm including it here as a bonus.

If you remember, there was code in the UsersUI init() method that set the height of the UI to 600px.  This is an issue for Vaadin that the UI has to have a defined height or it will not show.  However, 600px is a large and arbitrary value, surely there is a way we could size the portlet better.

And there is.  The com.vaadin.ui.Page class has access to the current browser details.  To demonstrate, I decided I would make my minimum portlet size 200px but, if there was more vertical space available, I'd expand to use it.  Not a very complex implementation, but it shows what is possible.  I ended up with the following:

int height = 200;

Page pg = Page.getCurrent();

if (pg != null)  {
   int browserHeight = pg.getBrowserWindowHeight();

   // so normally you may know that there is stuff on your page that should normally be about 800 px high.
   // we would want a minimum of 200 px in height, but if the browser height is 1500 why not grow to take
   // advantage of it?

   height = browserHeight - 800;

   if (height < 200) height = 200;
}

setHeight(height + "px");

This code in the init() method allows for choosing a dynamic starting size, but what if we want to change the height based upon the browser window size changing?  We can deal with that by registering as a browser resize listener.

First our class implements the Page.BrowserWindowResizeListener interface, then we can register as a listener in the UsersUI init() method:

if (pg != null) pg.addBrowserWindowResizeListener(this);

And our implementation of the interface uses similar logic to handle the resize:

/**
 * browserWindowResized: Event handler for the browser window resize.
 * @param browserWindowResizeEvent
 */
@Override
public void browserWindowResized(Page.BrowserWindowResizeEvent browserWindowResizeEvent) {
   int bheight = browserWindowResizeEvent.getHeight();

   int height = bheight - 800;

   if (height < 200) height = 200;

   setHeight(height + "px");
}

Like I said, this implementation is not the best.  If your height of stuff above the portlet is 800 px on a wide screen but grows to 1200 px when shrunk so the upper content wraps, well then the math is all wrong.  Also there's no thought given to the footer height in the calculation.

But the point was not to show a perfect implementation, just to show some capability.

Conclusion

So our theme is compiled and ready to go.  The code changes are complete so we build and deploy the updated portlet.  When we see our results, they look a lot better than the starting image:

Themed User Details

Compared to the starting image, it is easy to see that applying some Vaadin theming will make your Vaadin portlets just look better.  No, this is still probably not a view that will excite anyone, but after seeing how easy it is to edit and compile a theme using the Vaadin 7 Control Panel, it should be clear that it could be styled to get it up to anyone's expectations.

An important feature of the shared Vaadin environment and theme editing using the Vaadin 7 Control Panel: theme changes take effect (almost) immediately, no deployments necessary.  After you compile the theme, any time the Vaadin portlet is refreshed or a new user starts an instance, they'll get the updated theme.  This can be a big advantage if deployments within your organization are significant events that must be scheduled well in advance.

Happy Theming!

Auto Vaadin Add On Deployment

General Blogs February 4, 2015 By David H Nebinger

Introduction

In my last blog post, I closed with the following:

If you have the Vaadin 7 Control Panel installed and you've deployed the LazyPagedContainer Add On, you can download and deploy the vaadin-sample-portlet-1.0-SNAPSHOT.war file directly from this blog.

This is not completely correct.  The Vaadin 7 Control Panel includes functionality to deploy Vaadin Add Ons at deployment time.

Originally I added this feature to support deployment of Vaadin 7 portlets from the Liferay MarketPlace.  I want to be able to distribute Vaadin 7 plugins without giving the user a whole list of dependencies that have to be satisfied to use the plugin.  With this feature, deploying the plugin into the environment would also deploy the Add On, recompile the widgetset and the portlet would be ready to go.  The only requirement would be the Vaadin 7 Control Panel.

This feature has another use case that is valuable for enterprises - artifact deployment to multiple environments.

Imagine you're a developer and you've just completed development of your next enterprise Vaadin 7 portlet.  It works great in your local development environment, but to implementent all of the requirements you needed to use some additional Add Ons that are not currently in your environment, namely the Lazy Paged Container.

In your enterprise, you have a bunch of environments - testing environments, QA environments, production environment in a cluster...  Normally before your portlet could get deployed to those environments, you'd have to ensure the Add On was deployed, the widgetset compiled, etc., and then your portlet could be deployed.  Some of these environments you might have access to deploy the Add On to, but others may involve a separate Operations group that will look at pushing out the Add On as a deployment of it's own.

Well, the same feature to auto deploy Add Ons for MarketPlace plugins will also help in this environment.  Using the auto Add On deployment feature, you would augment your portlet to push the Lazy Paged Container during your portlet deployment - whatever your enterprise deployment process, the deployment of your Vaadin 7 portlet will deploy your Add On too.

In the remainder of this blog post we'll adapt the vaadin-sample-portlet project to handle the auto deploy of the Lazy Paged Container Add On.

Preparation

The Vaadin 7 Control Panel comes with a service jar that you will need in your project.  You should install the jar to your local Maven repository or deploy it to your local Nexus repository so it can be included in your project.  If you navigate to the vaadin7-control-panel-portlet/WEB-INF/lib directory on your app server, you'll find the vaadin7-control-panel-portlet-service-version.jar file (where version will be the version number for the service jar).

To install the jar to your local Maven repository, run the following command from this directory:

mvn install:install-file -Dfile=vaadin7-control-panel-portlet-service-version.jar \
  -Dgroupid=com.dnebinger.liferay -DartifactId=vaadin7-control-panel-portlet-service \
  -Dversion=version -Dpackaging=jar

Replace version with the version from the filename, note that there are two instances in the command line.

To deploy the jar to your local Nexus repo, your command line will be:

mvn deploy:deploy-file -Dfile=vaadin7-control-panel-portlet-service-version.jar \
  -Dgroupid=com.dnebinger.liferay -DartifactId=vaadin7-control-panel-portlet-service \
  -Dversion=version -Dpackaging=jar -Durl=http://user:pswd@nexus
Again the version number needs to be entered in the command line and the url should be changed to your local repository URL.
 

Project Changes

The first change will be in the pom.xml file.  We'll be adding a dependency on the service jar and removing the provided scope for the Lazy Paged Container artifact.

The new dependencies, based upon my local version, are:

<dependency>
    <groupId>com.dnebinger.liferay</groupId>
    <artifactId>vaadin7-control-panel-portlet-service</artifactId>
    <version>1.0.1.0</version>
</dependency>
<dependency>
    <groupId>org.vaadin.addons</groupId>
    <artifactId>lazy-paged-container</artifactId>
    <version>1.0.0</version>
</dependency>

Because we removed the provided scope from the pom.xml file, Maven will include the jar in the war's WEB-INF/lib directory.  Since the portal may not have the Add On jar (if it hasn't been deployed before), we will remove it as a portal dependency jar.  Also, since we're using the Vaadin 7 Control Panel service jar, we'll add it as a required deployment context so the portlet will not load unless the Vaadin 7 Control Panel is deployed and ready.  Below is the updated liferay-plugin-package.properties file:

name=vaadin-sample-portlet
module-group-id=liferay
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.vaadinonliferay.com
author=Vaadin On Liferay
licenses=LGPL

# First the vaadin jars, then spring jars.
portal-dependency-jars=\
        vaadin-server.jar,vaadin-shared.jar,guava-vaadin.jar,atmosphere-runtime-vaadin.jar,jsoup.jar,\
      streamhtmlparser-jsilver-vaadin.jar,vaadin-slf4j-jdk14.jar,json-java.jar,\
      commons-beanutils.jar,commons-collections.jar,commons-lang.jar,commons-io.jar,commons-pool.jar,commons-configuration.jar,commons-digester.jar,\
      spring-core.jar,spring-asm.jar,spring-context.jar,spring-context-support.jar,spring-expression.jar,spring-transaction.jar,spring-web.jar,spring-aop.jar

# We are dependent upon the Vaadin 7 Control Panel since we use the service jar.
required-deployment-contexts=vaadin7-control-panel-portlet

The next change is to add a startup action class extending one from the Vaadin 7 Control Panel service jar.  It's really a simple class, so it is below:

package com.dnebinger.liferay.vaadin.sample;

import com.dnebinger.liferay.vaadin.startup.AbstractVaadinAddonDeployStartupAction;

import java.util.ArrayList;
import java.util.List;

/**
 * class LazyPagedContainerDeployStartupAction: A startup action class to deploy the Lazy Paged Container Vaadin Add On.
 */
public class LazyPagedContainerDeployStartupAction extends AbstractVaadinAddonDeployStartupAction {
   private static final String LPC_JAR = "LazyPagedContainer.jar";

   /**
    * getAddonNames: Returns the names of all jars from the WEB-INF/vaadin/addons directory that should be deployed.
    * @return List The list of jar filenames.
    */
   @Override
   protected List<String> getAddonNames() {
      List<String> names = new ArrayList<String>(1);

      names.add(LPC_JAR);

      return names;
   }

   /**
    * getAddonVersion: Returns the encoded version for the Add On jar with the given name.
    * 
    * Version is encoded without periods but complete enough so updates will be deployed correctly.
    * For this example, Lazy Paged Container is verison 1.0.0 so the value we will return is 100.  That way if a
    * 1.1.0 or 1.0.1 or 2.0.0 version comes out, we can follow the version coding to get 110, 101, and 200 and
    * trigger the update deployment.
    * 
    * @param addonName Name of the Add On to get the version for.
    * @return int The encoded version number.
    */
   @Override
   protected int getAddonVersion(String addonName) {
      // you should be returning a version number for every Add On that you're hoping to deploy.
      if (LPC_JAR.equals(addonName)) {
         return 100;
      }
      
      return 0;
   }
}

When the startup action is invoked, the named Add On must be found in the portlet's WEB-INF/vaadin/addons directory and match the given name.  So create a WEB-INF/vaadin/addons directory and copy the Add On jar(s) to this directory.

The final change is to add the pieces so Liferay will handle our startup action.  We will do this by adding a hook to the portlet to add the portal properties for the startup action.

First we need to add the src/webapp/WEB-INF/liferay-hook.xml file:

<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd">

<hook>
    <portal-properties>vaadin-sample-portlet-hook.properties</portal-properties>
</hook>

We also need to create the src/resources/vaadin-sample-portlet-hook.properties file:

#
# vaadin-sample-portlet-hook.properties - Properties for the hook to add the app startup action.
#

application.startup.events=com.dnebinger.liferay.vaadin.sample.LazyPagedContainerDeployStartupAction

That's it!

Conclusion

With these changes in place, when you build and deploy the portlet, when it is started in the application container the startup action will process the LazyPagedContainer.jar file.

If it has either not been deployed before or if the version is greater than the currently installed version (considered an Add On upgrade), the jar will be copied to the portal's WEB-INF/lib directory, it will be added as a selected Add On (will show as checked in the Vaadin 7 Control Panel), and the widgetset will be rebuilt including the jar.

If it has already been deployed or the version is less than or equal to the deployed version, nothing happens (since it's already included).

So this eliminates the prework involved with getting all of the required Add Ons out of the way so you're back to just deploying your snazzy new Vaadin 7 portlet.

Developing a Portlet in Vaadin 7

General Blogs February 3, 2015 By David H Nebinger

Introduction

So I wanted to provide an example Vaadin portlet built using the Vaadin 7 shared environment.  Currently I've been migrating my general development efforts over to Intellij, so I thought this would be a good time to try out creating a Vaadin 7 portlet in Intellij and Maven.  The results are outlined in the rest of this blog entry.

Creating the Project

So to create the project, I just used Intellij's Maven integration to create a Liferay portlet.  From the starting page, I chose "Create New Project".

Intellij Starting Page

For lack of anything better, I used the Maven type to create a new Liferay portlet.  I used the liferay-portlet-archetype which, by default, creates a new Liferay MVC portlet, but we'll take care to remove that later on.  It will provide all of the right plumbing though to get the project started.

Create Maven Project

For the new project you have to specify your Maven artifact details.  The values I used are below.  One important note, there are some versions of Liferay and/or some application servers which require a plugin to include the plugin type as a suffix in the name.  I tend to just do that now for all Liferay artifacts just so I automatically include "-portlet" in the artifact id.

Maven Archetype Details

Next page you can review and, if necessary, change the settings being passed to Maven:

Maven Settings

Finally specify the project name which I've kept the same as my Maven artifactId.

Project Name

Updating the Project Files

Before we start creating the Vaadin source files we have to modify some of the project files.

The first easy modification to the project is to delete the view.jsp file, the icon.png file, the js directory and the css directory, all generated for the portlet by the archetype.  These files/directories will not be needed so there's no reason to keep them any longer.

Update pom.xml

The basic pom.xml file created by the archetype is set up for a Liferay MVC portlet.  We need to add some parts to it to leverage the Vaadin shared environment.

Before the <dependencies /> section, we have to define a new <repository />.  Insert the following:

<repositories>
    <repository>
        <id>vaadin-addons</id>
        <url>http://maven.vaadin.com/vaadin-addons</url>
    </repository>
</repositories>

This adds the Vaadin Add On repository definition to the project so Maven will be able to find dependency jars.

We also need to add a number of dependencies to the project:

<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-server</artifactId>
    <version>7.2.7</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.6.3</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-sass-compiler</artifactId>
    <version>0.9.6</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.vaadin.external.flute</groupId>
    <artifactId>flute</artifactId>
    <version>1.3.0.gg2</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>net.sourceforge.cssparser</groupId>
    <artifactId>cssparser</artifactId>
    <version>0.9.11</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.w3c.css</groupId>
    <artifactId>sac</artifactId>
    <version>1.3</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-shared</artifactId>
    <version>7.2.7</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.vaadin.external.google</groupId>
    <artifactId>android-json</artifactId>
    <version>0.0.20131108.vaadin1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.vaadin.external.google</groupId>
    <artifactId>guava</artifactId>
    <version>16.0.1.vaadin1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.vaadin.external.streamhtmlparser</groupId>
    <artifactId>streamhtmlparser-jsilver</artifactId>
    <version>0.0.10.vaadin1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.vaadin.addons</groupId>
    <artifactId>lazy-paged-container</artifactId>
    <version>1.0.0</version>
    <scope>provided</scope>
</dependency>

This pulls in all of the Vaadin jars and dependencies.  Additionally I've included commons-lang and the lazy-paged-container Add On jar that the portlet will be using.

Note that the <scope /> being used for all of the jars is "provided".  Maven will include the jars to satisfy compiling the Java code but will exclude them from the built war file artifact.

Updating the Portlet.xml File

The archetype generated an initial portlet.xml file that contains the values for the Liferay MVC portlet.  We'll strip that portlet definition out and replace it with the one we need for Vaadin:

<portlet>
       <!-- Keep portlet names simple -->
       <portlet-name>vaadin-users</portlet-name>
       <display-name>vaadin-users</display-name>

       <!-- Normal Vaadin portlets will use this class as the portlet class -->
       <portlet-class>com.vaadin.server.VaadinPortlet</portlet-class>

       <!-- Specify the main UI class which will be instantiated by the portlet -->
       <init-param>
           <name>UI</name>
           <value>com.dnebinger.liferay.vaadin.sample.UsersUI</value>
       </init-param>
       <!-- Specify the use of the shared portal widgetset -->
       <init-param>
           <name>widgetset</name>
           <value>com.vaadin.portal.gwt.PortalDefaultWidgetSet</value>
       </init-param>

       <expiration-cache>0</expiration-cache>
   <supports>
      <mime-type>text/html</mime-type>
   </supports>
   <portlet-info>
      <title>Vaadin Sample</title>
      <short-title>Vaadin Sample</short-title>
      <keywords>vaadin sample portlet liferay users lazy container</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>

The important parts here are the <portlet-class /> value and the UI init param.

The given portlet class is the class to use for Vaadin 7-based portlets.  Unlike GenericPortlet where you often need to subclass the portlet to provide an implementation with your business logic, the VaadinPortlet class rarely (if ever) needs to be subclassed.

The UI <init-param /> value is the class for the main UI class for your portlet.  This class extends com.vaadin.ui.UI and handles the initialization of the Vaadin portlet views.  The UsersUI class referenced here will be discussed later.

The remainder of the <portlet /> contents are standard entries used by many other portlets.  Customize as necessary.

Although not highlighted here in this blog, you should update the liferay-display.xml file using the value from the <portlet-name /> tag.

Updating the Liferay-Portlet.xml File

The next file to update is the liferay-portlet.xml file.  Again the Liferay MVC portlet entry will be stripped, and the Vaadin portlet entry must be added:

<portlet>
       <!-- Must match the value of the <portlet-name /> tag from portlet.xml. -->
       <portlet-name>vaadin-users</portlet-name>
       <!-- Instanceable indicates whether multiple copies are allowed on the same page. -->
       <instanceable>false</instanceable>
       <!-- ajaxable should always be false for Vaadin portlets -->
       <ajaxable>false</ajaxable>
</portlet>

Not really much here.  Javascript and CSS files are not normally used (you don't need separate JS files for Vaadin and styling comes from the Vaadin theme).  Many of the other standard values used in other portlet frameworks are not necessary for Vaadin portlets.

The only tag that is necessary is the <ajaxable /> tag, this value should be set to false for all Vaadin portlets.

Updating the Liferay-Plugin-Package.Properties File

The next file to modify is the liferay-plugin-package.properties file.  The change we're going to make here is the inclusion of the portal dependency jars that will be included during hot deployment.

Our liferay-plugin-package.properties file looks like:

name=vaadin-sample-portlet
module-group-id=liferay
module-incremental-version=1
tags=
short-description=
change-log=
page-url=http://www.vaadinonliferay.com
author=Vaadin On Liferay
licenses=LGPL

# First the vaadin jars, then the addon jar(s), then spring jars.
portal-dependency-jars=\
        vaadin-server.jar,vaadin-shared.jar,guava-vaadin.jar,atmosphere-runtime-vaadin.jar,jsoup.jar,streamhtmlparser-jsilver-vaadin.jar,\
        vaadin-slf4j-jdk14.jar,json-java.jar,\
        LazyPagedContainer.jar,\
        commons-beanutils.jar,commons-collections.jar,commons-lang.jar,commons-io.jar,commons-pool.jar,commons-configuration.jar,commons-digester.jar,\
        spring-core.jar,spring-asm.jar,spring-context.jar,spring-context-support.jar,spring-expression.jar,spring-transaction.jar,spring-web.jar,spring-aop.jar

Remember all of those provided scopes in the pom.xml file?  By declaring them as provided, Maven would not include the jars in the /WEB-INF/lib directory.  But since we need them after deployment, we list them as portal-dependency-jars so they all get pulled in.

By listing the Vaadin jars, the version of Vaadin 7 the portal is using will get pulled into your portlet during hot deployment.  This will ensure that your portlet has the same Vaadin version as the portal, and when Vaadin is upgraded (using the Vaadin 7 Control Panel), the version of Vaadin used by this portlet will be upgraded also.

The LazyPagedContainer.jar file is also listed as a dependency.  In my last blog entry, I demonstrated how to deploy the LazyPagedContainer Add On using the Vaadin 7 Control Panel.  If I had any other Add Ons that I wanted to use in this portlet, I would first deploy them using the Vaadin 7 Control Panel and recompile the widgetset.  Then I can include the jar file(s) as portal-dependency-jar entries and I can use the Add On(s) in my portlet.

Writing the Vaadin Portlet Code

Now this is where I need to back peddle a little bit...

Remember when I said I was going to do this portlet in Intellij?  Well that really was my plan.  But I got to this point where I was ready to start my CustomComponent subclasses and I just stopped.  Basically I was just unwilling to hand-code the initial component classes, defining all of the layouts and widgets, figuring out their alignment, etc.

So I quickly caved and fired up my trusty version of Eclipse that has the Vaadin IDE plugin installed.  If you are going to be doing Vaadin development, either for servlets or portlets or both, you really, really need this Eclipse plugin.

I mean, sure, I could decide to use a primary layout as a VerticalLayout, the first entry being a HorizontalLayout that has a VerticalLayout on the left (with the user detail labels) and an Embedded for the user portrait on the right, and the main VerticalLayout has a Button that is right aligned for the Back link.  I could declare all of the private members, write all the code to construct and initialize the components and wire them into the appropriate heirarchy.

But who would when you can lay everything out graphically?

Vaadin IDE

Isn't that sexy?  You can't do anything like this with your JSP frameworks, your javascript frameworks, your jsf frameworks, ...  And this isn't some storyboard or anything like that, behind the scenes the Vaadin IDE is reworking the Java code that implements what you see in this view.  In the end, the generated code is by no means complete (no event handlers are wired, etc.), but this is such a great head start towards building your views it is just too hard for me to give up.

So basically I started my Eclipse environment and created a fake Vaadin servlet so I could start my CustomComponents that I would be using in my portlet.  I laid them out visually such as you see above.  When I was done with the visual layout, I switched over to the code view to find all of the Java code the Vaadin IDE generated for me, copied it all, then switched over to Intellij to create the java classes and pasted all of the Vaadin IDE-generated code into my new class in Intellij.

Unfortunately there is no current Vaadin IDE plugin being built for Intellij (that I know of), so at some point I'm going to be faced with the choice to continue this awkward process (since I don't want to give up the Vaadin IDE) or bail on Intellij and stick with Eclipse to keep the Vaadin IDE close.  I'm new to Intellij and haven't developed the commitment to it that others have, so I'm not sure which way I'll end up going, but I'll keep you up to date.

Now back to the code...

Portlet Component Decomposition

For my interface, I decomposed it into the following components:

  • A detail component - The basic interface shown above, simply a page which shows basic user details and the user portrait.  Works on a single user.
  • A list component - Shows the list of Liferay users.  Will leverage the LazyPagedContainer to manage the pull of data from the Liferay API.
  • A tab component - Tab components (with tabs hidden) happen to be an easy way to quickly switch back and forth between the (hidden) tabs.  On one tab I'll put the list component and the other tab will have the detail component.  When a user is selected from the list, I'll switch tabs and update the detail component.  That back button on the detail page?  That will just get the tab component to switch back to the list component.
  • The UI class - This is needed by every Vaadin portlet to control the creation of the UI elements.

So, let's review some of the code.

The UserDetailComponent

The UserDetailComponent is the java class that implements the interface shown above.  Below is the class constructor:

public UserDetailComponent(UsersUI uui) {
   // Invoke the Vaadin IDE code to build the widget heirarchy from the visual design.
   buildMainLayout();
   setCompositionRoot(mainLayout);

   // set the initial values
   screenName.setValue("");
   emailAddress.setValue("");
   userId.setValue("");
   name.setValue("");

   // also need to clear the portrait, initialize it to the basic male portrait.
   String maleUrl = UserConstants.getPortraitURL(uui.getThemeDisplay().getPathImage(), true, 0);

   // set the url as the source for the user portrait.
   userPortrait.setSource(new ExternalResource(maleUrl));

   // change the back button style to a link.
   backLink.setStyleName(Runo.BUTTON_LINK);

   // add the back link listener.
   backLink.addClickListener(new Button.ClickListener() {
      @Override
      public void buttonClick(Button.ClickEvent clickEvent) {
         // get the ui object
         UsersUI uui = (UsersUI) getUI();

         // invoke our little switch method.
         uui.switchToListView();
      }
   });
}

The Vaadin IDE-generated code is invoked to initialize the view per the visual design.  The Labels are updated to clear out the initial values.  

The userPortrait is an Embedded component that will be used to show the user portrait; if the user doesn't have a portrait, the basic male portrait will be used, and that's what we initialize the value to.  Using this type of component, we will be able to show the real user portrait the user might have loaded to their profile.

The style of the Back button is changed to a link, basically it will look like a hyperlink.  A click listener is also added to deal with clicks on the link.  Inside the click listener, we get the UI instance the component is bound to (our UsersUI instance) and the switchToListView()  method is invoked to handle the switch.

In Vaadin, the UI instance is accessable to every component that is added to the heirarchy.  This makes the class a great extension point to add utility methods or manage navigation.

When switching to the detail view, the component needs to update with information for the user.  Here's the method:

/**
 * updateFromUser: Updates the screen elements for the given user id.
 * @param uId User id to update the view for.
 */
public void updateFromUser(final long uId) {
   User user = null;

   try {
      // try to get the user given the uId...
      user = UserLocalServiceUtil.fetchUser(uId);
   } catch (SystemException e) {
      logger.error("Error fetching user " + uId + ": " + e.getMessage(), e);
   }

   UsersUI uui = (UsersUI) getUI();

   if (user == null) {
      // we could not get a user record.  Reset all fields and return.
      screenName.setValue("");
      emailAddress.setValue("");
      userId.setValue("");
      name.setValue("");

      // also need to clear the portrait
      String maleUrl = UserConstants.getPortraitURL(uui.getThemeDisplay().getPathImage(), true, 0);

      userPortrait.setSource(new ExternalResource(maleUrl));

      return;
   }

   // set the labels from the values for the user.
   screenName.setValue(user.getScreenName());
   emailAddress.setValue(user.getEmailAddress());
   userId.setValue(String.valueOf(uId));
   name.setValue(user.getFullName());

   // also need to update the portrait.
   String portUrl = null;

   try {
      // get the portrait url for this user
      portUrl = user.getPortraitURL(uui.getThemeDisplay());
   } catch (PortalException e) {
      logger.error("Error getting user portrait url: " + e.getMessage(), e);
   } catch (SystemException e) {
      logger.error("Error getting user portrait url: " + e.getMessage(), e);
   }

   if (StringUtils.isBlank(portUrl)) {
      // don't have a url, default to the male portrait
      portUrl = UserConstants.getPortraitURL(uui.getThemeDisplay().getPathImage(), true, 0);
   }

   // update the portrait
   userPortrait.setSource(new ExternalResource(portUrl));
}

The comments here are self explanatory.

The line for getting the portrait URL for the user shows a call to a utility method exposed in the UsersUI class, the getThemeDisplay() method.  This method does what it says, it returns the current ThemeDisplay instance that is needed to get the portrait URL.  This method will come up later.

The UserListComponent

The UserListComponent is used to display the list of Liferay users.  It too was laid out using the Vaadin IDE in Eclipse, and that code was used in Intellij as the foundation for the class.  I just had to add the code to initialize the table:

public UserListComponent() {
   buildMainLayout();
   setCompositionRoot(mainLayout);

   // This container, based on the LazyPagedContainer, encapsulates the access to the UserLocalServiceUtil
   // class and it's methods to get to the users.
   userContainer = new LazyUserContainer();

   // do not allow row selection
   users.setSelectable(false);

   // set the container as the data source for the users table.
   users.setContainerDataSource(userContainer);

   // we want name, email, and screen name to be a link to click to the detail page, so we will add them
   // as extra columns that are buttons.
   users.addContainerProperty(FIELD_FULLNAME, Button.class, null, NAME, null, null);
   users.addContainerProperty(FIELD_EMAILADDRESS, Button.class, null, EMAILADDRESS, null, null);
   users.addContainerProperty(FIELD_SCREENNAME, Button.class, null, SCREENNAME, null, null);

   // Since those columns will be buttons, they need to be generated.  This generator will be used
   // to generate the column objects (since they are not a natural member of the User class).
   userColumnGenerator = new UserColumnGenerator();

   // Add the generated columns.
   users.addGeneratedColumn(FIELD_FULLNAME, userColumnGenerator);
   users.addGeneratedColumn(FIELD_EMAILADDRESS, userColumnGenerator);
   users.addGeneratedColumn(FIELD_SCREENNAME, userColumnGenerator);

   // add our visible columns so only the generated are used.
   // this will leave the other members of the User class outside of it.
   users.setVisibleColumns(new Object[] {FIELD_FULLNAME, FIELD_EMAILADDRESS, FIELD_SCREENNAME});

   // refresh the rows 
   users.refreshRowCache();
}

The LiferayUsersComponent

The LiferayUsersComponent manages the tab widget with our two views as tab pages (the tabs themselves are hidden).  This component was also laid out using the Vaadin IDE in Eclipse, and the generated code was copied to Intellij to edit.  I didn't really change any code in this class, however, I just added two utility methods for switching to selected tabs:

/**
 * switchToListView: Switches to the list view tab.
 */
public void switchToListView() {
   // choose the list tab.
   userPages.setSelectedTab(userListTab);
}

/**
 * switchToDetailView: Switches to the detail view tab.
 * @param userId The user id to display details for.
 */
public void switchToDetailView(final long userId) {
   // choose the details tab...
   userPages.setSelectedTab(userDetailTab);

   // update the detail view for the selected user.
   userDetailTab.updateFromUser(userId);
}

The UsersUI Class

The UsersUI class is not generated by the Vaadin IDE, you have to create this yourself.  Since the UsersUI class is pretty small, it will be presented in whole:

package com.dnebinger.liferay.vaadin.sample;

import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.theme.ThemeDisplay;
import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinPortlet;
import com.vaadin.server.VaadinPortletService;
import com.vaadin.server.VaadinPortletSession;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

import javax.portlet.PortletRequest;

/**
 * class UsersUI: Simple UI class to demonstrate Vaadin in the portal.  Highly commented for Liferay developers.
 *
 * The UI extension class is the main entry point for your Vaadin portlet.  It is here that you will create your initial UI.
 *
 * @version 1.0
 * @author dnebinger
 */

// Use the standard Liferay theme for the widgets.
@Theme("liferay")
public class UsersUI extends UI {

   private VerticalLayout mainLayout;

   private LiferayUsersComponent usersComponent;

   /**
    * init: The extension point, define the initial UI for the interface.
    * @param vaadinRequest The initial request which is used to initialize the display.
    */
   @Override
   protected void init(final VaadinRequest vaadinRequest) {
      // create the main vertical layout
      mainLayout = new VerticalLayout();

      // give it a margin and space the internal components.
      mainLayout.setMargin(true);
      mainLayout.setSpacing(true);
      mainLayout.setWidth("100%");
      mainLayout.setHeight("100%");

      // set the layout as the content area.
      setContent(mainLayout);

      // In the portal, the main widget cannot have an indeterminate height or it just won't render.  There's a number
      // of things going on between the Liferay JS, the Liferay CSS, and the GWT and Vaadin.  There is a bug open on
      // Vaadin, but until it is resolved it's best to come up with a reasonable height and set it.  Note this is just
      // an initial height to get it to render, there are corresponding things that can be done to update the height
      // later on...
      setHeight("600px");
      setWidth("100%");

      // create the users component, the component that has the (hidden) tabs.
      usersComponent = new LiferayUsersComponent(this);

      // add to the page.
      mainLayout.addComponent(usersComponent);

      // switch to the list view for the initial view.
      switchToListView();
   }

   /**
    * switchToListView: Utility method to switch to the list view.
    */
   public void switchToListView() {
      usersComponent.switchToListView();
   }

   /**
    * switchToDetailView: Utility method to switch to the detail view.
    * @param userId The user id to switch to.
    */
   public void switchToDetailView(final long userId) {
      usersComponent.switchToDetailView(userId);
   }

   /**
    * getThemeDisplay: Returns the current ThemeDisplay instance.
    * @return ThemeDisplay The found instance.
    */
   public ThemeDisplay getThemeDisplay() {

      ThemeDisplay td = null;

      // okay, the theme display is actually a request attribute, so we just need to get there...

      // start by getting the current portlet request
      PortletRequest portletRequest = VaadinPortletService.getCurrentPortletRequest();

      // get the ThemeDisplay instance from the request attributes
      td = (ThemeDisplay) portletRequest.getAttribute(WebKeys.THEME_DISPLAY);

      // return the instance.
      return td;
   }
}

A couple of notes on this class...

We start with the @Theme annotation.  This informs Vaadin that the given Vaadin theme should be used for the UI and all of it's components.  Note this is the Vaadin theme, it is not a Liferay theme.  To see what Vaadin themes are available, you can use the Vaadin 7 Control Panel and use the Themes tab:

Vaadin Themes

This shows the list of Vaadin themes available for your Vaadin portlets.  Note that the liferay theme here does not mean the actual Liferay theme, it's actually a clone of the Liferay Classic theme in the form of a Vaadin theme (blue buttons, etc.).

The UsersUI has the two switching utility methods, these are just pass thru to the component with the tabs, but since they are in the UsersUI class they are available to all components in the app.

Finally there is the implementation of the getThemeDisplay() method.  This method accesses the current PortletRequest instance to extract the ThemeDisplay instance from the attributes.  Nothing magic here, but it is a useful routine to keep around.

Result

After building and deploying the new portlet and dropping it in a page, you can see the results.

Here's the list view showing all active users:

Users Listing

And when you click on a user, you switch to the detail view:

Detail View

So I know what you're thinking - yuck.  It looks terrible.  Spacing is all weird, it's not at all colorful, it is just bland and boring.

And you're absolutely right.  But that is, of course, fixable.  I laid this thing out in a few hours, got the portlet working to the point where I could write this blog.  I did not spend any real time making it pretty, dealing with sizing of the view, etc.  But in a few additional hours, I could make it look pretty, make it look fresh and fine on a page.

The part that you don't see, the part that stands out - this thing rocks.  It is a full AJAX portlet.  Switching between the tabs is done entirely with JavaScript, there are no full page refreshes taking place.  I don't know of any other framework that is going to allow you to create a portlet like this in such a short amount of time that is all AJAX in the browser.

Conclusion

I hope this has been a useful introduction to Vaadin portlets.  It really doesn't do Vaadin justice, IMHO.  Like I said, the rendered views look pretty boring right now.  It doesn't take advantage of all of the Vaadin widgets available in the standard widgetset or any of the visual widgets available as Vaadin Add Ons.  It does however demonstrate how you can code an AJAXy portlet using only Java (there was no javascript in this example, there aren't separate pages as JSP, JSF, velocity templates, etc).  And if you're building business apps (where eye candy is not as important as getting the functionality done and out the door), this portlet may look just fine to you.

I think I will come back to this portlet in a future blog entry and address how it looks.  That will give me a chance to introduce creating custom Vaadin themes, accessing browser details for sizing, and making the view look good.

I have loaded the project into my own github account, you can access it from here: https://github.com/dnebinger/vaadin-sample-portlet.  Feel free to clone it, fork it, modify as you'd like.  Heck, I might even take pull requests if I get any.

If you have the Vaadin 7 Control Panel installed and you've deployed the LazyPagedContainer Add On, you can download and deploy the vaadin-sample-portlet-1.0-SNAPSHOT.war file directly from this blog.

Adding a Vaadin Add On to the Shared Environment

General Blogs February 2, 2015 By David H Nebinger

Introduction

So Vaadin provides a core set of widgets, standard widgets that you'd find in any web framework such as radio buttons, buttons, links and text input fields.

But like most other frameworks, we as developers want a richer toolset of widgets that go beyond the standard set, usually to encapsulate some bit of a control which is obviously self contained.

While other frameworks use their own methods for adding components to the standard toolset, Vaadin has the Add On.

Add Ons

Vaadin Add Ons are commercial and/or open source widgets that provide functionality beyond what is implemented in the standard core.

As an example, here's a few useful Add Ons from the full list available at Vaadin AddOn Directory:

  • Lazy Paged Container - A specialized container to support paged retrieves to the database, a useful base for adapting Vaadin to Liferay Service Builder APIs.
  • AceEditor - A rich text editor control for Vaadin.
  • OSGiMaskedTextField - A text field which supports a mask to limit input, i.e. "(###) ###-####" for a phone number.
  • And many more...

Seriously, there are many more.  At the time of this writing, there are 305 Add Ons available for Vaadin 7.

Honestly most of these I've never used, never looked at, and likely will never use.  But it is kinda reassuring that, should the need arise, I may be able to find a missing widget in the form of an Add On from the Vaadin Directory.

Add Ons, Vaadin and Liferay

Finding an Add On that you'd like to use is merely the initial step.  After the decision is made, well then you have to figure out how to use it.

This was probably the one thing that I struggled with for Vaadin and Liferay.  I could see what the Add Ons were, I could see some that I wanted to use, but for the life of me I couldn't figure out how to take the next steps.

Vaadin.com, which focuses on how you do things for servlets, well they were very helpful in telling you that you have to include the Add On when you build the widgetset and even had some magical build recipes to do that.  But when you're new to Vaadin, what does all of that mean?  And how does that info, the info that targets building servlets, how does that info apply in the portal?

So let's start with a basic premise - using Add Ons is really easy, and it can be done in Liferay in just a couple of steps.  But let's tackle some of the internals before we get to the steps...

So in Vaadin, the "widgetset" or the "compiled widgetset" is really just the sum total of compiled javascript (java compiled into javascript by GWT) that is bundled together and available for the Vaadin runtime in the browser.  So if you want to use an Add On, well then it has to be "included when you compile the widgetset", or basically it needs to be included in the process that translates java into javascript and bundles it to be available for the Vaadin browser runtime.

A corollary to that, if your Add On is not included in the compiled widgetset, even if you include the jar in your WEB-INF/lib directory, it will not be rendered in the browser because the javascript is not part of the bundle.

Before digging into the steps on how to use an Add On that this blog post is going to cover, I want to take a moment to discuss the two types of Vaadin environments in Liferay.

Vaadin actually supports developing portlets in two environments - a standalone environment and the shared environment.

In the Vaadin standalone environment, you actually build a complete Vaadin environment into your portlet.  You get the Vaadin themes, the Vaadin browser runtime (loaded by your portlet into the browser), your own compiled widgetset, etc.  This can be an easy way to create a Vaadin 7 portlet because it is totally self-contained.  My issue with this path?  Well if you are going to embrace Vaadin for your portlet development, it's likely that you're going to have a number of Vaadin portlets and possibly you're going to end up with two or more Vaadin portlets on a page.  So when this happens, because each portlet was created using the Vaadin standalone environments, you're increasing the browser resource usage to handle them - increasing memory usage, increasing bandwidth usage, etc.  Before you know it, you can have a big problem on your hands that will take you awhile to straighten out.  Also with the standalone environment, each portlet can use a different version of Vaadin; imagine trying to figure out why the browser might have issues running a portlet using 7.2.6 and another running 7.2.7 side by side?

The Vaadin shared environment was the initial Vaadin environment supported under Liferay.  In the Vaadin shared environment, the Liferay application hosts the only set of themes, the Vaadin browser runtime, the compiled widgetset, etc.  In the shared environment, there is one version of Vaadin used in the portal.  In the shared environment, the impact to the browser is greatly reduced and all portlets are consistent in the use of the same Vaadin version.

IMHO, the shared environment is the right direction, especially if you're going to be making multiple Vaadin portlets.

Using Add Ons in the Shared Environment

If you're using the Vaadin shared environment, you're using the Vaadin 7 Control Panel.  The Vaadin 7 Control Panel makes using add ons in Liferay a snap.

So let's break down the steps to get ready to use an Add On.  We're going to use the x Add On.  Download the Add On and save it somewhere locally on your system, then point your browser at your Liferay environment, log in as an administrator, go to the control panel to the Configuration section and choose the Vaadin 7 Control Panel.

From the navigation on the right side, select the Add On link to get the following view:

 Add Ons View

On the lower left corner, click the "Choose File" button to select the Add On jar file to upload: (the dialog will vary based on operating system)

Select Jar

Click on the "Upload Add-On" button to start the upload:

Before the upload is complete, you are presented with a confirmation page that provides details on the Add On.  Click the "Yes" button to finish the deploy or "No" to cancel the deploy:

Note: Some Add-Ons do not contain a widget definition.  This usually indicates the Add On is a non-visual or server-side extension.  The Lazy Paged Container has a definition of code for building a lazy reference to windowed data retrieved on demand (this is a useful class to manage retrieval of Liferay Service Builder data), but it has no visual implementation.

After approving the Add On deployment, you must check the Add On and then click the "Compile WidgetSet" button to rebuild the widgetset including your Add On(s):

As stated earlier, compiling the widgetset includes the necessary javascript for rendering Add Ons correctly in the browser.

After compiling the widgetset (click the "Done" button to finish the compile process), you'll end up on the Overview page.  The Overview page shows all of the Add Ons that are currently compiled into the widgetset:

Overview Page

At this point the Add On is available in the shared environment and your developers can leverage the Add On in their Vaadin portlets.  Don't worry, a blog post for doing this is on the way, will get it out as soon as I can.

A final note for all of you cluster admins - you'll need to repeat these steps on each node in your cluster.  Yes, I know, this is a total PITA, but Liferay doesn't have much of a mechanism to synchronize these kinds of things across the cluster.  Sure, there is some messaging which could help, but the Add Ons can be too large to push around the cluster as messages.  You're left to deploying Add Ons to the nodes in the cluster manually.  The Add Ons should be deployed to all nodes in the cluster (so they can all render the Vaadin portlets correctly).

 

Upgrading to Vaadin 7 in Liferay 6

General Blogs January 26, 2015 By David H Nebinger

Liferay ships with a pretty old copy of Vaadin 6, but most documentation and examples out now are for Vaadin 7.  It's pretty easy to upgrade the shared Vaadin environment to Vaadin 7, as simple as installing the Vaadin 7 Control Panel from the Marketplace.

When the Vaadin 7 Control Panel is installed, it will purge Vaadin 6 from the Liferay environment and copy an initial Vaadin 7.2.7 into the Liferay environment.

From there, you can use the Vaadin 7 Control Panel to upgrade/downgrade to another Vaadin 7 version.

Coming Soon: Vaadin 7 Control Panel

General Blogs October 2, 2014 By David H Nebinger

The Vaadin 7 Control Panel is a custom control panel designed to manage the shared Vaadin environment in Liferay.

What is the shared Vaadin environment?  It is one of two modes1 for creating Vaadin portlets and refers to the shared Vaadin environment hosted within the ROOT Liferay web application (under Vaadin 6, the shared Vaadin environment was the only supported mode).

Unfortunately managing the shared Vaadin environment has never been easy.  Vaadin requires not only jars, but also the theme and compiled widgetset files from the /html/VAADIN directory within Liferay.  Vaadin Add-Ons, deployed as Jar files, must be deployed to the ROOT/WEB-INF/lib directory (and included in the widgetset compile).  The only approved way of deploying these artifacts to Liferay is through plugins; a JSP hook can handle the theme files, but an EXT plugin is necessary for deploying the Add-On jars.

Vaadin 7 Control Panel to the Rescue!

The Vaadin 7 Control Panel solves these and other issues.  The new control panel has the following features:

  • An About Vaadin page that contains definitions for common Vaadin terms, helps those new to Vaadin understand Vaadin-speak:

About Vaadin Page

  • The Overview page summarizes everything in your shared Vaadin environment:

Overview Page

  • It is easy to change the shared Vaadin 7 version:

Change Version Page

  • Upgrade Vaadin even when the server cannot access the vaadin.com website:

Manual Vaadin Upload

  • The change version process reports detailed information on what is changed:

Change Version Details

  • Vaadin Add-Ons can be easily uploaded into Liferay for inclusion in the widgetset:

Add-On Upload

  • Before completing the upload, the Add-On details are presented for confirmation:

Add-On Confirmation

  • Additional dependencies for the widgetset compile can be included (these are sometimes needed for Add-Ons):

Additional Dependencies

  • Settings for the control panel can be changed inline, including memory settings used to compile the themes and widgetsets:

Settings

  • Custom themes can be created, edited, compiled, deleted, imported and exported.  The import/export feature will prove very useful to deploy themes to all nodes in a cluster, for theme promotion in corporate environments, etc.

Custom ThemesSelected Theme

  • Themes can be viewed inline.  Source files are presented in a syntax-highlighting viewer, images are previewed, and the folder hierarchy can be navigated: 

Theme Viewer

  • Custom themes can be edited inline using a syntax-highlighting editor.  Also new assets can be uploaded (images, other css files, etc.):

Custom Theme Editing

  • Compiling a theme shows detailed information about what is being done:

Theme Compiling

  • Widgetset compilation also gives detailed information:

Widgetset Compiling

Aside from these visual changes, there are a number of important non-visual changes.  The Vaadin 7 Control Panel supports localization (although currently only a language bundle will be available for English; submit your language bundle changes to support@vaadinonliferay.com for inclusion in a future release).

The Vaadin 7 Control Panel also includes a service layer.  By using the service layer, a Vaadin 7 portlet can:

  • Query for the version of the shared Vaadin 7.
  • Determine if the Valo theme is available.
  • List all available Vaadin themes.
  • List all available Vaadin Add-Ons.
  • Deploy Vaadin themes and/or Add-Ons after hot deployment.

This last item is significant.  Using the deployment features, a Vaadin plugin will be able to deploy custom themes and/or Add-Ons without requiring an administrator to set up the Vaadin environment in advance.  This opens the door for Vaadin 7 Marketplace plugins that need themes and/or Add-Ons as prerequisites, deploying them automatically so they are available when the portlet is used.  It can also be used in corporate environments to push themes and/or Add-Ons with plugins as they are promoted during development or to populate all nodes of a cluster, all without additional Liferay/Vaadin administration.

I'm really excited to get this published so it is available for the world to try.  Not just because it is a tool I've been working on for awhile, but because I see it opening doors for using Vaadin in the Marketplace as well as in the enterprise.

Vaadin is a great platform to build rich internet applications, we were just lacking a tool to pull everything together and make it easy to administrate.

 

 

 

1 Vaadin has been recommending a second mode for using Vaadin, a standalone mode.  In this mode, each individual portlet contains Vaadin and the theme(s) and the Add-Ons and the widgetsets, everything to be a working Vaadin portlet.  Since it is self contained, it is isolated from what goes on in the portal.  Unfortunately I believe there are some issues with this practice that have not been identified, discussed, or mitigated in any way.

For example, when you run a Vaadin portlet there is a client-side library that handles the DOM manipulation, javascript stuff, the theme application, etc.  The problem as I see it comes if you have a page with, say, 5 different Vaadin self-contained portlets.  This will lead to 5 different copies of the client-side library running in the browser!  Even if Vaadin were smart enough to handle them all in a single copy of the client side engine, what happens if one or more of the 5 were built with different versions of Vaadin, all self contained?

Same kind of issues with Add-Ons...  One plugin has version 1.0 of an addon while another has 1.1.  How does this work in the browser?  How will they be kept straight?  How do we know that there isn't some sort of bleed over from one to another?

Long story short, because of inadequate tools using the shared Vaadin environment in Liferay was a pain (some would use harsher words) and the standalone mode was seen as a way to allow developers to use Vaadin without having to figure out how to manage the shared environment.

With this new Vaadin 7 Control Panel, it will be much easier to manage the shared environment (which doesn't suffer from all of the issues the standalone mode may have) and my continuing recommendation would be to use it and avoid the standalone mode.

 

Vaadin Liferay Development...

General Blogs April 20, 2013 By David H Nebinger

NOTE: The following blog post is about Vaadin 6 and Liferay.  I'll be doing future posts on Vaadin 7, but for now I recommend sticking with Vaadin 6 in Liferay.

 

Introduction

About two years ago, I noticed the Liferay IDE allowed for the creation of a new type of portlet based on Vaadin.  Curious, I did some research and found I could create Liferay portlets based upon the Vaadin Framework.

According to the Vaadin FAQ, Vaadin ("Vaadin" sounds like vuh-din, emphasis on first syllable, the long 'a':s sound like the 'a' in "ago") is a Java web application framework. It is designed for creating rich and interactive applications that run in the browser, without any plugins. A server-driven architecture together with reusable component model is used to simplify programming of applications and for better web application security. No HTML, XML or JavaScript necessary and all Java libraries and tools are at your disposal.

Translation is that it's a framework that you do most of your development in Java and, since it is based on the GWT, runs mostly in the client browser and uses lots of AJAX to communicate with the backend.

It's not a flashy framework in that it's not really designed to support lots of browser eye-candy.  It is, however, very well suited for enterprise development where you want to support forms, tables, and other basic widgets to create real and responsive enterprise applications.

Unfortunately, the wizard in the Liferay IDE was the only info I found on creating Vaadin portlets.  I couldn't find a real developer guide, didn't understand some of the requirements from the Vaadin website, and I basically struggled through the development of an initial Vaadin portlet.

So this blog post is going to help explain Vaadin in Liferay and what you'll need to use to become an effective Vaadin portlet developer.

Terminology

Widgets

These are the UI elements that are rendered in the browser.  Vaadin includes support for a basic set of UI widgets and include buttons, checkboxes, option groups, tables, trees, labels, text fields, etc.

Widgets have two aspects: the server side code and the client side code.  The server side widget is referred to as a Component.  Components are instantiated, configured, and added to define what the client side will represent.  The client side code is in Javascript and is generated using GWT to compile the Java code for the components into the javascript version for the client side.

Widgetset

A widgetset is the set of compiled javascript for all of the widgets that are used in the Vaadin application.

Widgetsets have names.  The widgetset name is a Java class-like name complete with a package path, i.e. com.vaadin.portal.gwt.PortalDefaultWidgetSet.  There's actually a corresponding file in the classpath at the location defined by the widgetset name with the extension ".gwt.xml", and this file defines the widgetset and all included modules.  The com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml file is read by the GWT compiler to compile the widgetset used on the client side.

A Vaadin application requires a correctly compiled widgetset for the Vaadin version used in the application to render the client side correctly.

Theme

Vaadin widgets are rendered in the browser using a theme.  Vaadin ships with a number of themes out of the box, including a theme named "liferay" which is based on the standard Liferay classic theme in blue.

Custom themes are created by writing CSS.  Sounds pretty simple, but can be quite complex.  Every widget has it's own classes automatically added to them, and the components can have classes added to them in the Java code (components have an addStyleName() method to add a CSS class to the component, yes I know it's misnamed, but I think they were trying to avoid confusion with Java classes).

Add-Ons

Vaadin Add-Ons are supplemental widgets that can be added to a Vaadin application to add new widgets that can be used in the application.  For example, there are Add-Ons to provide integration with charting packages, new layouts, extended core widgets that provide additional functionality, etc.

When an Add-On is added to a Vaadin application, the widgetset must be recompiled to create the complete widgetset for the application.  If the widgetset is not recompiled, the server side will have the code for the component (so you the developer can create, configure, and add the component), but the client side will not be able to render the widget.

Add-Ons can be found in the Vaadin Add-On Directory.

Vaadin in Liferay

The Vaadin website covers Vaadin as servlets in great detail, and touches on Vaadin portlets somewhat, but there are some things about using Vaadin in Liferay that are important to keep in mind...

The Widgetset

Vaadin portlets use a single, shared widgetset.  This widgetset is normally com.vaadin.portal.gwt.PortalDefaultWidgetSet, but it can be changed by setting the "vaadin.widgetset" property in portal-ext.properties.

The single widgetset is used by all Vaadin portlets deployed in the portal, so the widgetset must contain all of the Add-Ons used by any single Vaadin portlet.  Have a single Vaadin portlet that uses, say, the Refresher Add-On?  It must be in the widgetset for all portlets.

The Theme

Vaadin portlets will, by default, use a single, shared theme.  This is actually a good thing because it will make your Vaadin portlets look consistent across the portal.

The default portal theme is "liferay", but it can be changed by setting the "vaadin.theme" property in portal-ext.properties.

The Add-Ons

Add-Ons must be deployed into Liferay's WEB-INF/lib directory.  This is the only directory that will be used to compile the widgetset (details coming shortly), so this is where they must go. Vaadin portlets that use the Add-On(s) will use the liferay-plugin-package.properties file to define a dependency on the portal's jar.

The Resources

The compiled widgetset and the theme files represent all of the static files (resources) that Vaadin portlets will be using.  These files are always part of the Liferay ROOT web application, and will normally be available as /html/VAADIN/...  Vaadin will automatically be looking for the VAADIN directory to get the static resources, and this directory is found in the "/html" path, but this can be changed by setting the "vaadin.resources.path" property in portal-ext.properties.  NOTE: The resources path must be part of the ROOT application and must be in an accessible path for the client browser, as the browser will be submitting HTTP requests to get the static resources.

Vaadin Control Panel

All Liferay instances that will be using Vaadin in their portlets must add the Vaadin Control Panel.  It's not included in Liferay by default, but your ability to leverage Vaadin in the portal will be severely limited without it.

There are two key functions that the Vaadin Control Panel provides:

  • The ability to change Vaadin versions on the fly.
  • The ability to compile the portal's single, shared widgetset.

The Vaadin Control Panel for Liferay is a portlet that provides a new control panel for Vaadin.  It can be downloaded from the Add-On directory here.

Download the portlet and drop it into the deploy directory, and Liferay should deploy it.  Note that the control panel portlet does not adhere to Liferay's packaging requirements (it's missing the crucial liferay-plugin-package.properties file), so it may complain about it during deployment, but should still be functional.  You may or may not need to restart your application container post-deployment (I have seen it deploy successfully and be available, but also have seen cases where a restart is necessary).

When you go to the control panel, you'll have a new entry at the bottom of the Portal section named "Vaadin".

The interface is rather simplistic:

Vaadin 6 Control Panel

The first thing to notice is the "Change Version" link at the top of the file.  Liferay by default comes with a fairly old version of Vaadin.  You're going to want to change your version of Vaadin in the portal to the latest version as soon as possible.

The next thing to notice is the "Select Add-ons" checkboxes.  When you download an Add-On, you'll have a jar file that contains the Add-On code.  The jar file must be put into Liferay's WEB-INF/lib directory.  You can see the path where the jar file must go in the filesystem.

The checkboxes here allow you to select and deselect Add-Ons that will be included in the widgetset compile.

The last thing to notice is the "Compile Widget Set" button.  When you change the Vaadin version or when you enable/disable Vaadin Add-Ons, you MUST recompile the widgetset using this button.  Failure to do so will result in errors on the client side.

When you hit the "Compile Widget Set" button, a bunch of stuff will scroll in the "Output Console" section of the window.  This is the output of the GWT widgetset compiler.  In most cases you should get a successful result at the end of the compile.  If you get errors in the window, I would search the Vaadin forums for a match or try posting to the Vaadin or Liferay forums.

Issues Upgrading Vaadin in Liferay

The Vaadin Control Panel makes changing Vaadin versions really easy, but it does not handle the upgrade completely...

The Vaadin Control Panel only changes the version of the vaadin.jar in Liferay, but does not deal with the Vaadin themes.  Vaadin themes are released for each Vaadin release, and the themes contain bug fixes also.

Vaadin provides a special download for Liferay users, the Vaadin 6 Liferay Update Package.  This download will include the precompiled widgetsets (that you won't use since you're compiling your widgetset using the Vaadin Control Panel) and the updated themes.  You'll want to extract the themes directory from the download and copy it up to the Vaadin resources directory (default would be ROOT/html/VAADIN directory).  I actually deploy this locally using a JSP hook plugin (create a JSP hook plugin, put the new themes directory in the hook plugin, build and deploy to let Liferay handle the updating of the ROOT webapp).

Conclusion

Well, that about covers administrating Vaadin in Liferay.  My next blog post will cover developing Vaadin portlets...

 

Service Builder Presentation Info

General Blogs April 20, 2013 By David H Nebinger

So I received bunch of emails on Service Builder after my webinar last month...  Thought I'd write up a blog entry that will end up in the search engines and hopefully lead folks here to get to the details...

Anyway, the recorded presentation is available on the Liferay LIVE Web Events page.  You can listen to the whole presentation and watch as my demo fails during the presentation...  wink

All of the projects used for demo are actually available in this forum post in the second message of the thread.

Now for the keywords that will get you here...

The presentation covers how to do some basic Service Builder functions, but also features:

  • one-to-many relationship handling.
  • many-to-many relationship handling.
  • accessing an external (non-Liferay) database.
  • using 'fake' (non-database-backed entities) to build shared code modules using Service Builder.
  • Vaadin and Service Builder integration.

 

Backup/Restore a Liferay Environment

General Blogs April 20, 2013 By David H Nebinger

Introduction

This page documents two important administrative functions: backing up Liferay (and restoration) and setting up a copy for development usage.

Having a backup of the database is an important issue, in order to restore the database after some sort of catastrophe. The first thing that we're going to cover is backing up the Liferay data.

Liferay uses a database for primary data storage, but also uses the filesystem to store things such as image files, documents, etc.

Since I'm using Liferay with a Mysql database running on a Linux box, these instructions will focus only on that implementation. But the details should be adaptable to any database and operating system that can host Liferay.

So first the plan: the current Mysql server is going to host a second database. The production database will be the one that the main Liferay instance will use, and the development database will be a relatively recent copy of the production database. It will be allowed to get out of sync with production because I don't want changes I'm in the middle of making overwritten just because cron thinks it is time.

Create the Development Database

Create the development database, lpdev, with the following commands:

$ mysql -u root -p mysql
mysql> create database lpdev;
mysql> grant all privileges on lpdev.* to 'lportal'@'%' with grant option;
mysql> quit;

This will create the database lpdev and give all privileges to the lportal user.

Create Backup Script

First we'll set up a backup script for the production database and data files. I'm going to create and use a local directory, /var/liferay/backups. This will centralize the backups to make them easy to use for restoration later on.

In my /etc/cron.daily folder I created a script liferay-backup.cron with the following contents:

#!/bin/sh
#
# Back up the Liferay data.
#

# Get a variable to store the current date.
date=`date -I`

#
# Backup the liferay mysql database.
#
mysqldump -u lportal -p<password> lportal | bzip2 -9 -c > /var/liferay/backups/lportal-$date.sql.bz2
#
# Also create a backup of the Liferay data files.
#
tar cjf /var/liferay/backups/lportal-$date.data.tar.bz2 -C /opt/liferay data

You will have to change the <password> tag, replacing it with your lportal user password. NOTE: There is no space between the -p and the password. If you don't have an /etc/cron.daily directory, you can do your standard cron thing to create the backup.

This will create two files in the /var/liferay/backups directory, the sql to recreate the database and a tar file to recreate the data directory. These files are still on the same Linux box as the database and the server, so you may want to integrate the files into an off-system datastore or removable media.

This backup script runs while Liferay is still active. There is the potential of database issues (capturing partially committed data) or filesystem issues (the Lucene indices in a state of flux). Running the backup in the very early morning will help protect against this, but the potential is still there...

Recovering Liferay/Refreshing Development

The steps to recover Liferay are pretty much the same as refreshing the development environment, the only difference being the database used on the command line and the location of the data when extracted.

Restoration and refreshing should be done while Liferay is not running as changing the data on the fly could impose some serious application issues. But if you find yourself having to recover the database, it's a good bet that Liferay is not running anyway.

Recovering the Database

Recovering the database is a one-line command:

$ bzcat /var/liferay/backups/liferay-<date>.sql.bz2 | mysql -u lportal -p<password> lportal

Replace the <date> tag with a valid date from your backups. Dates will be formatted as YYYY-MM-DD. Replace the <password> tag with your lportal user password. NOTE: There is no space between the -p and the password.

Refreshing the Development Database

To refresh the development database, lpdev, you'd run the following command:

$ bzcat /var/liferay/backups/liferay-<date>.sql.bz2 | mysql -u lportal -p<password> lpdev

Do the replacements as indicated in the Recovering the Database section above.

Recovering the Data

The filesystem data has things such as the image gallery files, documents, etc. Our backup has all of these files, but you should clean out your data directory prior to expanding the backed-up data. This will ensure that you won't have any lingering data from before the restoration.

Recovery is done through the following commands:

$ /bin/rm -rf /opt/liferay/data/*
$ tar xjf /var/liferay/backups/liferay-<date>.data.tar.bz2 -C /opt/liferay

After starting Liferay, you're going to want to go to the Control Panel, Server Administration page and choose "Reindex all search indexes". This will rebuild all of the Lucene indices from the restored information in the database and the data files and leave it in a consistent state.

Refreshing the Development Data

You'll know if your local Liferay data is out of sync when you start seeing broken image tags, etc., in your development portal. To fix these kinds of issues, you'll have to refresh the development data. Since we're doing development on a Windows box, refreshing the data is a bit more complicated. Basically you're going to complete the following steps:

  1. Get the liferay-<date>.data.tar.bz2 file from your Linux box to your Windows box.
  2. Delete the contents of the c:\liferay\bundle\data directory.
  3. Expand the contents in the c:\liferay\bundle directory (Since the archive already is prefixed with the data directory, you should not expand in the data directory or you'll have c:\liferay\bundle\data\data and Liferay won't find it at startup).
  4. After starting Liferay, you're going to want to go to the Control Panel, Server Administration page and choose "Reindex all search indexes" to ensure the Lucene indices are consistent.

Conclusion

So now you're all set w/ your backup and recovery for Liferay. You can also refresh your development environment so that it matches production.

If you have just created your development database, you're going to want to run the Liferay backup script to create the sql and data files. Then follow the steps to refresh your development environment. Don't forget to change the database to lpdev in your portal-ext.properties file in c:\liferay\bundle\tomcat-6.0.29\webapps\ROOT\WEB-INF\classes so you access the right database in development.

Liferay and SSL

General Blogs April 20, 2013 By David H Nebinger

Introduction

So I've got my Liferay site up and running under Tomcat and fronted by Apache HTTPd. The next thing I wanted to do was add an SSL certificate so that I could get it all under HTTPS...

SSL certificates, from sites like VeriSign or Thawte or Network Solutions are usually the players that come to mind when you want to get a certificate.

A quick Google search, however, yields scores of other companies that provide SSL certificates. After pricing a bunch of them, I finally settled on a certificate from GoDaddy. At $12.99 per certificate per year, it's hard to beat the price and they are handled in most browsers.

For the most part the instructions for getting a certificate on the GoDaddy site are straight-forward. There were a few hiccups along the way, mostly due to my use of the Apache Portable Runtime (APR) in conjunction with Apache HTTPd and Tomcat.

So I'm going to lay out all of the steps that I had to take in order to request the certificate, get the certificate, install the certificate in Apache and Tomcat, and finally get it all working.

Create the Certificate Signing Request

Creating the csr, or Certificate Signing Request, is a fairly simple process. Since we're getting a certificate to install into both Apache and Tomcat, you could look at two different sets of instructions, one for each server. Since I think (but do not know for sure) that getting the certificate into Tomcat is going to be the harder of the two, I elected to follow the Tomcat instructions.

To generate the csr for Tomcat, you have a number of commands to execute in the shell to create the csr file and then you have to paste the contents of the csr file into the GoDaddy form.  The GoDaddy instructions for creating the csr are here.

The first step involves creating the keystore that Tomcat will be referencing. You'll need to know where on the filesystem your keystore will be stored, because you'll eventually be pointing Tomcat to it for usage. On my Gentoo system, certificates are usually in the /etc/ssl directory, so that's where I built mine. I created the /etc/ssl/tomcat directory and then cd'd to that directory. The remainder of the shell script commands were all executed from this directory.

Creating the keystore involves running the following command:

$ keytool -keysize 2048 -genkey -alias tomcat -keyalg RSA -keystore tomcat.keystore

When you type this command, you'll be prompted with a series of questions, and the GoDaddy instructions tell you what needs to go into each field.

If you don't want to go through the prompts, a web-based form for building the command to create the keystore can be found at digicert.com. Note that you'll have to edit the script they generate to change the alias specified above, but otherwise the tool works quite well.

Next you need to generate the csr using the following command:

$ keytool -certreq -keyalg RSA -alias tomcat -file <your file name>.csr -keystore tomcat.keystore

Replace the <your file name> with the csr filename you want to use. It is not that important because you don't really send the file anywhere. I named mine dnebinger.csr.

The part that is missing from the GoDaddy instructions relates to whether you are using the Apache Portable Runtime (as I am). When using the APR, you will be needing the private key that is currently stored inside of the tomcat.keystore file. I couldn't find a way to extract the private key using keytool, but I did find a tool at https://code.google.com/p/java-exportpriv/ that could do it. Download the tool and run it as instructed from the link to get the PKCS#8 format and direct it to a file. Give the file a .pem extension; I used the tool to create my dnebinger.pem file.

$ java ExportPriv /etc/ssl/tomcat/tomcat.keystore tomcat {keystore_password} > /etc/ssl/tomcat/<your file name>.pem

Cat your .csr file and copy it into the clipboard. Go to the GoDaddy form and paste in your csr. You'll then have to wait for GoDaddy to create your certificate.

Wait for Your SSL Certificate

While waiting, I did get an email from GoDaddy indicating that they could not verify that I was in control of the domain (my whois information is blocked from public consumption, thank you Network Solutions!). One option was to create a specially named html file and serve it from my Apache web server. I followed the instructions to create the html file, naming it correctly and putting the right stuff inside. Since I have Apache fronting my Liferay/Tomcat and do not have html file extensions JkUnmount'd, I had to temporarily add the JkUnmount for html files so when GoDaddy would come looking for the file I'd be able to serve it up quickly and easilly. I then went to the GoDaddy site and followed their further instructions for validating using the special file. Domain control was verified immediately, and they created the certificate.

Download Your SSL Certificates

So, next comes downloading the certificate. When downloading, you choose the type of server that you're installing the certificate into. I chose first to download the Tomcat version, then I chose to download the Apache version. The certificates are downloaded in zip format, you'll need to expand them. I extracted the Tomcat version to /etc/ssl/tomcat and the Apache one to /etc/ssl/apache.

Setup Tomcat to Use the Certificate

You don't really have to follow the Tomcat instructions for installing the certificate, it is actually quite easy. Since I'm using APR, I don't need to install the certificate into the keystore, but I do need the private key.

Using the certificate in Tomcat is a matter of editing the /opt/liferay/tomcat/conf/server.xml file (use whatever path is appropriate for your local environment). Find the <Connector /> tag for port 8443 and add the following attributes:

SSLCertificateFile="/etc/ssl/tomcat/dnebinger.crt"
SSLCertificateKeyFile="/etc/ssl/tomcat/dnebinger.pem"
SSLPass="<your keystore password>"

And change the attribute for SSLProtocol so it says "TLSv1".

Setup Apache to Use the Certificate

Setting up Apache simply requires following GoDaddy's instructions. For my Gentoo system, I had to edit /etc/apache2/vhost.d/00_default_ssl_vhost.conf. For the SSLCertificateChainFile entry, they're referring to the gd_bundle.crt file that was part of the downloaded zip. The SSLCertificateKeyFile entry refers to the private key file that was created, in my case it is dnebinger.pem.

Setup Liferay to Use HTTPS

Since you've got this new certificate, you're going to want Liferay to use it. You need to edit your /opt/liferay/tomcat/webapps/ROOT/WEB-INF/classes/portal-ext.properties file and add the following entries:

  company.security.auth.requires.https=true
  session.enable.phishing.protection=false
  web.server.protocol=https

Conclusion

At this point everything should be configured and ready to go. Restart your Liferay/Tomcat and Apache servers, and then you can hit them using either the http or https urls. Since we've configured Liferay to prefer https, you should see that when you use the http url you will eventually be redirected to the https url.

Enjoy!

Fronting Liferay Tomcat with Apache HTTPd daemon

General Blogs April 20, 2013 By David H Nebinger

Introduction

So here's my situation...

I've got a Gentoo Linux server sitting around that I wanted to get Liferay 6.0.6 up and running on. Although this blog will cover the setup I did for my Gentoo box, for the most part you should be able to adapt what I've done for your Linux box. Heck, a lot of this will probably work on a Windows system too, but you're on your own as far as that goes...

Installing Dependencies and the Liferay Tomcat Bundle

My system already has the Java SDK, OpenSSL, and other dependent software installed, so I'm not going to rehash that installation and setup. Suffice it to say that you may find yourself installing some missing components along the way to satisfy dependencies...

Gentoo makes installation pretty easy for all of the components that I needed. Specifically I issued the following command:

$ emerge www-servers/apache dev-libs/apr dev-libs/apr-util www-apache/mod_jk

So that installs the basic software for Apache HTTPd version 2.2.17, but doesn't complete the configuration for us.

Next I downloaded the Liferay 6.0.6/Tomcat bundle in preparation for installation.

Now you might be asking yourselves why I didn't install Tomcat using Gentoo's emerge command and then install Liferay into Gentoo's Tomcat. The reason is that Gentoo's Tomcat actually gets installed to many different directories and doesn't retain the 'all in one directory' setup that's pretty standard w/ Tomcat installs. The tomcat/logs directory ends up over in /var/log, the tomcat/temp directory ends up over in /var/tmp, the tomcat/bin, tomcat/lib, and tomcat/webapps directories end up in /usr/share/tomcat-6, and tomcat/conf ends up in /etc. From a Linux standards perspective, this reorganization makes total sense. Knowing all of the reconfiguration I'd be doing in order to get Liferay up and running in this setup seems to be more trouble than it's worth, at least in the short term. Who knows, maybe if I get some time I'll explore what is involved in doing it the Gentoo way, but for now I've decided to skip it...

Instead I expanded the Liferay 6.0.6 Tomcat bundle to /opt, with the final installation path as /opt/liferay-portal-6.0.6. To make upgrading easier, I created a symbolic link as /opt/liferay using the following command:

$ ln -s /opt/liferay-portal-6.0.6 /opt/liferay

So the path for tomcat is now /opt/liferay/tomcat-6.0.29, and I created another symlink for that as /opt/liferay/tomcat.

The first thing I did was delete the provided JRE that is part of the bundle. This makes the startup.sh and shutdown.sh scripts unhappy as they want to use that JRE, so I had to edit them to use my installed Java environment. I also took the opportunity to hard code the CATALINA_HOME environment variable and tweak the Java command line arguments for memory handling, timezone, etc.

From here you'll want to skip over to Liferay.com and use their documentation to get your database defined, mail server changes done, and fix up your portal-ext.properties files.

At the end of all of this configuration, I could start up Tomcat and hit Liferay by going to Tomcat's port 8080 in order to verify that it was up and running.

So next we have to worry about setting up Apache so that it can front Tomcat. A lot of folks have trouble doing this (you'll see a lot of questions and stuff when you search your favorite search engine). I have to admit that I had to go back and forth tweaking the files until I got it all right...

So now I'm going to be referring to the Apache config files, specifically as initially installed in my Gentoo system. The file paths will probably be different on your system, but the content of the changes should basically be the same...

Configure mod_jk

Gentoo installed mod_jk as part of our previous emerge command, but we need to enable it so Apache will use it when it is running. So we have to edit /etc/conf.d/apache2 and find the line with the APACHE2_OPTS defined. At the end of the line (but still within the quotes), add -D JK. This will enable the loading of the mod_jk when Apache starts up.

The default configuration for mod_jk as installed in Gentoo is pretty complete and shouldn't require any significant editing. The only change I had to make to /etc/apache2/modules.d/88_mod_jk.conf was to change the only uncommented JkMount line so it read:

JkMount /* ajp13

I also changed the JkAutoAlias so that it pointed to /opt/liferay/tomcat/webapps, but honestly I don't know if it was really necessary or not.

Now, the one thing you'll see going forward is that I actually have the JkMount thing in another file. This change was the most obvious one (I mean, the default Gentoo file already had a JkMount here), but it didn't work the first time I started Apache up. So there will be another place in this blog where the JkMount will come up again, and if you do them all you should have the same success that I had.

Gentoo's workers file is /etc/apache2/jk-workers.properties. It's got a lot of comments in it, but basically you should end up w/ the following:

worker.list=ajp13,jkstatus
worker.ajp13.type=ajp13
worker.ajp13.host=localhost
worker.ajp13.port=8009
worker.jkstatus.type=status

The ajp13 is actually going to be our Liferay/Tomcat guy. Perhaps I should have changed it to, say, liferay, but I didn't feel that I wanted to make such sweeping changes to Gentoo's default config.

I said the JkMount would come up again, and here it is. I had to modify the /etc/apache2/vhosts.d/default_vhost.include file, and I added the following:

<IfModule jk_module>
  JkMount /* ajp13
</IfModule>

This change applies the JkMount to the default virtual host, and was necessary for Apache to pass the requests through to Liferay.

After these changes were made, I could fire up Apache and hit the regular port 80 of Apache and it passed the requests through to Tomcat, and it was all working great!

Have Apache Serve Liferay Static Content

The best reason to front Liferay/Tomcat with Apache is to let Apache handle the serving of the static content (images, stylesheets, etc) and let Tomcat deal w/ the dynamic content.

To do this, you're going to have to do some directory copying... First copy the /opt/liferay/tomcat/webapps/ROOT/html directory to Apache's htdocs directory, /var/www/localhost/htdocs in my case. You should also copy all of the other webapps directories (all except for ROOT) to the htdocs directory. By copying all of these directories, any incoming requests for static content will be handled by Apache rather than Tomcat.

NOTE: As you redeploy your portlets, themes, etc. to Liferay, you should also copy the directories over to the htdocs directory, otherwise Apache might serve an older version of the file(s).

For Apache to handle static files, you need to go back to the /etc/apache2/vhosts.d/default_vhost.include file and add some lines just below the JkMount line you added earlier. You'll end up with the following:

<IfModule jk_module>
  JkMount /* ajp13

  JkUnmount /*.jpg ajp13
  JkUnmount /*.jpeg ajp13
  JkUnmount /*.gif ajp13
  JkUnmount /*.png ajp13
  JkUnmount /*.ico ajp13
  JkUnmount /*.css ajp13
  JkUnmount /*.js ajp13
</IfModule>

By using JkUnmount, you're indicating to Apache that it should handle requests with the given extension(s) rather than passing them through to Tomcat.

The one obvious extension that is missing from the above is the .html extension. Since the servlet mapping mechanism in a web application can map .html extensions to a servlet, adding this extension might not give you the result you're expecting. The way I figure it, it's better to let Tomcat serve the single html file (if it is static) rather than break some servlet or portlet functionality, but it is really just a matter of research in the various web.xml files to see if you have any servlet mappings expecting .html extensions. If you don't have any such mappings (now or in the future), you can add the extension as a JkUnmount and let Apache handle them. If you do have the mappings, expect to have the mappings, or just don't want to do the research, then leaving the JkUnmount out for this extension is the safest bet.

Since we're talking about JkUnmounts, if you have other directories in your htdocs folder that Apache should always handle, then add them as JkUnmounts. For example, say I have a javadocs directory in my htdocs folder and I need Apache to handle it, I'd add the following line:

  JkUnmount /javadocs/* ajp13

Setup Liferay To Use Apache

The final step involves editing your /opt/liferay/tomcat/webapps/ROOT/WEB-INF/classes/portal-ext.properties file to include the following:

    web.server.http.port=80
    web.server.https.port=443

This ensures that Liferay will know that it is operating behind Apache HTTPd and will handle redirects correctly.

That's all there is to it. The fact that you're seeing this on port 80 rather than 8080 is proof that these instructions work!

My First Liferay Blog...

General Blogs April 16, 2013 By David H Nebinger

I was going to take a queue from Jelmer and start with just a test blog post, but don't want to take the wind out of his sails...  Must say, though, that your blog post did make me laugh Jelmer!  laugh

Instead, I'm going to lead w/ my blogging plans...

First, I've got a handful of blog postings I had put together about HTTPS/Apache Httpd/Tomcat/Liferay that I'm going to restore here.  Had them up on my home Linux box, but as it's my home server I end up making changes and playing with different versions of Liferay, so although the blog entries had value, they're not up anymore.  Pulling them over here will give them a little more permanence and keep them safe from my Linux server hacking...

Then comes the fun stuff, I'm going to dive into Vaadin portlet development under Liferay.  I'll cover the dev environment setup, the must-have Vaadin Control Panel, then maybe move into some actual Vaadin portlet development...

Oh, boy, I just can't wait...

Showing 15 results.
Items 20
of 1