Monday, August 20, 2007
It's been a while...
... since my last post. There is still some code waiting to be published, but I still don't have time to document it properly :( Currently I'm working on a data transformation project for one of our customers. I won't be writing any Java code in the near future. I'm changing my focus to Business Intelligence, so that will probably be the main topic of my future posts. Stay tuned.
Saturday, June 23, 2007
Our first ADF application is production-ready!
As you might have noticed, my last post was written over a month ago. The reason is simple: I was quite busy finishing our first ADF application that is now production-ready! :) Whew...
We've learned a lot about ADF and JDeveloper. Hopefully we'll be able to leverage the power of this framework in future applications. Did everything go smoothly? Well, no. We are still not comfortable with ADF Security (we had to remove the authorization support), because it does throw weird exceptions in some situations and the ADF Security wizard in JDeveloper is a problem itself (it's hard to do any teamwork with this wizard).
Another conclusion is that the JPA+EJB3+ADF stack is not as productive as we thought. I'm going to have another look at ADF BC in the near future.
Finally, a few things worth mentioning:
1. If you have a problem with locales (e.g. the default ADF messages show up in a different locale than your messages), you should have a look here.
2. If you are using Oracle XE and Firefox and you cannot edit SQL scripts in the web interface, this message will lead you to a solution.
3. I've enhanced Frank Nimphius's solution (JSF login form for container-managed authentication in Java Server Faces) to make it more useful. I'll publish my modifications as soon as I find some spare time. Stay tuned ;)
We've learned a lot about ADF and JDeveloper. Hopefully we'll be able to leverage the power of this framework in future applications. Did everything go smoothly? Well, no. We are still not comfortable with ADF Security (we had to remove the authorization support), because it does throw weird exceptions in some situations and the ADF Security wizard in JDeveloper is a problem itself (it's hard to do any teamwork with this wizard).
Another conclusion is that the JPA+EJB3+ADF stack is not as productive as we thought. I'm going to have another look at ADF BC in the near future.
Finally, a few things worth mentioning:
1. If you have a problem with locales (e.g. the default ADF messages show up in a different locale than your messages), you should have a look here.
2. If you are using Oracle XE and Firefox and you cannot edit SQL scripts in the web interface, this message will lead you to a solution.
3. I've enhanced Frank Nimphius's solution (JSF login form for container-managed authentication in Java Server Faces) to make it more useful. I'll publish my modifications as soon as I find some spare time. Stay tuned ;)
Thursday, May 17, 2007
Classpath conflicts
One problem kept bugging me for three weeks. It was quite irrational - I couldn't extend the functionality of the application, because changes in services (that were EJB3 session beans) were not visible. The problem occurred when deploying to embedded OC4J, but, surprisingly, not when deploying to OC4J standalone...
After getting lots of JBO-25221 (method not supported) and java.lang.NoSuchMethodError I thought I would investigate the class used at runtime. I found that the method that should be there wasn't there at runtime. So I decided to find out where did the class come from. Bertrand Delacretaz has an example of checking when was a Java class compiled. Small modifications to his example and the mysterious class is unmasked:
I was shocked when I saw the output - it turned out that another project that should have a small 2-class jar in my application had packed also a bunch of classes from the same model. The model was referenced by both projects as a dependency and the deployment profile had a magic checkbox selected:
That resulted in a silent classpath conflict I was not aware of... Finally, the problem is gone :)
After getting lots of JBO-25221 (method not supported) and java.lang.NoSuchMethodError I thought I would investigate the class used at runtime. I found that the method that should be there wasn't there at runtime. So I decided to find out where did the class come from. Bertrand Delacretaz has an example of checking when was a Java class compiled. Small modifications to his example and the mysterious class is unmasked:
MyClass.class.getResource( "MyClass.class" ).openConnection().getURL().toString()
I was shocked when I saw the output - it turned out that another project that should have a small 2-class jar in my application had packed also a bunch of classes from the same model. The model was referenced by both projects as a dependency and the deployment profile had a magic checkbox selected:
That resulted in a silent classpath conflict I was not aware of... Finally, the problem is gone :)
Tuesday, May 15, 2007
... is not a registered tag in that namespace?
Today JDeveloper broke my project. I don't know what exactly happened, but putting an ADF Faces tag inside a page resulted in JSP compilation errors, e.g.:
After a few minutes of trying different things I opened the web.xml file and found the problem:
Now that was confusing... Removing that piece of code helped. But how did it appear here? JDev only knows...
One OT to mention here: the code you see above was escaped (to be displayed properly by Blogger) using a very simple and effective tool I've come across recently. Check out Dietmar Aust's blog.
Error: http://xmlns.oracle.com/adf/faces:panelPage is not a registered tag in that namespace.
After a few minutes of trying different things I opened the web.xml file and found the problem:
<taglib>
<taglib-uri>
http://java.sun.com/jsf/core
</taglib-uri>
<taglib-location>
/WEB-INF/lib/jsf-impl.jar
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
http://xmlns.oracle.com/adf/faces
</taglib-uri>
<taglib-location>
/WEB-INF/lib/adf-faces-impl.jar
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
http://xmlns.oracle.com/adf/faces/html
</taglib-uri>
<taglib-location>
/WEB-INF/lib/adf-faces-impl.jar
</taglib-location>
</taglib>
Now that was confusing... Removing that piece of code helped. But how did it appear here? JDev only knows...
One OT to mention here: the code you see above was escaped (to be displayed properly by Blogger) using a very simple and effective tool I've come across recently. Check out Dietmar Aust's blog.
Friday, May 11, 2007
Extending ADF's FacesPageLifecycle
Recently I've encountered strange exceptions while testing my application. I pressed the Submit button and sometimes everything was fine, while at times the action bound to the button was not invoked, but errors were reported:
Unfortunately, there was no trace of this exception and I didn't even know where should I look for it. Then I came up with and idea: let's decorate the process of displaying errors and find out more about this exception. To achieve this, I had to extend ADF's FacesPageLifecycle:
Another question is: how can we tell ADF to use our lifecycle? That's easy too - we extend ADFPhaseListener:
Finally, we need to substitute the original ADFPhaseListener with our class in faces-config.xml:
That allowed me to locate the problem - the exception was thrown in the line containing:
because sometimes the field wasn't set...
The conclusion is simple - if a library throws a weird exception, don't blame the library, but check YOUR code first.
JBO-29000: null
java.lang.NullPointerException
Unfortunately, there was no trace of this exception and I didn't even know where should I look for it. Then I came up with and idea: let's decorate the process of displaying errors and find out more about this exception. To achieve this, I had to extend ADF's FacesPageLifecycle:
package januszm.adf.util;
import javax.faces.context.FacesContext;
import oracle.adf.controller.faces.lifecycle.FacesPageLifecycle;
import oracle.binding.AttributeBinding;
public class MyPageLifecycle extends FacesPageLifecycle {
protected void addMessage(FacesContext context, AttributeBinding binding,
Throwable error) {
super.addMessage( context, binding, error );
// the easiest thing we can do here
error.printStackTrace();
}
}
Another question is: how can we tell ADF to use our lifecycle? That's easy too - we extend ADFPhaseListener:
package januszm.adf.util;
import oracle.adf.controller.faces.lifecycle.ADFPhaseListener;
import oracle.adf.controller.v2.lifecycle.PageLifecycle;
public class MyPhaseListener extends ADFPhaseListener {
protected PageLifecycle createPageLifecycle() {
return new MyPageLifecycle();
}
}
Finally, we need to substitute the original ADFPhaseListener with our class in faces-config.xml:
<lifecycle>
<phase-listener>januszm.adf.util.MyPhaseListener</phase-listener>
</lifecycle>
That allowed me to locate the problem - the exception was thrown in the line containing:
this.someField.toString()
because sometimes the field wasn't set...
The conclusion is simple - if a library throws a weird exception, don't blame the library, but check YOUR code first.
Tuesday, May 8, 2007
JDeveloper 11g Tech Preview is out!
Check out Shay Shmeltzer's blog for details: http://blogs.oracle.com/shay/2007/05/07#a365
Saturday, May 5, 2007
Checking if passwords are equal in ADF
After spending some time trying to get Tomahawk's validateEqual working in ADF Faces (works perfectly in JSF, though) I've decided to implement a custom validation method. The second af:inputText wasn't connected to any ADF binding and this turned out to be the main troublemaker of the day. With the help of the Dev Guide validation started working quickly, but I've encountered a bunch of annoying little problems...
1. The error message would not display as expected. I expected something like "Repeat password - Passwords are not equal", but all I got was "com.sun.faces.el.ValueBindingImpl@9af3ee - Passwords are not equal". Fortunately, a quick forum search saved me this time (namely this thread and this one).
2. Both af:inputText components did not behave as expected after validation failure. JSF h:inputSecret has a redisplay attribute, but I didn't notice anything similar for af:inputText. When secret was set to true, something weird happened - after each validation failure the value of both components was initially set to ******, but it disappeared after pressing a key inside the component. After digging for a while I still don't know why the initial value is set to six stars, but I found the function that removes them:
Now that's interesting... Anyway, I tried to get rid of those stars for a long time. The first component that was bound to the password attribute was easier, because binding the component to the backing bean that performs validation and setting the value to null did the trick.
The second component kept setting its value to ****** despite setting it to null in the backing bean. After many unsuccessful attempts I removed those stars with a small JavaScript workaround inside the afh:body tag:
1. The error message would not display as expected. I expected something like "Repeat password - Passwords are not equal", but all I got was "com.sun.faces.el.ValueBindingImpl@9af3ee - Passwords are not equal". Fortunately, a quick forum search saved me this time (namely this thread and this one).
2. Both af:inputText components did not behave as expected after validation failure. JSF h:inputSecret has a redisplay attribute, but I didn't notice anything similar for af:inputText. When secret was set to true, something weird happened - after each validation failure the value of both components was initially set to ******, but it disappeared after pressing a key inside the component. After digging for a while I still don't know why the initial value is set to six stars, but I found the function that removes them:
function _clearPassword(a0,a1)
{
if(window.event!=(void 0))
a1=window.event;
if(a0.value!="******")
return true;
if((a1.keyCode==8)||
((a1.keyCode>=46)&&(a1.keyCode<112)))
a0.value="";
return true;
}
Now that's interesting... Anyway, I tried to get rid of those stars for a long time. The first component that was bound to the password attribute was easier, because binding the component to the backing bean that performs validation and setting the value to null did the trick.
The second component kept setting its value to ****** despite setting it to null in the backing bean. After many unsuccessful attempts I removed those stars with a small JavaScript workaround inside the afh:body tag:
onload="_getElementById(document, 'repeatedUserPassword').value = '';"
Subscribe to:
Posts (Atom)