Thursday, December 31, 2009

Bookmark and Share

Jetty is widely appreciated as low-footprint and lightning-fast web container. That makes it also a perfect fit to be used as development runtime, where short turnaround times are an absolut must.

I used to work with the Jetty Maven plugin, which supports hot-deploying applications after any code changes while Jetty is running. This works pretty well, but comes at the cost that your session data is lost during re-deployment and depending on your application's complexity it also can take some seconds to get it up running again.

So I tried another option: running Jetty in embedded mode. For that purpose Jetty provides a comprehensive API, which we can use to write a simple main class that starts up a Jetty instance serving the application we are currently developing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class JettyRunner {

    public static void main(String[] args) throws Exception {

        Server server = new Server();

        Connector connector = new SelectChannelConnector();
        connector.setPort(8080);
        connector.setHost("127.0.0.1");
        server.addConnector(connector);

        WebAppContext wac = new WebAppContext();
        wac.setContextPath("/myapp");
        wac.setBaseResource(
            new ResourceCollection(
                new String[] {"./src/main/webapp"}));

        server.setHandler(wac);
        server.setStopAtShutdown(true);
        server.start();
        server.join();
    }
}

The code is pretty much straight forward: first a connector with port and hostname is configured, then a context for the application is created and registered with the server, which finally is started up.

When we launch this class in debugging mode from within our IDE, code changes are immediately applied to the running application without the need to re-deploy or restart it due to Java's hot code replacement mechanism.

Furthermore all changes to the files under "src/main/webapp" are instantly visible, as the files are served directly from there.

The reduced number of required restarts/redeployments greatly improves development productivity. Basically restarting is only required when modifying deployment descriptors (such as web.xml) or when class signatures are modified (e.g. by adding new methods).

Running JSF applications

This works like a charm for basic servlets, but things are getting a bit more complicated, when JSF comes into play.

The reason is that JSF searches for all classes carrying any of the JSF annotations (such as @ManagedBean) when starting up. This scan takes place in the directory "META-INF/classes". As this folder doesn't exist in our case, no single managed bean will be detected.

How can this problem be solved? First of all the output folder of the application must be added to the WebAppContext's resource collection. In case of a Maven-based project we have to add the "target" directory:

1
2
3
4
5
...
wac.setBaseResource(
    new ResourceCollection(
        new String[] { "./src/main/webapp", "./target" }));
...

But the problem remains that JSF searches class files in "WEB-INF/classes", although in our case they are located under "classes".

We could modify the destination of class files (by setting Maven's property ${project.build.outputDirectory}, but I wouldn't really recommend this. Diverging from Maven's conventions makes your project harder to understand for other developers and as rumors go there still are Maven plugins around that directly access "target/classes" instead of referencing said property.

Resource aliases

I studied Jetty's API for a while and came across the concept of resource aliases which provides a neat solution to our problem. To define an alias for "WEB-INF/classes" just do the following:

1
2
3
4
...
WebAppContext wac = new WebAppContext();
wac.setResourceAlias("/WEB-INF/classes/", "/classes/");
...

Unfortunately this only works for single resources. While everything is fine when the folder "WEB-INF/classes" itself is accessed, the alias won't be applied when accessing resources contained within this folder, e.g. "WEB-INF/classes/MyManagedBean.class".

To tackle this problem I extended Jetty's WebAppContext to provide a means of pattern based alias resolution. The only overridden method is getResourceAlias():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class AliasEnhancedWebAppContext extends WebAppContext {

    @Override
    public String getResourceAlias(String alias) {

        @SuppressWarnings("unchecked")
        Map<String, String> resourceAliases = 
            (Map<String, String>) getResourceAliases();

        if (resourceAliases == null) {
            return null;
        }

        for (Entry<String, String> oneAlias : 
            resourceAliases.entrySet()) {

            if (alias.startsWith(oneAlias.getKey())) {
                return alias.replace(
                    oneAlias.getKey(), oneAlias.getValue());
            }
        }

        return null;
    }
}

Whenever an alias for a given resource is looked up, it is checked whether the resource name starts with one of the registered aliases. If that's the case, the aliased part will be replaced. Having registered the alias from the previous listing, e.g. "WEB-INF/classes/MyManagedBean.class" will be aliased with "classes/MyManagedBean.class".

