Showing posts with label seam. Show all posts
Showing posts with label seam. Show all posts

When using seam framework and ajax4jsf, there is a bug when trying to re render an area using aj4:poll. Here is my code:

<h:outputText id="currentDateTime" value="#{currentDatetime}" styleClass="dateTime">
<s:convertDateTime pattern="MMMM dd, yyyy - hh:mm:ss a"/>
</h:outputText>

<h:form>
<a4j:poll interval="1000" reRender="currentDateTime" eventsQueue="timerQueue"></a4j:poll>
</h:form>


The solution is not yet clear as some say they need to tweak the concurrent-request-timeout in components.xml and others say that you need to simply make sure that the ajax request is not aschronous by using the eventsQueue property. Although the idea worked for me, some knowledgeable people say that tweaking those things depends on app by app.

Here are some useful links:

http://sfwk.org/Community/ConversationEndedTimedOutOrWasProcessingAnotherRequest
http://docs.jboss.com/seam/2.0.1.GA/reference/en/html/conversations.html#d0e5208

Ajax4JSF is a library that easily adds ajax functionality to existing jsf components. As oppose to Icefaces which is a set of jsf components that already have built in ajax functionalities, Ajax4JSF offers a much flexible way to add ajax functionalities to jsf components. It offers refreshing of display without the need to refresh the entire form. On the downside, Ajax4JSF is harder to use for very complex jsf components.

Using Ajax4JSF in seam 2.0 is easy. Just remove the line in your faces-config.xml:

<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
and add the following code on your web.xml just aboe the seam listener definition:
<context-param>
<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
<param-value>com.sun.facelets.FaceletViewHandler</param-value>
</context-param>
You will also need to define the following on you xml schema:
xmlns:a4j="https://ajax4jsf.dev.java.net/ajax
The following code is an example of a simple clock functionality that updates its time by polling / reRendering the component. I didnt use a backing bean on this example:

<h:outputText id="currentDateTime" value="#{currentDatetime}" styleClass="dateTime">
<s:convertDateTime pattern="MMMM dd, yyyy - hh:mm:ss a"/>
</h:outputText>

<h:form>
<a4j:poll interval="1000" reRender="currentDateTime"></a4j:poll>
</h:form>

When using JBoss Tools 2.0.0 GA, the generated test project doesn't allow me to provide a custom persistence.xml. I'm not sure if this is a bug or the feature is not yet included on the given version. The persistence.xml being used when the application is deployed and when running test is the same. So what I did is update the hbm2ddl.auto property of the projectname-ejb/META-INF/persistence.xml to create/create-drop when running test and then when deploying the application, i switch it back to update.

Right now I don't want to waste my time just figuring out how to run test that uses a different persistence context. I have already spent 2 days just doing that but nothing happened. Its either I wait for a major JBoss Tools update or I'll try solving the problem again once I get some free time.

I've written a pom.xml that will emanage the dependencies using maven. The following is my pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:artifact="antlib:org.apache.maven.artifact.ant"
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>com.reyjexter</groupId>
<artifactId>exacto</artifactId>
<name>exacto</name>
<version>1.0</version>
<packaging>war</packaging>

<repositories>
<repository>
<id>jboss</id>
<name>The JBoss maven repo</name>
<url>http://repository.jboss.com/maven2/</url>
</repository>
</repositories>

<parent>
<groupId>org.jboss.seam</groupId>
<artifactId>root</artifactId>
<version>2.0.1.GA</version>
</parent>

<build>
<finalName>exacto</finalName>
<plugins>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<phase>generate-sources</phase>
<configuration>
<tasks>

<echo>***Deleting WEB-INF/lib dir</echo>
<delete>
<fileset dir="web/WEB-INF/lib" includes="**/*.jar"/>
</delete>

</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0</version>
<configuration>
<webappDirectory>/web</webappDirectory>
</configuration>
</plugin>

