Pages

Thursday, March 12, 2009

a Java developers Objective-C comments

This my language flame post ;)
So last month I have started developing for iPhone. In order to do so you have to use Objective-C because by default iPhone does not come with Java Virtual Machine. These are the things I most stumbled on Objective-C:
1. Square brackets !
When procedural language people see Lisp code first thing they say is : "What's with all that parentheses ?". Objective-C allthough being procedural, object oriented, language makes me say "What's with all that square brackets ?". You use square brackets to send messages to methods they are soon all around your code and look ugly.
2. Defining Classes and Properties
Objective-C adopts the single inheritance model like Java but, you have to define your classes in "the old header" files and implement them in a seperate, C file. There is no one public class for one file enforcement by the language so you are free to mess your class definitions and go "Where did I defined that ?".
If you want to define a property to use in the interface builder, you have to define it in three places. One in class definition, one to mark it as UI thing and the last is to generate getters, setters.
3. Memory Management Model and When Things Go Wrong
Hardest problems to spot for a Java guy like me was the pointer (or memory) access problems. You have to know what "retain" and "release" does before you start doing anything.
And Objective-C does not have the Java's detailed stack traces so when things go wrong you can have serious headaces and need to hit your head to walls. 
Still its realy fun to develop for the iPhone. Where else you can build a application that responds to your swings ?

Wednesday, March 11, 2009

Use OGNL expressions to fill your SelectOneMenu

JSF selectOneMenu component is loaded with "selectItems" tag. Like; 
<h:selectOneMenu id="som_city" value="#{valueObject.city}">
<t:selectItems value="#{cityService.getCities}" itemLabel="#{val.name}" itemValue="#{val.this}" var="val" />
</h:selectOneMenu>
With the help of some converter we are able to list cities in the combo with the expression "#{cityService.getCities}". But often what we realy want to do is list the cities of certain country which is perhaps choosen from another combo. What we need is another expression like "#{cityService.getCities(someCountry)}". 
To achive this I have overriden the myfaces UISelectItems and gave it the power of Ognl expressions:
import java.util.AbstractMap;
import java.util.HashSet;
import java.util.Set;

import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;

import ognl.Ognl;
import ognl.OgnlException;

import org.apache.myfaces.custom.selectitems.UISelectItems;

public class UISelectSmarterItems extends UISelectItems {

private String expString;

public String getExpString() {
if (expString != null)
return expString;

ValueBinding vb = getValueBinding("expString");
String v = vb != null ? (String) vb.getValue(getFacesContext()) : null;
return v;
}

public void setExpString(String expString) {
this.expString = expString;
}

@Override
public Object getValue() {
String str = getExpString();
if (str != null && str.length() > 0) {
setValue(evaluateExpression(str));
}

return super.getValue();
}

private Object evaluateExpression(String aExp) {
try {
return Ognl.getValue(aExp, new FacesEvaluationContext());
}
catch (OgnlException e) {
throw new RuntimeException(aExp);
}
}

private final class FacesEvaluationContext extends AbstractMap {

@Override
public Object get(Object key) {
return resolveVariable(key);
}

private Object resolveVariable(Object key) {
return getFacesContext().getApplication().createValueBinding("#{" + key + "}").getValue(getFacesContext());
}

@Override
public Set entrySet() {
return new HashSet();
}
}

@Override
public Object saveState(FacesContext context) {
Object values[] = new Object[2];
values[0] = super.saveState(context);
values[1] = expString;
return ((Object) (values));
}

@Override
public void restoreState(FacesContext context, Object state) {
Object values[] = (Object[]) state;
super.restoreState(context, values[0]);
expString = (String) values[1];
}

}
What I did is add expString property and give it the power of Ognl expression. In the end we are able write this;
<injsf:selectItems expString="cityService.getCities(someCity)"
var="val" itemLabel="#{val.name}" itemValue="#{val.this}"
/>

Smart JSF DataTable Columns

One of the common  and simple requirements of enterprise projects is that stylising your columns based on the data it contains like if the column is displaying a date it should be centered, if its a number it should be aligned right. The following will show you how you can make a smart enough datatable which knows what type needs what style.
I did this on the richfaces datatable but same logic could be used with other datatables.
1. Define the renderer
Since we are using rich faces we need to override the default renderer it comes with:
    <renderer>
<component-family>org.richfaces.Column</component-family>
<renderer-type>
org.richfaces.renderkit.CellRenderer
</renderer-type>
<renderer-class>
org.mca.example.web.renderkit.html.CellAutoAlignedRenderer
</renderer-class>
</renderer>
render-class tag is now CellAutoAlignedRenderer which we will implement.
2. Define the Renderer
The default rich faces renderer is org.richfaces.renderkit.CellRenderer.
We could achive the desired effect by simply overriding the
public String styleClass(FacesContext context, UIComponent component)
method.
import org.richfaces.renderkit.CellRenderer;

public class CellAutoAlignedRenderer extends CellRenderer {

@Override
public String styleClass(FacesContext context, UIComponent component) {
ValueExpression styleExpression = component.getValueExpression("styleClass");
if (styleExpression == null) {
Object value = getValueOfTheOnlyChild(context, component);
if (value instanceof Number) {
return super.styleClass(context, component) + " " + getNumberColumnStyle();
}
else if (value instanceof Date) {
return super.styleClass(context, component) + " " + getDateColumnStyle();
}
}
return super.styleClass(context, component);
}

public String getDateColumnStyle() {
return "dateColumn";
}

public String getNumberColumnStyle() {
return "numberColumn";
}

private Object getValueOfTheOnlyChild(FacesContext context, UIComponent component) {
if (component.getChildCount() == 1) {
UIComponent child = component.getChildren().get(0);
if (child instanceof ValueHolder) {
ValueHolder aValue = (ValueHolder) child;
return aValue.getValue();
}
}
return null;
}

}

"getValueOfTheOnlyChild" method gets the data from the column to determine the data type. "if (value instanceof Number) {" part does determines the style.
"copy paste"