tag:blogger.com,1999:blog-61333639590819331042024-02-02T06:53:20.473+01:00Big Al's BlogThe blog has moved to http://blogs.i2m.dk/allanAllan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.comBlogger35125tag:blogger.com,1999:blog-6133363959081933104.post-66525556455650241542009-03-16T14:44:00.004+01:002009-03-16T14:51:23.499+01:00Sending files through action listenersFor this weeks JSF tip, I’ll show you how to send binary data (such as a file) to the user by way of an action handler or listener. <br /><br />Say, you want to generate a custom PDF and send it to the user as he clicks a link. You need a JSF page, and a backing bean.<br /><br />Your JSF page may look like this:<br /><pre name="code" class="xml"><br /><h:form><br /> <h:commandLink id="lnkDownload"<br /> actionListener="#{myBean.onDownload}"<br /> target="_blank"<br /> value="Download PDF" /><br /></h:form><br /></pre><br /><br /><br />Your JSF backing bean may look like this:<br /><pre name="code" class="java"><br />public MyBean {<br /><br /> public void onDownload(ActionEvent event) {<br /> try {<br /> // here you need to get the byte[] representation of <br /> // the file you want to send<br /> byte[] binary_data = ;<br /> String filename = "generated_file.pdf”;<br /> FacesContext fctx = FacesContext.getCurrentInstance(); <br /> ExternalContext ectx = fctx.getExternalContext();<br /> <br /> HttpServletResponse response = (HttpServletResponse) ectx.getResponse();<br /> response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");<br /> response.setHeader("Content-Transfer-Encoding", "Binary");<br /> response.setHeader("Pragma", "private");<br /> response.setHeader("cache-control", "private, must-revalidate");<br /> <br /> ServletOutputStream outs = response.getOutputStream();<br /> outs.write(binary_data);<br /> outs.flush();<br /> outs.close();<br /> response.flushBuffer();<br /> <br /> fctx.responseComplete();<br /> } catch (IOException ex) {<br /> ex.printStackTrace();<br /> }<br />}<br /></pre><br /><br />That’s it for today.<br /><br />P.S. alternatively you can use this component which is less code intensive: <a target="_blank" href="http://kenai.com/projects/scales/pages/Download">http://kenai.com/projects/scales/pages/Download</a>Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com2tag:blogger.com,1999:blog-6133363959081933104.post-50731759965687064452009-03-09T21:35:00.003+01:002009-03-09T22:40:40.611+01:00JSF and I18NIt has been a busy year so far. Every year I start out thinking that I really need to relax because the previous year was too hectic, but every year it ends up being much more hectic. Anyway, I thought I’d post a JSF quick time that might shave some headache for people developing internationalised applications.<br /><br />Most JSF developers are aware of the resource-bundle tag in faces-config. Using this tag you can specify a resource bundle that should be available to all your pages using a given variable. For example, the code below will make a variable, msgs, available in all your pages without having to use the loadBundle tag.<br /><br /><pre name="code" class="xml"><br /><faces-config version="1.2"><br />...<br /> <application><br /> <resource-bundle><br /> <base-name>my.class.path.Messages</base-name><br /> <var>msgs</var><br /> </resource-bundle><br /> </application><br />...<br /></faces-config><br /></pre><br /><br />So, say that Messages.properties contains the following:<br /><br /><pre name="code" class="java"><br />HELLO_WHAT_IS_YOUR_NAME=Hello, what’s your name?<br /> </pre><br /><br />you can from any page reference this text by writing:<br /><br /><pre name="code" class="xml"><br /><h:outputText value=”#{mgs.HELLO_WHAT_IS_YOUR_NAME}” /> <br /></pre><br />or<br /><pre name="code" class="xml"><br /><h:outputText value=”#{mgs[‘HELLO_WHAT_IS_YOUR_NAME’]}” /><br /></pre><br /><br />I prefer the former as my favourite IDE (NetBeans) support code completion for all the messages in a managed resource bundle.<br /><br />So far so good. But what if you want to do something a bit more advanced, such as outputting “Hello Allan, welcome to my site. Your last visit was 7. February 2009 at 10:45”. You are not limited to static text in your resource bundle. You can provide placeholders for content that will be replaced at run-time. Let’s have a look at the Message.properties:<br /><br /><pre name="code" class="xml"><br />WELCOME_MESSAGE=Hello {0}, welcome to my site. Your last visit was {1,date,long} at {1,time,short}<br /></pre><br /><br />You’ll notice that the message is parameterised using two parameters. The first parameter we are expecting a string containing the name of the user, the second parameter is a java.util.Date containing both the date and time when user last visited the site. Notice that I’ve reused the second paramenter ({1}), one time for the date and the other for the time. On your JSF page you would use the message as follows (imaging that you have a bean called welcome containing a property for getting the name of the user and last visit):<br /><br /><pre name="code" class="xml"><br /><h:outputFormat value=”#{msgs.WELCOME_MESSAGE}”><br /> <f:param value=”#{welcome.userName}” /><br /> <f:param value=”#{welcome.lastVisit}” /><br /></h:outputFormat> <br /></pre><br /><br />Pretty neat, eh?<br /><br />What about the classical case of singular and plural messages? Imagine that you want to display the number of records in a table “There are 10 records in the table”. If the Message.properties contained:<br /><br /><pre name="code" class="xml"><br />RECORDS_IN_TABLE=There are {0} records in the table<br /></pre><br /><br />You’d end up an embarrassing problem if there was only one record in the table:<br /><br />“There are 1 records in the table” (This sentence is grammatical incorrect)<br /><br />Instead you would want it to output:<br /><br />“There is 1 record in the table”<br /><br />To do this, you have to use the choice pattern:<br /><br /><pre name="code" class="xml"><br />RECORDS_IN_TABLE=There {0, choice, 0#are|1#is|2#are} {0} {0, choice, 0#records|1#record|2#records}<br /></pre><br /><br />The format might look a bit awkward, but once you have understood the pattern it is simple:<br /><br /><table><tr><td>{0,choice</td><td>means, taking the first parameter and base the output on a choice of formats</td></tr><tr><td>0#are</td><td>if the first parameter contains 0 (or below), then it should print “are”</td></tr><tr><td>|1#is</td><td>or, if the first parameter contain 1, then it should print “is”</td></tr><br /><tr><td>|2#are}</td><td>or, if the first parameter contains 2 (or above), then it should print “are”</td></tr></table><br /><br />Now, that is nice! So let’s examine the output of these examples:<br /><br /><table><tr><td><pre name="code" class="xml"><br /><h:outputFormat value=”#{msgs.RECORDS_IN_TABLE}”><br /> <f:param value=”#{0}” /><br /></h:outputFormat><br /></pre></td><td>There are 0 records in the table</td></tr><tr><td><pre name="code" class="xml"><br /><h:outputFormat value=”#{msgs.RECORDS_IN_TABLE}”><br /> <f:param value=”#{1}” /><br /></h:outputFormat><br /></pre></td><td>There is 1 record in the table</td></tr><tr><td><pre name="code" class="xml"><br /><h:outputFormat value=”#{msgs.RECORDS_IN_TABLE}”><br /> <f:param value=”#{2}” /><br /></h:outputFormat><br /></pre></td><td>There are 2 records in the table</td></tr><tr><td><pre name="code" class="xml"><br /><h:outputFormat value=”#{msgs.RECORDS_IN_TABLE}”><br /> <f:param value=”#{10}” /><br /></h:outputFormat><br /></pre></td><td>There are 10 records in the table</td></tr></table><br /><br />Enjoy!Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com7tag:blogger.com,1999:blog-6133363959081933104.post-14587924451633414462009-02-02T10:45:00.003+01:002009-02-02T11:15:38.781+01:00Review: Getting Real -- The smarter, faster, easier way to build a successful web application<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidloYhbed5gb8loYoj3oC91QLEIDkEhaQuLOKokSxFHEX1ziNVYfM6vBb61YcrHhBMJj20vkoq-KzfCiHS5OXFntRMB0X1MK3qf7A-GKqNw7sV7250qUivBQDmbt4I2Gk00aKmEnA4pK4/s1600-h/320_383343.jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 215px; height: 322px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidloYhbed5gb8loYoj3oC91QLEIDkEhaQuLOKokSxFHEX1ziNVYfM6vBb61YcrHhBMJj20vkoq-KzfCiHS5OXFntRMB0X1MK3qf7A-GKqNw7sV7250qUivBQDmbt4I2Gk00aKmEnA4pK4/s400/320_383343.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5298141613439169778" /></a><br />Since mid last week I've been down with a terrible flu. It has been so bad that I haven't been able to look at the computer screen (imagine that!!). To pass time I picked up a <a href="http://www.lulu.com/content/383343" target="_blank">book that I picked up from Lulu.com</a> a few months ago called "<a target="_blank" href="http://gettingreal.37signals.com/">Getting Real -- The smarter, faster, easier way to build a successful web application</a>". The authors behind the book are the developers behind 37signals (probably most known for developing the Ruby on Rails framework). The contents of the book is actually freely available from their website, but since I'm spending more and more time away from the computer these days I decided to buy a paper copy.<br /><br />I absolutely loved the book. I knew that I would love the book when I read part of the disclaimer: "<em>If our tone seems too known-it-allish, bear with us. We think it's better to present ideas in bold strokes than to be wishy-washy about it. If that comes off as cocky or arrogant, so be it. We'd rather be provocative than water every down with "it depends..."</em>". It is so refreshing to read something that is written with confidence and not some generic advice that can mean everything and nothing.<br /><br />The book takes you through the stages of launching a web application from staffing, to interface design, to pricing and post-launch activities. Each chapter deals with a specific stage of the launch and provide easy-to-read, snappy, no bull advices on how to go about the given stage. Although I don't agree with everything in the book it is very enlighting, refreshing and entertaining. It reminds me a lot about the book <a target="_blank" href="http://www.amazon.com/How-Become-CEO-Rising-Organization/dp/0786864370">"How to become a CEO- The Rules for Rising to the Top of Any Organization" by Jeffrey J Fox</a>, which I can recommend for a quick entertaining read.<br /><br />It's a must read for everything developing web applications. I'll give this book <b>five stars out of five</b>!!Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-82468742568221263652009-01-08T17:25:00.003+01:002009-01-08T17:40:27.596+01:00Another big shot goes bustAnother big shot goes bust! This time it's the Indian IT "giant" Satyam (<a href="http://www.computing.co.uk/vnunet/news/2233443/satyam-chairman-admits-seven">http://www.computing.co.uk/vnunet/news/2233443/satyam-chairman-admits-seven</a>). This is not long after the Danish company; IT Factory, pulled a similar stunt (<a href="http://politiken.dk/newsinenglish/article605506.ece">http://politiken.dk/newsinenglish/article605506.ece</a>). I'm starting to think that when all things are going well, it's just an illusion with a few puppet masters pulling all the strings. However, I just can't believe that in both cases it is claimed that the auditors and board didn't have any knowledge of the wrong doings. If this is true then we must be talking about the dumbest people in the world.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-36197898365370715192009-01-02T01:50:00.004+01:002009-01-02T02:08:50.926+01:00Christmas present from SunJust as the year was ended I got a great Christmas present from Sun Microsystems.<br /><br />1) A cool NetBeans 10 year anniversary T-shirt for participating in the community acceptance test programme for NetBeans 6.5 (NetCAT)<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPTj1wqYtmQ09nf_uQTXvJCe68X3haQ2LZDb5dO8LoSApktsNhdUojVgilDiuTad0ltbUxpvVcO25Rdzym0STF4m-tPPOkXXThYnqQfmjyh-Jy602xYPbEwUUHuMExHA4rJlQYqDq69OM/s1600-h/nb_65_tshirt.gif"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 188px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPTj1wqYtmQ09nf_uQTXvJCe68X3haQ2LZDb5dO8LoSApktsNhdUojVgilDiuTad0ltbUxpvVcO25Rdzym0STF4m-tPPOkXXThYnqQfmjyh-Jy602xYPbEwUUHuMExHA4rJlQYqDq69OM/s400/nb_65_tshirt.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5286494407036699778" /></a><br /><br />2) A pass on my exam to become Sun Certified Specialist for NetBeans IDE<br /><br />The exam was special to me as it was my first ever certification exam. My score was 82%, with the least score in questions about building Java SE applications. I guess it shows that I've never build Java SE applications on NetBeans. Otherwise I think the exam was great. Studying for the exam revealed a lot of useful features that I had never used before, but now wondering how I could ever live without. I can highly recommend doing the exam!<br /><br />Thanks Sun!Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com1tag:blogger.com,1999:blog-6133363959081933104.post-8802873709917108042008-12-31T02:16:00.005+01:002008-12-31T02:26:58.259+01:00Setting JAVA_HOME on UbuntuA thing that always annoys me about installing Java is that it doesn't automatically set up the JAVA_HOME environment variable after installation. I guess this is to avoid having problems when you have multiple virtual machines installed. Anyway, I use Ubuntu Linux to host the majority of my Java Application Server. It is easy install Java (<code>sudo apt-get install sun-java6-jdk</code>) but there always seems to be a debate about where to set the <code>JAVA_HOME</code> environment variable. Some instructions say you should add it to your personal profile (e.g. <code>~/.bashrc</code>) others suggest adding it to the global profile (i.e. <code>/etc/profile</code>), some people even suggest adding it directly in the init script for the services that need the variable. My suggest is to add an executable shell script to <code>/etc/profile.d/</code> called <code>javahome.sh</code>. The content of the file would be: <code>export JAVA_HOME=/usr/lib/jvm/java-6-sun</code>. All shell scripts (i.e. executable files with the extension <code>.sh</code>) located in the <code>/etc/profile.d/</code> directory are loaded upon login and would therefore work for all users without having to change system files that may change upon the next O/S upgrade. To test the script simply type <code>source /etc/profile</code> This will reload the profile for the current user. To verify that the environment variable has been initialised type <code>export|grep JAVA_HOME</code><br /><br />Enjoy!Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com3tag:blogger.com,1999:blog-6133363959081933104.post-71153370050868119042008-11-24T00:31:00.004+01:002009-01-02T14:20:14.105+01:00Getting value expressions from f:attributesIf you have a custom converter or validator you may provide these with the option of letting developers specify attributes. For example, let's say that we are creating a converter that will allow the formatting of a <code>Calendar</code> object. Note, that the <code><f:convertDateTime /> </code> is for <code>Date</code> objects (which can be easily retrieved from a <code>Calendar</code>, but that is beside the point). So the custom converter I'll create here is for converting/formatting <code>Calendar</code> objects.<br /><br /><pre name="code" class="java"><br />package com.blogspot.bigallan.converters;<br /><br />import java.text.*;<br />import java.util.*;<br />import javax.el.ValueExpression;<br />import javax.faces.component.UIComponent;<br />import javax.faces.context.FacesContext;<br />import javax.faces.convert.Converter;<br /><br />public class CalendarConverter implements Converter {<br /><br /> /**<br /> * Not implemented as the converter is one-way only.<br /> */<br /> public Object getAsObject(FacesContext ctx, UIComponent component, String value) {<br /> return null;<br /> }<br /><br /> public String getAsString(FacesContext ctx, UIComponent component, Object value) {<br /> <br /> // Get the Calendar to convert<br /> Calendar calendar = (Calendar) value;<br /><br /> String pattern = "";<br /><br /> // Obtain attributes specified along with the converter<br /> Map<String, Object> attributes = component.getAttributes();<br /><br /> // Check if the pattern attribute was specified<br /> if (!attributes.containsKey("pattern")) {<br /> System.out.println("pattern was not specified");<br /> return "";<br /> } else {<br /> pattern = (String)attributes.get("pattern");<br /> }<br /><br /> // Create a DateFormatter for the pattern<br /> DateFormat outputFormat = new SimpleDateFormat(pattern);<br /><br /> // Format the calendar<br /> try {<br /> Date date = originalFormat.parse(calendar.getTime());<br /> return outputFormat.format(originalDate));<br /> } catch (ParseException ex) {<br /> ex.printStackTrace()<br /> return "";<br /> }<br /> }<br />}<br /></pre><br /><br />In <code>faces-config.xml</code> you would declare the converter like this:<br /><br /><pre name="code" class="xml"><br /> <converter><br /> <converter-id>calendarConverter</converter-id><br /> <converter-class>com.blogspot.bigallan.converters.CalendarConverter</converter-class><br /> </converter><br /></pre><br /><br />We can now use the converter in a view:<br /><br /><pre name="code" class="xml"><br /> <h:outputText value="#{myBean.calendarObject}"><br /> <f:converter converterId="calendarConverter" /><br /> <f:attribute name="pattern" value="d. MMMM yyyy" /><br /> </h:outputText><br /></pre><br /><br />When the code is rendered in the browser you'll get the calendar converter to something like this <em>24. November 2008</em>. So far so good. However, what if we didn't specify the date pattern as static text, but rather bind it to a value. This technique is efficient when you reuse the pattern in many places and want to keep the pattern in a central place. So say that we had a managed-bean called <code>common</code> with a method <code>getDateFormat() : String</code> that would provide the pattern. The code would look like this:<br /><br /><pre name="code" class="xml"><br /> <h:outputText value="#{myBean.calendarObject}"><br /> <f:converter converterId="calendarConverter" /><br /> <f:attribute name="pattern" value="#{common.dateFormat}" /><br /> </h:outputText><br /></pre><br /><br />When the code is rendered in the browser you'll get a blank response and see the following in the log, "<code>pattern was not specified</code>". The log statement is generated from out code above where we check for the attribute named "pattern". This is because of a requirement in the JSF 1.2 specification (JSR-252) that states (Section 9.4.2) that literal (static) text should be stored in the attribute map of the component and non-literal texts should be stored in the value expression map of the component. So to get the pattern from the value expression map we modify the <code>getAsString</code> method as follows: <br /><br /><br /><pre name="code" class="java"><br /> public String getAsString(FacesContext ctx, UIComponent component, Object value) {<br /> <br /> // Get the Calendar to convert<br /> Calendar calendar = (Calendar) value;<br /><br /> String pattern = "";<br /><br /> // Obtain attributes specified along with the converter<br /> Map<String, Object> attributes = component.getAttributes();<br /> <br /> // Check if the pattern attribute was specified<br /> if (!attributes.containsKey("pattern")) {<br /><br /> ValueExpression ve = component.getValueExpression("pattern");<br /> if (ve == null) {<br /> System.out.println("pattern was not specified");<br /> return "";<br /> } else {<br /> pattern = (String) ve.getValue(ctx.getELContext());<br /> }<br /> } else {<br /> pattern = attributes.get("pattern");<br /> }<br /><br /> // Create a DateFormatter for the pattern<br /> DateFormat outputFormat = new SimpleDateFormat(pattern);<br /><br /> // Format the calendar<br /> try {<br /> Date date = originalFormat.parse(calendar.getTime());<br /> return outputFormat.format(originalDate));<br /> } catch (ParseException ex) {<br /> ex.printStackTrace()<br /> return "";<br /> }<br /> }<br /></pre><br /><br />The difference is that we now first check to see if there is a literal value specified. If not, we check if there is a value expression, and if there is no value expression either we will fail. If there is a value express we evaluate it and use it as our pattern.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-38947259996559705682008-10-28T21:21:00.004+01:002008-10-28T21:24:10.891+01:00Open Source vs. Commercial SoftwareToday I stumbled upon the following article about Open Source vs Commercial Software. It's quite entertaining and shows may of the pros and cons for both open source and commercial software licensing.<br /><br /><a target="_blank" href="http://www.isitedesign.com/insight/08_07/open-source-versus-commercial-web-software.cfm">http://www.isitedesign.com/insight/08_07/open-source-versus-commercial-web-software.cfm</a><br /><br />Enjoy!Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com1tag:blogger.com,1999:blog-6133363959081933104.post-6402203673232054682008-10-24T23:12:00.003+02:002008-10-24T23:53:48.673+02:00Replacing TopLink Essentials with OpenJPA as my persistence providerDuring the development of my latest pet project I decided to go head-on with many of the latest Java Enterprise APIs. One of these was the Java Persistence API (JPA), which I had already used in a handful of projects before. On previous projects the persistence requirements were very simple. I could use JPA out-of-the-box with TopLink Essentials which is the standard set-up for a JPA project in NetBeans/GlassFish. However, for this new pet project of mine I was in need of storing large binary objects (BLOBs). I was shocked to discover that TopLink Essentials doesn't support the Fetching configuration for relationships and properties. Instead it will <code>Fetch.EAGER</code> everything in a relationship and property. This made my application crash hard (<code>OutOfMemoryException</code>) when ever I would query for all entities containing the BLOB. So, I set out to replace the persistence provider. First I looked at Hibernate. I used Hibernate before JPA was released and never had much trouble with it. Unfortunately I found that Hibernate also doesn't support the fetching configuration (in JPA mode). That lead me to OpenJPA which really surprised me. It is well documented, clean, easy to use, and support the fetch configuration. I've now replaced the persistence provider on two projects with OpenJPA and the performance has increased significantly. However, here are a few gotchas that you have to look out for:<br /><br /><ul><br /><li>Auto-generated identity fields must not have a preset value in your JavaBean (hence, this would give you problems: <br /><code><br />@Id<br />@GeneratedValue(strategy = GenerationType.IDENTITY)<br />private Long id = 0L<br /></code><br /><br />Instead you should write<br /><code><br />@Id<br />@GeneratedValue(strategy = GenerationType.IDENTITY)<br />private Long id;<br /></code><br /></li><br /><li>Collections are <code>Fetch.LAZY</code> by default, so if you got an existing using TopLink Essentials, you have to double check that your relations are not throwing <code>LazyInitializationException</code> upon fetching outside the transation.<br /></li><br /><li>Remember to specify the Fetch depth (<code>openjpa.MaxFetchDepth</code>) in <code>persistence.xml</code> for using the <code>Fetch.EAGER</code> configuration</li><br /><li>TopLink Essentials compiles named queries when your application is deploy on the application server, OpenJPA on the other hand compiles the named queries upon first usage.</li><br /><li>When enabling SQL DDL on OpenJPA it doesn't generate foreign key constraints, unlike TopLink Essentials</li> <br /></ul><br /><br />That's all for now. I'd love to hear about your experiences with OpenJPA or any other persistence provide you find suitable for your need.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com14tag:blogger.com,1999:blog-6133363959081933104.post-1887871901196049532008-10-10T22:07:00.003+02:002008-10-10T22:19:15.513+02:00CyclingFor the past week I've been cycling to and from work. That might not sound like a big deal to you, but it has certainly been a challenge for me. In the past it has been all to easy to jump into the car and head off for work. No more, I've decided. The distance to work is very do-able, 5.5 KM each way. It's better for me and it's better for the environment. The biggest problem so far has been the uphill route on my way back. Nevertheless, I've made great progress already. The first day was absolutely hell! When I got to work I could barely breathe and I had to spend several minutes in the bike shed to compose myself. On the third day I managed to cut off 5 minutes from the ride, and today I was only plagued by fatigue in my joints. I'm looking forward to seeing how I'll be feeling on Monday and if I can take another week.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-3560904380417772602008-10-09T20:10:00.004+02:002008-10-09T20:34:30.323+02:00MyFaces and Facelets - The Definitive GuideFor the past five months or so, I've had the pleasure of participating as a contributing author and editor of the recently released Apress publication, "MyFaces and Facelets - The Definitive Guide".<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.amazon.com/Definitive-Guide-Apache-MyFaces-Facelets/dp/1590597370/ref=sr_1_1?ie=UTF8&s=books&qid=1223575969&sr=8-1"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNnucDokfMBrhc258JklWhZ9-9TemIM9keMTXCed4KlppGAkts2Eqe440T3X-Rll5uqZmV38hVuLHCOf9yrM8Q3qDEEsr25prtsZ3DpdklckSfp3-zy8MOR809N8q-DIC6A45O2tscPa0/s400/51SuoTS1F5L._SS500_.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5255220312266266498" /></a><br /><br />It was a great experience that I hope that I'll be able to relive in the near future on other book writing projects. What I liked about the book was the focus on the array of JSF components under the MyFaces Apache project. Most people seem to think that MyFaces is simply an implementation of the JavaServer Faces specification. <a href="http://myfaces.apache.org">MyFaces</a> is an umbrella project for JavaServer Faces related technologies. The most famous of the sub-projects is the <a href="http://myfaces.apache.org/tomahawk/index.html">Tomahawk components</a> project which provides a lot of useful JSF component that I certainly couldn't live without.<br /><br />The focus of the book is on technologies under the Apache MyFaces project as well as the Facelets technology. Facelets is another very important JSF technology that deserves more attention from the community. There are lots of people using Facelets, but little development is going on to make it truly professional.<br /><br />The book is not for newcomers to JSF, but for programmers already familiar with the basics of JSF. If you are looking to get familiar with JSF I can highly recommend <a href="http://www.manning.com/mann/">JSF In Action by Kito D. Mann published by Manning</a>. <br /><br />Thanks to <a href="http://zwadia.com/">Zubin Wadia</a> and <a href="http://www.jroller.com/HazemBlog/">Hazem Saleh</a> for making the project a great experience!Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-2085139241349223462008-09-01T08:01:00.004+02:002008-09-01T08:23:33.041+02:00On the road again... (Uganda)<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWOVLNOkNLwujC9TvVPNqwMRTGEekyofeUkVI-mVwazA6jVYgc7oBULzKNdCMZV6IqtJBeo7jYSjJ813n6UdpheXj5nTwDkKFHUDthqvqY42_5xxQ7Q0IttnzmSrM6oyU8Jr9dYC0J_CM/s1600-h/uganda.gif"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWOVLNOkNLwujC9TvVPNqwMRTGEekyofeUkVI-mVwazA6jVYgc7oBULzKNdCMZV6IqtJBeo7jYSjJ813n6UdpheXj5nTwDkKFHUDthqvqY42_5xxQ7Q0IttnzmSrM6oyU8Jr9dYC0J_CM/s400/uganda.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5240931779616923442" /></a> I'm on the road again again. This time I'm in Uganda. Uganda has to be one of my absolute favorite countries. I've be dropping in and out of Uganda the past nine years and even lived here for a few years. What I like about Uganda is the friendliness of the people. Ugandans have to be the friendliest people in the world! That is not to say that there are no dodgy Ugandans, but overall they are very easy people to get along with.<br /><br />This time I'm not travelling for the company. Instead I'm here to assess some business opportunities for the near future. You would be surprised how many IT-related business opportunities you will find in a developing economy.<br /><br />Anyways, just wanted to drop a post on the blog to show that I'm still alive and well. More about my trip later.<br /><br />By the way, if you are ever in Uganda there are two things you must try; 1) A whole deep fried tilapia from the Lake Victoria 2) Roasted pork. Both usually come with a range of accessories such as avocado, cassava, and matoke.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com2tag:blogger.com,1999:blog-6133363959081933104.post-75290267753076019892008-08-06T13:39:00.003+02:002008-08-06T13:42:05.048+02:00Project-based formatting in NetBeans 6.5Being part of the NetBeans Community Acceptance Testing (NetCAT) Programme has definate advantages. For one, you get to try out all the new features planned and influence how they will work before being released to the general public (that is not quite true....anyone can download the daily development builds).<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio0R1Q_zBchjenoVYdf2QzcDQSimyvNb6_Mq1xMfwd33hqrKr39nasK72BS07OCBTI_ZpXDxbFy2gExXsizMNC-dfG4yc8eSxXRt6yoIKYNXbmbieYr4EPK3n68WuPup3dT7se-M09x90/s1600-h/netbeans_project-based_formatting.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio0R1Q_zBchjenoVYdf2QzcDQSimyvNb6_Mq1xMfwd33hqrKr39nasK72BS07OCBTI_ZpXDxbFy2gExXsizMNC-dfG4yc8eSxXRt6yoIKYNXbmbieYr4EPK3n68WuPup3dT7se-M09x90/s400/netbeans_project-based_formatting.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5231368460202353842" /></a><br /><br />One of the features in the upcoming NetBeans 6.5 that I'm particularly happy about is Formatting by project. In NetBeans it has always been one configuration for all projects. This is slowly changing. During NetCAT for 6.1 the "Shared Library" feature was implemented to detach library management from NetBeans and thereby making projects more portable. So, this time the brilliant guys on the NetBeans development team implemented a feature making it possible to do project-based formatting. This is a great feature when you work on many different projects with different formatting requirements. Way to go! My hope is that for the next version of NetBeans they will also have made template management project-based.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com10tag:blogger.com,1999:blog-6133363959081933104.post-62564827969040629152008-06-25T08:25:00.005+02:002008-06-25T08:36:53.748+02:00On the road again...<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlzkYmSojnRH3siKpHiKBN-i3GV9wQqQhY-vFRKBNTbJJayy18QaRov8ZEAlJrQXzlsz2zMI8kzESnRNgUNbsQZDwQXI-J5q7pHyJjbEYkMUb3ck4oF5NdIW0cfRCCD2yfI_swiSGfxwc/s1600-h/zambia.gif"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlzkYmSojnRH3siKpHiKBN-i3GV9wQqQhY-vFRKBNTbJJayy18QaRov8ZEAlJrQXzlsz2zMI8kzESnRNgUNbsQZDwQXI-J5q7pHyJjbEYkMUb3ck4oF5NdIW0cfRCCD2yfI_swiSGfxwc/s400/zambia.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5215704204174425298" /></a> After a lovely week back home in Denmark with my family, I am once again on the road. This time I'm in Zambia to conduct training and hand-over a system we have built for COMESA. I've been to Zambia twice before and always enjoy coming here as it is clean and people are friendly. Anyways, I still hope this will be must last trip this year as I really need to spend some time at home with my family.<br /><br />Note: If you are planning on going to Zambia I can highly recommend staying at the Intercontinental. At my first visit I was staying at Holiday-Inn. The food and service was excellent but the rooms were terrible!Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-31232457536671553532008-06-12T20:31:00.001+02:002008-06-19T20:33:53.474+02:00Finalised my mission in Djibouti and KenyaToday, I finalised my mission to Djibouti and Kenya. I've still got another three days until I'm back home, but at least my work is done. While in Djibouti I carried out four days of System Administration training for the Web Portal I'm putting into place. That was followed by a one day steering committee meeting and four days workshop on Portal Management in Nairobi. It has been a very exhausting trip as I caught a food poisoning in Djibouti two days after having arrived. The food poisoning persisted until yesterday (almost a week) after which I had to go see a doctor. Fortunately, Nairobi Hospital is located just opposite the venue where I was conducting the workshop. So after having consulted a doctor and taken a few samples, I was given some medicine that would hope initially until they had time to examine my samples. So, today I got a call from the doctor explaining that I had a fungus growing in my stomach that was developing into a yest infection. I was then given some antibiotica and now feeling very fine. However, the last week was hell. Imagine having to do presentation from morning till afternoon with a constant stomach ache and having to run off to the wash room after every meal. Anyways, it is now being treated and I'm feeling much better.<br /><br />Besides my illness I got to talk and meet some wonderful people from around Eastern Africa. Tomorrow morning I'm off to Dubai where I'll spend one day before heading home to the family! Traveling can be very tiring and stressful when you'd rather spend time with your wife and baby.<br /><br />That's all for now folks.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-69320548405331311542008-06-01T14:54:00.002+02:002008-06-01T15:05:01.323+02:00Dubai is hot!!Dubai is hot, in more than one sense. I'm currently on my way to Djibouti to finalise some work on a project. On my way I stopped in Dubai for two days as I've always been curious about the place. I was very pleasantly surprised as people were nice, the place was clean, and the city was beautiful!<br /><br />The real hotness though is the weather. I couldn't help laughing when I saw the sticker on the window in my hotel room.<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhITn6WNrO7CmXAtccQ61BdW_mVfyrMDG9PRmnkuJd0bdbYzwlH13mWs794emI4bn3wYsD7HHmXVNygf2o92oloVe5ObPvxjlzZQXAKfKqRmcDM_bDMis515xyRNJEQc4ozOURYhLJtzJo/s1600-h/31052008(020).jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhITn6WNrO7CmXAtccQ61BdW_mVfyrMDG9PRmnkuJd0bdbYzwlH13mWs794emI4bn3wYsD7HHmXVNygf2o92oloVe5ObPvxjlzZQXAKfKqRmcDM_bDMis515xyRNJEQc4ozOURYhLJtzJo/s320/31052008(020).jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5206898226683297794" /></a><br /><br />It says "WARNING - Humidity from outside may activate the fire alarm". I can testify to the hotness (between 40 and 50 degrees celcius) as I spent a whole day on the top deck of a Big Bus tour around Dubai (if you only got a day in Dubai I would strongly suggest the Big Bus Tour - it' is excellent!).<br /><br />Of all the places I've been I'd give it a 9 out of 10.<br /><br />That's all for now - I'm off to Djibouti in a few minutes.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-47106039259377740742008-05-08T19:40:00.012+02:002008-05-27T15:24:13.856+02:00Using Facelets with NetBeans 6.1 (without nbfaceletssupport)--<br /><em>Update 27. May 2008: You can download the Facelets NetBeans plug-in for 6.1 from: <a target="_blank" href="http://project-template.googlecode.com/files/nbfaceletssupport-6.1.zip">http://project-template.googlecode.com/files/nbfaceletssupport-6.1.zip</a></em><br />--<br /><br />I'm a fan of Facelets when it comes to templating for JSF applications. Prior to version 6.1 of NetBeans I was using the <a href="https://nbfaceletssupport.dev.java.net/" target="_blank">nbfaceletssupport</a> plug-in. Sure, it had its quirks, but overall it was a good plug-in. After installing NetBeans 6.1 and really got into using all the new cool features (shared libraries being the most significant) I realised that the nbfaceletssupport plug-in for NetBeans 6.0 didn't work and a fix had not yet been released at the <a href="https://nbfaceletssupport.dev.java.net/" target="_blank">nbfaceletssupport project site</a> (<em>note: Po-Ting Wu of Sun Microsystems has provided <a href=" http://blogs.sun.com/poting/entry/build_and_install_facelets_support" target="_blank">instructions on how to re-compile the plug-in for NetBeans 6.1</a></em>). This also happened when I switched from NetBeans 5.5.1 to 6.0, so I anticipate that this will also happen in the future. So, I thought to myself, why not use the powerful XML support already built-in NetBeans to give me what I need. What I really needed the plug-in for is code completion. So, here goes. First I decided to drop JSP pages (<code>.jsp</code>) for JSP documents (<code>.jspx</code>). The difference being that <code>.jspx</code> is pure XML and <code>.jsp</code> is HTML. <br /><br /><u>Facelets file as a JSP page (.xhtml)</u>:<br /><pre name="code" class="xml"><br /><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br /><html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"><br /> <head><br /> <title>JSP facelets file</title><br /> </head><br /> <body><br /><br /> <ui:composition template="/resources/templates/page.xhtml"><br /> <ui:define name="pageTitle">This is a page title</ui:define><br /> <ui:define name="pageContent">This is the page content</ui:define><br /> </ui:composition><br /><br /> </body><br /></html><br /></pre><br /><br/><br /><u>Facelets file as a JSP document (.jspx)</u>:<br /><pre name="code" class="xml"><br /><jsp:root version="2.0" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:t="http://myfaces.apache.org/tomahawk" xmlns:c="http://java.sun.com/jstl/core" xmlns:jsfExt="http://java.sun.com/jsf/extensions/dynafaces"><br /> <ui:composition template="templates/page.xhtml"><br /> <ui:define name="pageTitle">This is a page title</ui:define><br /> <ui:define name="pageContent">This is the page content</ui:define><br /> </ui:composition><br /></jsp:root><br /></pre><br /><br /><br />When creating facelets file as JSP document in NetBeans you will automatically get code completion (without any third-party plug-ins).<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJWGg5-OhlGGNZ0VTUCJYtLQ12oiNieCP4rds532lype4DJNPnkpG8FEn3sVJkDRM3HDbppY_4TijavK_EzCqjtVJj_Ga0e141Jiho-DPktevZqSH4O9q9RQG3uuIyCrIxjnK0SEVEnvc/s1600-h/facelets-codecompletion.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJWGg5-OhlGGNZ0VTUCJYtLQ12oiNieCP4rds532lype4DJNPnkpG8FEn3sVJkDRM3HDbppY_4TijavK_EzCqjtVJj_Ga0e141Jiho-DPktevZqSH4O9q9RQG3uuIyCrIxjnK0SEVEnvc/s320/facelets-codecompletion.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5204319771523845506" /></a><br /><br />For this to work, ensure that the following configuration is set it web.xml:<br /><br /><pre name="code" class="xml"><br /><context-param><br /> <param-name>javax.faces.DEFAULT_SUFFIX</param-name><br /> <param-value>.jspx</param-value><br /></context-param><br /></pre><br /><br/><br />and that the <a href="http://allan.lykke.christensen.googlepages.com/facelets.tld" target="_blank">faclets tag library descriptor (TLD)</a> is accessible in the classpath (eg. <code>/WEB-INF/tlds</code>).<br /><br /><br /><br/><br />References:<br /><ul><br /><li><a href="https://nbfaceletssupport.dev.java.net/">nbfaceletssupport Project Site</a></li><br /><li><a hreF="http://blogs.sun.com/poting/entry/build_and_install_facelets_support">Po-Ting Wu's Weblog: Build and Install Facelets Support Modules on NetBeans 6.1</a></li><br /></ul>Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com6tag:blogger.com,1999:blog-6133363959081933104.post-35438643744951882952008-05-06T20:41:00.005+02:002008-05-06T21:12:00.148+02:00Yearly conference at the local Danish IT Society branchLast week I went to the yearly conference for my local <a href="http://www.danskit.dk" target="_blank">Danish IT Society</a> branch. The topic of the conference was Enterprise Architecture. I was a bit unsure about attending as I was expecting some obscure high-level talks that has never seen the light of day. I was pleasantly surprised! All the speakers did a great job and managed to cover the various facets (from theory, to best practice, to practice) of Enterprise Architecture. What especially caught my attention was the excellent governance and organisational re-structuring implemented at NyKredit headed by their CIO (and president of Danish IT Society) Lars Mathiesen (You can read <a href="http://www.computerworld.dk/tag/Lars_Mathiesen?art" target="_blank">articles about Mathiesen on Computerworld.dk</a>). From a vendor point-of-view the Vice President SOA Strategy, Ivo Totev of Software AG flew in from Germany. Last year I went for another meeting arranged by Danish IT Society with Scrum founder Jeff Sutherland. I wasn't too impressed as there was too much "going-around-the-bush" and not a clear business case for Scrum. Anyways, I didn't know what to expect from Ivo Totev's presesentation. However, I was very impressed with his presentation about the best practices of Enterprise Architecture coupled with anecdotes about what was working and not working with their clients. If you've got interest in Enterprise Architecture, Service-oriented Architecture (SOA), and Business Process Management, I suggest visiting Software AG's customer community at <a href="http://communities.softwareag.com/" target="_blank">http://communities.softwareag.com/</a> where you'll interesting resources such as podcasts, blogs, discussion groups and even a freely downloadable PDF version of the book "BPM Basics for Dummies".Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-36344847533590116742008-04-18T16:21:00.003+02:002009-05-29T09:24:41.714+02:00Creating a generic error page for JSFSometimes using <code>FacesMessage</code>s is not sufficient for reporting errors. For example, if you have a runtime error (invalid JSF mark-up or NullPointerExceptions) it is difficult to report them using <code>FacesMessage</code>.<br /><br />Creating a generic error page for JSF is similar to creating a generic error page for plain JSP applications. You'll need a configuration in web.xml to tell the servlet container to redirect errors to a given page. Then you'll need to create that page as well as a backing bean that can show you the stacktrace or error message.<br /><br />web.xml<br /><pre name="code" class="xml"><br /><?xml version="1.0" encoding="UTF-8"?><br /><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><br /><br /> ... markup for your web app ...<br /> <br /> <error-page><br /> <error-code>500</error-code><br /> <location>/Error.jsp</location><br /> </error-page><br /> <br /></web-app><br /></pre><br /><br />With that we will get the servlet container to forward any Internal Server Errors (HTTP 500) to the page Error.jsp.<br /><br />Okay, now we need to create a bean that will prepare the error message based on the exception that was thrown:<br /><br />Error.java<br /><pre name="code" class="java"><br />package bigallan.beans;<br /><br />import java.io.PrintWriter;<br />import java.io.StringWriter;<br />import java.util.Map;<br />import javax.faces.context.FacesContext;<br />import javax.servlet.ServletException;<br /><br />public class Error {<br /> <br /> public Error() {}<br /> <br /> public String getStackTrace() {<br /><br /> // Get the current JSF context<br /> FacesContext context = FacesContext.getCurrentInstance();<br /> Map requestMap = context.getExternalContext().getRequestMap();<br /><br /> // Fetch the exception<br /> Throwable ex = (Throwable) requestMap.get("javax.servlet.error.exception");<br /> <br /> // Create a writer for keeping the stacktrace of the exception<br /> StringWriter writer = new StringWriter();<br /> PrintWriter pw = new PrintWriter(writer);<br /><br /> // Fill the stack trace into the write <br /> fillStackTrace(ex, pw);<br /> <br /> return writer.toString();<br /> }<br /> <br /> /**<br /> * Write the stack trace from an exception into a writer.<br /> *<br /> * @param ex<br /> * Exception for which to get the stack trace<br /> * @param pw<br /> * PrintWriter to write the stack trace<br /> */<br /> private void fillStackTrace(Throwable ex, PrintWriter pw) {<br /> if (null == ex) {<br /> return;<br /> }<br /> <br /> ex.printStackTrace(pw);<br /> <br /> // The first time fillStackTrace is called it will always be a ServletException<br /> if (ex instanceof ServletException) {<br /> Throwable cause = ((ServletException) ex).getRootCause();<br /> <br /> if (null != cause) {<br /> pw.println("Root Cause:");<br /> fillStackTrace(cause, pw);<br /> }<br /> } else {<br /> // Embedded cause inside the ServletException<br /> Throwable cause = ex.getCause();<br /> <br /> if (null != cause) {<br /> pw.println("Cause:");<br /> fillStackTrace(cause, pw);<br /> }<br /> }<br /> }<br />}<br /></pre><br /><br />Now that we have the Backing Bean we need to register it in faces-config.xml:<br /><br /><pre name="code" class="xml"><br />.. usual faces-config stuff ..<br /><br /> <managed-bean><br /> <managed-bean-name>Error</managed-bean-name><br /> <managed-bean-class>bigallan.beans.Error</managed-bean-class><br /> <managed-bean-scope>request</managed-bean-scope><br /> </managed-bean><br /></pre><br /><br />And lastly the JSP page (Error.jsp) displaying the error:<br /><pre name="code" class="xml"><br />.. usual JSP header stuff ..<br /><br /><h:panelGrid><br /> <h:outputText value="The follow error occured:" /><br /> <h:inputTextarea style="width: 100%;" rows="20" readonly="true" value="#{Error.stackTrace}" /><br /></h:panelGrid><br /></pre><br /><br />That's all!<br /><br />Enjoy.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com13tag:blogger.com,1999:blog-6133363959081933104.post-29797629382455242132008-04-02T11:46:00.004+02:002008-04-13T23:53:18.023+02:00Tomato juice on airplanesI've just returned from a two week business trip and there is something that just keeps puzzling me when I fly. The amount of people that drink tomato juice on airplanes just amazes me. I have never dined with anyone who ordered tomato juice neither I have ever tasted it. However, on airplanes it seems like people have the urge to drink tomato juice. Flying back from Uganda (via Nairobi) to Amsterdam, an 8+ hours journey my co-passenger only had tomato juice! Tomorrow I've got to go buy myself some tomato juice to see what the craze is all about.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-19890939858798209532008-03-29T21:34:00.003+01:002008-03-29T22:01:51.231+01:00Using my Nokia 6120 for presentations<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicRto7bSU_ryS7Ik2f5I2SpfrDqqddnikvxd3-Qzb8rcJKwfh-0l2dFxOoxlVNpr2P801ceN5iReL1oGqQpNMN8cUpNC1rx-f5nYbb_Gs2m2mvZBy8sDBeMwC7tG-P3hf_fV1Edb37KSI/s1600-h/nokiawirelesspresenter1.jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicRto7bSU_ryS7Ik2f5I2SpfrDqqddnikvxd3-Qzb8rcJKwfh-0l2dFxOoxlVNpr2P801ceN5iReL1oGqQpNMN8cUpNC1rx-f5nYbb_Gs2m2mvZBy8sDBeMwC7tG-P3hf_fV1Edb37KSI/s400/nokiawirelesspresenter1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5183267185305565842" /></a> Today I noticed a cool feature of my new Nokia 6120 mobile phone. From it's download menu I was able to download a presentation tool from Nokia that turns the phone into a remote control for my PC. I've been thinking about getting a separate presentation device as I do a fair share of presentations and hate having to walk back to my PC everytime I want to move to the next slide. So, the way it works is by having a java application on the phone that emulates the mouse and an application on the PC that turns the keypresses on the phone into mouse movesments on the PC. I've tried it out with PowerPoint and works great. The tool also supports other applications out of the box such as Winamp and Media Player. The desktop tool can futhermore configure the remote control for other programs as well by specifying what should happen when each individual key on the phone is pressed.<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiExt-2IuMA1W_DHOGP1QW8SNVf_m27PK9-IRJPM7RaBVJ3abV-MpHuOoCIroOtC406KL38w-0ntm-t7Ro4dFsgGTm9OkrNRf6vYQGVDRwDEiWL6sUDJ6nsRMcdlYx9FNZBZcz5SntOkk/s1600-h/nokiawirelesspresenter2.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiExt-2IuMA1W_DHOGP1QW8SNVf_m27PK9-IRJPM7RaBVJ3abV-MpHuOoCIroOtC406KL38w-0ntm-t7Ro4dFsgGTm9OkrNRf6vYQGVDRwDEiWL6sUDJ6nsRMcdlYx9FNZBZcz5SntOkk/s320/nokiawirelesspresenter2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5183271360013777570" /></a><br /><br />The application (containing both the desktop application and the Java ME application) can be downloaded from the Nokia Community Portal: Mosh.<br /><br />Links:<br /><ul><br /><li>Nokia Wireless Presenter<br/><a href="http://mosh.nokia.com/content/379183464B5803F5E040050AEE044DC0" target="_blank">http://mosh.nokia.com/content/379183464B5803F5E040050AEE044DC0</a></li><br /><li>Nokia MOSH<br/><a href="http://mosh.nokia.com/" target="_blank">http://mosh.nokia.com/</a></li><br /></ul>Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-86947100463261370832008-03-19T01:18:00.003+01:002008-03-19T02:14:28.583+01:00Shared libraries finally made it to NetBeansToday I installed NetBeans 6.1 beta. I've always been a great fan of NetBeans and participated in the Community Acceptance Testing programme (NetCAT) for version 4.0 and 6.0.<br /><br />I haven't had time to go through all the changes yet, but one thing caught my attention immediately, the "Shared Library" functionality. It has always amazed me that this feature was not implemented way sooner. I have never used the built-in library manager for third-party libraries as the information about the libraries were not included with the projects, i.e. when I create a third-party library in the Library manager for say Apache Commons Configuration and use that in my project, it will break the built for not only other developers by also my continuous integration server. The alternative is to simply add the third-party library directly to the project as jars. The downside about that is that you can't attach the source and JavaDocs, so the inline code completion becomes almost useless. A third alternative is to manage dependencies completely outside of the IDE using Ant and Maven build scripts. I use to do this when using Eclipse, however then you have to update the dependencies in both the IDE and the build script = twice the work.<br /><br />Back to NetBeans 6.1. When creating a project you now get the offer to enable "sharable libraries". When enabling this feature you are asked to specify the location where the libraries should be saved. By default it will suggest <code>..\libraries</code>, which is a bit strange considering that it is outside the project folder. I guess it depends on the configuration management practices used on the project. Personally I always check in third-party libraries (as long as there are no licensing issues preventing it). In that way I alaways know that I can build the software anywhere on any machine (that includes my CI box).<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif8aIIn2W3iCHi54MmJ5_p9aaY0IxIrti6aStYrWy6QbGpuiYpcIWb8ocG-DwhDdjuaR1pMP3jN9Il8UIHkL_RxvOOGJoVTuh-A1XE4XTGUZwJ25ePjplQDAPQExeVXixtDWLLN9RJAKI/s1600-h/Screen+2.png"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif8aIIn2W3iCHi54MmJ5_p9aaY0IxIrti6aStYrWy6QbGpuiYpcIWb8ocG-DwhDdjuaR1pMP3jN9Il8UIHkL_RxvOOGJoVTuh-A1XE4XTGUZwJ25ePjplQDAPQExeVXixtDWLLN9RJAKI/s400/Screen+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5179254055312983106" /></a><br /><br />After having enabled sharable libraries, NetBeans will automatically copy library to the specified folder when you add dependencies to your project. Furthermore, if you find out that you'd rather have your sharable libraries in a different location, you can simply change the location click "Save" and it will re-create the sharable libraries. Very neat!<br /><br />I can imagine that they will continue working on the feature at NetBeans and this feature will become even better before the next release.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com5tag:blogger.com,1999:blog-6133363959081933104.post-85026299077816552352008-03-18T12:15:00.003+01:002008-03-18T12:18:23.767+01:00Example of using custom facelet tagsRather than using includes when creating templates you can create your own custom facelet tags without the husle of creating a JSF component from scratch. As an example, I'll create a menu tag that can be used to switch a selected menu item on and off.<br /><br />Here is the menu (save it as <code>/WEB-INF/facelets/tags/menu.xhtml</code>):<br /><br /><pre name="code" class="xml"><br /><ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"><br /><h:panelGrid columns="10"><br /> <h:outputText styleClass="menuItem" value="Home" /><br /> <h:outputText styleClass="menuItem" value="Some page" /><br /> <h:outputText styleClass="menuItem" value="Another page" /><br /> <h:outputText styleClass="menuItem" value="Third page" /><br /></h:panelGrid><br /></ui:composition><br /></pre><br /><br />Here is the cascanding style sheet:<br /><pre name="code" class="css"><br />.menuItem {<br /> border: 1px solid black;<br />}<br /><br />.menuItemSelected {<br /> background: red;<br /> color: white;<br /> font-weight: bold;<br />}<br /></pre><br /><br />To make the menu into a tag you create a facelets tag library. I'll call it <code>mytags.taglib.xml</code> and place it in <code>/WEB-INF/facelets/</code>:<br /><br /><pre name="code" class="xml"><br /><?xml version="1.0"?><br /><!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd"><br /><facelet-taglib><br /> <namespace>http://bigallan.blogspot.com/mytags</namespace><br /> <tag><br /> <tag-name>menu</tag-name><br /> <source>tags/menu.xhtml</source><br /> </tag><br /></facelet-taglib><br /></pre><br /><br />To make the web application recognise your tag library you need to update add the following context parameter to <code>web.xml</code>:<br /><pre name="code" class="xml"><br /><context-param><br /> <param-name>facelets.LIBRARIES</param-name><br /> <param-value>/WEB-INF/facelets/mytags.taglib.xml</param-value><br /></context-param><br /></pre><br /><br />If you have more than one custom tag library you can separate them with semicolons (;)<br /><br />On your pages you can now include the menu tag:<br /><br /><pre name="code" class="xml"><br /><?xml version='1.0' encoding='UTF-8' ?><br /><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br /><html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:mytags="http://bigallan.blogspot.com/mytags"><br /> <head><br /> <title>My page</title><br /> <link href="css/styles.css" rel="stylesheet" type="text/css" /><br /> </head><br /> <body><br /> <mytags:menu home="true" /><br /> </body><br /></html><br /></pre><br /><br />All we need to do now is to look out for the attributes of the custom tag. Attributes are automatically turned into variables on the tag pages, so we simply make the following changes to <code>/WEB-INF/facelets/tags/menu.xhtml</code>:<br /><br /><pre name="code" class="xml"><br /><ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"><br /> <h:panelGrid columns="10"><br /> <h:outputText styleClass="menuItem #{home == 'true' ? 'menuItemSelected' : ''}" value="Home" /><br /> <h:outputText styleClass="menuItem #{somePage == 'true' ? 'menuItemSelected' : ''}" value="Some page" /><br /> <h:outputText styleClass="menuItem #{anotherPage == 'true' ? 'menuItemSelected' : ''}" value="Another page" /><br /> <h:outputText styleClass="menuItem #{thirdPage == 'true' ? 'menuItemSelected' : ''}" value="Third page" /><br /> </h:panelGrid><br /></ui:composition><br /></pre><br /><br />To turn all menu items on you code do the following:<br /><br /><pre name="code" class="xml"><br /><?xml version='1.0' encoding='UTF-8' ?><br /><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br /><html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:mytags="http://bigallan.blogspot.com/mytags"><br /> <head><br /> <title>My page</title><br /> <link href="css/styles.css" rel="stylesheet" type="text/css" /><br /> </head><br /> <body><br /> <mytags:menu home="true" somePage="true" anotherPage="true" thirdPage="true" /><br /> </body><br /></html><br /></pre><br /><br />Enjoy!<br /><br />Suggested reading on the subject: <br /><ul><br /><li><a href="http://www.ibm.com/developerworks/java/library/j-facelets/" target="_new">Facelets fits JSF like a glove</a></li><br /><li><a href="https://facelets.dev.java.net/nonav/docs/dev/docbook.html" target="_new">Facelets Developer Documentation</a></li><br /></ul>Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com11tag:blogger.com,1999:blog-6133363959081933104.post-76721705830753694342008-03-17T23:21:00.003+01:002008-05-06T20:20:47.194+02:00Creating timers in EJB3While the EJB 3.1 expert group is working on the improved timer service using annotations (See <a href="http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesEJB31" target="_new">New Features in EJB 3.1</a>) I thought that I'd just bring a small entry on using the timer service in EJB 3.<br /><br />The timer service works by telling the service when it should timeout (i.e. when shall the "alarm" go off). You can add to this by telling it when it should timeout the first time, and how often (in ms) it should timeout after that. You define which methods on the bean that should be invoked upon timeout by annotating them <code>@Timeout</code>. The timer service is initialised by annotating a <code>TimerService</code> object as a <code>@Resource</code>.<br /><br />Okay, before I show the code, these are the methods that we need:<br /><br /><ul><br /><li>A method for starting the timer</li><br /><li>A method for stopping the timer</li><br /><li>One or more listener methods that will be invoked when the timer has timed-out</li><br /></ul><br /><br /><pre name="code" class="java"><br />@Stateless<br />public class MyTimerBean implements MyTimerLocal {<br /><br /> /** Service used for scheduling tasks. */<br /> @Resource private TimerService timerService;<br /><br /> /**<br /> * Starts the scheduler.<br /> * <br /> * @param startDate<br /> * Start date<br /> * @param interval<br /> * Interval at which the timeout shall repeat<br /> * @param timerName<br /> * Timer to start<br /> */<br /> public void startTimer(Date startDate, Long interval, String timerName) {<br /> this.timerService.createTimer(startDate, interval, timerName);<br /> }<br /><br /> /**<br /> * Stops a given scheduler.<br /> * <br /> * @param timerName<br /> * Timer to stop<br /> */<br /> public void stopTimer(String timerName) {<br /> for (Timer timer : (Collection<Timer>) this.timerService.getTimers()) {<br /> if (timer.getInfo() instanceof String) {<br /> if (((String) timer.getInfo()).equals(timerName)) {<br /> timer.cancel();<br /> return;<br /> }<br /> }<br /> }<br /> }<br /><br /> /**<br /> * {@link Timeout} event handler for generating a report.<br /> * <br /> * @param timer<br /> * Timer that timed out<br /> */<br /> @Timeout<br /> public void generateReport(Timer timer) {<br /> if (timer.getInfo() instanceof String) {<br /> if (((String) timer.getInfo()).equals("Generate Report")) {<br /> ... do some processing ...<br /> }<br /> }<br /> }<br /><br /> /**<br /> * {@link Timeout} event handler for cleaning the cache.<br /> * <br /> * @param timer<br /> * Timer that timed out<br /> */<br /> @Timeout<br /> public void cleanCache(Timer timer) {<br /> if (timer.getInfo() instanceof String) {<br /> if (((String) timer.getInfo()).equals("Clean Cache")) {<br /> ... do some processing ...<br /> }<br /> }<br /> }<br />}<br /></pre><br /><br />Right, so we have a method for starting a timer (<code>startTimer</code>). This method needs to be invoked in order to start the timer. This is one of the drawbacks of the <code>TimerService</code>, you cannot tell it to just start when the application is deployed (will be there in EJB3.1). Instead I use a Servlet Context Listener to invoke the <code>startTimer</code> method when the accompaying webapplication is deployed:<br /><br /><pre name="code" class="java"><br />public class TimerInitialisationListener implements ServletContextListener {<br /><br /> /** Local interface for {@link MyTimerBean}. */<br /> @EJB private MyTimerLocal myTimer;<br /><br /> /**<br /> * Initialises the timer service.<br /> * <br /> * @param event<br /> * Event that invoked the listener<br /> */<br /> public void contextInitialized(ServletContextEvent event) {<br /> Calendar now = Calendar.getInstance();<br /> now.set(Calendar.HOUR_OF_DAY, 0);<br /> now.set(Calendar.MINUTE, 0);<br /> now.set(Calendar.SECOND, 0);<br /> int year = now.get(Calendar.YEAR);<br /> int month = now.get(Calendar.MONTH);<br /> int dayOfMonth = now.get(Calendar.DAY_OF_MONTH);<br /> int hourOfDay = now.get(Calendar.HOUR_OF_DAY);<br /> int minute = now.get(Calendar.MINUTE);<br /> Long repeat = 60000L * 60L * 24L;<br /> LogFactory.getLog(TimerInitialisationListener.class).info("Start time: " + now.getTime());<br /> LogFactory.getLog(TimerInitialisationListener.class).info("Repeat every: " + repeat + " ms (" + (repeat / 3600000L) + " hrs)");<br /><br /> myTimer.startTimer(new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute).getTime(), 60000L * 60L * 24L, "Generate Report");<br /> }<br /><br /> /**<br /> * Context is uninstalled from the servlet container.<br /> * <br /> * @param event<br /> * Event that invoked the listener<br /> */<br /> public void contextDestroyed(ServletContextEvent event) {<br /> LogFactory.getLog(TimerInitialisationListener.class).info("Stopping timer");<br /> myTimer.stopTimer("Generate Report");<br /> }<br />}<br /></pre><br /><br />When you deploy the enterprise application you will see that the timer is set to start at midnight and execute every 86400000 ms (i.e. every 24 hours). What you will notice is that it is only the <code>generateReport</code> method that is executed fully at every timeout as I've put in a check to ensure that it is the correct action being executed. Instead of using a String as the identifier of the <code>Timer</code> you can create create your own custom objects as pass them instead (just remember to make it serializable).<br /><br />That's all for now. I'll bring another entry when EJB3.1 has been released and the new timer service annotations have been implemented.<br /><br />On a side note, I've used Quartz before and it's great - I just like to stick to the standards if it can do the job.<br /><br />Checkout the <a href="http://java.sun.com/javaee/5/docs/api/javax/ejb/TimerService.html">JavaDocs for the TimerService</a> for more information.<br /><br /><strong>UPDATE: 6. May 2008</strong>: Yesterday I was preparing some code using the timer service and I noticed that only the first method annotated with <code>@TimeOut</code> is executed upon timeout. Therefore, use only one <code>@TimeOut</code> method per SessionBean.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0tag:blogger.com,1999:blog-6133363959081933104.post-6131105967192167292008-03-15T00:25:00.005+01:002008-03-15T18:41:01.149+01:00Yippiee my new phone arrivedFor a long time my old phone has been way past retirement. It was a Qtec 2020 (I believe). I've always loved smartphones and hated the glorified music players (e.g. Sony Ericsson). I don't see the point in the fancy music player phones, but that is probably because I'm perfectly happy with my iPod and have no plans of replacing it for something less cool.<br /><br />Anyways, the Qtec acted up a long time ago. I used it as my organiser, phone and GPS for the car. When it suddenly started losing all its memory and at the same time I misplaced my stylus, I thought that it was high time to get a new phone. So this time I decided not to get a smartphone (mostly because the complete lack of market for smartphones in Denmark - this makes it very expensive!). Instead I got myself a <a href="http://europe.nokia.com/A4399010" target="_new">Nokia 6120</a> with all the latest services provided on the 3G network (Skype, MSN, MobileTV, etc).<br /><br /><a href="http://www.netbeans.org/kb/60/mobility/mobile-dilbert.html"><img src="http://www.netbeans.org/images/mobility/dilbert/end-result.png" align="left" border="0" style="padding-right: 10px;" alt="From the End-to-End Web Service Tutorial on NetBeans.org" title="From the End-to-End Web Service Tutorial on NetBeans.org" /></a> So far I'm loving the phone! It is fully compatible with Java MIDP 2.0 - so I'll have to get cracking with Java ME to make some applications soon. Can anybody recommend a good starting point for Java ME programming? My background in Java is purely enterprise and web. NetBeans got some cool mobile development aids that I'll be trying out - but I'd really like to know the basics before I start all the dragging and dropping. In anycase I think this is a good place to start: <a target="_new" href="http://www.netbeans.org/kb/60/mobility/index.html">NetBeans 6.0 Mobility Documentation</a>. It's got a pretty good tutorial for creating a mobile Dilbert browser.Allan Lykke Christensenhttp://www.blogger.com/profile/00646797647221121520noreply@blogger.com0