Friday, December 17, 2010
ViewAccessScope - why it's useful
I ended up often using the JSF ViewScope, exposed as a CDI scope though the Seam Faces CDI extension. When used in conjunction with JSF viewParams to propagate information between pages, the result is a book-markable end user experience.
The problem with this is that the "business conversation" is now restricted to a single page. JSF components that provide a tabbed interfaces allow one to pack a lot into a single page, in a clear and structured way, but there are times when it just makes more sense to navigate to a new page (or view in JSF speak).
This is where the ViewAccessScope comes in. It's a scope defined in MyFaces CODI (a CDI extension). The ViewAccessScope is like a long-lived conversation, where the conversation ends as soon as you use a view that does not reference the ViewAccessScoped bean.
The pattern I see as being incredibly useful, is to initiate a "business conversation" by passing viewParams to a page, then navigate through appropriate views to complete the process. When we come to a page that no longer references the ViewAccessScoped bean, the business conversation is over. This is a perfect fit with how I think of structuring my apps.
Now to try it out, and see how well it works!
Saturday, November 20, 2010
CDI does events too!
Adam Bien does a fantastic job introducing CDI events in his blog entry. There are only three really noteworthy lines of code that I will repeat here:
- @Inject Event
events; events.fire(new HelloEvent(...)); public void listenToHello(@Observes HelloEvent helloEvent){ ... }
Thursday, July 15, 2010
My Glassfish support subscription came through - finally
Call me eager, call me insane, I had a JavaEE 6 app up and running in production on Glassfish 3.0 one month after it's release. The improvements in JSF 2 and CDI were too compelling for me to hold off adopting, and sure enough, the application was quick and painless to develop.
I did however pay a price for being an early adopter - a Glassfish / Weld bug was preventing my JSF login pages from working. Fortunately I was able to quickly find an (ugly) workaround to get me going using JSPs. This brings me to the interesting nugget of this post: the story of my first use of our Glassfish v3 support contract.
I promptly reported the bug to Glassfish, using the support tools provided, and was overall impressed at how quickly the bug was isolated, and a resolution was found. All I had to do was wait for the patch, and my problem would disappear. So I waited for the patch. And waited. And waited...
I reported the bug in January, and heard of a fix in February. The patched release was supposed to come out in March. By May, there was still no release. I made a little noise, and got some attention from both Glassfish support, and the Glassfish Community, but was told the release was delayed by Oracle buying Sun, and the associated "Change in Control". I was however assured that the release was imminent.
Sure enough, Glassfish 3.0.1 was released June 17th, with the fix to my bug - a turnaround of 5 months. While annoyed that I had to wait so long for the fix, I do appreciate having that support structure in place to ensure we get our apps working. I'm just glad we had a workaround.
Here's to looking forward to a regular release schedule for Glassfish patches!
Friday, June 25, 2010
JSF Validation Failed Notice
<h:outputtext styleclass="errorMessage globalMessage" value="Request *not* saved due to input errors" rendered="#{facesContext.validationFailed}" />The user then knows they should look through the page to correct the individually marked validation failures.
Friday, April 9, 2010
From svn to mercurial, the hg rises!
hg = git >> svnThat settled it. I had to pick one, and move forward. I chose mercurial, not because it stood out above git, but it seemed to be more widely adopted in the communities I was interested in. Joel Spolsky's mercurial primer settled it for me. Mercurial was on it's way in. I had identified identified some key obstacles I needed to overcome to replace my subversion infrastructure with a new mercurial one. I had to figure out:
- How to install hg in CENTOS 5
- How to import the revision history from svn into hg
- How to get LDAP authentication to work with hg
- How to integrate hg with hudson (our continuous integration server)
- How to get the maven release plugin to work with hg
1) Install mercurial in CENTOS 5
I hunted around for a while looking for an RPM, but found nothing recent. On a twitter recommendation, I tried installing from source. Turned out to be pretty easy. The install ended up putting mercurial in my /usr/local/lib64 directory, which is not one of the default places python looks for it's modules. I had to do set the PYTHONPATH environment variable pointing to this directory to get things to work.2) svn import into hg
Turns out mercurial has this functionality built in with the bundled Convert Extension. One has to enable this extension in a mercurial configuration file, then it's pretty simple to point the "hg convert" command at your subersion repo. Done and done!3) LDAP integration
I'd achieved svn LDAP integration using apache, so I was quite happy to see hg did the same thing. I set up the hgwebdir.cgi script to serve my newly imported hg repositories, hi-jacking the LDAP authentication from my svn setup. Worked like a charm.Update, here's the apache config for authentication:
# cat /etc/httpd/conf.d/hg.conf ScriptAlias /hg "/var/www/hg/hgwebdir.cgi"Note: the group terms are specific to the IBM Tivoli LDAP server.Order deny,allow Deny from all Allow from 10.0.0.1 AuthType Basic AuthBasicProvider ldap AuthName "LDAP password" AuthLDAPURL "ldaps://ldap.domain.com/ou=users,dc=domain,dc=ccom?uid?sub?(&(uniqueidentifier=*)(objectclass=eperson))" AuthLDAPGroupAttribute ibm-allmembers require ldap-group cn=mis,ou=web,ou=Groups,dc=domain,dc=com Satisfy Any
4) hg integration with Hudson
This one seemed simple enough, given that there is a mercurial plugin for hudson. It was simple enough to install, but took a bit of effort to get going. I had to go into the hudson configuration, and define a mercurial "instance" pointing to a wrapper that set the PYTHONPATH environment variable, then delegated the argument to mercurial itself. Again, I think this is due to the /usr/local/lib64 path the mercurial installer chose. Maybe this could be done more cleanly, but it's working now.Another hiccup with the hudson configuration, was that there was no place to put a username and password, as one did with the svn/hudson config. I worked around this by adding the IP of my hudson server to the "allow from" section of my apache config file. Thus hudson could pull from my hg repos without authenticating.
A few hurdles with this one, but nothing severe.
Update (in answer to a comment):
My hg warpper looks like:
# cat /usr/local/bin/hg_pythonpath_wrapper #!/bin/sh export PYTHONPATH=/usr/local/lib64/python2.4/site-packages /usr/local/bin/hg "$@"
To get hudson to use this wrapper, goto: Manage Hudson -> Configure System Scroll down to the mercurial section, click the "Add Mercurial" plugin, and point the executable to the above wrapper.
5) The maven release plugin
I use the maven release plugin to perform my releases. I initially tried to get maven to push/pull from the "central" hg repository I had setup, but ran into similar authentication issues as I did with hudson. I read some advice on using the maven release plugin with mercurial, and realized I was still thinking in terms of subversion. Of course it makes more sense to do the release against a local hg repo, and only push the change-sets if the release worked. Oh I love mercurial! And that's it. One day later, and I've converted our multi-module subversion repository into several mercurial directories served by apache with LDAP authentication. Our hudson continuous integration polls the "primary" mercurial repository, and maven tags releases against my local repo. I was told correctly, one you ditch subversion and go with mercurial, you'll never go back.Wednesday, January 20, 2010
Glassfish V2 and V3 on the same host, behind mod_jk
I've jumped on the JavaEE 6 bandwagon, with one application already in production. The developer productivity improvements in JavaEE6/Glassfish V3 are tremendous. The only downside is that I still have some JavaEE 5 applications in production. The JavaEE 5 apps can't migrate to JavaEE 6 until Icefaces supports JSF 1.2.
One workaround to this is to bundle the JSF 1.2 implementation with your application, then configure the classloader using the sun-web.xml file to load this bundled JSF library instead of the container's JSF 2.0 library. This however only works with a standalone WAR file; when the WAR is bundled in an EAR, and references other EJB-JAR's, this trick isn't possible. Yet I still wanted to move new application development to JavaEE 6.
My solution was to run both Glassfish V2 and Glassfish V3 on the same box, with mod_jk forwarding requests to the appropriate container. In this way I am able to keep my existing JavaEE 5 / Icefaces applications running, and deploy new applications to the JavaEE 6 environment.
The first step was to get GF v2, and GF v3 running on the same machine. I have GF v2 running on the standard ports, and I incremented each port by 1 for GF v3. It looks like:
GF v2 Port | GF v3 Port | |
HTTP | 8080 | 8081 |
HTTPS | 8181 | 8182 |
HTTP - ADMIN | 4848 | 4849 |
IIOP | 3700 | 3701 |
IIOP SSL | 3820 | 3821 |
IIOP SSL-MUTUALAUTH | 3920 | 3921 |
JMX | 8686 | 8687 |
JMS | 7676 | 7677 |
Next, we had to get mod_jk installed and working. The glassfish support team (yes, I pay for support!) pointed me to the following resources:
- V2 instructions - http://weblogs.java.net/blog/2006/03/17/running-glassfish-apache-httpd
- V3 instructions - http://weblogs.java.net/blog/2009/06/24/running-glassfish-v3-apache-httpd
These were a great starting point, from which I ended up with the solution.
mod_jk.conf:
#mod_jk/1.2.28 LoadModule jk_module modules/mod_jk.so JkWorkersFile /etc/httpd/conf.d/worker.properties # Where to put jk logs JkLogFile /var/log/httpd/mod_jk.log # Set the jk log level [debug/error/info] JkLogLevel info # Select the log format JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " # JkOptions indicate to send SSL KEY SIZE, JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories +DisableReuse # JkRequestLogFormat set the request format JkRequestLogFormat "%w %V %T" # Should mod_jk send SSL information (default is On) JkExtractSSL On # What is the indicator for SSL (default is HTTPS) JkHTTPSIndicator HTTPS # What is the indicator for SSL session (default is SSL_SESSION_ID) JkSESSIONIndicator SSL_SESSION_ID # What is the indicator for client SSL cipher suit (default is SSL_CIPHER) JkCIPHERIndicator SSL_CIPHER # What is the indicator for the client SSL certificated? (default is SSL_CLIENT_CERT) JkCERTSIndicator SSL_CLIENT_CERT # Set the following if you want all vhosts to inherhit JkMounts from global JkMountCopy All # Send requests to GlassFish JkMount /javaee6app* worker1 JkMount /javaee6app/* worker1 JkMount /javaee6app* worker2 JkMount /javaee6app/* worker2 # Send all glassfish-test requests to GlassFish JkMount /glassfish-test/* worker1 JkShmFile /var/log/httpd/jk-runtime-status
And worker.properties:
## Define 1 real worker using ajp13 worker.list=worker1,worker2 # Set properties for worker1 (ajp13) worker.worker1.type=ajp13 worker.worker1.host=localhost.localdomain worker.worker1.port=8009 #Only used for a member worker of a load balancer. #worker.worker1.lbfactor=50 #Do not use cachesize with values higher then 1 on Apache 2.x prefork #worker.worker1.cachesize=10 #connection_pool_size replace cachesize as of v1.2.16 worker.worker1.connection_pool_size=1 worker.worker1.connection_pool_timeout=0 worker.worker1.socket_keepalive=1 #Socket timeout in seconds worker.worker1.socket_timeout=60 worker.worker2.type=ajp13 worker.worker2.host=localhost.localdomain worker.worker2.port=8010 #Only used for a member worker of a load balancer. #worker.worker2.lbfactor=50 #Do not use cachesize with values higher then 1 on Apache 2.x prefork #worker.worker2.cachesize=10 #connection_pool_size replace cachesize as of v1.2.16 worker.worker2.connection_pool_size=1 worker.worker2.connection_pool_timeout=0 worker.worker2.socket_keepalive=1 #Socket timeout in seconds worker.worker2.socket_timeout=60
These are not the worker.properties as prescribed in the above links. After implementing the initial solution, I got reports from the wild of users mysteriously losing sessions. After much reading about mod_jk, I think I narrowed down the problem to a cachesize/connection_pool_size > 1 in conjunction with the prefork mpm apache module. Apparently this is a no-no.
So with these settings in place, I am able to develop new apps in JavaEE 6, while still running my older JavaEE 5 apps, on the same box. Looking forward to Icefaces 2.0 though, so I can drop this needless complexity!