Tuesday, April 10, 2012

Richfaces4 + Mojarra + Facelets

Here is my pom.xml & web.xml for Richfaces4 + Mojarra + Facelets

 <?xml version="1.0" encoding="UTF-8"?>  

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.confucius</groupId>
<artifactId>HelloWorldJSF</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>A JSF project using myfaces</name>
<url>http://www.confucius.org</url>


<!-- Project dependencies -->
<dependencies>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
</dependency>

<dependency>
<groupId>com.sun.facelets</groupId>
<artifactId>jsf-facelets</artifactId>
<version>1.1.11</version>
</dependency>

<dependency>
<groupId>org.richfaces.ui</groupId>
<artifactId>richfaces-components-ui</artifactId>
</dependency>

<dependency>
<groupId>org.richfaces.core</groupId>
<artifactId>richfaces-core-impl</artifactId>
</dependency>

<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>

</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.richfaces</groupId>
<artifactId>richfaces-bom</artifactId>
<version>4.1.0.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
</project>


 <?xml version="1.0"?>  

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

<!-- Use Documents Saved as *.xhtml -->
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>

<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<!-- Welcome files -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

</web-app>

Thursday, July 29, 2010

Eclipse maven import - maven dependencies not showing up

If the maven dependencies are not showing up in your imported project, check the .classpath file in your project. Make sure it has the Maven specific entry:

<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>

Saturday, April 24, 2010

JSP: Nested custom tags

Here is a simple example of a nested custom tag (which renders a pie chart). Note that I use JQuery to manipulate the DOM.

Here is the test JSP (PieChartTest.jsp):
<html>
<head>
<title>Pie Chart</title>
<script type="text/javascript" src="js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="js/fasttags.js"></script>
<%@ taglib uri="/WEB-INF/tlds/FastTags.tld" prefix="fast" %>
</head>
<body>
<fast:piechart radius="100">
<fast:pieslice name='Vanguard 2045' value='75000'/>
<fast:pieslice name='Fidelity 2040' value='50000'/>
<fast:pieslice name='Principal 2035' value='20000'/>
<fast:pieslice name='Citibank Money Market' value='5000'/>
</fast:piechart>
</body>
</html>



Here is the PieChart Tag class (PieChartTag.java):
package org.fastkangaroo.fasttags;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;


public class PieChartTag implements Tag, Serializable {

private PageContext pc = null;
private Tag parent = null;
private int radius = 90;
private List<String> namesList = new ArrayList<String>();
private List<String> valuesList = new ArrayList<String>();

public void addSlice(String name, String value){
namesList.add(name);
valuesList.add(value);
}

public void setPageContext(PageContext p) {
pc = p;
}

public void setParent(Tag t) {
parent = t;
}

public Tag getParent() {
return parent;
}

public int doStartTag() throws JspException {
namesList = new ArrayList<String>();
valuesList = new ArrayList<String>();
return EVAL_BODY_INCLUDE;
}

public int doEndTag() throws JspException {
try {
pc.getOut().write("<table id='legend'/>");
pc.getOut().write("<br/>");
pc.getOut().write("<div id='tooltip'></div>");
pc.getOut().write("<canvas id='canvas' width='" + (radius+5)*2 + "' height='" + (radius+5)*2 + "'/>");
pc.getOut().write("<script>draw(" + this.namesList.toString() + "," + this.valuesList.toString() + "," + radius + ");</script>");
} catch(IOException e) {
throw new JspTagException("An IOException occurred.");
}
return EVAL_PAGE;
}

public void release() {
pc = null;
parent = null;
}


/**
* @param radius the radius to set
*/
public void setRadius(int radius) {
this.radius = radius;
}

/**
* @return the radius
*/
public int getRadius() {
return radius;
}

}



Here is the PieSlice Tag class (PieSliceTag.java):
package org.fastkangaroo.fasttags;

import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;


public class PieSliceTag extends BodyTagSupport {

private PageContext pc = null;
private Tag parent = null;
private String name = null;
private String value = null;

public void setPageContext(PageContext p) {
pc = p;
}

public void setParent(Tag t) {
parent = t;
}

public Tag getParent() {
return parent;
}

public int doStartTag() throws JspException {
try {
PieChartTag parent =
(PieChartTag)findAncestorWithClass(this, PieChartTag.class);
if (parent != null){
parent.addSlice("'" + this.name + "'", this.value);
}
}
catch(Exception e) {
throw new JspTagException("An IOException occurred.");
}
return SKIP_BODY;
}

public int doEndTag() throws JspException {
return EVAL_PAGE;
}

public void release() {
pc = null;
parent = null;
}

/**
* @return the name
*/
public String getName() {
return name;
}

/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}

