Wednesday, January 21, 2009

Pass action as Facelets-Parameter

There is a problem to pass an action as a Facelet-Parameter to a Fragment via ui:include an ui:param.
With the J4Fry-Action-Wrapper (http://www.j4fry.org/jsfErrorhandling.shtml) as a part of the J4Fry-JSF-Components (http://www.j4fry.org/jsfComponents.shtml) you've got the possibility to pass the action (e.g. for a h:commandButton) to a Facelets-Fragment.

Example
Main-Page

...
<ui:include src="Fragments/myFragment.xhtml">
<ui:param name="myAction" value="myBean.doSomething" />
</ui:include>
...

Fragment

<h:commandButton value="Execute doSomething" action="#{action[myAction].trigger}" />

To use that solution you have to download the J4Fry-JSF-Components (with dependencies described here: http://www.j4fry.org/jsfComponents.shtml) and place the JAR-File into your lib-directory from the webapplication. Thats it!

Friday, January 16, 2009

JSF VariableResolver & PropertyResolver

Resolving
Mit Hilfe des VariableResolvers und des PropertyResolvers löst JSF die EL-Expressions auf.
Der VariableResolver ist zuständig für den linken Teil der Expression. Für den restlichen rechten Teil ist der PropertyResolver zuständig.

Beispiel:
Bean Person:

public class PersonBean implements java.io.Serializable {
private Address address;
...
}

Klasse Address

public class Address implements java.io.Serializable {
private City city;
private String street;
private String zipCode;
...
}

Klasse City

public class City implements java.io.Serializable {
private String name;
...
}

JSF-Tag

<inputField value="#{personBean.address.city.name}" />

Der VariableResolver löst "personBean" auf.
Der PropertyResolver löst in Teilschritten zuerst "address" und anschließend "city" auf um zum Schluß auf die Property "name" der Klasse City zuzugreifen.

Implementierung eigener Variable- und PropertyResolver
Schritt 1
Anlegen der Klassen CustomVariableResolver und CustomPropertyResolver
Klasse CustomVariableResolver

package org.j4fry.jsf;
public class CustomVariableResolver extends VariableResolver {
private Logger log = Logger.getLogger(CustomVariableResolver.class);

// Ursprünglicher VariableResolver
private VariableResolver variableResolver;

public CustomVariableResolver(VariableResolver variableResolver) {
this.variableResolver = variableResolver;
}

@Override
public Object resolveVariable(FacesContext arg0, String arg1)
throws EvaluationException {
log.info("resolve: " + arg1);
// Delegation an ursprünglichen VariableResolver
return variableResolver.resolveVariable(arg0, arg1);
}
}

Klasse CustomPropertyResolver

package org.j4fry.jsf;
public class CustomPropertyResolver extends PropertyResolver {
private Logger log = Logger.getLogger(CustomPropertyResolver.class);

// Ursprünglicher PropertyResolver
private PropertyResolver propertyResolver;

public CustomPropertyResolver(PropertyResolver propertyResolver) {
this.propertyResolver = propertyResolver;
}

@Override
public Object getValue(Object fromObject, Object property)
throws EvaluationException, PropertyNotFoundException {
log.debug("getValue: fromObject[" + fromObject + "] property[" + property + "]");
// Delegation an ursprünglichen PropertyResolver
return propertyResolver.getValue(fromObject, property);
}

@Override
public void setValue(Object toObject, Object property, Object value)
throws EvaluationException, PropertyNotFoundException {
log.debug("setValue: toObject[" + toObject + "] property[" + property + "] value[" + value + "]");
// Delegation an ursprünglichen PropertyResolver
propertyResolver.setValue(toObject, property, value);
}

// Bei den restlichen Methoden wird einfach an den PropertyResolver delegiert

@Override
public void setValue(Object arg0, int arg1, Object arg2)
throws EvaluationException, PropertyNotFoundException {
propertyResolver.setValue(arg0, arg1, arg2);
}

@Override
public Class getType(Object arg0, int arg1) throws EvaluationException,
PropertyNotFoundException {
return propertyResolver.getType(arg0, arg1);
}

@Override
public Class getType(Object arg0, Object arg1) throws EvaluationException,
PropertyNotFoundException {
return propertyResolver.getType(arg0, arg1);
}

@Override
public Object getValue(Object arg0, int arg1) throws EvaluationException,
PropertyNotFoundException {
return propertyResolver.getValue(arg0, arg1);
}

@Override
public boolean isReadOnly(Object arg0, int arg1)
throws EvaluationException, PropertyNotFoundException {
return propertyResolver.isReadOnly(arg0, arg1);
}

@Override
public boolean isReadOnly(Object arg0, Object arg1)
throws EvaluationException, PropertyNotFoundException {
return propertyResolver.isReadOnly(arg0, arg1);
}

}

Die Klassen werden jeweils von den JSF-eigenen Resolvern abgeleitet. Zudem bekommt jeder CustomResolver einen Konstruktor der den ursprünglichen Resolver übergeben bekommt. Das ist wichtig um in den Methoden ggf. die Verarbeitung an diesen Resolver zu delegieren.

Schritt 2
CustomResolver in der faces-config.xml bekannt machen

<application>
<variable-resolver>
org.j4fry.jsf.CustomVariableResolver
</variable-resolver>
<property-resolver>
org.j4fry.jsf.CustomPropertyResolver
</property-resolver>
</application>

Interpretierung der Log-Ausgaben
Als Beispiel dient die o.g. EL-Expression #{personBean.address.city.name}

Lesender Zugriff
1. Auflösen von personBean durch VariableResolver
Logausgabe: resolve: personBean
2. Auflösen von address durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.beans.PersonBean@1f68572] property[address]
3. Auflösen von city durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.model.Address@1b335b7] property[city]
4. Auflösen von name durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.model.City@15c018] property[name]

