AlloyUI

Liferay portlet file upload tutorial

Here’s a Liferay portlet file upload tutorial to show you how to handle file uploading by clients.
First we need to define our upload form JSP. This can be shown using Liferay MVCPortlet’s default view.jsp.
We will define our upload form as an AlloyUI form element and w

view.jsp


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui"%>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<portlet:defineObjects />

<portlet:actionURL name="upload" var="uploadFileURL"></portlet:actionURL>

<aui:form action="<%= uploadFileURL %>" enctype="multipart/form-data" method="post">

	<aui:input type="file" name="fileupload" />
	
	<aui:button name="Save" value="Save" type="submit" />

</aui:form>

And now we need to handle the upload action that we are calling by submiting this form.
Note some important parts that people often miss in their code, like checking if there’s enough room on the device to actually store the file and refuse additional file uploads when the device has less than 1GB of free space.

Full example class


import java.io.File;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;

import org.apache.commons.io.FileUtils;

import com.liferay.portal.kernel.upload.UploadPortletRequest;
import com.liferay.portal.util.PortalUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;

public class RelatedFilesPortlet extends MVCPortlet {

	private final static int ONE_GB = 1073741824;
	
	private final static String baseDir = "/tmp/uploaded/";
	
	private final static String fileInputName = "fileupload";

	public void upload(ActionRequest request, ActionResponse response)
			throws Exception {

		UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(request);

		long sizeInBytes = uploadRequest.getSize(fileInputName);

		if (uploadRequest.getSize(fileInputName) == 0) {
			throw new Exception("Received file is 0 bytes!");
		}

		// Get the uploaded file as a file.
		File uploadedFile = uploadRequest.getFile(fileInputName);

		String sourceFileName = uploadRequest.getFileName(fileInputName);

		
		// Where should we store this file?
		File folder = new File(baseDir);

		// Check minimum 1GB storage space to save new files...
		
		if (folder.getUsableSpace() < ONE_GB) {
			throw new Exception("Out of disk space!");
		}

		// This is our final file path.
		File filePath = new File(folder.getAbsolutePath() + File.separator + sourceFileName);

		// Move the existing temporary file to new location.
		FileUtils.copyFile(uploadedFile, filePath);
	}

}

Why use Liferay?

The Good side of Liferay

Liferay is NOT just a Java based CMS. It’s a complete portal environment that’s suitable for large enterprise usage. It should be used as a platform to develop in-house applications or intranet. If you need just a small website to promote something then Liferay is not for you.

Some people compare Liferay with PHP based CMS systems like Joomla or Wordpress but that’s completely wrong. Liferay does contain CMS and it’s not a bad one. It’s rather useful for providing small applications and even better for big applications.

Supporting JSR 168 and JSR 286 means you can deploy Portlet applications that others have developed. Liferay also has a very good support for groups and communities allowing you to build team sites and custom environments for different user-groups with ease. Some cool features that you get with Liferay out of the box are:

  • User and Group management
  • Multi-site support for having different pages and themes for different user groups
  • Proper Access rights and Role management
  • Internationalization
  • Document library management
  • Wiki, Blogging and Forums
  • Service Oriented Architecture
  • Theme support
  • Integrates with other existing systems using LDAP, RSS, iFrames and other technologies

Liferay

 

The Bad side of Liferay

Developing applications and portals for the first time is a taunting task and comes with a rather massive learning curve. If you plan to use Liferay Service Builder and do everything “the Liferay way” then you have to plan probably at least couple of weeks for learning it first.

If you need to develop a small application quickly AND you don’t have an existing Liferay installation already in-house then you can get your application done way faster by NOT using Liferay. But once you have learned Liferay and have enough need for proper portal then Liferay becomes rather irresistible.

When it comes to documentation and tutorials then it’s not the best situation either. It does have a massive developer’s guide. But the Wiki is filled with tons of content that’s rather old and not updated for the latest releases.