/**
* @return the value
*/
public String getValue() {
return value;
}

/**
* @param value the value to set
*/
public void setValue(String value) {
this.value = value;
}

}

Here is the TLD (FastTags.tld):
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>FastTags</shortname>
<uri>http://www.fastkangaroo-software.org</uri>
<info>Fast Tags Library</info>

<tag>
<name>piechart</name>
<tagclass>org.fastkangaroo.fasttags.PieChartTag</tagclass>
<bodycontent>scriptless</bodycontent>
<info>PieChart Tag</info>
<attribute>
<name>radius</name>
<required>false</required>
</attribute>
</tag>

<tag>
<name>pieslice</name>
<tagclass>org.fastkangaroo.fasttags.PieSliceTag</tagclass>
<bodycontent>empty</bodycontent>
<info>PieSlice Tag</info>
<attribute>
<name>name</name>
<required>true</required>
</attribute>
<attribute>
<name>value</name>
<required>true</required>
</attribute>
</tag>
</taglib>


Here is the javascript (fasttags.js)
var slices = new Array();
var pieTooltips = new Array();
var pie_radius = 90;
jQuery(document).ready(function(){
$("#canvas").mousemove(function(e){
tooltip(e);
});
})

function tooltip(e) {
var offset = $("#canvas").offset();
xpos = e.pageX - offset.left;
ypos = e.pageY - offset.top;
radius = Math.sqrt((xpos-(pie_radius+5))*(xpos-(pie_radius+5)) + (ypos-(pie_radius+5))*(ypos-(pie_radius+5)));
if (radius < pie_radius){
if (xpos > (pie_radius+5)) {
if (ypos < (pie_radius+5)) {
tan = ((pie_radius+5) - ypos)/(xpos -(pie_radius+5));
angle = 2*Math.PI - Math.atan(tan);
}
else {
tan = (ypos - (pie_radius+5))/(xpos -(pie_radius+5));
angle = Math.atan(tan);
}
}
else {
if (ypos < (pie_radius+5)) {
tan = ((pie_radius+5) - ypos)/((pie_radius+5) - xpos);
angle = Math.PI + Math.atan(tan);
}
else {
tan = (ypos - (pie_radius+5))/((pie_radius+5) - xpos);
angle = Math.PI - Math.atan(tan);
}
}
for (i = 0; i < slices.length; i++) {
if (angle < slices[i]){
$("#tooltip").html(pieTooltips[i-1]);
break;
}
}
}
}

function draw(names,values,radius) {
pie_radius = radius;
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
var total = 0;
for (i=0; i < values.length; i++){
total += values[i];
}
slices = new Array();
slices[0] = 0;
for (i=0; i < values.length; i++){
slices[i+1] = slices[i] + 2*Math.PI*values[i]/total;
}
var colors = ["#F1CAA0", "#AB1100","#22CC00","#CCBB22","#FF6600","#FFDD00","#00CC00","#FF1100","#44CC00","#FFCC11"]
$('#legend tr').remove();
pieTooltips = new Array();
for (i = 0; i < slices.length-1; i++) {
// Draw shapes
ctx.beginPath();
ctx.moveTo(radius+5,radius+5);
ctx.arc(radius+5,radius+5,radius,slices[i],slices[i+1],false);
ctx.moveTo(radius+5,radius+5);
ctx.fillStyle = colors[i];
ctx.fill();
var newRow = '<tr><td bgcolor="' + colors[i] + '" width="20px"></td><td style="padding-left:10px">' + names[i] + '</td><td style="padding-left:10px">' + values[i] + '</td><td style="padding-left:10px">(' + divide(values[i]*100,total) + '%)</td></tr>';
$(newRow).appendTo('#legend');
pieTooltips[i] = names[i] + ' : ' + values[i] + ' (' + divide(values[i]*100,total) + '%)';
}
}
}

function divide ( numerator, denominator ) {
// In JavaScript, dividing integer values yields a floating point result (unlike in Java, C++, C)
// To find the integer quotient, reduce the numerator by the remainder first, then divide.
var remainder = numerator % denominator;
var quotient = ( numerator - remainder ) / denominator;

// Another possible solution: Convert quotient to an integer by truncating toward 0.
// Thanks to Frans Janssens for pointing out that the floor function is not correct for negative quotients.
if ( quotient >= 0 )
quotient = Math.floor( quotient );
else // negative
quotient = Math.ceil( quotient );

return quotient;

}

