Tuesday, December 04, 2007

Tracing MyFaces with AspectJ, Tomcat and Maven 2

When I started to learn Spring, I faced with AOP. It's new and interesting for me. It's really not easy to understand a new concept and to do some refactoring of my own brain while the most of documentation and books are in English (not my native language). There is not (almost) problem with English itself, but understanding a new concept is hard.

AOP is powerfull. Really. Relocating cross-cutting concerns to aspects is nice idea. Since I can intercept the methods executions of my own classes, I became very interested in how to trace any third-party libraries. In fact it's pretty cool to be able to see internals of MyFaces, Hibernate or whatever in action to get a deeper understanding what is going on behind the scene...

I found a wiki page about tracing MyFaces with AspectJ. Many thanks to Cagatay Civici for this article, really helpful. It is a starting point for my experiments. I'm using aspect source code from this article.

My environment is the following : JDK 1.5, Maven 2, Tomcat 5, MyFaces, AspectJ 1.5.


Cagatay restrict his article to
statically compiled AspectJ. But as you'll see later, runtime weaving on JDK 1.5 is not so hard to implement.

The first issue I came across is how to compile AspectJ aspect with Maven 2. Bingo ! There is a Maven plugin. So, placing some Trace.aj at src\main\java will work.

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<outxml>true</outxml>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
Please note, that outxml=true. It's important since it is flag to "Generate aop.xml file for load-time weaving with default name.(/META-INF/aop.xml)".

The final part of config is agent setup for Tomcat. According to docs it's should be started with one additional JVM argument - javaagent.

Now we have tracing aspect, can compile it with Maven and know how to start Tomcat with right option. As for me, I like Cargo plugin. It is useful for integration testing for example, but in this case it is just a very nice Maven 2 plugin to put all together. With this config we can automatically download tomcat 5 distribution, unpack it, run tomcat with our -javaagent option
and deploy war. A lot of work, huh ? :)

<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<container>
<containerId>tomcat5x</containerId>
<zipUrlInstaller>
<url>
http://www.eu.apache.org/dist
/tomcat/tomcat-5/v5.5.25/bin/apache-tomcat-5.5.25.zip
</url>
<installDir>
${java.io.tmpdir}/donloadedByCargo
</installDir>
</zipUrlInstaller>
<output>
${project.build.directory}
/tomcat5x.logs/container.log
</output>
<append>false</append>
<log>
${project.build.directory}
/tomcat5x.logs/cargo.log
</log>
</container>
<configuration>
<type>standalone</type>
<home>
${project.build.directory}/tomcat5x
</home>
<properties>
<cargo.servlet.port>
8080
</cargo.servlet.port>
<cargo.jvmargs>
-javaagent:"${user.home}\.m2\repository
\aspectj\aspectjweaver\1.5.3\aspectjweaver-1.5.3.jar"
</cargo.jvmargs>
<cargo.logging>high</cargo.logging>
</properties>
<deployables>
<deployable>
<groupId>com.mycoolcompany.fun</groupId>
<artifactId>MyFacesAspectJ</artifactId>
<type>war</type>
<properties>
<context>MyFacesAspectJ</context>
</properties>
</deployable>
</deployables>
</configuration>
</configuration>
</plugin>
As you can see, cargo.jvmargs element contains a path to aspectjweaver-1.5.3.jar library, in my case it is in my local repository already. After all to see it in action just type "mvn clean package cargo:start" and you are ready to go !

Trace will be available in the file "C:\trace.out" as defined in aspect source code. Exploring it's contents is another story, I guess.

Wednesday, November 14, 2007

JSF : MyFaces and Sun RI profiles for Maven 2

I've used MyFaces as implementation of JSF 1.1 specification. Why ? The main reason is great community and great support for Maven 2 - maven-archetype-myfaces for example, + Tomahawk.

And now, I'm interested in what is the difference between the two ? Any comments appreciated.