It's certainly not perfect (e.g. nested replacements are not considered), but I would regard it good enough for being used in the scenario at hand. So let's look how all this fits together:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class JettyRunner {

    public static void main(String[] args) throws Exception {

        Server server = new Server();

        Connector connector = new SelectChannelConnector();
        connector.setPort(8080);
        connector.setHost("127.0.0.1");
        server.addConnector(connector);

        WebAppContext wac = new AliasEnhancedWebAppContext();
        wac.setContextPath("/myapp");
        wac.setBaseResource(
            new ResourceCollection(
                new String[] {"./src/main/webapp", "./target"}));
        wac.setResourceAlias("/WEB-INF/classes/", "/classes/");

        server.setHandler(wac);
        server.setStopAtShutdown(true);
        server.start();
        server.join();
    }
}

That way we are finally able to run a JSF application on an embedded Jetty instance, providing us with a very efficient way of development.

EL libraries

Unfortunately my happiness was short lasting as I ran into another problem: Using method parameters within EL expressions gave me parsing errors wrapped into a javax.faces.view.facelets.TagAttributeException.

The reason is that method invocations with parameters are a feature of Unified EL version 2.2 which is leveraged by JSF 2. As others already pointed out, you need to replace the EL JARs (API and impl) of you web container with the new ones.

Using Maven this can be done by adding the following dependencies to your project's pom.xml (if required, add the java.net Maven repository to your settings.xml first):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
<dependency>
    <groupId>javax.el</groupId>
    <artifactId>el-api</artifactId>
    <version>2.2</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>el-impl</artifactId>
    <version>2.2</version>
    <scope>runtime</scope>
</dependency>
...

When working with the JSF 2 reference implementation Mojarra furthermore the expression factory to be used must be set to the one from the new EL implementation by specifying the following context parameter within your web.xml:

1
2
3
4
5
6
...
<context-param>
  <param-name>com.sun.faces.expressionFactory</param-name>
  <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>
...

Having done that, you are now able to use parametrized method invocations within EL expressions, which is especially useful when performing actions on the rows of a data table.

28 comments:

Anonymous said...

Thank for the example. I use Mojarra 2.0.2 and Jetty 7.0.2 in an embedded mode. When i start the JettyRunner i get the following exception:
Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory
Have you any idea?

Unknown said...

That's a bit hard to say without having the actual code at hand. Can you find any more information in your server log? Have you registered the Faces servlet within web.xml? Note, that I used Jetty 6.x for the example, maybe something changed with Jetty 7, haven't tried that out so far.

Anonymous said...

Thank you very much for the tips!

marciowb said...

Thank you for the valorous tips.

Unknown said...

Thanks for your comment. Great to hear you like the post :-)

Henrik said...

Great article. I stumbled upon it, because I have seen this in a Wicket project and was looking for a similar solution for JSF.

Chris Caspanello said...

This is a great tutorial. Can you post your full POM file? I feel like I'm having some dependency version issues.

Célio Vasconcelos said...

I love you so much!

Unknown said...

شركة تسليك مجاري المطبخ بالرياض
شركة تسليك مجاري بالرياض

شركة تسليك مجارى الحمام بالرياض
level تسليك المجاري بالرياض
افضل شركة تنظيف بالرياض
تنظيف شقق بالرياض
شركة تنظيف منازل بالرياض
شركة غسيل خزنات بالرياض
افضل شركة مكافحة حشرات بالرياض
رش مبيدات بالرياض
شركة تخزين عفش بالرياض
شركة تنظيف مجالس بالرياض
تنظيف فلل بالرياض
ابى شركة تنظيف بالرياض

afaf elgamal said...


شركة رش مبيد بالدمام
شركة مكافحة حشرات بالدمام


شركة عزل اسطح بالدمام

شركة تنظيف فلل بالدمام

شركة تنظيف منازل بالدمام
شركة تنظيف موكيت بالدمام
شركة تنظيف مجالس بالدمام
شركة تنظيف بالدمام

شركة نقل اثاث بالدمام

afaf elgamal said...


شركة تنظيف مجالس بالرياض
شركة تنظيف موكيت بالرياض


شركة عزل حمامات بالرياض
شركة تنظيف مساجد بالرياض