The official developer and administration guides are good but often lack information about some crucial parts or fail to provide decent examples. While they claim to be developer friendly I have to admit that some parts of the development platform is severely lacking. Also note that releases are rather infrequent. Also one should be very cautious because early versions are always rather buggy.

AlloyUI that’s provided with Liferay for Javascript and UI is rather difficult to learn and seems also a very large investment time-wise – save yourself the trouble and use jQuery or some other favorite JS library instead.

AlloyUI Icons for Liferay 6.2

AlloyUI iconlist for Liferay 6.2

It’s here for reference because I had a hard-time finding it in google search results and finally found a link in the AlloyUI docs but it’s in the end of the page and hard to notice. Original Up to date list of AlloyUI Icons is available here: http://liferay.github.io/alloy-bootstrap/base-css.html#icons

AUI Icons

Some of you may be searching for them using “AUI Icons”. I know It’s the first thing I wrote into Google and all the results are far away from the resource I actually wanted – That is: A list of AUI Icons I could use during my Liferay developments. This is why this page is created. Yes, this text here serves to make google actually index this page also for AUI Icons keywords because otherwise I would always have to find it using AlloyUI Icons. Yes, It’s annoying but oh-well, it’s better than spending long minutes finding the Glyphicons list that Alloy is using.

Update: Even better list found!

Seems this is the best list so far!

All credits goes to Glyphicons

140 icons in sprite form, available in dark gray (default) and white, provided by Glyphicons.

  •  icon-glass
  •  icon-music
  •  icon-search
  •  icon-envelope
  •  icon-heart
  •  icon-star
  •  icon-star-empty
  •  icon-user
  •  icon-film
  •  icon-th-large
  •  icon-th
  •  icon-th-list
  •  icon-ok
  •  icon-remove
  •  icon-zoom-in
  •  icon-zoom-out
  •  icon-off
  •  icon-signal
  •  icon-cog
  •  icon-trash
  •  icon-home
  •  icon-file
  •  icon-time
  •  icon-road
  •  icon-download-alt
  •  icon-download
  •  icon-upload
  •  icon-inbox
  •  icon-play-circle
  •  icon-repeat
  •  icon-refresh
  •  icon-list-alt
  •  icon-lock
  •  icon-flag
  •  icon-headphones
  •  icon-volume-off
  •  icon-volume-down
  •  icon-volume-up
  •  icon-qrcode
  •  icon-barcode
  •  icon-tag
  •  icon-tags
  •  icon-book
  •  icon-bookmark
  •  icon-print
  •  icon-camera
  •  icon-font
  •  icon-bold
  •  icon-italic
  •  icon-text-height
  •  icon-text-width
  •  icon-align-left
  •  icon-align-center
  •  icon-align-right
  •  icon-align-justify
  •  icon-list
  •  icon-indent-left
  •  icon-indent-right
  •  icon-facetime-video
  •  icon-picture
  •  icon-pencil
  •  icon-map-marker
  •  icon-adjust
  •  icon-tint
  •  icon-edit
  •  icon-share
  •  icon-check
  •  icon-move
  •  icon-step-backward
  •  icon-fast-backward
  •  icon-backward
  •  icon-play
  •  icon-pause
  •  icon-stop
  •  icon-forward
  •  icon-fast-forward
  •  icon-step-forward
  •  icon-eject
  •  icon-chevron-left
  •  icon-chevron-right
  •  icon-plus-sign
  •  icon-minus-sign
  •  icon-remove-sign
  •  icon-ok-sign
  •  icon-question-sign
  •  icon-info-sign
  •  icon-screenshot
  •  icon-remove-circle
  •  icon-ok-circle
  •  icon-ban-circle
  •  icon-arrow-left
  •  icon-arrow-right
  •  icon-arrow-up
  •  icon-arrow-down
  •  icon-share-alt
  •  icon-resize-full
  •  icon-resize-small
  •  icon-plus
  •  icon-minus
  •  icon-asterisk
  •  icon-exclamation-sign
  •  icon-gift
  •  icon-leaf
  •  icon-fire
  •  icon-eye-open
  •  icon-eye-close
  •  icon-warning-sign
  •  icon-plane
  •  icon-calendar
  •  icon-random
  •  icon-comment
  •  icon-magnet
  •  icon-chevron-up
  •  icon-chevron-down
  •  icon-retweet
  •  icon-shopping-cart
  •  icon-folder-close
  •  icon-folder-open
  •  icon-resize-vertical
  •  icon-resize-horizontal
  •  icon-hdd
  •  icon-bullhorn
  •  icon-bell
  •  icon-certificate
  •  icon-thumbs-up
  •  icon-thumbs-down
  •  icon-hand-right
  •  icon-hand-left
  •  icon-hand-up
  •  icon-hand-down
  •  icon-circle-arrow-right
  •  icon-circle-arrow-left
  •  icon-circle-arrow-up
  •  icon-circle-arrow-down
  •  icon-globe
  •  icon-wrench
  •  icon-tasks
  •  icon-filter
  •  icon-briefcase
  •  icon-fullscreen

