4/27/2011

The button/link/text component needs to have a Form in its ancestry. Please add h:form

If you get an error message like the one above and you are using Mojarra 2.1.1 then it might be that a mojarra brought you into trouble.


Try to create an icefaces page and use a menuItem like this:

<ice:form>

<ice:menuBar value="Bar" orientation="Vertical">
<ice:menuItem value="Iten">
<ice:menuItem value="TestItem" actionListener="#{bean.click}" />
</ice:menuItem>
</ice:form>


If you get an exception with the message "The button/link/text component needs to have a Form in its ancestry. Please add h:form", try to replace MOjarra 2.1.1 with the older 2.0.4 version. Then it should work.



If you like this post it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

4/23/2011

Happy Easter !

So - I am off to my easter vacation. Just wanted to say "goodbye" for a couple of days. It has been a great pleasure to see 100 - 200 people visiting my page everyday and I am really proud of it. I will now spend some time with my family and watch all episodes of "outsourced" that I can get a hold on.
http://en.wikipedia.org/wiki/Outsourced_(TV_series)


See you next week !!!




If you like this blog it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

How to read and write cookies in ICEfaces 2.0

Just a quick note before I leave to my easter vacation. If you try to get and set cookies in ICEfaces 2.0 like you did in 1.82 you will likely fail to do so. The 1.82 way was:



Map cookies = ((HttpServletRequest)((BridgeExternalContext) FacesContext.getCurrentInstance().getExternalContext()).getRequest()).getCookies();

Not very intuitive, if you ask me. I clearly prefer the 2.0 - way, which is the official JSF 2.0 way:

//Setting the cookie

FacesContext.getCurrentInstance().getExternalContext()
.addResponseCookie("CookieName", "CookieValue", null);

//Getting the cookie

Map<String, Object> requestCookieMap = FacesContext.getCurrentInstance().getExternalContext().getRequestCookieMap();



If you need to add more properties you can do so by providing a properties map when calling addResponseCookie. Which properties you can add to the map is described here:


Official Oracle JavaDoc


If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

4/22/2011

An Overview of Liferay Services - Part 1

Whenever you work with Liferay and you do more then just adding portlets to a page you will need to work with Liferay Services. They provide CRUD - access to all Users, Roles, Groups, Blogs, Forum Entries etc etc etc. This series of entries has the aim to provide an overview to let you find out quickly the Service that you need to get the data that you want. Just a hint: Whenever you access a Service you will most likely do it by using the "XXLocalServiceUtil" - helper classes that Liferay provides. I will link this series on the front page of my blog so it will be very fast accessible.




Getting the Addresses of Users


If you want to get the address details of Users, you will use the AddressLocalServiceUtil. The table you are looking for is "address" and the entity (of course) also "Address". The address table contains only address information like street, city, a region id and a country id. If you need information about the region and country itself you will need other Services.


table name: Address
entity: Address
Service class: AddressLocalServiceUtil


Getting Blogs 


If you want to retrieve all Blogs posted by Users you can use the BlogsEntryLocalServiceUtil. The table is called "blogsentry". The blogsentry table contains all you need to know about blogs - including the createDate. The content of the blog is in html format, so be sure to strip this before you process it.


table name: BlogsEntry
entity: BlogsEntry
Service class: BlogyEntryLocalServiceUtil




Getting Infos about Chats


If you want to retrieve data about chats ( the chat portlet is available from liferay) you can do this by queriyng two tables "chat_entry" and "chat_status". The first table contains the chat messages (they won´t get deleted), the second contains the status of people that chat (online, offline etc.). The second table is very handy if you want to display the online status of people in the portal.


table name: chat_entry
entity: Entry
Service class: EntryLocalServiceUtil


table name: chat_status
entity: Status
Service class: StatusLocalServiceUtil






Here is a summary


Model DescriptionLiferay ServiceTable Name
Addresses of all registered UsersAddressLocalServiceUtiladdress
All Blog entriesBlogsEntryLocalServiceUtiladdress
All chats heldEntryLocalServiceUtilchat_entry
Online Status of Liferay Portal UsersStatusLocalServiceUtilchat_status