Maven 2 is my friend here, since I can use profiles - one for JSF RI, another one for MyFaces. I guess it could be useful for someone else, so here is the code :

<profiles>
<profile>
<id>jsfri</id>
<activation>
<property>
<name>jsf</name>
<value>ri</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>1.1_02</version>
<exclusions>
<exclusion>
<groupId>java.servlet.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>1.1_02</version>
<exclusions>
<exclusion>
<groupId>java.servlet.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>java.net</id>
<name>java.net Maven 1 Repository</name>
<url>
https://maven-repository.dev.java.net/nonav/repository
</
url>
<layout>legacy</layout>
</repository>
</repositories>
</profile>
<profile>
<id>myfaces</id>
<activation>
<property>
<name>jsf</name>
<value>myfaces</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-api</artifactId>
<version>1.1.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version>1.1.6-SNAPSHOT</version>
</dependency>
<!--
<dependency>
<groupId>org.apache.myfaces.tomahawk</groupId>
<artifactId>tomahawk</artifactId>
<version>1.1.6-SNAPSHOT</version>
</dependency>
-->
</dependencies>
<repositories>
<repository>
<releases>
<enabled>false</enabled>
</releases>
<snapshots/>
<id>apache-maven-snapshots</id>
<url>
http://people.apache.org/repo/m2-snapshot-repository
</url>
</repository>
</repositories>
</profile>
</profiles>
To switch between profiles use "mvn -Djsf=ri" or "mvn -Djsf=myfaces".

Monday, November 12, 2007

JSF : hacking redirect and request scope managed bean

Strting with MyFaces project and Maven 2 is very easy :

mvn archetype:create
-DarchetypeGroupId=org.apache.myfaces.maven
-DarchetypeArtifactId=maven-archetype-myfaces
-DarchetypeVersion=1.0-SNAPSHOT
-DgroupId=com.mycoolcompany.web
-DartifactId=jsfRedirect

When project is created, you can run web app (jetty is used here) :

mvn -U -PjettyConfig jetty:run
Now we have a skeleton of application. Let's try to understand how to deal with redirect.

Let's check what happens when form is submitted. Current config is
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/page2.jsp</to-view-id>
</navigation-case>

First request :

GET /jsfRedirect/helloWorld.jsf HTTP/1.1
Accept: */*
Accept-Language: ru
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322; .NET CLR 2.0.40903)
Host: localhost:8080
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=zm2pcktnv9vl

Response :

HTTP/1.1 200 OK
Content-Type: text/html; charset=ISO-8859-5
Content-Language: ru
Content-Length: 7742
Server: Jetty(6.1.6rc1)
There is nothing special here.

Form submit:

POST /jsfRedirect/helloWorld.jsf HTTP/1.1
Accept: */*
Referer: http://localhost:8080/jsfRedirect/helloWorld.jsf
Accept-Language: ru
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322; .NET CLR 2.0.40903)
Host: localhost:8080
Content-Length: 3892
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=zm2pcktnv9vl
Posted data is the following:

form:input1 testString
form:button1 press me
autoScroll 0,0
form_SUBMIT 1
form:_idcl
form:_link_hidden_
javax.faces.ViewState ___very__loong__

___very__loong__ is really very long string and I don’t want to post it, you can check it by yourself if you want.

As we can see, our submitted value were sent as form:input1 POST parameter. Please notice that at helloWorld.jsp we have assigned id="form" to h:form and id="input1" to h:inputText.

I guess org.apache.myfaces.AUTO_SCROLL is responsible for autoScroll param value.
To see it in action take a look here.

Responce is:

HTTP/1.1 200 OK
Content-Language: ru
Content-Type: text/html; charset=ISO-8859-5
Content-Length: 6781
Server: Jetty(6.1.6rc1)


....

And now let’s see what will change when redirect is used.

<navigation-case>
    <from-outcome>success</from-outcome>
<to-view-id>/page2.jsp</to-view-id>
<redirect/>
</navigation-case>