شركة تنظيف منازل بالرياض

شركة رش مبيد بالدمام
شركة مكافحة حشرات بالدمام

شركة تنظيف خزانات بالدمام

Unknown said...


تقدم شركة العربي شركة للخدمات المنزلية بحائل خدماتها في مجال تنظيف وتعقيم وعزل الخزانات

شركة تنظيف خزانات بحائل


شركة عزل خزانات بحائل

شركة رواد الحرمين said...

شركه تنظيف منازل بالجبيل

شركه تنظيف منازل بالقطيف

شركه تنظيف منازلبالخبر

شركه تنظيف منازل بالدمام

شركة رواد الحرمين said...

بموقع مؤسسة الحرمــين فخدماتنا ليس لها بديل واسعارنا ليس لها مثيل ،ولدينا فريق عمل يتصل مع العملاء على جسور الثقه
شركه تنظيف منازل بالجبيل
والصدق والامانه فى العمل ، وهدفنا هو ارضاؤك وراحتك ، لا تقلق ونحن معك

شركه عزل فوم بالجبيل
لا تجهد نفسك ونحن تحت امرك ورهن اشارتك .
أبرز خدمات مؤسسة الحرمــين للمقاولات العامة بالدمام والرياض

شركه عزل فوم بالدمام


شركه عزل اسطح بالاحساء

شركه كشف تسربات المياه بالاحساء


شركة رواد الحرمين said...

بموقع مؤسسة الحرمــين فخدماتنا ليس لها بديل واسعارنا ليس لها مثيل ،ولدينا فريق عمل يتصل مع العملاء على جسور الثقه
شركه تنظيف منازل بالجبيل
والصدق والامانه فى العمل ، وهدفنا هو ارضاؤك وراحتك ، لا تقلق ونحن معك

شركه عزل فوم بالجبيل
لا تجهد نفسك ونحن تحت امرك ورهن اشارتك .
أبرز خدمات مؤسسة الحرمــين للمقاولات العامة بالدمام والرياض

شركه عزل فوم بالدمام


شركه عزل اسطح بالاحساء

شركه كشف تسربات المياه بالاحساء


cleaning said...

شركة تنظيف بالرياض الفيلا الجديده ؛ من خلال تنظيف و غسيل الموكيت و السجاد و الكليم و إزالة بقع الطعام منها أو التخلص من الاتربه و الغبار في وقت قياسي جدا ، كما خدمة الغسيل شقق فلل مجالس موكيت كنب مساجد خزانات منازل غسيل شقق
غسيل فرشات غسيل فلل

شركة تنظيف مجالس
شركة تنظيف بالرياض توفير كافه الادوات والمعدات اللازمه في عمليه النظافة لحصول العميل علي منزل نظيف خالي من اي اوساخ بعمالة مدربة باسعار مميزة نظافة شقق موكيت سجاد كنب ستائر فلل منازل مجالس واجهات شقق مجالس كنب سجاد خزانات
تنظيف فلل
شركة تنظيف خزانات
شركة تنظيف فلل ومنازل وشقق
تنظيف مجالس فرشات ستائر كنب بالرياض

تقدم خدمات
تعقيم منازل
نظافه عامه وخدمات المنزلى
مكافحة حشرات

حلى بلاط تلميع زوجتك وتلميع اثاث
مكيفات فك وتركيب مكيفات
شركة غسيل خزانات
تعقيم شامل للمنزل
شركة تنظيف بحائل
شركة تنظيف بالرياض

تهتم بتنظيف شقق فلل خيام استراحات

تنظيف مكيفات كنب سجاد

مجالس فرشات مكافحة حشرات

تنظيف عزل خزانات

تعقيم فلل مكاتب شركات جلي بلاط سيراميك

بارخص الاسعار

رقيه احمد said...

شركة تنظيف بالرياض

تنظيف افران بالرياض

شركة تنظيف شقق بالرياض

شركة تنظيف منازل بالرياض

شركة تنظيف مجالس بالرياض

شركة تنظيف فلل بالرياض

شركة تنظيف موكيت بالرياض

شركة تنظيف مكيفات بالرياض

رقيه احمد said...