If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

4/20/2011

Custom Attributes / Custom Fields in Liferay

If you are working with Liferay and you need to store some data, say about a User, you will not always create a new service. Sometimes it´s just a property that needs to be stored and a new Service would be overweight for this requirement. This is the time to create Custom Attributes or Custom Fields as they are called in Liferay 6.


List of Custom Fields in the Liferay Control Panel (Liferay 6)
But no matter how they are called on the GUI - they are Expando values on the inside. This post will show you how to set and retrieve expando values programmatically.


ExpandoValues can be added to a lot of liferay objects: Users, Organizations, Pages, Images, Calendar Events etc. If you store a value, either by using the Control Panel or programmatically they will be stored using the following structure. Note that you have to know this structure for storing and retrieval. The examples on how to actually retrieve or store something will follow later down.


ExpandoTable


This table stores the information which tableId matches which classname (= entity). To find out the className that matches your entity, simply query the ClassNameLocalServiceUtil:


long userClassNameId = ClassNameLocalServiceUtil.getClassNameId(User.class.getName());


Now, get the tableId you need for the User table:
ExpandoTable table = ExpandoTableLocalServiceUtil.getDefaultTable(companyId, userClassNameId );
The information about the default table for your entity is something you need to get the data out of the database.


ExpandoColumn


ExpandoColumns holds the information, which columnId matches the type of expando value you want to retrieve or store. Use it, to get the last information to retrieve or store your data:
ExpandoColumn column = ExpandoColumnLocalServiceUtil.getColumn(tableId, name);
You can retrieve the column with the tableId and its name.


ExpandoValue


The ExpandoValue table holds all values that are stored in the liferay portal. And this is one of the main reasons why you should never ever store too much data in custom fields: they all land in ONE table !!!!! Never use custom attributes to store something, a service is made for !!!


To retrieve a value use the following line of code:
ExpandoValueLocalServiceUtil.getValue(tableId, columnId, classPK);
tableId is the id of your default  table, columnId the id of the retrieved column and classPK the primary Key of the entity you want to retrieve. In our example it would be the userId.


To store an expando value, it´s just the other way around:
ExpandoValueLocalServiceUtil.addValue(classNameId, tableId, columnId, classPK, data);
Should be pretty straight forward.


If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

Inter - Portlet Communication in Liferay 6: liferay trigger and bind

If you try to use Liferay.bind() and Liferay.trigger() in Liferay 6 you will notice that they won´t work any more. I described the client side IPC here:


http://liferay-blogging.blogspot.com/2011/04/inter-portlet-communication-in-liferay.html


In Liferay 6, they renamed the functions. What you now have to use is Liferay.on() and Liferay.fire().

If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

4/17/2011

How to create Services in Liferay

I am currently preparing a bigger post. Until it´s release I wanted to share a little "Liferay Service Builder tutorial" with you. It´s one of the basic things you can do in Liferay and one of the reasons why developing with Liferay is some much fun and so flexible.


So ... first: What is the Liferay Service Builder? What does it do ? Do I HAVE to use it ?


To answer in one sentence: The Liferay Service Builder enables you to create in minutes all you need to store and retrieve data in your portlets. This includes table scripts, automatic table creation and CRUD convenience methods to store and retrieve your data.


Normally you create your service in your portlet and that´s it. But you can also allow other portlets to access your service. In this tutorial we will now create a "Hello World" Liferay Service that you can access from all of your portlets.


So before we begin, please create a new portlet called "hello-service-builder" (by using the Liferay IDE)


Create your Service definition.


The first part is to create your service. Create a file called service.xml in your WEB-INF folder. This file will contain all the information about your service.


For our example here we create a service that persists a hello world phrase - a small sentence the user can enter. Add the following to your service.xml:




<?xml version="1.0"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.0.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_0_0.dtd">


<service-builder package-path="de.test">
<namespace>Hello</namespace>


<entity name="HelloWorld" table="helloWorldTable" local-service="true"
remote-service="false">


