Happy Holidays – 2011

It took more than I would like, to write a new blog post. It was maybe because I was working from Sunday to Sunday on a great project, or maybe because I could not find an blank spot in my mind to fill with a new blog post. It is time to write again a post.

This one is a simple one, the Happy Holidays post is always an easy way to remove that task from your ToDo list.

For me, this year is one of those when you feel you have done a lot, change a lot, and it is probably why I feel I’m not the same one -and I’m not talking about getting older, which is also true :-) . This year I had the opportunity to work closer on a start-up company and to travel to New York City to work side-by-side with the team over there. I do not have words to express how much I learned. Now I feel closer to my personal goals. Being part of such start-up company was an amazing time.

I’m happy because this year is finally ending with all the changes it brought to me. I’m happy because this year was the year it was, but also happy because I’m pretty sure the next will be even better and even more challenging.

IThe last paragraph of this post is to thank you all the people who spend valuable time with me: my family (the first and most important) which is always supporting me, my friends (the old and the new ones), my coworkers, and my students (the ones who get A+ and those who didn’t). Happy holidays, and I wish you spend some great time with your beloved ones.


JBoss Portal Fail!

Ok, I do not like to write about useless stuff, but this time, I got into deep troubles because one of my clients ask me to implement a portal page on top of JBoss Portal. My first thought was “Ok, if it is as good as JBoss Application Server, it should be good enough”.

So I downloaded it -the 2.7.2 bundled version. I started working on it, simple configuration and customization. I even bought a book, because, I still do believe that books are good for reference.

Oh Dear God! What a SHAME, the book JBoss Portal Server Development [Packt Publishing] is nothing more than printed version of the online Reference Guide. I read the customers reviews before get the book but to be honest, I found websites with useful tips and post. I believe I will donate the book… for recycling.

About the product, I don’ t have enough word to express my frustration.

Content Management

When you read on JBoss Portal documentation it is not a CMS, it really means it doesn’t even work to store content at all.

  • CMS performance will decrease dramatically as you load and modifies your content. BIG BIG FAIL! TIP JCR performance gets BETTER if you switch the repo to the FS instead of using databases.
  • CMS doesn’ t have Search functionality. Even when JCR has a great index analyser, JBoss Portal fails. I downloaded (svn co) the 2.7.2 version source code from the repos. “core-search” module doesn’t compile. Ant scripts are too fragmented and hard to read. You’ll have to replace and FIX all the jar dependencies to make it work. Note: I didn’t test it, but probably repo works flawless on 2.6.8 version -looking at the scripts and code it could be possible. Once you make it work, the deploy target will not work. Server will consume too memory and then CRASH!
  • Portal Pages and CMS content are not related. I built my own search portlet -fragment of code is at the end of this post. It is not easy to match Portal Pages with CMS content -I didn’ t tried it, however I’m pretty sure it is possible.

Documentation

Official docs are good enough -not great but good to be a Open Source project, however Wiki is a shame, its confusing and incomplete. There are a lot of unexplained things like how to get sources, and how to compile, troubleshooting, and stuff like that.

PortalSwap is a FAIL… it is supposed to be a community place to share portlets but there are like four simple portlets.

Community and DevTeam Support

Well, I was contacted -in some how- by the DevTeam on twitter. The truth, I “tweet” my frustration several weeks ago! and they noticed – At the beginning I was angry about the product but then I realized that IT IS FOR FREE, so let’s try to change and improve things! I wrote a nice email to the DevTeam. All I want is to get paid (from my client) and also to contribute to the project.

I’m still waiting for the answer from DevTeam, without mention that the “Twitter Support” was more like a complain than a “Branding Strategy”. So there is no community support, and DevTeam doesn’t know about Customer Care. My suggestion is, next time you contact a frustrated developer, try to convince to “help DevTeam” instead of debate!

As a recap, JBoss AS is a great product, JBoss Portal is seems to me like a “work in progress” – Maybe it is a students project!

Search Portlet Source

The original code have been edited -please let me know if it works for you.

package xxx;
 
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
 
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletSecurityException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.UnavailableException;
import javax.portlet.WindowState;
 
import org.apache.log4j.Logger;
import org.jboss.portal.cms.CMS;
import org.jboss.portal.cms.CMSException;
import org.jboss.portal.cms.Command;
import org.jboss.portal.cms.model.File;
import org.jboss.portal.core.cms.ui.CMSPortlet;
import org.jboss.portal.search.FederatedQuery;
import org.jboss.portal.search.QueryConversionException;
import org.jboss.portal.search.federation.SearchFederation;
import org.jboss.portal.search.impl.jcr.JCRQuery;
import org.jboss.portal.search.impl.jcr.JCRQueryConverter;
 
public class SearchPortlet extends CMSPortlet {
 
	private static Logger log = Logger.getLogger(SearchPortlet.class);
	private SearchFederation SearchService;
	private CMS CMSService;
 
	public void init(PortletConfig config) throws PortletException {
		super.init(config);
	}
 
	public void destroy() {
		super.destroy();
	}
 
	/*
	 * (non-Javadoc)
	 *
	 * @see javax.portlet.Portlet#init()
	 */
	@Override
	public void init() throws PortletException {
		this.SearchService = (SearchFederation) getPortletContext().getAttribute("SearchFederationService");
		this.CMSService = (CMS) getPortletContext().getAttribute("CMS");
 
		if (this.SearchService == null) {
			throw new PortletException("Search Service Not Available");
		}
 
		if (this.CMSService == null) {
			throw new PortletException("CMS Not Available");
		}
 
		super.init();
	}
 