Schreibender Zugriff
1. Auflösen von personBean durch VariableResolver
Logausgabe: resolve: personBean
2. Auflösen von address durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.beans.PersonBean@1f68572] property[address]
3. Auflösen von city durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.model.Address@1b335b7] property[city]
4. Setzen von name durch PropertyResolver
Logausgabe: setValue: toObject[org.j4fry.model.City@15c018] property[name] value[Munich]

Thursday, January 15, 2009

HttpURLConnection connection pool

Lately i had to set up a server to server HTTP connection with up to 200 parallel open connections. After some fiddling I succeeded with a nice and small sized URLConnection solution. It' identical for HttpURLConnection and HttpsURLConnection (with SSL). At first, you need to know that URLConnection's design requires a new URLConnection instance for every request you want to make. Cast the URLConnection to HttpURLConnection to gain access to the HTTP specific properties like requestMethod and connectionTimeout:

URL url = new URL("HTTPS", server, port, serverPath);
huc = (HttpURLConnection) url.openConnection();

Now you need some configuration. These are the properties I needed (using org.apache.commons.util.Base64):

huc.setDoOutput(true);
huc.setReadTimeout(socketTimeout);
huc.setConnectTimeout(connectionTimeout);
huc.setRequestMethod("POST");
authorizationString = "Basic " + new String(Base64.encode(username + ":" +password)).getBytes("ISO-8859-1")), "ISO-8859-1");
huc.setRequestProperty ("Authorization", authorizationString);
os = huc.getOutputStream();

Write your request (it goes to the buffer):

os.write(request);
os = huc.getOutputStream();

When you call getInputStream() your request is issued to the server and you get the response stream for further processing. You need to close the InputStream to free the underlying Socket for reuse. It's internally pooled:

try {
is = huc.getInputStream();
response = readResponse(is, huc.getContentLength());
} finally {
is.close();
}

private String readResponse(InputStream is, int length) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = 0;
int read = 0;
while (read < length) {
b = is.read();
baos.write(b);
}
return baos.toString("ISO-8859-1");
}

Configure your connection pool with Java system properties:

-Dhttp.maxConnections=200
-Dsun.net.http.errorstream.enableBuffering=true

Monday, January 12, 2009

Upgrading from MyFaces 1.1.5 to JSF 1.2 RI