</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.jboss.seam</groupId>
<artifactId>jboss-seam</artifactId>
<exclusions>
<exclusion>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
</exclusion>
<exclusion>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.el</groupId>
<artifactId>jboss-el</artifactId>
</exclusion>
<exclusion>
<groupId>jboss</groupId>
<artifactId>javassist</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.jboss.seam</groupId>
<artifactId>jboss-seam-ui</artifactId>
</dependency>

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

<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>1.8</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.jboss.seam</groupId>
<artifactId>jboss-seam-debug</artifactId>
<version>2.0.1.GA</version>
</dependency>

<dependency>
<groupId>org.richfaces.framework</groupId>
<artifactId>richfaces-api</artifactId>
<version>3.1.3.GA</version>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.richfaces.framework</groupId>
<artifactId>richfaces-impl</artifactId>
<version>3.1.3.GA</version>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.faces</groupId>
<artifactId>jsf-impl</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</exclusion>
<exclusion>
<groupId>javax.faces</groupId>
<artifactId>jsf-api</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.richfaces.ui</groupId>
<artifactId>richfaces-ui</artifactId>
<version>3.1.3.GA</version>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.faces</groupId>
<artifactId>jsf-impl</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</exclusion>
<exclusion>
<groupId>javax.faces</groupId>
<artifactId>jsf-api</artifactId>
</exclusion>
</exclusions>
</dependency>

</dependencies>

</project>

The code simply removes the jar libraries from web/WEB-INF/lib and copies the maven dependencies to that folder.

I'll be posting a different configuration for ear and ejb jar in a couple of days

Joda time and Seam / EJB

To use joda time libraries in seam project, simply copy joda-time-1.5.jar to PROJECTNAME-ear project folder and add the following in your application.xml:

<module>
<java>joda-time-1.5.jar</java>
</module>


When restarting jboss app server, the library for some unknown reason is not copied to deploy directory and Exception saying that joda time library cannot be found. Just copy the jar for to
PROJECTNAME-ear.ear folder in jboss deploy dir (for exploded deployment only)

Using hibernate validation, we can decouple the validation rules and at the same time make it reusable for future projects. For example we want to validated if the username given already exist on the database and usually we just put our validation logics on the session bean or action (in struts). At the start of the project this looks ok but as the project progress and some new specification changes, new functionalities are added and some parts of your code gets refactored things get a bit messier.

Instead of simply dumping all the validation logic on the session bean we can create a custom hibernate validator which later can be used by annotating the getter of the entity property. Below is my code to validate if the username if it already exist on my database.

Username.java - The validator annotation definition

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ValidatorClass(UsernameValidator.class)
public @interface Username {
String message() default "Username already exists";
}


UserValidator.java - The validator class implementation

public class UsernameValidator implements Validator, Serializable{

private static final long serialVersionUID = -1458203631809206211L;

public void initialize(Username parameters) {
}

public boolean isValid(Object value) {
UserHome userHome = (UserHome) Component.getInstance("userHome");
User user = userHome.findUser((String)value);

// return true if no user with the given value was found
if(user == null) {
return true;
}

// return true if the user retrieved is equals to the current instance in home
if(user.getId() == userHome.getInstance().getId()) {
return true;
}

// return false if the username exist on our database
return false;
}

}
User.java - and finally, the entity class

public class User extends BaseEntity {

private static final long serialVersionUID = 6148649482941380604L;
private String username;

@Length(min=3, max=32, message="Username should be 3-32 characters")
@NotNull
@Username
public String getUsername() {
return username;
}
}
The validation code above simply tries to retrieve the user from database. If it returned null it means that no user with the given user name exist to it returns true (meaning the validation is successful). If a user with the given username is found, it checks if the user instance from userHome component is the same so that the validation will still be successful if we try to save it without modifying anything. Returning false will cause the validation process to return error message which can be later display by using in our xhtml.


References:

hibernate docs

hibernate validator source codes


Extending EntityQuery in seam 2.0.1 GA is not working properly. For some reason, the 'firstResult' is not injected by default and isNextExists() method always return false. The solution i found was to override both setFirstResult() and isNextExists() method. I manually injected the firstResult request context parameter, created an implementation of isNextExists() and everything seems to be working. Here is my EntityQuery subclass:

@Name("userList")
public class UserList extends EntityQuery {

private static final long serialVersionUID = 4676553441988735518L;

public UserList() {
setMaxResults(2);
}

@Override
public String getEjbql() {
return "select user from User user";
}

@RequestParameter("firstResult")
@Override
public void setFirstResult(Integer firstResult) {
if(firstResult==null) {
firstResult = 0;
}
super.setFirstResult(firstResult);
}

@Override
public boolean isNextExists() {
if(getFirstResult() + getMaxResults() < getResultCount()) {
return true;
}
return false;
}
}


And my xhtml code:


<s:link view="/userList.xhtml" value="Previous" rendered="#{userList.previousExists}">
<f:param value="#{userList.previousFirstResult}" name="firstResult" />
</s:link>

<s:link view="/userList.xhtml" value="Next" rendered="#{userList.nextExists}">
<f:param value="#{userList.nextFirstResult}" name="firstResult" />
</s:link>

I was trying my first integration test but just using the default generated test class and xml meta data by jboss tools, i get the following error:

ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Instantiated: name=DeploymentFilter state=Described
java.lang.IllegalStateException: Class not found: [Ljava.lang.String;
at org.jboss.metadata.spi.signature.Signature.stringsToClasses(Signature.java:174)

i tried the following things:

1. followed this http://wiki.jboss.org/wiki/Wiki.jsp?page=ClassNotFoundJava.lang.StringInJDK6
2. downloaded jboss embedded beta
3. upgraded to seam 2.1.0 AI

none of them worked for me.

lastly, i tried downloading seam 2.0.1 GA and installed jdk 1.5. i configured the test project's compiler compliance level to 5.0 instead of 6.0 (6.0 default for some reason. maybe because my default jdk is 1.6) and the result were so much better.

to remove the error message saying something like this:
Could not instantiate Seam component: authenticator
drools related libraries needs to be included since we are using the rule based engine and Identity class is part of it. just include the seam/lib/drools-core.jar, seam/lib/drools-compiler.jar and seam/lib/core.jar.

after copying the drools related libraries and executing the test, a different kind of error is thrown. this time an error saying that the "security.drl is missing" you will need to copy that file from seam/seam-gen/resource/security.drl and place it to projectname-test/bootstrap/deploy/ folder.

run it again and the test will be successful!

embedded jboss is needed when testing seam components or ejb's but based on the jboss seam integration testing documenation, the stable version have problems when using jdk 1.6. since there are compatability issues when testing using seam 2.0 GA on jdk 1.6, i think staying with 2.0.1GA and jdk 1.5 is better at the moment.

After creating a new project using JBoss Tools 2.0.0 GA, Seam 2.0.0 GA and tried deploying the application, I encountered this problem:

java.lang.RuntimeException: error while reading /WEB-INF/components.xml
at org.jboss.seam.init.Initialization.initComponentsFromXmlDocument(Initialization.java:136)
at org.jboss.seam.init.Initialization.create(Initialization.java:86)
at org.jboss.seam.servlet.SeamListener.contextInitialized(SeamListener.java:34)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3856)

and somewhere below the stack trace...


Caused by: java.lang.IllegalArgumentException: Exception setting property org.jboss.seam.core.init.jndiPattern on component org.jboss.seam.core.init. Expression @jndiPattern@ evaluated to null.
at org.jboss.seam.init.Initialization.installComponentFromXmlElement(Initialization.java:407)
at org.jboss.seam.init.Initialization.installComponentsFromXmlElements(Initialization.java:257)
at org.jboss.seam.init.Initialization.initComponentsFromXmlDocument(Initialization.java:132)
... 138 more


i think the problem here was when building the application. the value of @jndiPattern@ in components.properties should replace the same constant name defined in components.xml but for some reason, it did not.

my simple solution (although not very elegant) is to hardcode the value in components.xml. so instead of using @jndiPattern@ i copied its value from components.properties

Older Posts Home

Blogger Template by Blogcrowds