	/*
	 * (non-Javadoc)
	 *
	 * @see javax.portlet.GenericPortlet#doView(javax.portlet.RenderRequest,
	 * javax.portlet.RenderResponse)
	 */
	@Override
	protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException, UnavailableException {
 
		String portalInstance = request.getWindowID().substring(0, request.getWindowID().indexOf('/', 1));
		PortletRequestDispatcher prd = null;
 
		String operation = (String) request.getParameter("op");
 
		if (operation != null && operation.equals("search")) {
			String queryString = (String) request.getParameter("query");
			if (queryString != null && queryString.length() > 0) {
				request.setAttribute("files", this.getFiles(queryString, portalInstance));
				prd = this.getPortletContext().getRequestDispatcher("/WEB-INF/jsp/results.jsp");
			} else {
				prd = getPortletContext().getRequestDispatcher("/WEB-INF/jsp/search.jsp");
			}
			prd.include(request, response);
		} else if (operation != null && operation.equals("display")) {
			super.doView(request, response);
		} else {
			prd = getPortletContext().getRequestDispatcher("/WEB-INF/jsp/search.jsp");
			prd.include(request, response);
		}
	}
 
	/*
	 * (non-Javadoc)
	 *
	 * @see javax.portlet.Portlet#processAction(javax.portlet.ActionRequest,
	 * javax.portlet.ActionResponse)
	 */
	@Override
	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, PortletSecurityException, IOException {
 
		String operation = (String) request.getParameter("op");
		PortletPreferences prefs = request.getPreferences();
 
		if (operation == null || operation.equalsIgnoreCase("ask")) {
			response.setRenderParameter("op", "ask");
			//FIXME response.setWindowState(WindowState.NORMAL);
		}
		else {
			//FIXME response.setWindowState(WindowState.MAXIMIZED);
			response.setRenderParameter("op", operation);	
 
			if (operation.equals("search")) {
				String queryString = (String) request.getParameter("query");
				if (queryString != null && queryString.length() > 0) {
					response.setRenderParameter("query", queryString);
				}
			}
 
			if (operation.equals("display")) {
				String uri = request.getParameter("uri");
				response.setRenderParameter("uri", uri);
				super.processAction(request, response);
			}
		}
	}
 
	private List getFiles(String queryString, String portal) {
		List files = null;
 
		if (queryString != null && queryString.length() > 0) {
			FederatedQuery query = new FederatedQuery(queryString);
			JCRQueryConverter converter = new JCRQueryConverter();
 
			try {
				Command searchCommand = CMSService.getCommandFactory().createSearchCommand((JCRQuery) converter.convert(query));
				files = (List) CMSService.execute(searchCommand);
				//FIXME: "portal" parameter was used to filter files depending on the portal instance but it was removed for this example!
			} catch (CMSException e) {
				log.error("CMS Error", e);
			} catch (QueryConversionException e) {
				log.warn("Conversion Error", e);
			}
		}
 
		return (files == null) new ArrayList() : files;
	}
}

Include the following lines on your jboss-portlet.xml file.

<service>
	<service-name>CMS</service-name>
	<service-class>org.jboss.portal.cms.CMS</service-class>
	<service-ref>:service=CMS</service-ref>
</service>
 
<service>
	<service-name>SearchFederationService</service-name>
	<service-class>org.jboss.portal.search.federation.SearchFederation</service-class>
	<service-ref>:service=SearchFederationService</service-ref>
</service>

And do not forget to include the following lines on your portlet.xml file.

<portlet>
	<description>DESC</description>
	<portlet-name>SearchPortlet</portlet-name>
	<display-name>NAME</display-name>
	<portlet-class>xxx.SearchPortlet</portlet-class>
	<supports>
		<mime-type>text/html</mime-type>
		<portlet-mode>VIEW</portlet-mode>
	</supports>
	<resource-bundle>Resource</resource-bundle>
	<portlet-info>
		<title>SEARCH</title>
	</portlet-info>
	<portlet-preferences>
		<preference>
			<name>indexpage</name>
			<value>/default/index.html</value>
			</preference>
		<preference>
			<name>setBrowserTitle</name>
			<value>false</value>
		</preference>
	</portlet-preferences>
</portlet>
 
<filter>
	<filter-name>JBoss Portlet Filter</filter-name>
	<filter-class>org.jboss.portlet.filter.JBossPortletFilter</filter-class>
	<lifecycle>ACTION_PHASE</lifecycle>
	<lifecycle>RENDER_PHASE</lifecycle>
</filter>
 
<filter-mapping>
	<filter-name>JBoss Portlet Filter</filter-name>
	<portlet-name>SearchPortlet</portlet-name>
</filter-mapping>

Please THIS IS NOT A PERFECT SOLUTION, but it is a solution. It uses the existing CMSPortlet to display the content -and this approach causes an issue -due to WindowState changes. I hope someone find it useful and improves it. Feel free to contact me if you have any question.


Twestival Bogota – Feb/12/2009

As part of a meet-us-now-face-2-face Colombian fever / frenzy, there is another initiative around charity! -charity: water Few months after the Facebook events fever now we are facing the Twitter invitations frenzy. However I spent few lines commenting about Twestival Bogota, because it deserves it. BTW: I will not assist due to previous personal engagements.

Any who wants additional information feel free to visit the Twestival site.


VII Encuesta de Gerencia de Proyectos de TI

Con el motivo de la VII Jornada de Gerencia de Proyectos, se presenta la VII Encuesta de Gerencia. Los interesados pueden en responderla aquí.