In this case form submission looks the same as before, but response is different, as expected :

HTTP/1.1 302 Found
Location: http://localhost:8080/jsfRedirect/page2.jsf
Content-Length: 0
Server: Jetty(6.1.6rc1)

"Location" http header means redirect for browser i.e. GET request. In this case the value of request scoped managed bean will be lost between requests (POST ant then GET), since HTTP is a stateless protocol.

How to avoid data loss ? Ohh.. it is a long story. To save data between requests I need to save managed bean in session. I can get access to http session object using faces context:


public class HelloWorldBacking {
....
public String sendSessionHack(){
FacesContext facesContext =
FacesContext.getCurrentInstance();
Map session =
facesContext.getExternalContext().getSessionMap();
session.put("myBackingBean",this);
return "successSessionHack";
}
}
Ok, but how to get this value back in view ? It is a long story...

Maybe "there is no one way to do it", but I see only one - PhaseListener.
If you know any other, please give me a sign! Code listed below will act at RESTORE_VIEW phase and then check if there is a session param with name myBackingBean, and finally assign
this value to managed bean via programmatically operations with JSF EL.

package org.apache.myfaces.blank.listener;

import javax.faces.event.PhaseListener;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;

import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.el.ValueBinding;

import org.apache.myfaces.blank.HelloWorldBacking;

import java.util.Map;

public class MyPhaseListener implements PhaseListener
{
public PhaseId getPhaseId()
{
return PhaseId.RESTORE_VIEW;
}

public void beforePhase(PhaseEvent e)
{
FacesContext facesContext =
FacesContext.getCurrentInstance();
Map session =
facesContext.getExternalContext().getSessionMap();
HelloWorldBacking backingBean =
(HelloWorldBacking)session.get("myBackingBean");

if(backingBean!=null)
{
ApplicationFactory appFactory =
(ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
Application application =
appFactory.getApplication();
ValueBinding valueBinding =
application.createValueBinding("#{helloWorldBacking}");
valueBinding.setValue(facesContext,backingBean);
session.remove("myBackingBean");
}
}

public void afterPhase(PhaseEvent e)
{
// don't care
}
}
Not so trivial, isn't it? :)
BTW, to enable custom phase listener you need to add this snip of code in faces config file, examples-config.xml in our case :

<lifecycle>
<phase-listener>
org.apache.myfaces.blank.listener.MyPhaseListener
</phase-listener>
</lifecycle>

Thursday, November 01, 2007

JSF : Redirect to URL with param from navigation-case

I'm evaluating JSF now. I have to admit that some of JSF ideas are pretty nice, but there are many non-intuitive things which make life hard. From another point of view, it is framework, with it's own rules of the game.

From my little experience I could say that JSF doesn't like the way of passing params via GET. Of course it is possible, but I couldn't say it is trivial and easy as in Struts for example. So, here is some technical stuff.

I need to to redirect from navigation-case to URL with param which is a property of a managed bean. It looks like this :

<navigation-rule>
<from-view-id>/add.jsp</from-view-id>
<navigation-case>
<from-outcome>added</from-outcome>
<to-view-id>/view.jsf?myParam=#{myManagedBean.id}</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
I've tried to figure out how to do it, but had no success here. In fact I found solution, but it's more something like a hack than solution.
So, I've asked MyFaces mailing list. Many thanks to all the people who answered me.

To keep the story short, here is solution. Custom view and navigation handlers should be added to use managed bean property as url param in navigation-case.

I think to myself... should I use core JSF or switch to Apache Orchestra, or JBoss Seam to make development with JSF less painful ? JSF is still young, 1.2 is the latest version of specification and frameworks that use JSF has many additional functionality. Who knows ?

Friday, September 21, 2007

static final String[] is not final ?

Lets take final variable and try to assign new value to it. Well , we 'll have no luck here - "cannot assign a value to final variable myVar" yet at compilation stage. But having a deal with final arrays is something different. Here is an example :

class FinalArray
{
public static final String[] array = {"a", "b","c"};
public static void main(String args[])
{
array[0] = "aaa";
System.out.println(array[0]);
}
}
Output will be "aaa". It is still not possible to do something like

String[] some_array = {"aaa", "bbb","ccc"};
array = some_array;

but possible per-element assigning new values to final array elements:
class FinalArray
{
public static final String[] array = {"a", "b","c"};
public static void main(String args[])
{
String[] some_array = {"aaa", "bbb","ccc"};
for(int i=0;i<length;i++)
{
array[i] = some_array[i];
}

for(String element: array)
{
System.out.println(element);
}
}
}
So, it is final, you say ?

Thursday, August 30, 2007

User driven startups community

Startups is everywhere. YouTube, MySpace, Skype and a lot of other very famous names. The number of new startups increase quickly, but only 1 of maybe hundreds or even thousands will be on top. But which of them ? Nobody knows. Friendly speaking I'm still don't understand why MySpace is so popular. One thing which I get form MySpace on regular basis is a spam - friend requests. Something like "Take a look at my nude pics at this site. MySpace don't allow to post it here." Damn !

Closer to name of post :) I've found this site quite interesting - http://www.killerstartups.com