When upgrading the example project I encountered 7 issues:
  • Using the same tag attribute for a JSF tag twice was silently ignored with 1.1.5 and now throws an exception with 1.2
  • Using less columnClasses than columns in a panelGrid rendered the remaining columns without CSS class with 1.1.5 and now repeats the columnClasses for the remaining columns with 1.2
  • MyFaces 1.1.5 rendered either a name or and id attribute for each tag, so scripts could always identify them. 1.2 RI renders commandLinks with neither name nor id, imposing minor scripting changes
  • MyFaces 1.1.5 updated the model with null, when a radio button not clicked and the bean property is a String, the 1.2 RI updates with ""
  • 1.2 RI writes an exception stacktrace to the log when a phase listener throws a bug. MyFaces 1.1.5 was silently ignoring them
  • When a bean implemented Map and a bean property was set through DI in faces-config, MyFaces 1.1.5 called Map.put(). 1.2 RI doesn't, so implementing a separate setter for upgrading was necessary
  • When a property of a bean in session scope is set through DI (faces-config) and the property is a bean in request scope this would silently upgrade the ssecond beans life to session scope. MyFaces 1.1.5 would ignore this while 1.2 RI throws an exception
Thanks to Ganesh for identifying the differences.

Fehlendes Bundle com.sun.el.Messages

Auf Grund von einem fehlenden Bundle kann es bei der Nutzung von Faclets zu folgender java.util.MissingResourceException kommen:

java.util.MissingResourceException: Can't find bundle for base name com.sun.el.Messages, locale de_DE
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:836)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:805)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:549)
at com.sun.el.util.MessageFactory.(Unknown Source)
at com.sun.el.parser.AstValue.getTarget(Unknown Source)
at com.sun.el.parser.AstValue.getType(Unknown Source)
at com.sun.el.ValueExpressionImpl.getType(Unknown Source)
at com.sun.facelets.el.TagValueExpression.getType(TagValueExpression.java:60)
at com.sun.facelets.el.LegacyValueBinding.getType(LegacyValueBinding.java:94)

Ein Grund für die Exception könnte ein NullPointer innerhalb einer EL-Expression sein die JSF bzw. Facelets versucht aufzulösen.

Um die ursprüngliche (etwas aussagekräftigere ;-)) Exception zu sehen könnt ihr einfach folgendes JAR-File in eure Webapplication einbinden: http://j4fry.org/resources/el-messages.jar.
Enthalten sind die englischen und deutschen Property-Files.

Saturday, January 10, 2009

Facelets Template-Parameter

Es gibt mehrere Möglichkeiten Facelets-Templates zu parameterisieren.
  1. Über ui:insert und ui:define
  2. Über EL und ui:param
Facelets Template:

<html>
<head>
<link rel="stylesheet" type="text/css" href="#{myStylesheet}" media="screen, projection" />
</head>
<body>
<ui:insert name="myContent">No content supplied.</ui:insert>
</body>
</html>

Facelets Template-Client:

<ui:composition template="MyTemplate.xhtml">
<ui:param name="myStylesheet" value="http://my.host.com/css/style.css" />
<ui:define name="content">
<h1>My Content</h1>
</ui:define>
</ui:composition>


Über ui:insert ist es möglich Blockplatzhalter zu definieren.
Mit ui:param können auch Inline-Passagen definiert werden.

Die Frage wurde in unserem XING JSF-Developers-Forum (https://www.xing.com/net/jsf) gestellt.

Welcome! / Willkommen!

Welcome to the J4Fry Blog.
In this blog the J4Fry members have got the opportunity to post sth about Java especially about Java-Web-Development.
We're looking foward to read some comments to our blog posts.

Have fun!
So long, cheerz Alex
____________________________________

Willkommen im J4Fry Blog.
In diesem werden wir J4Fry Members hin und wieder etwas über Java speziell über Java-Webentwicklung posten.
Wir freuen uns eure Kommentare zu unseren Posts zu lesen.

Viel Spaß!
mfg Alex
____________________________________

J4Fry Website: http://www.j4fry.org/
J4Fry Team: http://www.j4fry.org/team.shtml
Webprofil Alexander Bell: http://www.j4fry.org/alexanderbell.shtml
Webprofil Ganesh Jung: http://www.gpsjava.de/