Liferay Life – Developing Social Applications leveraging OpenSocial

Here is recording of last Liferay Life session. This time Paul Hinz reviewed the basics of Open Social and Liferay’s implementation.

Advertisements

Community voice

What is community for should be a easy question. But if you think a little longer, for example in context of Liferay the answer is not so easy to define. There are many thins you can used it for but there are only few options that will get you most benefit. As a proud member of  The Community I can say that in my opinion those options are:

1. Community can be used for getting requirements for next release of your product.

At Liferay: in my opinion last year was a one way road. There were requests from Community, there were Wiki proposals pages and Liferay used those for preparing roadmap but we didn’t get any feedback or questions. It was more dictatorship than democracy. I know that WordPress is like dictatorship too but there is a big difference because WP is more narrowed product and there is so big community that you wont be able to filter those good ideas (one WP Forum thread contains more posts than whole Liferay forum).  It changed since James Falkner took role of Community Leader. He started 100 Paper Cuts program which will help Liferay to define at least part of our needs. He’s also a person responsible for hearing us out. So now this is starting to look as two-way highway. +1pt for James here.

2. Community can be used as part of marketing.

At Liferay: well it was not. If you don’t speak with Community Community won’t speak about you. Maybe it will be but not the way you want. If you want people to talk about you you must give them a good cause. You can give them a super fast, good documented product (works well with WordPress), you can give them superb functionalities (like RIAK) and / or you can give them loads of information to process (I love how Magento is doing that with their daily updated blog).  In my opinion Liferay didn’t used all power of Community in this case. Product is good but information flow is terrible. There are of course Liferay LIVE sessions but  if their are announced a day before it’s not very useful for you (-1 pt for Paul for not telling soon enough about today Liferay Influencer Briefing).  I hope this will change for better with Community Leadership program and revamp of Community landing page

3. Community can do part of your job

You can achieve more if you stimulate Community to do part of your job in role of developers, testers or analytics. It’s a nice example of barter when company gives basic product and support (in meaning of patches) and Community gives code, tests or planning job. Actually this is the part where Liferay is doing a great job.  There are many partner companies that contribute good quality code. There is a clear information about how you can contribute. Two things missing are Liferay employee that will commit all those Community Contributed solutions to trunk and Liferay Marketplace (Paul we want to sell portlets!).

So to summarize you can get many things from Community but first you must put your own work into building a proper relations with it. As you can see on example of Liferay you can do it in a wrong way but changing that always pays up and it’s never to late for doing that. Working with Community is a never ending process like SEO positioning so never leave you Community alone without proper attention or you will get such negative and frustrated opinion like this one. Talk to us, work with us, give us tools that will help us make more money and we will share that revenue with you in form of good feedback, word of mouth, additional code for you and licence (if you sell those 😉 ).

 

And one message to the Community: be active and give Liferay staff a chance to correct their previous misdeeds 🙂

And one more time about documentation

I know that Liferay documentation is already on “Community Complaints” lists (you can check it here) but I couldn’t resist.

from geekandpoke.typepad.com

Why I can’t use portal-impl in my portlet?

When I started my adventure with liferay and I was young I had a big headache with a view: „Why liferay developers didn’t share portal-impl.jar for external portlets. This is so stupid”. When we don’t have access to this module our development is very difficult. I can’t extend my Action class and I must manually attend all incoming requests beacause portal-impl.jar provides most classes used by the portal’s portlets. Why I can’t use this one?

Today, when I spent a long time with liferay my answer is: NO, you should not use a portal-impl.jar in your portlet. Remember: NEVER put portal-impl into anywhere other than where it came from. This will cause untold problems beacause portal-impl is the central core of the portal and it is a main piece of cake. So you can’t put portal-impl in lib directory in your portlets or in other strange places. Why? Liferay uses all kinds of classloader tricks to get access to various classes. So adding portal-impl to library folder in your portlet will realy mess this up. There will be duplicated instances of classes which are load from different class loaders. Additionaly portal-impl.jar contains internal classes of liferay core implementation, so if you use it in this version remember that next one can change all method’s or just remove some classes.