KillerStartups.com is a user driven internet startups community. Entrepreneurs, investors, and bloggers are staying informed on up-and-coming internet startups using our blog platform, where internet entrepreneurs submit their startup to see what others think about it.

Nice idea.

I have some startup ideas but no prototype yet. Even I'll have a prototype, to find a venture capitalist or some kind of investor can be impossible at the place where i leave - Sumy, Ukraine. So, everything I can do for now is to read what other people are doing.

BTW, what about startups in Java world ? I mean something done in Java ? Only PHP+MySQL ? :) Hmm.. wait a minute... JSESSIONID cookie at FeedBurner. Maybe I'm wrong but JSESSIONID is part of servlet spec and web applications should not mess with it. Do you know any others ?

Monday, August 27, 2007

Maven: The Definitive Guide (1.0 Alpha 2)

It seems to be that this is very nice book about Maven 2. Maybe it can help me to understand Maven 2 concepts even better. I'd found link to this book at this blog. I'm agree with author, Maven 2 is a really painful sometimes. Ant and Maven concepts are very different and a lot of time is needed to switch between them.

Friday, August 10, 2007

Brainbench Java exam - passed

Yesterday I have passed Brainbench exam, Java 2 Fundamentals. Exam details:

Test: Java 2 Fundamentals
Date: 09-Aug-2007
Score: 3.88
Weights: 100% Java 2 Fundamentals
Elapsed time: 68 min 39 sec
Percentile:Scored higher than 84% of previous examinees

There were 40 questions, 3 minute per question. My transcript is here.

Friendly speaking, I'm not satisfied with my score. But I've got it without any preparation, just for fun. It is my first certification, by the way. I'm going to pass another exam at brainbench on J2EE 1.4. It is free now. Why not ?

I have no idea about authority of Brainbench certification. If you have any information, comments are highly welcome.

Thursday, July 26, 2007

Declarative transaction management with Spring 2 and AspectJ

I'm playing with Hibernate, Spring 2 and AOP. Configuring this stuff were some kind of challenge for me. But now it woks. I faced wery interesting exeption during configuration. Since I'm using Maven 2, Spring + Hibernate dependency looks like this:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-hibernate3</artifactId>
<version>2.0.5</version>
</dependency>

Exception is looks like this :

org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:
Line 63 in XML document from class path resource [applicationContext.xml] is invalid;
nested exception is org.xml.sax.SAXParseException: cvc-complex-type.2.4.c:
The matching wildcard is strict, but no declaration can be found for element 'aop:config'.
Caused by: org.xml.sax.SAXParseException: cvc-complex-type.2.4.c:
The matching wildcard is strict, but no declaration can be found for element 'aop:config'.
Strange ! I have appropriate configuration for namespaces at my applicationContext.xml :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
Config :
<aop:config>
<aop:advisor id="serviceTxAdvisor"
pointcut="execution(public *
com.company.service.impl.ServiceImpl.*(..))
"
advice-ref="txAdviceForService" />
</aop:config>