<column name="helloWorldId" type="long" primary="true" />
<column name="helloWorldPhrase" type="String" />
<column name="createDate" type="Date" />


</entity>


</service-builder>




This is the definition of our service. It will have a primaryKey called helloWorldId, a phrase that we can enter and a createDate so that we know when our phrase got persisted.


By specifying the tableName we can tell the Liferay Service Builder to not autogenerate a tableName. This is very important when you have to access the same table from different portlets. By adding a package-path we specify the packafge, liferay generates the model and service file into. 




Generate the service.


If you have generated the portlet by using the Liferay IDE you will have a build.xml file in the root of your portlet. Please execute the "build-service" target and refresh your workspace.


You should now see a lot of new classes and folders:




As you can see, Liferay generates SQL scripts and classes. If you would deploy the portlet right now, you could see a database table being created instantly - absolutely no need to care for the database.


If you need to have database create scripts for various databases such as mysql, oracle etc. you can execute the ant target "build-db". The ServiceBuilder will then create all the sql scripts you need to create the "Hello World Service" data tables.




Accessing your data


If you have already worked with Liferay Services, you will know, that Liferay allows access to it´s Services always by its XYZLocalServiceUtil classes. They are basically a set of static methods to allow you a convenient way to get your data.


If you take a look at the generated classes you now have, you will see the class HelloWorldLocalServiceUtil which you can use send CRUD commands to the Hello World Service.


I won´t go into much detail here, but the LocalServiceUtil class is all you need to store your data from within your portlet.


Extend your LocalServiceUtil class


If you want to extend the static methods, your autogenerated LocalServiceUtil class provides you, you have to do the following:


Write the methode into the LocalServiceImpl class (for example HelloWorldLocalServiceImpl), the run "buid-service" again, refresh your project / workspace and you will find the method in your LocalServiceUtil. Liferay actually creates interfaces from implementation classes ... not really sure what I should think about that.


One common method, everybody creates in the LocalServiceImpl is an add() - method that takes the parameters your bean will hold, creates an instance of it and persists it in the database.
You can do it like this:



public void addNewHelloWorld(Date createDate, String helloWorldPhrase){

long primaryKey = CounterLocalServiceUtil.increment(HelloWorld.class.getName());


HelloWorld helloWorld= helloWorldPersistence.create(primaryKey);
helloWorld.setCreateDate(createDate);
helloWorld.setHelloWorldPhrase(helloWorldPhrase);
helloWorld.setHelloWorldId(primaryKey);
addHelloWorld(helloWorld);
}



First: Let liferay count your primary key by using the CounterLocalServiceUtil. Second: Let liferay do the initial creation by calling the helloWorldPersistence. Then add your properties and call the "add" method from the HelloWorldLocalServiceBaseImpl class.


That´s all ... you can now start using your very own Liferay Service.




If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

4/11/2011

Getting the Address of a User

If you want to retrieve the address of a user in liferay, you have to use the AddressLocalServiceUtil with the contactId of the User - ignore the UserId. Liferay is able to connect addresses to more entities than just users, so you need to use the fabulous "classNameId - classPK" connection once again:


Here is the code:



long classNameId = ClassNameLocalServiceUtil.getClassNameId(Contact.class);

long contactId = user.getContact().getContactId();
query.add(PropertyFactoryUtil.forName("classNameId").eq(
classNameId));

query.add(PropertyFactoryUtil.forName("classPK").eq(contactId));


List<Address> address= 
ddressLocalServiceUtil.dynamicQuery(query);





This should return only one result - the address of the User you want to have.




If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

4/07/2011

Setting the current page in the Liferay Search Container

Initially I wanted to write a tutorial on how to use the liferay search-container. But after I struggeled a lot with forcing the search-container to survive page refreshs I want to share my experience with my audience.


The problem is the following: If you click on a link on a portlet page where a search-container is used the search container is reset. The current page switches back to the first page and your search result is lost. If you take a look at the SearchContainer object yuo´ll find in com.liferay.portal.kernel.dao.search you´ll notice that there is a variable called "_cur" which holds the current page. There is a setter for the variable but no getter ! I don´t know if they forgot to implement it or if this is intended.


