Appliweb

All dimensions of your web developments

Affichage des articles dans java

You often need to generate .bat and .sh files for your java project.

Using Maven, this can be a tricky task because, basically, you don’t know at all times what libraries and what versions are included.
As Maven « controls » the library dependencies for you, it’s impossible to add manually the classpath into the script files.

Here is a solution, where maven automatically generates the classpath for you. The solution comes (as often with Maven) from a plugin, the dependency plugin.

Basically, we will do the following:
– Generate the classpath for windows and unix in a file using the dependency plugin.
– Dynamically insert the classpath into batch files
– Assemble all the libraries in a single subdirectory referenced by the classpath.

poursuivre la lecture…

I’ve been trying Google app. engine in my spare time.

I maintain a small library (RER) and make an html designer tool for Java (Appliweb), so I tried to make it work under GAE.

I know GAE supports persistence with JPA, using the datanucleus library.

But only basic stuff is supported, and you can easily forget about the rest. For example, I knew that many to many relationships did not work, that inheritance is hard to make it eventually work (that’s why I added ValueObject supports in RER library), but many times I encounter strong limitations, and I think this last one will make me rethink on GAE supports:

Let me explain, I have the following classes and mapping.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Entity(name="Article")
@Table(name="ARTICLE")
public class ArticleImpl implements Article {
@Id
@GeneratedValue
protected Long id;

@Basic
@Column(length=3000)
protected String content;

@ManyToOne(optional=false)
protected Writer writer;

@ManyToOne(optional=false)
@Column(name="BLOG")
protected Blog blog;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Entity(name="Blog")
@Table(name="BLOG")
public class BlogImpl implements Blog
{

@Id
@GeneratedValue
protected Long id;

@Basic
@Column(length=256)
protected String rootUrl;

@ManyToOne(optional=false)
protected User owner;

@OneToMany(targetEntity=ArticleImpl.class)
protected Set<? extends Article> articles=new HashSet<ArticleImpl>();
}

See the OneToMany relationship between ArticleImpl and BlogImpl ? It’s quite standard isn’t it ?

But that fails completely in GAE, with the following error message:

1
2
3
javax.persistence.PersistenceException: Error in meta-data for net.appliweb.rera.test.jpa.model.ArticleImpl.id: Cannot have a java.lang.Long primary key and be a child object (owning field is net.appliweb.rera.test.jpa.model.BlogImpl.articles).

at org.datanucleus.jpa.NucleusJPAHelper.getJPAExceptionForNucleusException(NucleusJPAHelper.java:264)

To my point of view, it’s clearly not understandable why Long primary keys are not supported. I don’t want to switch to Integer, not because a blog can have more than 4 billions articles, but because the application can have millions of blogs with millions of articles (who knows ?), and I always put Long for the Id of an entity.

It seems ArticleImpl is considered a child of BlogImpl, and it cannot have it’s own life (and Long Id) outside of BlogImpl. That’s clearly not what I want.

Conclusion:
Don’t try to use JPA for GAE persistence, because the design of a RDBMS and GAE are too different, and you will always have problems like this.

2nd conclusion:
I’m back in trying to find another solution. Supporting both RDBMS and GAE would be nice.

About Android,

We all know Android is getter bigger and bigger each day. More applications
(http://www.androlib.com/appstats.aspx), more phones
(http://en.wikipedia.org/wiki/List_of_Android_devices),
are coming each day, and this is growing exponentially.

I really enjoy this, mainly because:

  • It’s an OpenSource platform
  • Java is the main development language for it
  • I don’t like Apple we-decide-everything-and-you-pay business model.

As you can see, in 2 years, Android has become  one of the main competitor in the smartphone market (along with Nokia, BlackBerry and Apple).

Now let’s talk about Java Mobile Edition

  • It is the real winner for low-end phones
  • In high-end market, only Nokia and BlackBerry supports it, and it seems you’ll have to use proprietary API for a good result.
  • Evolution is too slow for mobile: Inside the JCP for JavaME, I’m sure there are lots of discussions between competitors companies, and that takes a lot of time.
  • Who understands the MIDP/CDC/CLDC concepts (http://java.sun.com/javame/technology/index.jsp) ?

Oracle didn’t ask me, and I’m sure they have lots of smart people thinking of these facts, but that won’t prevent me from telling my opinion.

I know this is almost infeasible from a business and maybe technical point of view, but I think it would be a good thing if:

Android becomes the next Java ME !

And I mean, the last Android version, that takes shape rapidly in Google offices. Don’t try to take one version and go again with 3 year release schedules !

Let’s just imagine if Oracle (-and Nokia, and BlackBerry, and Sony-Ericssson, etc…) decided to follow Google on JavaME:

The not so good things:

  • Oracle will loose control of mobile market software developement, but they are loosing it anyway, and I’m not sure they’re interested in it.
  • Of course, Android is not just Java, but it’s a Linux OS too. And I think all the phone makers would have to switch to it too.
  • And even if the language is Java, the JVM that’s running is not really Java… But who cares ?

The really good things:

  • We would have a new release every 6 monthes, with the features of the latest phones !
  • There would be as many hardware maker backing Java as a mobile platform
  • Apple would have a run for their money – What a dream
  • Java ME will be the coolest thing in mobile again !

Oracle, If you hear me, just think about this.

Gerard.

Hi,

I see all over internet that Adobe is going to sue Apple over their new licensing document, preventing Flash products to work on the iPhone / iPad / iTouch whatever. See here:

http://www.itworld.com/legal/104320/adobe-vs-apple-going-get-uglier

Two things comes to my mind:

- Why Oracle don’t do the same with Java mobile platform for iPhone ? Where is oracle fighting for Java mobile platform? I ask Oracle, because now they formally own Java now, But I have nothing against them. I would tell the same to SUN if it still existed.

- If the trial is taking place, and let’s say Apple loose, would that mean we can port Java to Apple’s stuff ?

GC.

This post follows the first explanation about why writing a back-to-basic library.

I created the RER library (the name will be explained later). It is a kenai project, you can find here: RER Library, source code will be there soon.

This library will only provides good development principles that will allow you to develop a « good » application.

This library will provide:

- Easy Dao writing based on JPA
- Support for other kind of persistence model (JDO ? iBatis ?)
- Support for writing Entity with Interface / implementation separation
- Easy-to-understand-yet-highly-extensible transaction management
- Best practices in web database-base developments

It won’t provide:

- Complicated stuff and technology you don’t have time to understand anyway
- Aspects, magical dependency injection, bytecode instrumentations, annotations, etc…
- Many dependencies to myriads of other libraries in specific versions incompatible with others.

It consists in:

- A set of interface along with their implementation classes
- Singleton and Factory patterns (yes ! with static methods !)
- Configurable with simple java method calls (yes, calling a method, anyone knows this ?)

It will be compatible with:

- Any OS, Application Server (or not)
- Java version 5
- Any java library – Spring, Gwt, Swing, Guice, Wicket, Google App. Engine, J2EE, J2SE etc… just because it’s only made of simple Java classes !

I’m using Java since 1995, yes, that’s 15 years ago. I perfectly remember the first time I read something about it, in a French IT newspaper.

It said something about a new platform that can execute dynamic content on Mozilla, whatever your OS is.

I immediately jumped into downloading the beta version, and started developping with it… Well, I never ended !

It was a time were java was not serverside development, where displaying an (ugly) window was quite an achievement.

Now, customer ask me to do a web application, that queries millions of data, generates excel and pdf files, calls and provides WebServices… This has come to quite a complexity in development now…. And each new Java release or new libraries aims to « simplify development »…

To me, the more we simplify, the more complicated it seems to be: AOP, Annotations, Dynamic bytecode modifications, class loading Weavering, dependency injection, and now, inter-type declaration (ITD). And still, it’s difficult to do simple things, like a working form in JSF, or cancelling a transaction in Seam, or even writing a good and extensible business layer….

For the Appliweb project,I want to go back to basic stuff.

So I’m currently writing a simple library that allows simple Daos, Entities based development, along with transaction management and other stuff….

This library will be Apache 2.0 licensed, will do no more than provides simple classes and methods.

More on it later…..

More dynamic form with ValueListener

Next difficulty: I add a checkbox, and when the user check this box, I want some other fields to appear.

For now, only one input field will be enough, but this field, when displayed, must be filled by the user. It is mandatory.

How do you do that ?

Simply add the checkbox and the input, and map the rendered attribute of the input to the same model value of the checkbox.

1
2
3
4
5
6
7
8
9
10
11
<ice:outputLabel value="Extended Search:" />
<ice:selectBooleanCheckbox id="extendedSearch"
   value="#{searchPage.extendedSearch}" />
<ice:outputLabel value="Extension:"
   rendered="#{searchPage.extendedSearch}"/>
<s:decorate template="/layout/decorate.xhtml" rendered="#{searchPage.extendedSearch}">
    <ice:inputText id="extension"
       value="#{searchPage.extension}" required="true"/>
    <ice:message for="extension" styleClass="message"
       errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/>
</s:decorate>

The result should be, after a click in the check box:

But, nothing happens.

We have to tell JSF to generate an event as soon as the user click on the checkbox. By default, JSF does nothing.

We simply use our famous attribute partialSubmit= »true »

1
2
3
<ice:selectBooleanCheckbox id="extendedSearch"
   value="#{searchPage.extendedSearch}"
   partialSubmit="true" />

Now, when we click on the checkbox, we have the dependant input field displayed or not. Great ! But we’re not done yet with this.

Let’s try to input an incorrect value in the integer field, then check the box:

Ooopps, the integer input just gets validated before the checkbox can modify the model value, so the dependant input field don’t display.

We need to set the immediate= »true » attribute:

1
2
3
<ice:selectBooleanCheckbox id="extendedSearch"
   value="#{searchPage.extendedSearch}"
   immediate="true" partialSubmit="true" />

We must leave the partialSubmit= »true », otherwise no event occurs when clicking on the checkbox.

After testing, same (bad) result ! The validation error is displayed, but what’s annoying is that the checkbox is now checked, without the dependent input field displayed !

We need another trick: This trick, is to call a method when the value of the checkbox is changed. We do it like that:

1
2
3
4
<ice:selectBooleanCheckbox id="extendedSearch"
   value="#{searchPage.extendedSearch}"
   immediate="true" partialSubmit="true"
   valueChangeListener="#{searchPage.extendedSearchChanged}" />

And the code for the called method is this:

1
2
3
4
5
6
7
8
9
public void extendedSearchChanged (ValueChangeEvent evt)     {
// We set the value so that the
//  depedant fields are displayed or not
setExtendedSearch((Boolean)evt.getNewValue());

// Using this, we bypass all validations
// stuff, and redisplay directly the page.
FacesContext.getCurrentInstance().renderResponse();
}

And the result is just perfect! You can check / uncheck, you see the dependant input field disappearing or appearing accordingly, even if bad values are entered.

Icefaces partialSubmit and immediate compared

Now let’s try something else: We want, next to the « Search » button, another one, « Back to Home », that goes directly to another page, let’s say the home page.
If we simply add the button in the .xhtml page, and click on it, we have the following result:

1
2
3
<ice:commandButton id="homeAction"
value="Back to Home"
action="#{searchPage.backToHome}" />

Result:

You can see that we cannot go back to the homepage without setting required fields in the form. That’s clearly not good.
One of the solution to this, according to icefaces documentation, is to use partialSubmit= »true » in the button. This tell Icefaces to ignore all mandatory components that are not filled.
Let’s try:

1
2
3
<ice:commandButton id="homeAction"
value="Back to Home" action="#{searchPage.backToHome}"
partialSubmit="true" />

And the result is working !

But, suppose that you’ve typed a wrong value in the first field, and press « Back to home » ?
Here is the result:

What happened ? partialSubmit bypassed the required check, but not the integer validation.

To avoid these 2 checks, we need to use another attribute in the button, it’s immediate= »true ». That means: When I press the button, just handle the button’s action, and forget about all other fields.

1
2
3
<ice:commandButton id="homeAction"
value="Back to Home" action="#{searchPage.backToHome}"
immediate="true" />

And the result works, even with a bad value in the integer field!

A small think appeared to me today, regarding Netbeans.

I noticed that when I run a test for a single file (Right-click on the file, then Test):

The first time the test was running ok, but the second time, I had a strange error from Datanucleus, telling me my classes are wrong….

That was really annoying, so I checked a little bit further this and set debugging option to Maven and to Ant in the settings dialog.

The first time I test the file, I get this:

1
2
3
4
NetBeans: Executing '/mnt/local/files/apache-maven-2.2.1/bin/mvn -Dtest=BasicTest -Dnetbeans.execution=true -debug test-compile surefire:test'
NetBeans:      JAVA_HOME=/mnt/local/files/jdk16+ Error stacktraces are turned on.Apache Maven 2.2.1 (r801777; 2009-08-06 21:16:01+0200)Java version: 1.6.0_17Java home: /mnt/local/files/jdk1.6.0_17/jreDefault locale: fr_FR, platform encoding: UTF-8OS name: "linux" version: "2.6.32.8-1-jolicloud" arch: "i386" Family: "unix"
[DEBUG]Building Maven user-level plugin registry from: '/home/gerard/.m2/plugin-registry.xml'[DEBUG]Building Maven global-level plugin registry from: '/mnt/local/files/apache-maven-2.2.1/conf/plugin-registry.xml'
Scanning for projects...

Typicall maven stuff.

Now, the second time:

1
2
3
4
5
6
7
Adding reference: ant.PropertyHelper
Detected Java version: 1.6 in: /mnt/local/files/jdk1.6.0_17/jre
Detected OS: Linux
Adding reference: ant.ComponentHelper
Trying to override old definition of task java
 +Datatype java org.apache.tools.ant.module.bridge.impl.ForkedJavaOverride
parsing buildfile jar:file:/mnt/local/files/netbeans-6.8/java3/ant/nblib/org-netbeans-modules-ant-browsetask.jar!/org/netbeans/modules/ant/browsetask/antlib.xml with URI = jar:file:/mnt/local/files/netbeans-6.8/java3/ant/nblib/org-netbeans-modules-ant-browsetask.jar!/org/netbeans/modules/ant/browsetask/antlib.xml
It’s an ant execution !

I don’t know why, but the second time Netbeans is running the unit test with Ant, and no more Maven. How can it be possible ?

What’s the point ? I wouldn’t care less if that didn’t make my test fail….

Basic error handling

Seam, JSF and Java all team up together to help developers in displaying error messages to the user.

JSF provides the basis, with the FacesMessage mechanism. Anywhere in your code, you can create FacesMessages, and add them to a FacesMessages object. Then, when the next page displays, the error messages are displayed to the user.

You can use special tags for that in your .xhtml page:

1
2
<ice:messages id="messages" globalOnly="true" styleClass="message"
    errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/>

Notice icefaces allows us to set various css style depending on the type of error.

The result is here:

Now, when a validation is bad, we want to highlight the input field, then display the error message next to it. Fortunately, JSF allows a developer to assign an error message to a field, and by default the validators and converters do just that.

And Seam, allows us to define specific html code when a field is in error. This is done using the s:decorate tag, and the best option is to refer to a template file that will be reused for all fields.

Now the input field is declared like that:

1
2
3
4
5
<s:decorate template="/layout/decorate.xhtml">
  <ice:inputText id="nbElements" value="#{searchPage.nbElements}" />
  <ice:message for="nbElements" styleClass="message"
    errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/&gt;
</s:decorate>

and for the field that must not be null or empty, we just add an required= »true » attribute:

1
2
3
4
5
<s:decorate template="/layout/decorate.xhtml">
  <ice:inputText id="notNull" value="#{searchPage.notNull}" required="true" />
  <ice:message for="notNull" styleClass="message"
      errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/>
</s:decorate>

and the content of the error template file is this:

1
2
3
4
5
6
7
<div class="errorDiv">
  <span class="#{invalid?'errors':''}>
    <s:validateAll>
      <ui:insert/>
    </s:validateAll>
  </span>
</div>

The errors css style just sets the component border to Red.

Now, if we try some basic errrors, like by inputing letters in a field mapped to an integer value, here is the result:

Notice the error message is more precise than the previous screenshot. Any error message can be changed in JSF by a simple properties file.

That’s all for basic error handling. Next time, we’ll try to see the behavior of the current page for all errors defined in the first part.