<tx:advice id="txAdviceForService"
transaction-manager
="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>

Solution suggested at Spring forum doesn't work for me. I had no success with Xerces. So, I decided to digg a little more. As a result I've found two missing dependencies that should make me happy:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>2.0.5</version>
</dependency>

Weird exception vanished. I'm very happy now.

BTW, even you use spring dependency, you should add spring-aspects dependency as well to be able to use aop:config.

Thursday, July 19, 2007

Java developers for US Army

It seems to be that US army really using Java. At least they are recruting Java programmers. Take a look here.

Minimum requirements:

* Java, J2EE - at least 2-3 years
* Struts framework - at least 1 year
* Oracle, Sybase, DB2 or any other major database - at least 2 years
* XML - 1-2 years
* UML - at least general understanding
* Documentum - nice to have, no mandatory


Well, Struts +1 !

Military visitors ...

I haven't many visitors at my blog. But all of them are very interesting for me. Nevertheless, there are some that I couldn't expect to see. They are military. The most exciting is Pentagon. Here is screen shot of Google Analytics :

After some digging I have found others and here is complete list:

  1. usaisc-cecom : "The mission of the US Army Communications-Electronics Command (CECOM) is to develop, acquire and sustain superior information technologies and integrated systems, enabling battlespace dominance for America's warfighters."
  2. The Pentagon
  3. Office of the Chief of Naval Research
  4. Headquarters, USAAISC
I'm for peace :) Anyway, thanks for visit. It's still unclear for me what they attempt to find here. I'm not sure, but as far as I know, open source software is used in US army. Who knows :)

Tuesday, July 10, 2007

Build EJB3 with jBoss and Maven 2 - better solution

I'm working on project which is not in touch with EJB3, but Maven 2 is is used intensively. I remember my post about building EJB3 with jBoss and Maven 2. In fact that solution works, but I'm not satisfied with it. Since I'm became a little bit stronger in Maven 2 I decided to improve that solution.

So, the task is to build EJB3 entity and EJB3 session bean with Maven 2 and jBoss dependent jars. First, we setting up non another repository where Maven can find jboss jars :

<repositories>
<repository>
<id>jboss-maven2</id>
<url>http://repository.jboss.com/maven2</url>
</repository>
</repositories>

A little bit of magic should be added :)
<parent>                             
<groupId>jboss</groupId>
<artifactId>jboss-parent</artifactId>
<version>2</version>
</parent>

And finally, dependencies. JPA :
<dependency>                                  
<groupId>jboss</groupId>
<artifactId>jboss-persistence-api</artifactId>
<version>3.0.0-SNAPSHOT</version>
</dependency>

EJB3 :
<dependency>                          
<groupId>jboss</groupId>
<artifactId>jboss-ejb-api</artifactId>
<version>4.2.0.GA</version>
</dependency>

That is all ! Complete pom.xml looks like this :
<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>com.mycompany.beans</groupId>
<artifactId>SimpleEJB3</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SimpleEJB3</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>jboss</groupId>
<artifactId>jboss-parent</artifactId>
<version>2</version>
</parent>
<repositories>
<repository>
<id>jboss-maven2</id>
<url>http://repository.jboss.com/maven2</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>jboss</groupId>
<artifactId>jboss-persistence-api</artifactId>
<version>3.0.0-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>jboss</groupId>
<artifactId>jboss-ejb-api</artifactId>
<version>4.2.0.GA</version>
</dependency>
</dependencies>

</project>

If there is something wrong with this solution, or maybe you have some improvement, give me a sign.

UPD

Complete example with source code is here : http://code.google.com/p/ostas-blog-src/