نقل العفش نقل الاثاث نقل العفش والاثاث في المدينة المنورة خدمات تنظيف خدمات التنظيف رش الحشرات مكافحة الحشرات خدمات التنظيف بالمدينة المنورة مؤسسة نقل العفش في المدينه المنوره غسيل الخزانات تنظيف الخزانات بالمدينة المنورة , النظافة العامة , خدمات تنظيف المدينة المنورة

شركة نقل عفش بالمدينة المنورة
شركة نقل اثاث بالمدينة المنورة
شركة مكافحة النمل الابيض
مكافحة حشرات بالمدينة المنورة
شركة رش مبيدات بالمدينة المنورة
شركة نظافة بالمدينة المنورة
شركة تنظيف شقق ومنازل بالمدينة المنورة

احمد said...

شركة تنظيف خزانات بالجبيل

شركة تنظيف خزانات بالقطيف

شركة تنظيف خزانات بالخبر

شركة تنظيف خزانات بالاحساء

شركة تنظيف خزانات بالدمام

Awad Elsayed said...

شركة الصفرات للتنظيف بالرياض

شركة مكافحة حشرات بجازان

mostafa eid said...

سائق عربى فى ميلانو
سائق عربى فى ايطاليا
سائق عربى فى ميلانو
سائق عربى فى ايطاليا
سائق عربى فى روما

شمس المملكة said...


شركة مكافحة حشرات بالظهران
شركة تنظيف استراحات بالظهران
شركة تنظيف منازل بالظهران
شركة تنظيف مكيفات بالظهران
شركة تنظيف مكيفات بالرياض
شركة تنظيف خزانات بالظهران
شركة شمس المملكة

شمس المملكة said...


شركة تنظيف مطاعم بالرياض
شركة تنظيف مكيفات بالدمام
شركة تنظيف مجالس بالرياض
شركة تنظيف استراحات بحي الامل بالدمام
شركة تنظيف مجالس بحي الحزام الذهبي بالخبر
شركة تنظيف مجالس بحي الشاطئ بالدمام
شركة تنظيف استراحات بحي النور بالدمام
شركة تنظيف مجالس بحي السوق بالدمام
شركة تنظيف خزانات بحي الروضة بالدمام

محمد حمدى said...

شركة ترميم بالرياض
معلم كهربائي بالرياض
معلم جبس بورد بالرياض
شركة عزل خزانات بالرياض
شركة كشف تسربات المياه بالرياض
شركة تنظيف مكيفات بالرياض
شركة تنظيف مكيفات بالدمام
معلم دهانات بالرياض

نقل اثاث دبي said...



شركة ليلى نقل اثاث دبي هي شركة تقدم خدمات المنزلية و أثاث المكاتب
و الفنادق داخل الإمارات المتحدة في أي وقت و في كل مكان.
نقل اثاث دبي
نقل اثاث الشارقة
نقل اثاث عجمان
نقل اثاث الفجيرة
نقل اثاث العين

periyannan said...

Interesting post!!! Thanks for posting such a useful information. I wish to read your upcoming post to enhance my skill set and keep blogging.
Nice blog,I understood the topic very clearly,And want to study more like this.

python internship | web development internship |internship for mechanical engineering students |mechanical engineering internships |java training in chennai |internship for 1st year engineering students |online internships for cse students |online internship for engineering students |internship for ece students |data science internships

lilian said...

شركة نقل اثاث في دبي اسرع خدمة نقل الاثاث باحترافية عالية من خلال فريق من خبراء نقل وتخزين الاثاث
نوفر لعملائنا خدمات نقل الاثاث من الباب للباب تخزين تغليف فك وتركيب الاثاث
نقل عفش بسعر رخيص
نقل اثاث دبي
شركة نقل اثاث دبي
نقل اثاث الشارقة
نقل اثاث ابوظبي
نقل اثاث العين
نقل اثاث الفجيرة

lilias said...


شركة شحن من دبي الى الكويت البحرين السعودية لبنان العراق من اهم شركات الشحن في اللامارات شحن سيارات اثاث عفش فرش معدات ثقيلة امتعه حقائب ملابس
خدمة شحن بري جوي بحري رخيصة واحترافية
شحن من الامارات الى العراق
شحن من الامارات الى لبنان
شحن من الامارات الى السعودية
شحن من الامارات الى الكويت
شحن من الامارات الى البحرين