Well, here my (hackish) solution to fix this: Implement the method on your own and set the current value when using the search container in your JSP.


First, add the search container to your ext-let (or ext environment in your are using Liferay 5). Second, add the following method:


public void setCur(int cur){
    this._cur = cur;
    _iteratorURL.setParameter(_curParam, String.valueOf(cur));
    setTotal(_total);
}


This makes sure, that the parameter is set and the internal data is processed correctly.
Now deploy you ext and take your portlet. Add the following to your JSP that is using the search-container:



<liferay-ui:search-container emptyResultsMessage="no-entries-were-found"  iteratorURL="<%= portletURL%>" >


<liferay-ui:search-container-results >
<%if (yourOverwrittenCurValue!= -1){
searchContainer.setCur(yourOverwrittenCurValue);
}
[...]

What you do is to set the cur variable with your own value. In my case it´s the variable "yourOverwrittenCurValue".  But how do you get this variable ? The solution is: use the getCur() variable to get the actual value and put it into the session. In your "render" method, retrieve it from the session and provide it to your JSP.

Object curObject= request.getPortletSession().getAttribute("cur");
if (curObject!= null){
request.setAttribute("cur", curObject);
request.getPortletSession().setAttribute("cur", null);
}

All you have to do now is to retrieve the request value in your JSP and you´re done :)


If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

4/05/2011

Tutorial: How to enhance the Liferay Asset Publisher

Have you ever wondered how you could change the asset publisher to (for example) also display the ratings of the assets you show? Have you ever tried to display more meta data of the documents you display ? In Liferay, this is controlled by the display styles of the asset publisher. You need to create your own display style to change how the asset publisher renders its output.


Today we will enhance the Asset Publisher to provide us more ways to display the data retrieved!


Register new display style


First, you need to allow the User to choose a new display style. The standard styles are table,title-list,abstracts and full-content. To add a new one, add the following line to your portal-ext.properties in your ext:


asset.publisher.display.styles=table,title-list,abstracts,full-content,your-display-style


Next, add the following line to your language.properties (in a hook, for example): 


your-display-style = Name Of Your Display Style


This makes sure, that you can internationalize your titles and the user has something meaningful to read.


Create a Hook for the asset publisher


The last step is to create a JSP in a hook for the asset publisher that formats the display of the assets the way you want. So let the Liferay IDE create a hook for you and add the following to your liferay-hook.xml: 


<custom-jsp-dir>/META-INF/custom_jsps</custom-jsp-dir>


Now, rebuild the directory structure for the asset publisher in your custom JSP dir: html / portlet / asset_publisher / display.


Put a JSP called your_display_style.jsp into this directory. This is the file, that will be called when a User selects your new display style. 


I think it would be the best, if you just copied an existing one, to see how the iteration over the asset entries is done. You can then adopt it the way you like.




If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

4/04/2011

Inter Portlet Communication in Liferay - Part 2

One thing that is really nice to do, for example if you use ICEfaces portlets is to use the Liferay Client - Side IPC Feature. It´s pure JavaScript and very easy to use. It uses the following two methods (Liferay 5.1 and above):



  • Liferay.trigger(eventName, data)
  • Liferay.bind(eventName, function, scope)


By using bind, you can bind a javascript function to an event. The function will be called if the event gets fired

Example:

 Liferay.bind('your-event',
 function(event, data){
   var message = data.message;
   //... do important stuff
});


You can trigger the event by using the 'trigger' function:

Liferay.trigger('your-event', {message: 'Hello IPC - World'});

This allows you to let any portlet that is capable of JavaScript communicate with each other.



If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.

How to create your own portal-wide properties in Liferay

If you need to set your own properties, for example to display or hide certain data, you can do the following. Add your property to the portal-ext.properties like this (your portal-ext.properties can be found in your ext in the source folder of ext/impl):


your.property.here = My special property value


Then deploy your ext, and access it wherever you want by using this:


String yourPropertyValue= PropsUtil.get("your.property.here");


That´s all :) I like it !






If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.