Tuesday, March 2, 2010

Could not start the MySQL service: Error 1067

I had to reinstall MySQL 5.1 - but once I did that, I could not start the service with the 1067 error. The problem was that the earlier install was writing the data to C:\MySQL InnoDB Datafiles\ and the new version was writing to C:\ProgramData\MySQL\MySQL Server 5.1\data

So I:
1. backed up my C:\ProgramData\MySQL\MySQL Server 5.1\data then deleted it
2. Reinstalled MySQL and started the service - this time the service started and it created a new C:\ProgramData\MySQL\MySQL Server 5.1\data
3. Stopped the service
4. I copied all my database folders from backup to this new \data directory
5. COpied the ibdata1 from C:\MySQL InnoDB Datafiles\ to this new \data (overwritng the existing file)
6. Restarted service

Saturday, August 29, 2009

richfaces pickList - validation error

A common error when using pickList is a "Value is not valid" error.

One reason for this is that the selectItem list does not contain one of the selected values. This happens often when you try to created a pre-selected list.

For example, suppose your selectItems are: A, B, C, D, E
And A & B are already selected.

This means that when the pickList is shows, you want A & B to appear in the right side, and you want C, D, E to appear on the left side.

What you need to do is put all five - A, B, C, D & E in the selectItems list (left side list).
Then in the list which will hold the selected items (right side list - the one that you will bind to the value attribute of the picklist), you need to put the select Item value of A & B.

richfaces will automatically show A & B on the right and C, D, E on the left.

However, if you put A & B in the right side list, and pnly C, D, E in the left side list - you will get a value is not valid error!


Secondly, remember that if your value is a non-String object, then you need to override the "equals" method in your Object class.

richfaces pickList - converters

Here are a few things to remember when using richfaces pickList:

1. If the value of your selectItem is a non-String object type, then you need to write a converter. You can have a property on your backing bean to hold an instance of the converter, and you can point the pickList converter to use it.

Like below:

1. -------------- Converter ----------------------------

package org.fastkangaroo.quasimodo.converters;

import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

import org.fastkangaroo.quasimodo.entities.UserProfile;

public class UserProfileConverter implements Converter {
private Map choiceMap;

public Object getAsObject(FacesContext arg0, UIComponent arg1, String label) {
return choiceMap.get(label);
}

public String getAsString(FacesContext arg0, UIComponent arg1, Object obj) {
UserProfile userProfile = (UserProfile) obj;
String label = userProfile.getFirstName() + " " + userProfile.getLastName() + " " + userProfile.getMiddleName();
return label;
}

/**
* @param choiceMap the choiceMap to set
*/
public void setChoiceMap(Map choiceMap) {
this.choiceMap = choiceMap;
}

}


2. ------------------ Beacking Bean --------------------------

public class ProjectBean {

...
private UserProfileConverter userProfileConverter;

...

+ getter/setter
}




3. ------------------- XHTML ------------------

<rich:pickList id="memberPickList"
value="#{projectBean.selectedMembers}"
converter="#{projectBean.userProfileConverter}"
validator="#{projectBean.projectMembersValidator}" >
<f:selectItems value="#{projectBean.memberSelection}" />
</rich:pickList>

richfaces DataTable - getting selected row

Unfortunately, a simple thing like getting which row in the rich:DataTable was selected is not so simple!

For excellent examples, see this page:
http://balusc.blogspot.com/2006/06/using-datatables.html

And, in addition, remember this:

1. Binding the datatable in your xhtml to a backing bean datatable (using the 'binding' attribute) will work only if the backing bean is in request scope. If it is in session scope, you will get a duplicate Id error when you refresh or revisit the page.

2. If you put a commandButton (or commandLink) on each row - it will work only if the action handler backing bean is in session scope. If it is in request scope, the action handler will not be called.

So, these two things are in contradiction to each other. The solution, if you are in this situation, is to have two backing beans - one for binding the datatable and another for handling the commandButton!

Now, if the reason you are binding the datatable in the first place is to use dataTable.getRowData() to identify the row - so that you can get to the row object, then you are in trouble. Because the action handler will go to a different backing bean!

The solution is to use f:setPropertyActionListener to pass the selected row object to the commandButton, as below:
<a4j:commandLink value="#{project.name}" action="#{projectBean.view}">
<f:setPropertyActionListener target="#{projectBean.project}" value="#{project}" />
</a4j:commandLink>

The backing bean, in this case projectBean should have a property called 'project' with getters and setters.