<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2302320112187282548</id><updated>2012-02-16T22:14:32.750+01:00</updated><category term='cooking'/><category term='Service'/><category term='Eager'/><category term='JPA'/><category term='Spring 3'/><category term='SQL'/><category term='FetchType'/><category term='JAVA'/><category term='CSS'/><category term='Google Wave'/><category term='Portal'/><category term='New Blog'/><category term='JOIN'/><category term='IT'/><category term='Hibernate'/><category term='ITSM'/><category term='UI'/><category term='One-To-Many'/><category term='Initial'/><category term='Google'/><category term='Apples'/><category term='Richfaces'/><category term='Portlet'/><category term='Development'/><category term='side dish'/><category term='Spring MVC'/><category term='Hourglass'/><category term='Database'/><category term='Software Design'/><category term='Start'/><category term='Delegation'/><category term='JSR 286'/><category term='Software'/><category term='mshop'/><category term='Responsibilities'/><category term='JSF'/><category term='Communication'/><category term='Persistence'/><category term='Events'/><category term='Liferay'/><category term='File Upload'/><category term='apple sauce'/><category term='Status'/><category term='OneToMany'/><title type='text'>Software Technology Geek</title><subtitle type='html'>From time to time I stumble upon problems while developing software whose answers are quite easy but poorly documented. This blog should serve as an information assembly for others as well as a reference book for myself</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-6509422216243556676</id><published>2011-09-07T21:00:00.002+02:00</published><updated>2011-09-07T21:05:57.005+02:00</updated><title type='text'>JAVA SE 7 has been released, what about JAVA SE 8</title><content type='html'>Simon Ritter gave a talk about the further development of the JAVA platform at JavaZone 2011 in Oslo. In this blog entry I will try to recap the main aspects of his presentation titled Moving Java Forward: Java SE 7 has been released, what about Java SE 8? and give some additional information where it seems feasible.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-style:italic;"&gt;Review in the History of Java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;JAVA has been started as a project at SUN led by James Gosling back in 1992. The outcome was a compact basis for writing applets which slowly evolved into one of the most widely used programming platforms.&lt;br /&gt;&lt;br /&gt;In 1998 the platform made a first major step away from being only a programming and execution environment for applets and swing applications. Back then SUN released version 1.1.2 - named JAVA 2.&lt;br /&gt;&lt;br /&gt;Then came 2004 and the announcement of JAVA 5 which finally paved the way into the enterprise platform market. A large set of bitterly missed features were added like generics or annotations.&lt;br /&gt;&lt;br /&gt;The next major release (JAVA 6) opened the JVM for scripting languages and provided some management and monitoring features.&lt;br /&gt;&lt;br /&gt;On 28th of July 2011 Oracle announced the latest version so far: JAVA 7. It contains features like:&lt;br /&gt;&lt;br /&gt;    * Parts of Project Coin (strings in switch statements, underscores in binary int literals)&lt;br /&gt;    * NIO.2 (I/O improvement towards enhanced platform independence)&lt;br /&gt;    * Fork/Join Framework (flexible and reusable synchronization barriers)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-style:italic;"&gt;Oracle acquired SUN - mission changed?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Since Oracle acquired SUN in January 2010, a lot of rumors and news were spread: positive and negative ones. Unfortunately, this as well as the fact that employees needed to re-position themselves within the new context led to a smaller break in the development of the language. But fortunately Oracle seems to have an open ear to the community and its customers and finally identified four major aspects to follow:&lt;br /&gt;&lt;br /&gt;    * grow the developer base&lt;br /&gt;    * grow the platform adoption&lt;br /&gt;    * increase the platform competitiveness&lt;br /&gt;    * adapt to change&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Beside that, they decided not to have the different stacks (JAVA SE, JAVA EE and JAVA ME) maintained separately but to combine all efforts in one committee in order to reflect that there is just one language.&lt;br /&gt;&lt;br /&gt;Although the company committed itself to the adoption of new ideas, this does not imply that they support the incorporation of all suggestions made by users. The overall goal concerning the implementation of language enhancements and new features is code readability. In his talk, Simon Ritter made a nice side blow towards Perl.&lt;br /&gt;&lt;br /&gt;Up to now it sounds like if Oracle is trying to get in charge on decisions made whether a feature will be added to the next release or not. But, as Simon Ritter argued in his talk, Oracle will stick to the java community process. However, they will slightly change it to meet the fusion of the three different language stacks: JAVA SE, JAVA EE and JAVA ME. In the end there is one committee which reflects the fact that there is only one language.&lt;br /&gt;&lt;br /&gt;Besides work concerning the language itself there is an ongoing process covering the consolidation of the two runtime environments living within the same company: Hotspot and JRockit, where Hotspot is used as source enhanced by JRockit features.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-style:italic;"&gt;JAVA SE 7 is out, what’s up to JAVA SE 8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So far I have just talked about the history and what happened when Oracle acquired SUN last year. Now I will give some hints on what’s coming next for JAVA 8, which is planned to be released in October 2012.&lt;br /&gt;&lt;br /&gt;Maybe I am wrong but from what I have heard and read so far, I would say that JAVA 8 promotes in large parts features that will enhance the multi-core support and bring new language features supporting the programming model required for these types of hardware architectures.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Lambda expressions in parallel collections&lt;/span&gt;&lt;br /&gt;A good point to start from is the sorting of collections. Actually it can be done in a serialized way by simply stepping through its contents using a simple for-loop. In JAVA 8 there will be parallel collections having a special filter method the progammer has to provide a predicate to. Filtering will be done with the best hardware utilization as possible. Beside that the collections will have a map function to filter out those attributes the caller is really interested in.&lt;br /&gt;&lt;br /&gt;Since JAVA 8 will bring lambda expressions to the platform, these can be used for the filtering purpose as well like:&lt;br /&gt;&lt;br /&gt;    cars.filter( #{Car c -&gt; c.seats == 2} ).map( #{Car c -&gt; c.age} ).max();&lt;br /&gt;    (returns the max. age of all cars having just two seats)&lt;br /&gt;&lt;br /&gt;Think about how much code you need to implement this feature using inner classes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Single Abstract Method Classes&lt;/span&gt;&lt;br /&gt;The concept of single abstract method (SAM) classes will make it easier to write inner classes having only one single method. Actually Runnable#run or Comparator#compare are examples of SAMs.&lt;br /&gt;&lt;br /&gt;Today we write the following:&lt;br /&gt;   &lt;br /&gt;    car.dummyMethod( new Runnable() { public void run(System.out.println(c.seats));});&lt;br /&gt;&lt;br /&gt;Using lambda expressions combined with SAM, we can do the same thing as follows:&lt;br /&gt;   &lt;br /&gt;    car.dummyMethod ( #{Car c -&gt; System.out.println(c.seats)} );&lt;br /&gt;&lt;br /&gt;But we will need to follow a set of rules to leverage SAM classes and lambda expressions at their best:&lt;br /&gt;&lt;br /&gt;   1. Lambda expressions are applicable only in a context where they could be converted into SAM types (eg Runnable, Comparator, Callable, EventHandler):&lt;br /&gt;          Object test = #{ 123 } is not allowed&lt;br /&gt;   2. Lambda expressions must not have any break or continue statements. Their return type is inferred from the overall set of return statements within the expression.&lt;br /&gt;   3. The variable this has the same value as it would have outside the statement.&lt;br /&gt;   4. Variables accessed from lambda expressions must not be modified (should be final).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Extension methods&lt;/span&gt;&lt;br /&gt;The main idea behind extension methods is the evolvement of APIs without breaking the backwards compatibility. Neal Gafter has written a nice blog entry about this: http://gafter.blogspot.com/2007/11/closures-prototype-update-and-extension.html&lt;br /&gt;At the core of if it, an interface which is extended after it has been made publicly available provides a static standard implementation of the new method(s). All classes implementing the interface and do not provide code for the new method will the standard implementation automatically.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Value classes&lt;/span&gt;&lt;br /&gt;Writing DTOs or value classes is one of the most time consuming tasks producing nothing else than classes having some attributes with their associated getter and setter methods. The concept of value classes tries to provide a simple solution where those attributes accessed via getter and setter methods are marked with a special keyword property, ie:&lt;br /&gt;   &lt;br /&gt;    class Node { Node property parent; Node property leftChild; Node propert rightChild; }&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Collection literals&lt;/span&gt;&lt;br /&gt;Collection literals will solve a common problem when filling lists, sets or maps on creation with pre-defined data. Today this works a follows:&lt;br /&gt;   &lt;br /&gt;    List&lt;Integer&gt; digits = Collections.unmodifiableList(Arrays.asList([1,2,3]);&lt;br /&gt;&lt;br /&gt;The new approach simplifies this:&lt;br /&gt;&lt;br /&gt;    List&lt;Integer&gt; digits = [1,2,3];&lt;br /&gt;    Map&lt;Integer, String&gt; namedDigits = { 1 : “one”, 2 : “two”, 3 : “three” };&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;module-info.java&lt;/span&gt;&lt;br /&gt;I am trying to write a good introduction to this the fourth time right now thus I am just showing the layout of the named file proposed in Simon Ritters talk:&lt;br /&gt;&lt;br /&gt;    module com.mnxfst.product @ 1.0 {&lt;br /&gt;        requires jdom @ 1.0;&lt;br /&gt;        requires rome @ 1.0;&lt;br /&gt;        class org.openjdk.aggregator.Main;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;The goal is not just to get rid of the classpath option but also to give the runtime environment sufficient information on how to run the named application correctly. Therefore only those library versions will be used that the developer named in module-info.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Profiles and Modules&lt;/span&gt;&lt;br /&gt;The idea behind profiles and modules is to have a single language platform where you choose appropriate components from to support a certain context, eg. enterprise or mobile. In JAVA 8 this is promoted through Project Jigsaw.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;font-style:italic;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Although most of the things I wrote about the upcoming JAVA 8 release are not quite new, I love to see how precise they got by now. Therefore I would like to dedicate the last paragraph to an evaluation of the listed topics:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Oracle acquired Sun&lt;/span&gt;&lt;br /&gt;I hope that Oracle will stick to the JAVA community process and keep the platform as free and accessible as possible.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Lambda expressions&lt;/span&gt;&lt;br /&gt;Although lambda expressions look a bit different from the java code we currently know, I expect them to improve the language a lot. Not only that they reduce the lines of written code but also make it more readable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Single Abstract Methods&lt;/span&gt;&lt;br /&gt;The same that applies to lambda expressions is also valid for SAMs: they will reduce the written code and make the remaining lines more readable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Value Classes&lt;/span&gt;&lt;br /&gt;In the age of code generators and other neat little helpers, I do not see a real use case for value classes beside the fact that they definitely will reduce the written code. Although I am a bit skeptical, I can say for sure that I will use them if they are available since it spares me to execute the code generator.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Collection Literals&lt;/span&gt;&lt;br /&gt;On first sight I was a bit excited about this feature since it makes it really easy to create and fill a collection, list or map on creation. But then they reminded me about the problems I had with the auto (un)boxing feature that moved in with JAVA 5 (int i = list.get(0) might exit with a NPE).&lt;br /&gt;Unfortunately I expect to see the same problems again thus this feature - although really nice and time saving - is not what I was waiting for.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;module-info&lt;/span&gt;&lt;br /&gt;Since Simon Ritter did not talk too exhaustivly about this feature I am not sure how it will work in practice. Let’s assume an application requires commons-logging 1.0 and a component used by the application requires commons-logging 2.0, how will this work without any troubles? If you’ve got any suggestions or information, please let me know since I am eager to learn about it.&lt;br /&gt;After all I think this is a nice enhancement cleaning up the classpath a bit.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Profiles and Modules&lt;/span&gt;&lt;br /&gt;Personally, I have never understood why there are three different type of JAVA specs: SE, EE and ME. Providing a common platform which can be extended concerning its installation footprint according to a specific profile seems to be reasonable. Therefore I must say that I am excited about this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-6509422216243556676?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/6509422216243556676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2011/09/java-se-7-has-been-released-what-about.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/6509422216243556676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/6509422216243556676'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2011/09/java-se-7-has-been-released-what-about.html' title='JAVA SE 7 has been released, what about JAVA SE 8'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-881157755700635741</id><published>2011-08-27T00:26:00.000+02:00</published><updated>2011-08-27T00:27:25.623+02:00</updated><title type='text'>Getting Primeface and JSF EL to work on Google App Engine</title><content type='html'>Lately I decided to use the &lt;a href="http://code.google.com/appengine/"&gt;Google cloud infrastructure&lt;/a&gt; as runtime foundation for a new project. At least two reasons led to a positive decision towards Google's App Engine: (1) a very strict but straight development paradigm and (2) the availability of a free quota.&lt;br /&gt;&lt;br /&gt;Since I need to get some presentable results quickly and did not want to spend precious time learning a new ui framework, I chose to try out the availability of JSF 2.0 on GAE in interaction with &lt;a href="http://www.primefaces.org"&gt;Primefaces&lt;/a&gt;. Fortunately I stumbled across an &lt;a href="https://sites.google.com/a/wildstartech.com/adventures-in-java/Java-Platform-Enterprise-Edition/JavaServer-Faces/sun-javaserver-faces-reference-implementation/configuring-jsf-20-to-run-on-the-google-appengine"&gt;article&lt;/a&gt; by Derek Berube on how to setup Primefaces in a GAE environment.&lt;br /&gt;&lt;br /&gt;Unfortunately I ran into two small but annoying errors that kept me away from making any progress for a while. The first one appeared everytime I requested a JSF page:&lt;br /&gt;&lt;br /&gt;java.lang.UnsupportedOperationException&lt;br /&gt;at javax.faces.context.FacesContext.getCurrentPhaseId(FacesContext.java:660)&lt;br /&gt;at javax.faces.event.ExceptionQueuedEventContext.&lt;init&gt;(ExceptionQueuedEventContext.java:158)&lt;br /&gt;at javax.faces.event.ExceptionQueuedEventContext.&lt;init&gt;(ExceptionQueuedEventContext.java:106)&lt;br /&gt;&lt;br /&gt;I could get rid of it by replacing the recommended &lt;a href="http://java.net/projects/mojarra/"&gt;Mojarra&lt;/a&gt; version 2.0.4 by 2.0.3.&lt;br /&gt;&lt;br /&gt;The second problem is associated with &lt;a href="http://download.java.net/maven/2/javax/el/el-api/2.2/el-api-2.2.jar"&gt;SUNs implementation&lt;/a&gt; of the expression language. So, I replaced it by the &lt;a href="http://www.jboss.org"&gt;JBoss&lt;/a&gt; implementation but had to make changes to get it working, since it breaks the law of not spawning any threads. Therefore I copied the modified contents of &lt;a href="http://code.google.com/p/ctpjava/source/browse/trunk/projects/google-appengine/samples/appengine-sample/src/org/jboss/el/util/ReferenceCache.java?r=75"&gt;org.jboss.el.util.ReferenceCache&lt;/a&gt;&lt;br /&gt;into the source folder of my project.&lt;br /&gt;&lt;br /&gt;Finally I got my project using Primefaces 2.2.1 and JBoss-EL 2.0.1 working.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-881157755700635741?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/881157755700635741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2011/08/getting-primeface-and-jsf-el-to-work-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/881157755700635741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/881157755700635741'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2011/08/getting-primeface-and-jsf-el-to-work-on.html' title='Getting Primeface and JSF EL to work on Google App Engine'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-7035821587952001029</id><published>2011-03-10T20:54:00.003+01:00</published><updated>2011-03-10T20:57:41.993+01:00</updated><title type='text'>Concurrency and Performance (Intro)</title><content type='html'>In my last blog articles, which are unfortunately more than 4 months old, I wrote about an application I developed during my spare time. Lately I began&lt;br /&gt;to migrate mshop from Spring 3 to JEE 6 for some reasons I may talk about in an upcoming article. &lt;br /&gt;&lt;br /&gt;During the refactoring, I came across certain concurrency and performance topics which puzzled me for some time. In parallel a colleague of mine established a company interal workshop series about current software development topics. Since I do think that concurrency and performance are two fundamental topics in software engineering, I offered to prepare a little series about these subjects. As these presentations contain no company secrets, I decided to present them at this place as well. If you have got any ideas or topics you would like to read about, do not hesitate to contact me.&lt;br /&gt;&lt;br /&gt;In order to make you aware of the subjects to come, I will present you a typical concurrency situation producing invalid data. Let's assume we have two actors A and B where both share a common bank account BA they try to withdraw money from. To map this into a software I used a very naive approach and modeled a bank account implementation as follows: &lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;/**&lt;br /&gt; * Provides an unsafe bank account implementation&lt;br /&gt; */&lt;br /&gt;public class UnsafeBankAccount {&lt;br /&gt; &lt;br /&gt; private int amount = 0;&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Initializes the account&lt;br /&gt;  * @param initialAmount&lt;br /&gt;  */&lt;br /&gt; public UnsafeBankAccount(int initialAmount) {&lt;br /&gt;  this.amount = initialAmount;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * Withdraws a named amount of money from the account. In&lt;br /&gt;  * case the withdrawal is allowed the method returns true&lt;br /&gt;  * otherwise false&lt;br /&gt;  * @param a&lt;br /&gt;  * @return&lt;br /&gt;  */&lt;br /&gt; public boolean withdrawMoney(int a) {&lt;br /&gt;  &lt;br /&gt;  if(a &lt; amount) {&lt;br /&gt;   amount = amount - a;&lt;br /&gt;   return true;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  return false;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * Returns the current amount of money stored &lt;br /&gt;  * in this account&lt;br /&gt;  * @return&lt;br /&gt;  */&lt;br /&gt; public int getAmount() {&lt;br /&gt;  return amount;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt;}&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;In a single-threaded environment this implementation would cause no trouble since it is accessed in a sequential manner. If you tend to use the &lt;i&gt;UnsafeBankAccount&lt;/i&gt; in a multi-threaded setting, you might observe inconsistent states between the results of &lt;i&gt;UnsafeBankAccount#withdrawMoney&lt;/i&gt; and &lt;i&gt;UnsafeBankAccount#getAmount&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Assume the following situation: the actors A and B share a common bank account BA they wish to withdraw money from. At first each checks the current state of the account calling &lt;i&gt;UnsafeBankAccount#getAmount&lt;/i&gt; and then decide to withdraw a certain amount of money without overchecking the account. What &lt;i&gt;could&lt;/i&gt; happen is:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;   &lt;li&gt;The initial amount of BA is $100&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;A checks the account and sees that the account holds $100&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;A orders to withdraw $30 from the account&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;While the software validates the condition of the if-clause in &lt;i&gt;UnsafeBankAccount#withdrawMoney&lt;/i&gt; to true the scheduler interrupts the computation and hands over the control to the thread of B&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;B checks the account as well and also sees that the account holds $100&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;B orders to withdraw $80 from the account&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;The execution thread handling the order of B as well validates the if-clause in &lt;i&gt;UnsafeBankAccount#withdrawMoney&lt;/i&gt; to true, recalculates the current state of the account and returns true&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;Now the execution thread handling the order of A also recalculates the current state of the account and returns true as well&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;If any of the customers checks BA, they will see that the account is overchecked by $10&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;A different situation could be:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;   &lt;li&gt;The initial amount of BA is $100&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;A orders to withdraw $30 from the account&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;Before &lt;i&gt;UnsafeBankAccount#withdrawMoney&lt;/i&gt; has the chance to update the variable &lt;i&gt;amount&lt;/i&gt;, the scheduler interrupts the current thread&lt;/li&gt;&lt;br /&gt;   &lt;li&gt;Now B checks the current account state by calling &lt;i&gt;UnsafeBankAccount#getAmount&lt;/i&gt; and sees that the account still holds $100&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;To ensure that the bank account works as expected in both cases, we need to ensure that (1) the amount variable is always in a consistent state and (2) each call returning the amount sees the most current value.&lt;br /&gt;The magic element in this case is the synchronized modifier which will be used to guard the reading and writing accesses to &lt;i&gt;amount&lt;/i&gt;. This leads to the following modification:&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;/**&lt;br /&gt; * Provides a thread-safe implementation of a bank account&lt;br /&gt; */&lt;br /&gt;public class ThreadSafeBankAccount {&lt;br /&gt;&lt;br /&gt; private Integer amount = null;&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * Initializes the account&lt;br /&gt;  * @param intialAmount&lt;br /&gt;  */&lt;br /&gt; public ThreadSafeBankAccount(int intialAmount) {&lt;br /&gt;  this.amount = Integer.valueOf(intialAmount);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; /**&lt;br /&gt;  * Withdraws a named amount of money from the account. In&lt;br /&gt;  * case the withdrawal is allowed the method returns true&lt;br /&gt;  * otherwise false&lt;br /&gt;  * @param a&lt;br /&gt;  * @return&lt;br /&gt;  */&lt;br /&gt; public boolean withdrawMoney(int a) {&lt;br /&gt;&lt;br /&gt;  synchronized(amount) {&lt;br /&gt;   if(a &lt; amount) {&lt;br /&gt;    amount = amount - a;&lt;br /&gt;    return true;&lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;   return false;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * Returns the current amount of money stored &lt;br /&gt;  * in this account&lt;br /&gt;  * @return&lt;br /&gt;  */&lt;br /&gt; public int getAmount() {&lt;br /&gt;  synchronized(amount) {&lt;br /&gt;   return amount;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;The implementation above ensures that no read or write access takes place while another thread reads or writes the &lt;i&gt;amount&lt;/i&gt; variable. Depending on the use case mapped by the implementation, the synchronisation used in the getter method could be omitted, eg. the caller does not wish to retrieve the latest and most current value.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-7035821587952001029?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/7035821587952001029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2011/03/concurrency-and-performance-intro.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/7035821587952001029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/7035821587952001029'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2011/03/concurrency-and-performance-intro.html' title='Concurrency and Performance (Intro)'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-1931626137343132196</id><published>2010-10-18T17:56:00.014+02:00</published><updated>2010-10-18T21:48:44.445+02:00</updated><title type='text'>mShop - Screenshots</title><content type='html'>It's been a while (again) since I provided you with information about the current state of affairs concerning the mshop implementation. Today I would like to present some screenshots and detailed information about how I implemented the features I presented in my last post (eg. object class hierarchy definition and alike).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Creating attribute types&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Object class definitions within the application consist of an unique name and a set of attributes. Each ettribute has its own value type like &lt;i&gt;STRING&lt;/i&gt;, &lt;i&gt;INTEGER&lt;/i&gt; or &lt;i&gt;TIMESTAMP&lt;/i&gt;. Assigning these atomic values types directly would strip down the possibility to have a differentiated handling per attribute. Take an object class &lt;i&gt;person&lt;/i&gt; having attributes &lt;i&gt;firstname&lt;/i&gt; and &lt;i&gt;lastname&lt;/i&gt; both of type &lt;i&gt;STRING&lt;/i&gt; for example. When an user approves the order of an instance of type &lt;i&gt;person&lt;/i&gt; the application could not handle the values of &lt;i&gt;firstname&lt;/i&gt; and &lt;i&gt;lastname&lt;/i&gt; in different ways but as every &lt;i&gt;STRING&lt;/i&gt; in the context. The reason is that attribute names are just free text values having no impact on the processing.&lt;br /&gt;&lt;br /&gt;In order to remove that limitation, mshop introduces own &lt;i&gt;attribute types&lt;/i&gt; where each type is assigned a concrete value type like &lt;i&gt;STRING&lt;/i&gt; or &lt;i&gt;INTEGER&lt;/i&gt;. Take the example above. We would create an attribute type &lt;i&gt;FIRSTNAME&lt;/i&gt; of value type &lt;i&gt;STRING&lt;/i&gt; and maybe a type &lt;i&gt;BIRTHDAY&lt;/i&gt; of value type &lt;i&gt;TIMESTAMP&lt;/i&gt;. This gives the user the option to modify the handling of approved instances according the attribute types, eg combining the values of types &lt;i&gt;FIRSTNAME&lt;/i&gt; and &lt;i&gt;LASTNAME&lt;/i&gt; to a value &lt;i&gt;givenName&lt;/i&gt; that is provided to a ldap server.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh4.ggpht.com/_cjVfsyitfcc/TLxt0Dbzj9I/AAAAAAAAAD8/QOXHLDss6m8/create-attribute-type.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 418px; height: 231px;" src="http://lh4.ggpht.com/_cjVfsyitfcc/TLxt0Dbzj9I/AAAAAAAAAD8/QOXHLDss6m8/create-attribute-type.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Creating object class orders&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The driving force behind mshop are user defined object classes which serve as blueprints for concrete object instances (eg. class &lt;i&gt;com.mnxfst.blog.Person&lt;/i&gt; is the defining type for instance &lt;i&gt;Christian Kreutzfeldt&lt;/i&gt;). Therefore you need to define classes before your users are able to order instances of those types.&lt;br /&gt;&lt;br /&gt;Creating an object class requires you to provide some more detailed information and must be carried out with a certain amount of care since it is the foundation of the later running system.&lt;br /&gt;&lt;br /&gt;The definition dialog has three different tabs. The first tab lets you provide &lt;i&gt;common&lt;/i&gt; information about the class like its name, if it is an abstract class, the activation date or the set of attributes.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh3.ggpht.com/_cjVfsyitfcc/TLxyJQmx89I/AAAAAAAAAEA/Vw_IzaF2V6M/01-create-object-class-order.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 340px; height: 391px;" src="http://lh3.ggpht.com/_cjVfsyitfcc/TLxyJQmx89I/AAAAAAAAAEA/Vw_IzaF2V6M/01-create-object-class-order.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh3.ggpht.com/_cjVfsyitfcc/TLx0pNcKc0I/AAAAAAAAAEE/iwHWwTNsH_4/02-create-object-class-order.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 381px; height: 256px;" src="http://lh3.ggpht.com/_cjVfsyitfcc/TLx0pNcKc0I/AAAAAAAAAEE/iwHWwTNsH_4/02-create-object-class-order.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The second tab lets you specify detailed information on how certain object class instances will behave in the approval workflow. You can define for each configuration (attribute value setting) the required audit level (how many people must approve the order) and what kind of operations are allowed for specific value settings. &lt;br /&gt;&lt;br /&gt;The attached screenshot shows a configuration where object instances of the ordered type which are referencing the city of Hamburg and the specific street &lt;i&gt;Kehrwieder&lt;/i&gt; need to be approved by two people for the operations &lt;i&gt;create&lt;/i&gt;, &lt;i&gt;update&lt;/i&gt; and &lt;i&gt;delete&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;These settings alone do not configure the concrete workflow path afterwards but represent the building bricks for it. In case an user orders an instance of type &lt;i&gt;Person&lt;/i&gt; the application checks the attribute value settings and matches them against the associated workflow configuration in order to look up  the required audit level.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh3.ggpht.com/_cjVfsyitfcc/TLybFW3tJxI/AAAAAAAAAEI/0KvbtNly5is/03-create-object-class-order.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 405px; height: 194px;" src="http://lh3.ggpht.com/_cjVfsyitfcc/TLybFW3tJxI/AAAAAAAAAEI/0KvbtNly5is/03-create-object-class-order.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The third tab finally lets you define approvers for ordered object class instances. Compared to the second tab, this one behaves nearly the same but adds another field: &lt;i&gt;priority level&lt;/i&gt;. The audit level defines on which approval level the named user is provided with an workflow item for a specific order. The priority level gives you the opportunity to define proxy rules in case a named approver does not answer within a defined timespan.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh4.ggpht.com/_cjVfsyitfcc/TLyeLeFmb2I/AAAAAAAAAEM/36kn6nRAko4/04-create-object-class-order.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 330px; height: 231px;" src="http://lh4.ggpht.com/_cjVfsyitfcc/TLyeLeFmb2I/AAAAAAAAAEM/36kn6nRAko4/04-create-object-class-order.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Approving object class order&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;After having fully specified an object class, it needs to be approved by at least one object class approver. The object class approver opens the dialog displayed below and chooses to view all &lt;i&gt;open/unanswered&lt;/i&gt; object class orders. In order to have the chance to validate the object class configuration he is allowed to browse through all the settings the originator made. The handling and behavior is quite straight forward and needs only little description.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh3.ggpht.com/_cjVfsyitfcc/TLyfEkJUZXI/AAAAAAAAAEQ/Tll7pj_kPeg/01-approve-object-class-order.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 349px; height: 288px;" src="http://lh3.ggpht.com/_cjVfsyitfcc/TLyfEkJUZXI/AAAAAAAAAEQ/Tll7pj_kPeg/01-approve-object-class-order.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Order object class instance&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In case an object class has been approved its available to all users which are allowed to order instances of that type. The screenshot down below shows a set of classes the user can choose from.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh4.ggpht.com/_cjVfsyitfcc/TLygjUZu49I/AAAAAAAAAEU/VOK4ra2SH0Y/01-order-object-class-instance.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 375px; height: 340px;" src="http://lh4.ggpht.com/_cjVfsyitfcc/TLygjUZu49I/AAAAAAAAAEU/VOK4ra2SH0Y/01-order-object-class-instance.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The next step shows a set of available parent classes the user can choose from to define a hierarchy.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh4.ggpht.com/_cjVfsyitfcc/TLyhRueNbCI/AAAAAAAAAEY/WCgmZLsXIuk/02-order-object-class-instance.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 375px; height: 125px;" src="http://lh4.ggpht.com/_cjVfsyitfcc/TLyhRueNbCI/AAAAAAAAAEY/WCgmZLsXIuk/02-order-object-class-instance.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The third step lets the user specify values for the assigned attributes. The last step finally sends the object class instance order into the workflow process.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh3.ggpht.com/_cjVfsyitfcc/TLyh3RMpR_I/AAAAAAAAAEc/TtqE4TTfqn8/03-order-object-class-instance.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 317px; height: 229px;" src="http://lh3.ggpht.com/_cjVfsyitfcc/TLyh3RMpR_I/AAAAAAAAAEc/TtqE4TTfqn8/03-order-object-class-instance.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Approve order object class instance&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The final view I would like to present today is the dialog for approving object class instance orders. Each approver is presented a list of all orders that he is allowed to approve / reject. By selecting a single workflow item he is able to see all required order details like common information (audit level, priority level, object class name and alike) and the attribute value settings. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh5.ggpht.com/_cjVfsyitfcc/TLyi7sZON8I/AAAAAAAAAEg/0UxWM3LA3pQ/01-approve-order-object-class-instance.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 407px; height: 242px;" src="http://lh5.ggpht.com/_cjVfsyitfcc/TLyi7sZON8I/AAAAAAAAAEg/0UxWM3LA3pQ/01-approve-order-object-class-instance.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh3.ggpht.com/_cjVfsyitfcc/TLyi7tRQUmI/AAAAAAAAAEk/Yrt5wXj2_4s/s640/02-approve-order-object-class-instance.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 286px;" src="http://lh3.ggpht.com/_cjVfsyitfcc/TLyi7tRQUmI/AAAAAAAAAEk/Yrt5wXj2_4s/s640/02-approve-order-object-class-instance.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Actually most of the dialogs do not look very fancy and colorful but I will try to improve on that until the first release of the application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-1931626137343132196?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/1931626137343132196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2010/10/mshop-screenshots.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/1931626137343132196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/1931626137343132196'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2010/10/mshop-screenshots.html' title='mShop - Screenshots'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_cjVfsyitfcc/TLxt0Dbzj9I/AAAAAAAAAD8/QOXHLDss6m8/s72-c/create-attribute-type.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-618400815917506171</id><published>2010-06-30T21:34:00.002+02:00</published><updated>2010-06-30T21:36:16.385+02:00</updated><title type='text'>mShop - The object classes</title><content type='html'>It's been a while since I wrote my last post about the mshop application. Today I would like to present the &lt;br /&gt;data structure which is visible to the application user and offers him the ability to model his problem domain&lt;br /&gt;as best as possible. &lt;br /&gt;&lt;br /&gt;As I have stated in my last article, most applications leave you with a rather inflexible data structure which&lt;br /&gt;requires you either to adopt your problem domain to the software system or modify the software system in its&lt;br /&gt;core parts to support your problem domain. Neither way is an acceptable solution to your problem.&lt;br /&gt;&lt;br /&gt;When I started to design the mshop application, I had in mind that establishing a kind of a centralized order process&lt;br /&gt;within a company must adhere to the fact that the users are not willing to use one service for ordering objects &lt;br /&gt;of type A (like user accounts) and another service for ordering objects of type B (like computers or other office&lt;br /&gt;supplies). Beside that the whole workflow based approval process needs to be independent from the concrete object&lt;br /&gt;types handled by the system.&lt;br /&gt;&lt;br /&gt;Therefore I tried to define a very generic data structure and a highly flexible approval engine. Both elements&lt;br /&gt;will be presented more detailed in the following paragraphs.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Data structure&lt;/b&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;The data structure basically follows the &lt;a href="http://en.wikipedia.org/wiki/Object_oriented_design"&gt;object oriented design&lt;/a&gt; techniques used for software component specification. The following types are provided&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;attributes&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;attribute types (like integer, date ...)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;classes&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;objects (as class instances)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;A class is composed of an arbitrary number of attributes which have a specific type which could be a&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;INTEGER&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;DECIMAL&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;STRING&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;TIMESTAMP&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;BOOLEAN&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;BLOB&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;OBJECT_REFERENCE&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;CUSTOM_TABLE_REFERENCE&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Most of these types are self-explanatory except &lt;i&gt;OBJECT_REFERENCE&lt;/i&gt; and &lt;i&gt;CUSTOM_TABLE_REFERENCE&lt;/i&gt;. An attribute&lt;br /&gt;of type &lt;i&gt;OBJECT_REFERENCE&lt;/i&gt; is allowed not to hold a value but a reference to another object (eg. a user references&lt;br /&gt;another user to model the supervisor relationship). This gives the user the maximum power to model complex relationships.&lt;br /&gt;&lt;br /&gt;The other special type (&lt;i&gt;CUSTOM_TABLE_REFERENCE&lt;/i&gt;) has been implemented but is not in use. The idea behind this attribute type is the ability to reference objects or values that are completely unknown to the application and must not be modeled&lt;br /&gt;within the domain. Actually this is just an extension point that might be used in the future.&lt;br /&gt;&lt;br /&gt;When an attribute is assigned to a class, the user needs to specify some attribute values of this relationship&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;NAME - name of the attribute (eg. firstname, lastname, email, ...)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;DESCRIPTION&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;MIN_TIMES - defines how many values must be assigned to this at minimum (used for list modeling)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;MAX_TIMES - defines how many values can be assigned to this at maximum (used for list modeling)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;REQUIRED - a value for this attribute must be provided&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;VISIBILITY - defines the visibility of this attribute (public, protected, private - read more down below)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;ATTRIBUTE_TYPE - defines the attribute type (eg. INTEGER, DECIMAL, STRING, ...)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The &lt;i&gt;VISIBILITY&lt;/i&gt; of an attribute defines the scope within the attribute is visible to any accessor. If the attribute&lt;br /&gt;is marked to be &lt;i&gt;PRIVATE&lt;/i&gt; only the class or instance is allowed to read and write values from / to it. If the attribute is&lt;br /&gt;marked to be &lt;i&gt;PROTECTED&lt;/i&gt; the class or instance and all ancestors and its instances of the defining class are allowed&lt;br /&gt;to read and write values from / to it. If the attribute is marked to be &lt;i&gt;PUBLIC&lt;/i&gt; all classes and instances are allowed to&lt;br /&gt;read and write values from / to it.&lt;br /&gt;&lt;br /&gt;Although there are no limitations concerning the depth of a class hierarchy and the number of attributes within it, the user&lt;br /&gt;must be aware that each new level has an impact on the overall performance of the current hierarchy.&lt;br /&gt;&lt;br /&gt;After having defined the classes the application allows to create instances (objects) from these blueprints. Therefore the application reads the class definition (including all ancestors) and provides the user with a dialog that requires him to provide values for all attributes visible to him. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Approval engine&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The job of the approval engine is to analyze incoming object orders using a &lt;a href="http://en.wikipedia.org/wiki/Xpath"&gt;XPath&lt;/a&gt; like expression language and forward them to a suitable set of approvers (might be a single one as well). If a required number of users have approved the order it will be either forwarded for final processing (like creating user accounts or ordering printers) or - if required - forwarded to another set of approvers (two men rule). This depends on approval information provided for the underlying class. &lt;br /&gt;&lt;br /&gt;Each class can have one or a whole set of approval information where each element defines how entities must be handled that apply to the given path expressions:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;OBJECT_CLASS - defines the class that this element provides approval information for&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;AUDIT_LEVEL - defines the audit level (1..n, two men rule)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;DISABLED - the element will not be used by the approval engine&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;ORDER_CREATE_ALLOWED - if an object applies to the given path expressions, it might be created&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;ORDER_UPDATE_ALLOWED - if an object applies to the given path expressions, it might be updated&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;ORDER_DELETE_ALLOWED - if an object applies to the given path expressions, it might be deleted&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;PATH_EXPRESSIONS - set of strings holding path expressions. if any object positively evaluates against all of these expressions, the options mentioned above will be applied&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The approval engine reads the type of an incoming object order and fetches all approval information entities for that type. All path expressions of each entity are evaluated against the object. If any of them fits, the rules defined by the associated approval information entity will be used by the engine on how to further process the object order (eg. which audit level it requires, if an object might be&lt;br /&gt;created at all).&lt;br /&gt;&lt;br /&gt;Now the engine finally needs to identify all possible approvers for the ordered object. Therefore a quite similar information entity is used. If differs from the one above only by adding the following attribute&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;PRIORITY_LEVEL&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The &lt;i&gt;PRIORITY_LEVEL&lt;/i&gt; is used by the approval engine in case the current set of approvers did not respond within a given timespan. Now the engine needs to forward the order element to a second/third/fourth ... round of approvers where the priority level identifies the specific round when an approver enters the ring. &lt;br /&gt;&lt;br /&gt;Before the engine forwards an order to an approver it uses the path expression set to evaluate if the ordered object can be handled by a specific approver. If the path expressions are all valid, the engine checks if the operation (create, update, delete) might be carried out the by approver at all.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Although I just provided you with only a small view, I guess you got a good hint on how flexible the application's data structure is. In the upcoming articles I will talk a bit about the license model of mshop and provide you with some screenshots and more information about key features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-618400815917506171?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/618400815917506171/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2010/06/mshop-object-classes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/618400815917506171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/618400815917506171'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2010/06/mshop-object-classes.html' title='mShop - The object classes'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-3119904542800717652</id><published>2010-04-21T00:16:00.000+02:00</published><updated>2010-04-21T00:18:28.995+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Responsibilities'/><category scheme='http://www.blogger.com/atom/ns#' term='Service'/><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='Delegation'/><category scheme='http://www.blogger.com/atom/ns#' term='ITSM'/><category scheme='http://www.blogger.com/atom/ns#' term='mshop'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Design'/><title type='text'>mShop - an introduction</title><content type='html'>Today I would like to start a little series of articles about a personal software project called &lt;i&gt;mShop&lt;/i&gt;. The mShop application is a response to a discussion I had with some friends a while ago about the handling of internal orders for office supplies and other items you need to carry out your daily work, eg. printer paper, pencils, desktop computers, user accounts or permissions. The key question was if there are any professional tools to comply with the following requirements:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;define products having arbirary attributes during runtime&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;flexible delegation of responsibilites concerning the approval of product orders&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;automatic delegation of approved order items into sub-systems for further processing, eg. unix server for user account creation.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;being cheap within boundaries&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;We came to the conclusion that there are indeed sophisticated tools like &lt;a href="www.activeentry.info"&gt;ActiveEntry&lt;/a&gt; or one might use an existing open source shopping platform and modify it according to his needs. BUT, the solutions are either expensive, limited in their feature set or require the owner to use their inflexible data structures. &lt;br /&gt;&lt;br /&gt;That finally let to my decision to specify and implement an application that is compatible with the features mentioned above. According to my nick &lt;i&gt;mnxfst&lt;/i&gt; I took the first char (&lt;i&gt;m&lt;/i&gt;) of it and added the postfix &lt;i&gt;shop&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;To keep the articles short, I split them up into a series where each entry concentrates on a different key feature of mShop. The next article will discuss the definition of objects users might order via the web shop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-3119904542800717652?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/3119904542800717652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2010/04/mshop-introduction.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/3119904542800717652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/3119904542800717652'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2010/04/mshop-introduction.html' title='mShop - an introduction'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-493608301493018582</id><published>2010-03-21T12:59:00.004+01:00</published><updated>2010-03-28T12:30:36.712+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JOIN'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Persistence'/><category scheme='http://www.blogger.com/atom/ns#' term='One-To-Many'/><category scheme='http://www.blogger.com/atom/ns#' term='OneToMany'/><category scheme='http://www.blogger.com/atom/ns#' term='Database'/><category scheme='http://www.blogger.com/atom/ns#' term='Software'/><category scheme='http://www.blogger.com/atom/ns#' term='Eager'/><category scheme='http://www.blogger.com/atom/ns#' term='FetchType'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='JAVA'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>FetchType.EAGER - Cannot simultaneously fetch multiple bags</title><content type='html'>I just came across a quite interesting problem that might give you a hint on how &lt;a href="http://www.hibernate.org"&gt;hibernate&lt;/a&gt; internally works. Assume you have the following object association:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;A references B&lt;/li&gt;&lt;br /&gt; &lt;li&gt;A has a one-to-many relationship with C and the fetch type is set to &lt;i&gt;FetchType.EAGER&lt;/i&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;B has a one-to-many relationship with D and the fetch type is set to &lt;i&gt;FetchType.EAGER&lt;/i&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If you try to initialize hibernate using such a layout, you will receive an error message saying something like &lt;i&gt;cannot simultaneously fetch multiple bags&lt;/i&gt;. &lt;br /&gt;&lt;br /&gt;Since my mappings were okay until I added a test case for &lt;i&gt;B&lt;/i&gt; and the relationships of B were correct on first sight, I started to search for a possible reason. I came across different solutions, among them I found &lt;a href="http://www.jroller.com/eyallupu/entry/hibernate_exception_simultaneously_fetch_multiple"&gt;this one&lt;/a&gt; from Eyal Lupu. It did not directly solve my problem, but let me analyze the code from a different point of view. &lt;br /&gt;&lt;br /&gt;Eyal writes, that it is not allowed to have two mapped lists in one entity being marked with &lt;i&gt;FetchType.EAGER&lt;/i&gt; because the sql statements generated would lead  to an incorrect loading of the desired entity. If you look at my example above, there is just one list per entity to be loaded eagerly, so why does it fail? The solution to that problem is the first statement of my example: &lt;i&gt;A references B&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;If you refer from one to another entity without further fetch type definition, hibernate will always apply &lt;i&gt;FetchType.EAGER&lt;/i&gt;. That again leads to a join operation between the relations that contain A and B. Since the relationships between A - C and B - D are also marked to be loaded eagerly, they will be incorporated into the sql statement creation as well. Guess what operation will be used to compute the entities of the relationship: &lt;i&gt;JOIN&lt;/i&gt;. And that leads us back to Eyals posting.&lt;br /&gt;&lt;br /&gt;Eyal suggests to add an &lt;i&gt;@IndexColumn&lt;/i&gt; annotation which replaces the bag semantics with list semantics that gives hibernate a hint on how to handle elements of that type. Another solution - and that's the one I chose - is to mark the connection between A and B as begin fetched lazy. In case you need the relationship between A and B being resolved on entity loading, a third solution would be to mark one or both of the &lt;i&gt;one-to-many&lt;/i&gt; relationships as being fetched lazy.&lt;br /&gt;&lt;br /&gt;Next to the &lt;i&gt;FetchType.EAGER&lt;/i&gt; problem it is a good idea to have some of the relationships mentioned in the example above marked as being loaded lazy. Loading all associated objects eagerly and having a relationship that for example represent a chain of ancestors would leave you with a large set of objects loaded although you need just only one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-493608301493018582?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/493608301493018582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2010/03/fetchtypeeager-cannot-simultaneously.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/493608301493018582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/493608301493018582'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2010/03/fetchtypeeager-cannot-simultaneously.html' title='FetchType.EAGER - Cannot simultaneously fetch multiple bags'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-2835700411787947697</id><published>2010-03-08T23:30:00.003+01:00</published><updated>2010-03-08T23:36:15.676+01:00</updated><title type='text'>Object change tracking</title><content type='html'>Assume you have the task to write an audit proof software that could be easily resetted into a previous, fully &lt;br /&gt;operable state for all objects managed by the application. I am going to describe the approach how I solved the &lt;br /&gt;issue for my assignment.&lt;br /&gt;&lt;br /&gt;The reason for resetting a software system into a previous state is for example the ability to trace back &lt;br /&gt;changes made at a specific time by a know or unknown user. Usually features like this are implemented through a &lt;br /&gt;logging component having a more or less high resolution. Unfortunately the information captured only give a very &lt;br /&gt;limited view on the context the changes were made in. Writing all required information into a single log entry &lt;br /&gt;would be a quick but brute force solution and would let appear the log to be unreadable to auditors.&lt;br /&gt;&lt;br /&gt;A second aspect - and that's the driving force beside the traceability of changes in my project - is the &lt;br /&gt;possibility to have an automatic replay of all changes made to objects between two defined timestamps and the &lt;br /&gt;provisioning of these modifications into attached sub-systems. These tasks cannot be achieved through a simple &lt;br /&gt;logging mechanism since next to the data directly involded into certain actions, transitively affected information &lt;br /&gt;within the context of these objects are required as well. Therefore a more complex and more complete solution &lt;br /&gt;must be found which still is managable on all system levels - from abstract ui level to low database level.&lt;br /&gt;&lt;br /&gt;A very common approach for recording changes within datasets is to save delta information representing the &lt;br /&gt;transition between two states instead of creating a copy of the original state adding the changes made by the &lt;br /&gt;process. The latter would lead in my case where I comprehend the whole object context as dataset to a redundant &lt;br /&gt;enlargement of the whole database.&lt;br /&gt;&lt;br /&gt;To avoid redundant information and an explosion of managed data objects, I decided to follow the idea of saving &lt;br /&gt;only delta information covering the named dataset. &lt;br /&gt;&lt;br /&gt;Within in my project, I do have to manage a lot of objects which are linked among each other and where changing a &lt;br /&gt;linked objects attribute value could lead automatically to a semantic change of the originating object. Since the &lt;br /&gt;changed object could be linked by &lt;i&gt;n&lt;/i&gt; other objects, a complete and stable approach in saving the state &lt;br /&gt;transition would be the storage of the changed object as well as all linking objects. This would not be as many &lt;br /&gt;data as writing a whole copy of the objects context but it produces unecessary redundant information.&lt;br /&gt;&lt;br /&gt;I decided to follow a much easier and quite simple way to solve this problem. Whenever an object changes, itself &lt;br /&gt;and its ancestors can be identified for any time through the unique object id &lt;b&gt;and&lt;/b&gt; a version stamp. All &lt;br /&gt;links between objects are designed such that they reference the unique object id as well as the version stamp. &lt;br /&gt;&lt;br /&gt;If someone changes an object, a new version is created whereas all existing links point to the version controlled &lt;br /&gt;ancestor. Other objects that will be linked with the changed one in the future only see the most current version. &lt;br /&gt;This leads to an overall consistent state.&lt;br /&gt;&lt;br /&gt;But this concept is too basic to intercept all requirements. Sometimes changes to object attribute values are of &lt;br /&gt;such a minor state that they would have no influence on the link semantics at all. Therefore it must be possible &lt;br /&gt;to mark changes in such way that no version is created but the most current one is modified. &lt;br /&gt;&lt;br /&gt;There is indeed the other hand extreme as well. Sometimes changes made to objects have such an impact that they &lt;br /&gt;must be expanded to all linked objects too. In this case all links to former versions are upgraded to the most &lt;br /&gt;current one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-2835700411787947697?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/2835700411787947697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2010/03/object-change-tracking.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/2835700411787947697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/2835700411787947697'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2010/03/object-change-tracking.html' title='Object change tracking'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-1695037441763246265</id><published>2010-01-10T22:48:00.007+01:00</published><updated>2010-01-10T23:07:11.230+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JSR 286'/><category scheme='http://www.blogger.com/atom/ns#' term='Portal'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='Portlet'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring 3'/><category scheme='http://www.blogger.com/atom/ns#' term='Liferay'/><title type='text'>Portlet Development With Spring 3.0</title><content type='html'>Portlet Development With Spring 3.0&lt;br /&gt;&lt;br /&gt;Some weeks ago I started planning a dedicated online community backed by a Liferay portal instance. Up to now I spent most of my time defining use case scenarios, evaluating software tools and convincing people from my idea. Lately I began to write smaller portlets that provide basic features which are not included in Liferay and by the way give me a deeper insight into portlet development using Liferay.&lt;br /&gt;&lt;br /&gt;I will write more about that platform in one of the upcoming posts but for now I would like to report about my odyssey collecting information on how to develop &lt;a href="http://jcp.org/en/jsr/detail?id=286"&gt;JSR 286 portlets&lt;/a&gt; supported by the Spring 3.0 framework in a Liferay environment. &lt;br /&gt;&lt;br /&gt;If you want to develop portlet for any version of the Liferay portlet, you might use the ext environment provided by the Liferay team. Although I appreciate the help to develop applications for their portal, I definately don't want to learn how to use a proprietary development environment but use my knowledge about standard portlet development and get onto the road quickly.&lt;br /&gt;&lt;br /&gt;I searched a while until I came across some expedient documentation about how to integrate Spring 3 and standard portlets (JSR 168 and 286). The Spring framework provides you with a &lt;a href="http://static.springsource.org/spring/docs/3.0.0.RELEASE/api/org/springframework/web/portlet/DispatcherPortlet.html"&gt;dispatcher portlet&lt;/a&gt; that maps incoming portlet requests to registered handlers.&lt;br /&gt;&lt;br /&gt;After having assembled all required information, I started developing my first Liferay portlet. The following steps are the ones I carried out (abbreviated):&lt;br /&gt;&lt;br /&gt;The first step creates a directory layout as follows:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;/myPortlet&lt;br /&gt;/myPortlet/src/&lt;br /&gt;/myPortlet/src/main&lt;br /&gt;/myPortlet/src/main/java&lt;br /&gt;/myPortlet/src/main/java/sourceCodeGoesHere&lt;br /&gt;/myPortlet/src/main/webapp/&lt;br /&gt;/myPortlet/src/main/webapp/WEB-INF/&lt;br /&gt;/myPortlet/src/main/webapp/WEB-INF/classes/&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The next step is to add configuration files required by Liferay:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;/myPortlet/src/main/webapp/WEB-INF/liferay-display.xml&lt;br /&gt;/myPortlet/src/main/webapp/WEB-INF/liferay-portlet.xml&lt;br /&gt;/myPortlet/src/main/webapp/WEB-INF/portlet.xml&lt;br /&gt;/myPortlet/src/main/webapp/WEB-INF/web.xml&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;The &lt;i&gt;liferay-display.xml&lt;/i&gt; configuration file defines the category the user can find the tool in when adding a new applicaton to a portal page (&lt;a href="http://www.google.de/#q=liferay-display.xml"&gt;see Google for more information&lt;/a&gt;).&lt;/li&gt;&lt;br /&gt; &lt;li&gt;If you want to control the access to the portlet, you need to modify &lt;i&gt;liferay-portlet.xml&lt;/i&gt; which holds the names of the role that are allowed to use the portlet (&lt;a href="http://www.google.de/#q=liferay-portlet.xml"&gt;see Google for more information&lt;/a&gt;).&lt;/li&gt;&lt;br /&gt; &lt;li&gt;The file &lt;i&gt;portlet.xml&lt;/i&gt; contains the core definition of you portlet: display name, class, init parameters and alike. Normally you would provide the name of your custom portlet class but since we are using Spring, we must tell the portlet container to forward all incoming portlet requests to the Spring &lt;i&gt;dispatcher portlet&lt;/i&gt;. Additionally we need to give the path of the Spring context configuration file.:&lt;br /&gt; &lt;code&gt;&lt;br /&gt; &amp;lt;portlet-app&amp;gt;&lt;br /&gt;  .&lt;br /&gt;  .&lt;br /&gt;  &amp;lt;portlet-name&amp;gt;mySamplePortlet&amp;lt;/portlet-name&amp;gt;&lt;br /&gt;  &amp;lt;display-name&amp;gt;My Sample Portlet&amp;lt;/display-name&amp;gt;&lt;br /&gt;  &amp;lt;portlet-class&amp;gt;org.springframework.web.portlet.DispatcherPortlet&amp;lt;/portlet-class&amp;gt;&lt;br /&gt;  &amp;lt;init-param&amp;gt;&lt;br /&gt;    &amp;lt;name&amp;gt;contextConfigLocation&amp;lt;/name&amp;gt;&lt;br /&gt;    &amp;lt;value&amp;gt;/WEB-INF/classes/my-sample-portlet-context.xml&amp;lt;/value&amp;gt;&lt;br /&gt;  &amp;lt;/init-param&amp;gt;&lt;br /&gt;  .&lt;br /&gt;  .&lt;br /&gt; &amp;lt;/portlet-app&amp;gt;&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;At last we have the &lt;i&gt;web.xml&lt;/i&gt; file. Internally the Spring framework handles the whole custom portlet as web application with the dispatcher portlet as entry gate. Thus the &lt;i&gt;web.xml&lt;/i&gt; configures the custom portal application like in any other Spring application: it needs a path to the Spring context definition file, names a set of listeners and defines how to handle incoming requests (-&gt; ViewRendererServlet).&lt;br /&gt;      &lt;code&gt;&lt;br /&gt;  &amp;lt;web-app ...&amp;gt;&lt;br /&gt;    .&lt;br /&gt;    .&lt;br /&gt;    &amp;lt;context-param&amp;gt;&lt;br /&gt;      &amp;lt;param-name&amp;gt;webAppRootKey&amp;lt;/param-name&amp;gt;&lt;br /&gt;      &amp;lt;param-value&amp;gt;mySamplePortletportlet&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/context-param&amp;gt;&lt;br /&gt;    &amp;lt;context-param&amp;gt;&lt;br /&gt;      &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;      &amp;lt;param-value&amp;gt;/WEB-INF/classes/my-sample-portlet-context.xml&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/context-param&amp;gt;&lt;br /&gt;    &amp;lt;listener&amp;gt;&lt;br /&gt;      &amp;lt;listener-class&amp;gt;org.springframework.web.util.WebAppRootListener&amp;lt;/listener-class&amp;gt;&lt;br /&gt;    &amp;lt;/listener&amp;gt;&lt;br /&gt;    &amp;lt;listener&amp;gt;&lt;br /&gt;      &amp;lt;listener-class&amp;gt;org.springframework.web.context.ContextLoaderListener&amp;lt;/listener-class&amp;gt;&lt;br /&gt;    &amp;lt;/listener&amp;gt;&lt;br /&gt;    &amp;lt;servlet&amp;gt;&lt;br /&gt;      &amp;lt;servlet-name&amp;gt;ViewRendererServlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;      &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.ViewRendererServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;      &amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;&lt;br /&gt;    &amp;lt;/servlet&amp;gt;&lt;br /&gt;    &amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;      &amp;lt;servlet-name&amp;gt;ViewRendererServlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;      &amp;lt;url-pattern&amp;gt;/WEB-INF/servlet/view&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;    &amp;lt;/servlet-mapping&amp;gt;   &lt;br /&gt;    .&lt;br /&gt;    .&lt;br /&gt;  &amp;lt;/web-app&amp;gt;&lt;br /&gt;      &lt;/code&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Now I need to implement a controller for handling incoming requests. Since I am mapping incoming requests to a &lt;i&gt;common&lt;/i&gt; Spring MVC application, the implementation of a request controller takes the same steps as for a standalone web application. See Google for extended information on how to implement Spring MVC controllers, define request, action or render mappings and how to identify incoming request parameters. &lt;br /&gt;&lt;br /&gt;I omit the source code and continue with the definition of the Spring context. As defined in the &lt;i&gt;web.xml&lt;/i&gt; and the &lt;i&gt;portlet.xml&lt;/i&gt; I create a new file in &lt;i&gt;/WEB-INF/classes/&lt;/i&gt; named &lt;i&gt;my-sample-portlet-context.xml&lt;/i&gt;. In order to the get application running the following beans must be defined at minimum:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt; &amp;lt;bean id="mySamplePortletViewController" class="com.me.MySamplePortletViewController"&amp;gt;&lt;br /&gt;   &amp;lt;property name="debugMode" value="true"/&amp;gt;&lt;br /&gt; &amp;lt;/bean&amp;gt;   &lt;br /&gt;&lt;br /&gt; &amp;lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&amp;gt;&lt;br /&gt;   &amp;lt;property name="cache" value="false" /&amp;gt;&lt;br /&gt;   &amp;lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /&amp;gt;&lt;br /&gt;   &amp;lt;property name="prefix" value="/" /&amp;gt;&lt;br /&gt;   &amp;lt;property name="suffix" value=".jsp" /&amp;gt;&lt;br /&gt; &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;bean class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping"&amp;gt;&lt;br /&gt;   &amp;lt;property name="interceptors"&amp;gt;&lt;br /&gt;    &amp;lt;bean class="org.springframework.web.portlet.handler.ParameterMappingInterceptor"/&amp;gt;&lt;br /&gt;   &amp;lt;/property&amp;gt;&lt;br /&gt; &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The first bean names the controller which should receive incoming requests (as defined by the RequestMapping annotations in the source code). The second bean defines the type of view used for displaying contents to the user. In this case I use JSP backed by JSTL. The last bean is the one that handles the mappings defined in the source code of the controller implementation. The provided interceptor implementation makes sure that the incoming request parameters are mapped correctly to method parameters.&lt;br /&gt;&lt;br /&gt;Finally you need to create and implement the file (JSP) referenced in the controller source code as destination used for displaying information to the user. That's all.  ... well not everything ... there are some pitfalls I stumpled upon that I would like to write about so that you are not going to make the same mistakes as I did.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;RequestMappings&lt;/b&gt;&lt;br /&gt;The JSR 168 standard only knew about request mappings, whereas JSR 286 portlets differentiate incoming requests by the phase they originate from and which purpose they serve:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Action Request (Annotation: ActionMapping)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Render Request (Annotation: RenderMapping)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Even Request (Annotation: EventMapping)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Resource Request (Annotation: ResourceMapping)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;If you want to learn about these types, please check out Google for further information. I urgently advise you to use these specialised annotations although Spring lets you use the generalized RequestMapping annotation. First of all it helps to make the source code more readable, second: you know which method handles which request type, confusions excluded!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;RenderMapping requires String result&lt;/b&gt;&lt;br /&gt;As mentioned above, after processing an incoming request, the portlet controller sends the response to a defined view page. The name of that page is provided by the result of the method that handles render requests -&gt; the method must return a string.&lt;br /&gt;If it returns 'view', the user will be redirected to 'view.jsp'.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Unit testing&lt;/b&gt;&lt;br /&gt;If you want to test your portlet controller, check out the &lt;a href="https://src.springframework.org/svn/spring-framework/trunk/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/mvc/annotation/Portlet20AnnotationControllerTests.java"&gt;test cases&lt;/a&gt; for the Spring framework itself. Since the usage of init methods is quite common, you should be aware that the init method of your controller is executed before the &lt;i&gt;setUp&lt;/i&gt; method within a &lt;a href="http://www.junit.org"&gt;JUnit&lt;/a&gt; test case. So, if you plan to access data in your init method which is created by the &lt;i&gt;setUp&lt;/i&gt; method, you need to explicitly call the init method in your test method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-1695037441763246265?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/1695037441763246265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2010/01/portlet-development-with-spring-30.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/1695037441763246265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/1695037441763246265'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2010/01/portlet-development-with-spring-30.html' title='Portlet Development With Spring 3.0'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-5038892543225743467</id><published>2009-12-17T22:32:00.001+01:00</published><updated>2009-12-21T20:56:10.630+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Google Wave'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='Communication'/><title type='text'>Thoughts on Google Wave</title><content type='html'>Lately I received an invitation to &lt;a href="http://wave.google.com"&gt;Google Wave&lt;/a&gt; from a &lt;a href="http://twitter.com/rahnaward"&gt;colleague&lt;/a&gt; at the otto group (btw, thanks for that, David). &lt;br /&gt;&lt;br /&gt;First I thought, that Wave is another way of spending my precious time. Some people say, that Google just tries to revolutionize the communication tool market with its Google Wave application and are curios if that will work given the set of existing communication tools with their broad feature set. Beside that some point out that the feature of adding arbitrary content at any location within a wave could discourage non-digital natives from using the new technology.&lt;br /&gt;&lt;br /&gt;I fully agree that Google tries again to revolutionize a market, but I disagree with the implicated estimation that Google just adds another communication tool. Although Wave is still in beta mode, it is already visible what the driving force behind the scene is. Google does not provide us with another isolated publishing pipe like &lt;a href="http://twitter.com/mnxfst"&gt;Twitter&lt;/a&gt; or alike but enhances our way of information exchange by combining different communication channels into an integrated application.&lt;br /&gt;&lt;br /&gt;From my point of view, one of the main problems with today's communication tools is the fact that some of them are very famous but none of them really maps the real life way of conversation into the digital world. That again leaves us with sometimes fragmented conversations that are unnecessarily protracted because the exchanged textual informations (for the case of an email) do not fully explain the intentions of the participants. In real life we tend to support such situations with additional material from different sources, eg. maps or photos, to clarify our statements.&lt;br /&gt;&lt;br /&gt;Google actually tries to solve what I expressed in my last statement: support a conversation with information from a variety of sources. Make no mistake about the hype Google created around Wave, the application is still under development and has more the feeling of a very active research project than an enterprise enabled communication tool. But if you strip down the initial character of its current state (by 17/12/2009) you must realize that Google heralds a new era of compelling messaging experience as for example Mozilla also tries do achieve with its &lt;a href="https://mozillalabs.com/raindrop"&gt;Raindrop&lt;/a&gt; project.&lt;br /&gt;&lt;br /&gt;Finally neither the Google nor the Mozilla approach will help us today to avoid the face-off with situations like Frank Schirrmacher wrote about: he complained that his head cannot follow the constant flow of information anymore (see &lt;a href="http://www.spiegel.de/spiegel/0,1518,661307,00.html"&gt;www.spiegel.de&lt;/a&gt;, german only). But on the other hand they help us to steer into the right direction. A very tiny but important step is the traceability of a Waves conversation history which does not only help the non-digital natives to find out when a certain piece of information was inserted into a conversation and by whom.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-5038892543225743467?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/5038892543225743467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2009/12/thoughts-on-google-wave.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5038892543225743467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5038892543225743467'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2009/12/thoughts-on-google-wave.html' title='Thoughts on Google Wave'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-5239405938467276747</id><published>2009-12-01T14:17:00.005+01:00</published><updated>2009-12-03T13:38:52.541+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Events'/><category scheme='http://www.blogger.com/atom/ns#' term='Richfaces'/><category scheme='http://www.blogger.com/atom/ns#' term='JSF'/><category scheme='http://www.blogger.com/atom/ns#' term='Hourglass'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><category scheme='http://www.blogger.com/atom/ns#' term='Status'/><title type='text'>Hourglass display with Richfaces</title><content type='html'>Hourglass display with Richfaces&lt;br /&gt;&lt;br /&gt;Yesterday we started with a preliminary application test to be prepared for the final integration test next month.&lt;br /&gt;Since the web based application works on large datasets which could sometimes lead to extended response times at &lt;br /&gt;frontend level, one of the first things the users asked for, were a hourglass or something alike to show that the &lt;br /&gt;server is still processing the request.&lt;br /&gt;&lt;br /&gt;Since the application is based on &lt;a href="http://www.jboss.org/richfaces"&gt;Richfaces&lt;/a&gt; I searched for any feature that could help me and discovered the &lt;i&gt;&lt;a href="http://docs.jboss.org/richfaces/3.3.2.GA/en/realworld/html/a4j_status.html"&gt;status&lt;/a&gt;&lt;/i&gt; tag.&lt;br /&gt;&lt;br /&gt;The first thing I wanted to try out, was to display a message simply informing the user that the current request is still in processing mode. In order to do so, only two things needs to be done:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Define the message display behaviour using the &lt;i&gt;status&lt;/i&gt; tag&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Bind the status handler to a control that sends an ajax request to the backend&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  &amp;lt;a4j:status id="testStatus" startText="Request processing started" stopText="Request processing ended"/&amp;gt;&lt;br /&gt;  &amp;lt;a4j:commandButton action=".." value=".." status="testStatus"/&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The next time the user clicks on the command button a message will appear and inform him about the processing state.&lt;br /&gt;&lt;br /&gt;Well, that kind of behaviour gives your users a slight hint on what the system is currently doing, but hey, an overlay graphic displaying a hourglass or alike is much cooler, isn't it. Therefore I continued to search for an appropriate solution to that &lt;br /&gt;problem and finally found one written by &lt;a href="http://javathreads.de/2008/10/tutorial-ajax-ladeanzeige-wie-bei-google-mit-jboss-richfaces/"&gt;Markus K&amp;uuml;hle&lt;/a&gt; (in german only). Compared to my little example above, the main concept does not change. A status handler is defined as well as the binding with the command button. In order to create an overlay message, we need to work with cascade style sheets:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;* html body { margin: 0; overflow-y: hidden; padding: 0; }&lt;br /&gt;&lt;br /&gt;#globalStatusDiv {&lt;br /&gt;  position: relative;&lt;br /&gt;  left: 50%;&lt;br /&gt;  top: 200px;&lt;br /&gt;  width: 100px;&lt;br /&gt;&lt;br /&gt;  text-align: center;&lt;br /&gt;  margin-left: -50px;&lt;br /&gt;  height: 25px;&lt;br /&gt;  line-height: 25px;&lt;br /&gt;  background-color: #FFF;&lt;br /&gt;  padding: 2px 15px 2px 10px;&lt;br /&gt;  color: #000;&lt;br /&gt;  font-family: Verdana,Arial,Helvetica,sans-serif;&lt;br /&gt;  font-size: 14px;&lt;br /&gt;  font-weight: bold;&lt;br /&gt;  z-index: 10000;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#globalStatusDiv img {&lt;br /&gt;  vertical-align: middle;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Next, we must define a &lt;i&gt;div&lt;/i&gt; which contains the information to be displayed and bind it to a &lt;i&gt;status&lt;/i&gt; tag:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;link href="/css/status.css" rel="stylesheet" /&amp;gt;&lt;br /&gt;&amp;lt;div id="globalStatusDiv" style="display:none;"&amp;gt;&lt;br /&gt;  &amp;lt;img src="/images/working.gif"/&amp;gt;&amp;#160;%&amp;lt;h:outputText value="#{generalMsg.general_loading_message}"/&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt; &lt;br /&gt;&amp;lt;a4j:status id="globalWaitStatus" forceId="true" layout="none"&lt;br /&gt;            onstart="jQuery('#globalStatusDiv').fadeIn('fast')"&lt;br /&gt;            onstop="jQuery('#globalStatusDiv').fadeOut('slow')" /&amp;gt; &lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The binding with a command button does not differ from the simple example above:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;a4j:commandButton action=".." value=".." status="globalWaitStatus"/&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-5239405938467276747?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/5239405938467276747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2009/12/hourglass-display-with-richfaces.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5239405938467276747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5239405938467276747'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2009/12/hourglass-display-with-richfaces.html' title='Hourglass display with Richfaces'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-5094164726303772857</id><published>2009-10-07T11:59:00.001+02:00</published><updated>2009-10-07T11:59:53.089+02:00</updated><title type='text'>How to convince people of good ideas</title><content type='html'>Although I originally planned / promised to write about caching strategies and method interception in spring &lt;br /&gt;applications, I decided to insert a different topic that concerns me since I gave a presentation the other day. &lt;br /&gt;The main goal of that event was to show the current implementation state to the upcoming users.&lt;br /&gt;&lt;br /&gt;The initiator of that project defined the platform in a very broad manner and with a scope that overlapped &lt;br /&gt;more than one company. In doing so an integrated management process could be achieved for handling user/object &lt;br /&gt;associations which would unify existing concepts that are alike for all expected participators - that implicates&lt;br /&gt;that all of them currently hold and maintain individual applications for handling their own isolated process. &lt;br /&gt;It's needless to mention that the unification of theses processes would lead to an economization even for &lt;br /&gt;future applications. This affects the support for such a process as well as the application administration and maintenance.&lt;br /&gt;&lt;br /&gt;Up to here the idea sounds very promising and reasonable. That's maybe why we were commissioned to implement&lt;br /&gt;that piece of software. Unfortunately the project was altered within the scope of the number of participants and&lt;br /&gt;thus in its importance. By reducing the scope to currently one / two partners, the whole idea was definitely&lt;br /&gt;crippled. Although it's crucial to mention that the implication of such a project is the requirement for an even&lt;br /&gt;bigger project that has the goal of unifying the required meta data and management concepts. On the other hand&lt;br /&gt;even that project would lead to a unified concept on a more abstract level. &lt;br /&gt;&lt;br /&gt;The question I ask myself now, is how to convince the people in charge of broadening the scope to the one formerly&lt;br /&gt;defined and turn the project into an overall success? I appreciate all comments on that issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-5094164726303772857?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/5094164726303772857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2009/10/how-to-convince-people-of-good-ideas.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5094164726303772857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5094164726303772857'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2009/10/how-to-convince-people-of-good-ideas.html' title='How to convince people of good ideas'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-5503398407657032154</id><published>2009-09-15T21:45:00.004+02:00</published><updated>2009-09-15T21:58:46.405+02:00</updated><title type='text'>Why more software developers should write blogs</title><content type='html'>It's been a while since I wrote my last blog post and with a view to Dustin Marx &lt;a href="http://marxsoftware.blogspot.com/2009/09/more-software-developers-should-write.html"&gt;comment&lt;/a&gt; on software developers that should write blogs, I feel to be caught red-handed. &lt;br /&gt;&lt;br /&gt;To improve myself, I noted two topics, I would like to talk about in the upcoming posts:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;ol&gt;caching strategies in web applications&lt;/ol&gt;&lt;br /&gt;  &lt;ol&gt;method interception in spring&lt;/ol&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-5503398407657032154?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/5503398407657032154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2009/09/why-more-software-developers-should.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5503398407657032154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5503398407657032154'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2009/09/why-more-software-developers-should.html' title='Why more software developers should write blogs'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-2533206263889473383</id><published>2009-09-06T12:37:00.008+02:00</published><updated>2009-09-06T12:48:33.428+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='apple sauce'/><category scheme='http://www.blogger.com/atom/ns#' term='side dish'/><category scheme='http://www.blogger.com/atom/ns#' term='Apples'/><category scheme='http://www.blogger.com/atom/ns#' term='cooking'/><title type='text'>Apple sauce</title><content type='html'>Today I got up and looked out of my living room window and saw that the nightly wind has torn off a large amount of &lt;a href="http://lh4.ggpht.com/_cjVfsyitfcc/SqOQy23NXRI/AAAAAAAAACg/2b6cx_LPlEY/s576/apples.jpg"&gt;apples&lt;/a&gt; from the &lt;a href="http://lh5.ggpht.com/_cjVfsyitfcc/SqOQzPrt5cI/AAAAAAAAACk/bSFCDQxmrRs/s800/apple-tree.jpg"&gt;tree&lt;/a&gt; in our garden. Since I really like to eat apple sauce as side dish, I decided to pick up some of the fruits and cook them. I found a rather simple recipe although it does not avoid the work to peel the apples:&lt;br /&gt;&lt;br /&gt;* peel the apples and remove all decayed pieces&lt;br /&gt;* cut the remaining parts into small pieces&lt;br /&gt;* put 250g of apples and 6 table spoon of water into a small box that can be placed in a microwave&lt;br /&gt;* heat the box for 6min in the microwave (800W)&lt;br /&gt;* mash the cooked apples and mix it with sugar as you like it&lt;br /&gt;&lt;br /&gt;Acutally I don't know how long it can be stored in the fridge.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-2533206263889473383?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/2533206263889473383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2009/09/apple-sauce.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/2533206263889473383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/2533206263889473383'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2009/09/apple-sauce.html' title='Apple sauce'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-2896299317007786398</id><published>2009-08-31T13:15:00.033+02:00</published><updated>2009-09-15T21:43:58.348+02:00</updated><title type='text'>Spring Security - Basics</title><content type='html'>During the last days I had the assignment to secure a spring based application I currently work on. Although I had no experience integration spring security into an application, I decided to use this &lt;em&gt;standard&lt;/em&gt; technology rather than writing my own security layer.&lt;br /&gt;&lt;br /&gt;The task to accomplish was well-defined:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;provide a form-based login mechanism&lt;/li&gt;&lt;br /&gt;&lt;li&gt;authenticate the user against a local database&lt;/li&gt;&lt;br /&gt;&lt;li&gt;role/group information are not required since they arise from the data that will be processed by the application&lt;br /&gt;&lt;/li&gt;&lt;li&gt;support the user with complete and meaningful error messages &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately the documentation which is available for spring security (M3) is not very exhaustive and thus not helpful in order to reach the designated goal quickly. Thus I dug myself through various sources including forum posts, javadocs, documentation of earlier spring security versions and sourcecode. Finally I had a set of information which helped me to assemble a login module for my application.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Basic configuration&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&amp;lt;b:beans xmlns:security="http://www.springframework.org/schema/security"       &lt;br /&gt;       xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;security:http entry-point-ref="customAuthenticationEntryPoint" &lt;br /&gt;   session-fixation-protection="newSession" access-denied-page="/index.jsp"&amp;gt;&lt;br /&gt;  &amp;lt;security:logout logout-success-url="/index.jsp" invalidate-session="true"/&amp;gt;&lt;br /&gt;  &amp;lt;security:anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/&amp;gt;&lt;br /&gt;  &amp;lt;security:intercept-url pattern="/dialogs/**" access="ROLE_USER"/&amp;gt;&lt;br /&gt;  &amp;lt;security:intercept-url pattern="/index.jsp" access="ROLE_ANONYMOUS"/&amp;gt;      &lt;br /&gt; &amp;lt;/security:http&amp;gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &amp;lt;authentication-manager alias="authenticationManager"/&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;b:bean id="customAuthenticationManager" class="CustomAuthenticationManager"&amp;gt;&lt;br /&gt;  &amp;lt;b:property name="userService" ref="userService"/&amp;gt;&lt;br /&gt;  &amp;lt;b:property name="passwordEncryptionAlgorithm" value="SHA"/&amp;gt;&lt;br /&gt;  &amp;lt;b:property name="baseRoleName" value="ROLE_USER"/&amp;gt;&lt;br /&gt; &amp;lt;/b:bean&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;b:bean id="customizedUrlAuthenticationFailureHandler" class="CustomAuthenticationFailureHandler"&amp;gt;&lt;br /&gt;  &amp;lt;b:property name="defaultFailureUrl" value="/index.jsp"/&amp;gt;&lt;br /&gt; &amp;lt;/b:bean&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;b:bean id="customizedFormLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter" &amp;gt;&lt;br /&gt;  &amp;lt;security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/&amp;gt;&lt;br /&gt;  &amp;lt;b:property name="authenticationManager" ref="customAuthenticationManager"/&amp;gt;&lt;br /&gt;  &amp;lt;b:property name="allowSessionCreation" value="true"/&amp;gt;&lt;br /&gt;  &amp;lt;b:property name="authenticationFailureHandler" ref="customizedUrlAuthenticationFailureHandler"/&amp;gt; &lt;br /&gt; &amp;lt;/b:bean&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;b:bean id="customAuthenticationEntryPoint" class="CustomAuthenticationEntryPoint"&amp;gt;&lt;br /&gt;  &amp;lt;b:property name="loginFormUrl" value="/index.jsp"/&amp;gt;&lt;br /&gt; &amp;lt;/b:bean&amp;gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&amp;lt;/b:beans&amp;gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;security:http&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The first block configures the security layer as such. It defines the entry point into the layer (&lt;b&gt;customAuthenticationEntryPoint&lt;/b&gt;) where all requests will be redirected to, the urls to secure (&lt;b&gt;intercept-url&lt;/b&gt;) and the logout behavior (&lt;b&gt;logout-success-url&lt;/b&gt;).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;customAuthenticationManager&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;customAuthenticationManager&lt;/b&gt; bean implements the core authentication behavior. Incoming requests that belong to an user session which has not passed the security layer before are handled by this bean. It overrides the &lt;b&gt;&lt;a href="http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/authentication/AuthenticationManager.html#authenticate%28org.springframework.security.core.Authentication%29"&gt;authenticate&lt;/a&gt;&lt;/b&gt; method and performs the necessary principal and credentials checks.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;customizedUrlAuthenticationFailureHandler&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;customizedUrlAuthenticationFailureHandler&lt;/b&gt; defines the steps to carry out in case the authentication fails. In this case I created a new one next to the standard implementation since I had the requirement to implement a special error handling.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;customizedFormLoginFilter&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;customizedFormLoginFilter&lt;/b&gt; defines that the application uses the basic username / password scheme to authenticate new users. Spring security also provides implementations for &lt;a href="http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/openid/OpenIDAuthenticationProcessingFilter.html"&gt;open id authentication&lt;/a&gt; or &lt;a href="http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/cas/web/CasProcessingFilter.html"&gt;CAS&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;customAuthenticationEntryPoint&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;customAuthenticationEntryPoint&lt;/b&gt; defines the class that provides the implementation of the authentication entry point of the security layer. All incoming requests will be directed into this class. I use the &lt;a href="http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/web/AuthenticationEntryPoint.html#commence(javax.servlet.http.HttpServletRequest,%20javax.servlet.http.HttpServletResponse,%20org.springframework.security.core.AuthenticationException)"&gt;commence&lt;/a&gt; method to remove all previous error messages.&lt;br /&gt;&lt;br /&gt;As you can see, the configuration (and implementation) of a custom spring security login filter is straight forward. Since I did not want to overflow the blog with source code, I omitted it. If you are interested in it, feel free to contact me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-2896299317007786398?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/2896299317007786398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2009/08/spring-security-basics.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/2896299317007786398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/2896299317007786398'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2009/08/spring-security-basics.html' title='Spring Security - Basics'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-5734499663767367670</id><published>2009-08-21T19:18:00.020+02:00</published><updated>2009-09-15T22:34:41.070+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Richfaces'/><category scheme='http://www.blogger.com/atom/ns#' term='File Upload'/><category scheme='http://www.blogger.com/atom/ns#' term='JSF'/><category scheme='http://www.blogger.com/atom/ns#' term='UI'/><category scheme='http://www.blogger.com/atom/ns#' term='JAVA'/><title type='text'>FileUpload with Richfaces</title><content type='html'>&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:trebuchet ms;"&gt;The other day I had an assignment to write a CSV upload and download interface for a JSF (Richfaces) based web application. On first sight, that isn't a really tricky task since it was realised many times before by a lot of people - including me. Therefore I was quite confident to implement that feature quite quickly ... until it came to the point where I tried out what I implemented. Unfortunately, the file was not uploaded although my code wrote the correct filename to the log output. This is my sourcecode:&lt;br /&gt; &lt;code&gt;&lt;br /&gt;public void uploadListener(final UploadEvent uploadEvent) {&lt;br /&gt;  UploadItem uploadItem = uploadEvent.getUploadItem();&lt;br /&gt;  String fileName = uploadItem.getFileName();&lt;br /&gt;  String csvFile = new String(uploadItem.getData());&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;The method signature follows the requirements set by richfaces in order for a method to receive incoming upload events. Usually the upload item variable should contain all required information, especially the required file data. &lt;br /&gt;&lt;br /&gt;The reason why the upload item is not filled as expected, is the AJAX filter option &lt;i&gt;&lt;b&gt;createTempFile&lt;/b&gt;&lt;/i&gt; which is set to &lt;i&gt;true&lt;/i&gt; by default. Under these circumstances the uploaded file data will not be made available to the upload item variable, but is written into a temporary file on disk. To change this behavior, its necessary to switch the config option of &lt;i&gt;org.ajax4jsf.Filter&lt;/i&gt; to &lt;i&gt;true&lt;/i&gt; in the web.xml. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-5734499663767367670?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/5734499663767367670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2009/08/fileupload-with-richfaces.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5734499663767367670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5734499663767367670'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2009/08/fileupload-with-richfaces.html' title='FileUpload with Richfaces'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2302320112187282548.post-5456414357417271570</id><published>2009-08-21T14:11:00.016+02:00</published><updated>2009-09-15T22:35:30.886+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Initial'/><category scheme='http://www.blogger.com/atom/ns#' term='Start'/><category scheme='http://www.blogger.com/atom/ns#' term='New Blog'/><title type='text'>Initial Commit</title><content type='html'>&lt;span style=";font-family:trebuchet ms;font-size:100%;"  &gt;Hello everybody and welcome to my new blog. I guess most people starting a blog have thoroughly planned the topics they want to write about. Actually I did the same, but writing an inital post to introduce the blog and its author is much harder than expected. I could write a long essay about me, my work and how I made the decision to start this blog - probably most people would be bored beyond belief. Therefore I omit that and give you a quick summary about me and the topics you can expect from the upcoming posts.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Who am I?&lt;/span&gt;&lt;br /&gt;My name is Christian Kreutzfeldt and I work as a software engineer in Hamburg / Germany. Mainly I deal with a lot of topics that are associated with the development of enterprise software written in JAVA. Actually I work on a project that deals with the definition and implementation of a role and permission management.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What can you expect?&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;As you can read in the nice textare that covers my face in the page header, I stumble upon a lot of interesting topics during my day-by-day work. I plan to use this blog as a kind of reference book for myself as well as an information assembly for others. Most topics that I will cover will be associated with J2EE in the one or another way.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2302320112187282548-5456414357417271570?l=mnxfst.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mnxfst.blogspot.com/feeds/5456414357417271570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mnxfst.blogspot.com/2009/08/initial-commit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5456414357417271570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2302320112187282548/posts/default/5456414357417271570'/><link rel='alternate' type='text/html' href='http://mnxfst.blogspot.com/2009/08/initial-commit.html' title='Initial Commit'/><author><name>Christian Kreutzfeldt</name><uri>http://www.blogger.com/profile/10274663555361657054</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://3.bp.blogspot.com/_cjVfsyitfcc/So6JJQxFcYI/AAAAAAAAAAw/IgjoBFh8SL0/S220/ck.jpg'/></author><thr:total>0</thr:total></entry></feed>