Glyphicons attribution

Glyphicons Halflings are normally not available for free, but an arrangement between Bootstrap and the Glyphicons creators have made this possible at no cost to you as developers. As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.

 

AUI Autocomplete with service builder json datasource

Since it’s not so trivial to correctly understand AlloyUI Autocomplete that’s shipped with Liferay 6.2 then here’s an example on how to make an autocomplete that uses a custom service builder json web service as a datasource.
We will use AUI Autocomplete widget and then user Liferay Service library to fetch the result from our own custom service builder built JSON web service.

This is the look we are trying to achive:
aui autocomplete service builder

Full portlet view.jsp code:


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>

<portlet:defineObjects/>
<liferay-theme:defineObjects />

<aui:input name="contactName" type="text" />

<aui:script use="autocomplete-list,aui-base,aui-io-request-deprecated,autocomplete-filters,autocomplete-highlighters,datasource,datasource-get,datatable-datasource">

// Please note that this contact portlet service is a service builder generated JSON web service.
// We pass the groupId as a query param because our service expects it. Liferay has a nice javascript method for finding the group id.
var contactSearchDS = new A.DataSource.IO({source: '/api/jsonws/contact-portlet.contact/get-contacts-by-name?groupId='+Liferay.ThemeDisplay.getScopeGroupId()});

var contactSearchQueryTemplate = function(query) {
        // Here's an example on how to pass additional parameters to the query for you service
        // In our case we are fetching only the first 20 items and specify the ordering by name
	var output = '&name='+query.trim()+'&sort=name&dir=asc&start=0&end=20';
	return output;
}

var contactSearchLocator = function (response) {
	var responseData = A.JSON.parse(response[0].responseText);
// For debugging you can do: console.debug(responseData);
    return responseData;
};

var contactSearchFormatter = function (query, results) {
	return A.Array.map(results, function (result) {
// For debugging: console.debug(result.raw);
		return '<strong>'+result.raw.fullName+'</strong><br/>'+result.raw.mobile+' '+result.raw.phone+' '+result.raw.email;
	});
};

var contactSearchTextLocator = function (result) {
// This is what we place in the input once the user selects an item from the autocomplete list.
// In our case we want to put contact full name in there.
	return result.row.fullName;
};

var contactSearchInput = new A.AutoCompleteList({
	allowBrowserAutocomplete: 'false',
	resultHighlighter: 'phraseMatch',
	activateFirstItem: 'false',
	inputNode: '#<portlet:namespace/>contactName',
	render: 'true',
	source: contactSearchDS,
	requestTemplate: contactSearchQueryTemplate,
	resultListLocator: contactSearchLocator,
        resultFormatter: contactSearchFormatter,
	resultTextLocator: contactSearchTextLocator		
});

</aui:script>		

We’ll post an example of “multi-autocomplete” input also soon. That one requires a lot more code but allows selecting multiple contacts and shows them as “tags” above the input box. Much like the facebook name finder works.

As always, if you have questions or suggestions then please comment below.