In portal-service.jar liferay provides a set of methods, which you can use in your own implementation. It sits in the global classpath (on tomcat this is <tomcat>/lib/ext/*.jar). All the services and utilities are available from these.

Wait a second… this feature looks nice, but how can I develop my controller (for example struts)? You should use apache struts bridge to handle lifecycle of struts portlet (refer sample-struts-portlet in community svn plugin repository). Also Liferay provides some kinds of bridges (e.g. mvc, php, python and more) and it is the simplest and the best way to create your own action class or your own controller. In my opinion there are some very important reasons to do with this way:

  • your code is totally independent
  • portlets are more flexible
  • there is a big chance that your code will be working with newer version of liferay
  • you write code with framework you like

But Liferay’s StrutsPortlet bridge should not be used for any new development. If you really must use Struts 1.x it’s better to use Apache portlet bridge. You can also use Liferay’s MVCPortlet. Or, you can use one of the other frameworks supported by Liferay: Spring MVC, Struts 2, and JSF.

DOC_22

Week in Review: Community Road map, liferay.org and las call for 100 Paper Cuts

Liferay Live – Liferay Community Roadmap

Here is todays Liferay Live session about Liferay Community Roadmap. Hope you will enjoy it 🙂

Liferay 6.0: Liferay’s lost potential – is it true?

Micheal wrote on eweek.com labs review about Liferay 6. He named it “Liferay’s lost potential”. Is it a proper title for that review – I leave this answer for you to decide. In my opinion true is somewhere in the middle.

There are many negative sides of using this platform because Liferay is buggy. I’m not telling that because I saw so many tickets in JIRA (I know that many of them are out-of-date) but because I use Liferay every day for different things. I know that there are no flawless applications (but WordPress is so close to that) but usability bugs in 2011? My favorite is that one where you must login to webdav using your userID instead of normal login. In that moment of Liferay administration training all my clients have this special look on their faces (it looks similar to WTF).  Also (because I’m from country where English is not primary language) all the localization bugs (but those will be solved in upcoming Liferay 6.1).

It’s nice to have 60+ portlet out-of-the-box but most of them look like simple “proof of concept” (Words and Hello Velocity portlets should be moved from Liferay bundle to Community Plugins repository!!!) , others are old and now almost useless (Translator portlet say hello to Google Translate) and others will never be used on any big portal (yeah, I’m talking about you Password Generator portlet and Loan Calculator portlet).

User documentation is still poor. My favorite part is the explanation of Review date field in Web Content edition page – see for yourself and look for “review date” in official Administrator Guide. Developer documentation is just a little bit better thanks to Liferay developers who started updating JavaDoc. Functionality documentation? I saw many tickets in JIRA but never any doc with good specification how should that part of Liferay work (maybe that is why there are so many usability flaws).

And themes? Yep, WordPress has them. I never show my clients Liferay themes available in Community Repository. Never. NEVER. Why? Take one (at random) and try building nice looking site without any CSS coding. Impossible. But there is a little change coming up in that matter.

So why do we like Liferay? We like it because it’s the only option if you want to build news portal without writing all the code from scratch. If you stabilize your own branch of Liferay CE or buy Liferay EE it will serve you well for many projects. You will have working API, some standardized integration code and very powerful feature of “web content structures and templates”.  You will also be able to configure you portal using one portlet – Asset Publisher – the only portlet that can do everything you will need. And don’t forget building verticals (based on community or instance feature of Liferay) in couple of clicks. You won’t see that in other CMS systems.

And speed? Well, WordPress is faster than Liferay but remember that TIE fighter is always faster than Imperial Star Destroyer. You don’t need that second one to set up one blog but you won’t be able to build heavy-traffic horizontal portal with the first one.

Week in Review: community programs, localization,

  • Jonas X. Yuan has twitted some interesting stuff:

#Liferay 6.1 - Allow for #retrieval of #localized  title and summary from #AssetPublisher
#Liferay 6.1 - #Localization of #title and #description of web content

       At last, Liferay localization features got proper attention. Building multi-language sites will be much easier with those changes.

  • Liferay annouced training courses schedule. As Jeffrey Handa wrote there are new tranings prepared for this year: Theme training, Advanced Developer training and Social Office Admin training (which will be based on Social Office 1.6!!!). Enroll today – there are early bird discounts
  • James Falkner annouced two community programs.  First is “100 Paper Cuts” based on similar project from Canonical Ltd. (makers of Ubuntu Linux). The second one is Community Leadership Program. Now you can be a leader and close some unecessary tickets or review community contribiutions. Both should speed up process of applying community made patches to Liferay core and rise up ease of use for Liferay Portal CMS.
  • Some nice improvements were maid to Category portlet
  • Alimozzaman Rony wrote on his blog a post about velocity variables that are defined in init.vm. We think it’s a very good compilation so we added those to Liferay Wiki page about velocity template language

Tips & Tricks: add new structure’s field into web content

During my everyday work some people asked me: „Is it possible to add new type of structure’s field. If yes, how can I do it?”. In my opinion the fastest way to achieve this result is overriding few files in ext plugin or hook. We decided to use hook. In this post We show you the example, how we did it. Our new field is a datetime component.

Firstly, we should know in liferay there are two places where we can add and edit structure’s fields, So we must check our new functionality two times:

  1. CP -> Web content -> Structures (tab) -> Add or edit structure
  2. CP -> Web content -> add or edit web content -> change structure

Files which are responsible to render and serve structure’s fields in first point:

  • html/portlet/journal/js/main.js
  • html/portlet/journal/edit_article_content_xsd_el.jsp
  • html/portlet/journal/edit_structure_xsd_el.jsp

In second point:

  • html/portlet/journal/edit_article_structure extra.jspf
  • html/portlet/journal/edit_article_extra.jsp

Ok, let’s get started.

1. Create a new hook and configure that it can override jsps files. For example:

<hook>
<custom-jsp-dir>/custom_jsps</custom-jsp-dir>
</hook>

2. Copy html/portlet/journal/js/main.js into custom_jsps folder. In this step we must register new model’s field (below registerFieldModel method’s declaration).

registerFieldModel('Date', 'date', 'DateField', true);

Next we add new field’s type to map called „model” in function _fieldInstanceFactory()

var model = {
  'boolean': Journal.FieldModel.Boolean,
  'document_library': Journal.FieldModel.DocumentLibrary,
  'image': Journal.FieldModel.Image,
  'image_gallery': Journal.FieldModel.ImageGallery,
  'link_to_layout': Journal.FieldModel.LinkToPage,
  'list': Journal.FieldModel.List,
  'multi-list': Journal.FieldModel.MultiList,
  'selection_break': Journal.FieldModel.SelectionBreak,
  'text': Journal.FieldModel.Text,
  'text_area': Journal.FieldModel.TextArea,
  'text_box': Journal.FieldModel.TextBox,
  'date': Journal.FieldModel.Date
};

3. Copy html/portlet/journal/edit_article_content_xsd_el.jsp and add code inside journal-article-component-container. We compare our new type with elType variable.

<c:if test='<%= elType.equals("date") %>'>
  <%@ include file="/html/portlet/journal/edit_article_content_xsd_date_el.jspf" %>
</c:if>

Ok, it  looks fine, but what’s is in edit_article_content_xsd_date_el.jspf“? This is the main point of this tutorial. In this file we define „look and feel” our new component. For example:

<aui:fieldset>
<%
Calendar cal = CalendarFactoryUtil.getCalendar(timeZone, locale);
if (elContent != null && !elContent.equals("")) {
  DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd H:m");
  Date date = (Date)formatter.parse(elContent);
  cal.setTime(date);
}

%>

<aui:field-wrapper>
  <div>
    <liferay-ui:input-date
      dayParam="dateDay"
      dayValue="<%= cal.get(Calendar.DATE) %>"
      disabled="<%= false %>"
      firstDayOfWeek="<%= cal.getFirstDayOfWeek() - 1 %>"
      monthParam="dateMonth"
      monthValue="<%= cal.get(Calendar.MONTH) %>"
      yearParam="dateYear"
      yearValue="<%= cal.get(Calendar.YEAR) %>"
      yearRangeStart="<%= cal.get(Calendar.YEAR) %>"
      yearRangeEnd="<%= cal.get(Calendar.YEAR) + 5 %>"
    />

    &nbsp;

    <liferay-ui:input-time
      amPmParam="dateAmPm"
      amPmValue="<%= cal.get(Calendar.AM_PM) %>"
      hourParam="dateHour"
      hourValue="<%= cal.get(Calendar.HOUR) %>"
      minuteParam="dateMinute"
      minuteValue="<%= cal.get(Calendar.MINUTE) %>"
      minuteInterval="<%= 1 %>"
    />
  </div>
</aui:field-wrapper>
</aui:fieldset>

You must know that elContent variable contains our field’s value (date in this example).

4. Copy html/portlet/journal/edit_structure_xsd_el.jsp and add our new type into select’s list.

<option <%= elType.equals("date") ? "selected" : "" %> value="date"><liferay-ui:message key="date" /></option>

Okey, let’s deploy our hook and look into add structure form. What are we seeing? Oh, our new field’s type.
What’s next? We must allow to edit structure directly in edit article form.

5. Let’s look inside edit_article_structure_extra.jspf file and copy them. Then we define „look and feel” our new field inside journalFieldModelContainer div by adding new div with dataType=”<type>” attribute.

<div dataType="date">
<%
String elContent = "";
%>
<%@ include file="/html/portlet/journal/edit_article_content_xsd_date_el.jspf" %>
</div>

6. In file html/portlet/journal/edit_article_extra.jsp we add to menu (lists of field’s types) our new component because we want allow „drag and drop” functionality. So we create new div’s tag with dataType=”<type>” attribute inside journalComponentList div.

<div dataType="date">
<liferay-ui:message key="date" />
</div>

We have new component with great design but how we save selected date and time value. Let’s see main.js file. There is getContent method where there are a lot of “if” conditions. So, we must write a new one:

if (type == 'date') {
	var dateContents = componentContainer.all('select');
	var date = [Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN];

	if (dateContents) {
		dateContents.each(
			function(select, selectIndex, selects) {
				var options = select.all('option');
				if (options) {
					options.each(
						function(option, optionIndex, options) {
							if (option.get('selected')) {
								//name selecta, zawierajacego wybrany item
								var selectName = select.get('name');
								var selectedValue = option.val();

								if (selectName.match(/dateDay$/)) {
									date[0] = selectedValue;
								} else if (selectName.match(/dateMonth$/)) {
									date[1] = selectedValue;
								} else if (selectName.match(/dateYear$/)) {
									date[2] = selectedValue;
								} else if (selectName.match(/dateHour$/)) {
									date[3] = selectedValue;
								} else if (selectName.match(/dateMinute$/)) {
									date[4] = selectedValue;
								} else if (selectName.match(/dateAmPm$/)) {
									date[6] = selectedValue;
								}
							}
						},
						select
					);
				}
			}
		);

	}
	content = instance.getDateAsString(date);

}

Also we must define the „getDateAsString” function

getDateAsString: function(stringDateArray) {
		if (stringDateArray.length != 7) {
			return '';
		}
		var intDateArray = new Array(stringDateArray.length);
		var notNaNExist = false;
		for (var i = 0; i < stringDateArray.length; i++) {
			intDateArray[i] = parseInt(stringDateArray[i], 10);
			if (intDateArray[i] != NaN) {
				notNaNExist = true;
			}
		}

		if (!notNaNExist) {
			return '';
		}

		var day = intDateArray[0];
		var month = intDateArray[1];
		var year = intDateArray[2];
		var hour = intDateArray[3];
		var minute = intDateArray[4];
		var second = 0;
		var ampm = intDateArray[6];

		if (!isNaN(month)) {
			month = month + 1;
		}

		if (ampm == 1 && !isNaN(hour)) {
			hour = hour + 12;
		}

		if (month < 10) {
			month = '0' + month;
		}
		if (day < 10) {
			day = '0' + day;
		}
		if (hour < 10) {
			hour = '0' + hour;
		}
		if (minute < 10) {
			minute = '0' + minute;
		}
		if (second < 10) {
			second = '0' + second;
		}

		return year + '-' + month + '-' + day + ' ' + hour + ':' + minute;
	}

I know that my code is not optimal. This post is only tutorial how to write new fields of structure. If you have better idea how resolve this problem just write to me.

If you want download all source files or download ready to deploy war file click links:

* I wrote this hook using trunk version of liferay CE (rev. 70450)

Update on Newsletter portlet for Liferay Portal

When we first started developing Newsletter portlet we thinked about doing it fast (we needed for our project). That is why we made it directly in Liferay code thinking that later it will be excluded to ext-plugin (and later to external portlet). Well Summer and Fall went by and nothing changed. Almost nothing – we mastered portlet communications and re-use of Liferay portlets (exactly Asset Publisher). So when I wrote about Newsletter portlet I didn’t know that my developers started work on moving it from Liferay core to ext-plugin external portlet. This will allow us to be more independent from Liferay source code changes and to develop changes for next milestones much quicker than expected.

As for business side of that portlet – we want to release it on double licence (currently I’m thinking about which one we should use).  One will be commercial licence with support, user guide. Probably it will be unlimited licence so you will but it one and use it forever so you don’t have to worry about cost of buying it (it will be cheap 🙂 ).

Second one will be free licence. And here we’re thinking how to do it. We can limit functionalities (IMHO it’s not so good idea) but without our advertisement or we can give full functionalities but with little non intrusive ads (for example with our company website address in footer of every mail. Or maybe give it all but only for educational and non-profit purposes?

What do you think about that? Which one would you prefer?