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:
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?
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.
Thank you very much for the tips!
Thank you for the valorous tips.
Thanks for your comment. Great to hear you like the post :-)
Great article. I stumbled upon it, because I have seen this in a Wicket project and was looking for a similar solution for JSF.
This is a great tutorial. Can you post your full POM file? I feel like I'm having some dependency version issues.
I love you so much!
شركة تسليك مجاري المطبخ بالرياض
شركة تسليك مجاري بالرياض
شركة تسليك مجارى الحمام بالرياض
level تسليك المجاري بالرياض
افضل شركة تنظيف بالرياض
تنظيف شقق بالرياض
شركة تنظيف منازل بالرياض
شركة غسيل خزنات بالرياض
افضل شركة مكافحة حشرات بالرياض
رش مبيدات بالرياض
شركة تخزين عفش بالرياض
شركة تنظيف مجالس بالرياض
تنظيف فلل بالرياض
ابى شركة تنظيف بالرياض
شركة رش مبيد بالدمام
شركة مكافحة حشرات بالدمام
شركة عزل اسطح بالدمام
شركة تنظيف فلل بالدمام
شركة تنظيف منازل بالدمام
شركة تنظيف موكيت بالدمام
شركة تنظيف مجالس بالدمام
شركة تنظيف بالدمام
شركة نقل اثاث بالدمام
شركة تنظيف مجالس بالرياض
شركة تنظيف موكيت بالرياض
شركة عزل حمامات بالرياض
شركة تنظيف مساجد بالرياض
شركة تنظيف منازل بالرياض
شركة رش مبيد بالدمام
شركة مكافحة حشرات بالدمام
شركة تنظيف خزانات بالدمام
تقدم شركة العربي شركة للخدمات المنزلية بحائل خدماتها في مجال تنظيف وتعقيم وعزل الخزانات
شركة تنظيف خزانات بحائل
شركة عزل خزانات بحائل
شركه تنظيف منازل بالجبيل
شركه تنظيف منازل بالقطيف
شركه تنظيف منازلبالخبر
شركه تنظيف منازل بالدمام
بموقع مؤسسة الحرمــين فخدماتنا ليس لها بديل واسعارنا ليس لها مثيل ،ولدينا فريق عمل يتصل مع العملاء على جسور الثقه
شركه تنظيف منازل بالجبيل
والصدق والامانه فى العمل ، وهدفنا هو ارضاؤك وراحتك ، لا تقلق ونحن معك
شركه عزل فوم بالجبيل
لا تجهد نفسك ونحن تحت امرك ورهن اشارتك .
أبرز خدمات مؤسسة الحرمــين للمقاولات العامة بالدمام والرياض
شركه عزل فوم بالدمام
شركه عزل اسطح بالاحساء
شركه كشف تسربات المياه بالاحساء
بموقع مؤسسة الحرمــين فخدماتنا ليس لها بديل واسعارنا ليس لها مثيل ،ولدينا فريق عمل يتصل مع العملاء على جسور الثقه
شركه تنظيف منازل بالجبيل
والصدق والامانه فى العمل ، وهدفنا هو ارضاؤك وراحتك ، لا تقلق ونحن معك
شركه عزل فوم بالجبيل
لا تجهد نفسك ونحن تحت امرك ورهن اشارتك .
أبرز خدمات مؤسسة الحرمــين للمقاولات العامة بالدمام والرياض
شركه عزل فوم بالدمام
شركه عزل اسطح بالاحساء
شركه كشف تسربات المياه بالاحساء
شركة تنظيف بالرياض الفيلا الجديده ؛ من خلال تنظيف و غسيل الموكيت و السجاد و الكليم و إزالة بقع الطعام منها أو التخلص من الاتربه و الغبار في وقت قياسي جدا ، كما خدمة الغسيل شقق فلل مجالس موكيت كنب مساجد خزانات منازل غسيل شقق
غسيل فرشات غسيل فلل
شركة تنظيف مجالس
شركة تنظيف بالرياض توفير كافه الادوات والمعدات اللازمه في عمليه النظافة لحصول العميل علي منزل نظيف خالي من اي اوساخ بعمالة مدربة باسعار مميزة نظافة شقق موكيت سجاد كنب ستائر فلل منازل مجالس واجهات شقق مجالس كنب سجاد خزانات
تنظيف فلل
شركة تنظيف خزانات
شركة تنظيف فلل ومنازل وشقق
تنظيف مجالس فرشات ستائر كنب بالرياض
تقدم خدمات
تعقيم منازل
نظافه عامه وخدمات المنزلى
مكافحة حشرات
حلى بلاط تلميع زوجتك وتلميع اثاث
مكيفات فك وتركيب مكيفات
شركة غسيل خزانات
تعقيم شامل للمنزل
شركة تنظيف بحائل
شركة تنظيف بالرياض
تهتم بتنظيف شقق فلل خيام استراحات
تنظيف مكيفات كنب سجاد
مجالس فرشات مكافحة حشرات
تنظيف عزل خزانات
تعقيم فلل مكاتب شركات جلي بلاط سيراميك
بارخص الاسعار
شركة تنظيف بالرياض
تنظيف افران بالرياض
شركة تنظيف شقق بالرياض
شركة تنظيف منازل بالرياض
شركة تنظيف مجالس بالرياض
شركة تنظيف فلل بالرياض
شركة تنظيف موكيت بالرياض
شركة تنظيف مكيفات بالرياض
نقل العفش نقل الاثاث نقل العفش والاثاث في المدينة المنورة خدمات تنظيف خدمات التنظيف رش الحشرات مكافحة الحشرات خدمات التنظيف بالمدينة المنورة مؤسسة نقل العفش في المدينه المنوره غسيل الخزانات تنظيف الخزانات بالمدينة المنورة , النظافة العامة , خدمات تنظيف المدينة المنورة
شركة نقل عفش بالمدينة المنورة
شركة نقل اثاث بالمدينة المنورة
شركة مكافحة النمل الابيض
مكافحة حشرات بالمدينة المنورة
شركة رش مبيدات بالمدينة المنورة
شركة نظافة بالمدينة المنورة
شركة تنظيف شقق ومنازل بالمدينة المنورة
شركة تنظيف خزانات بالجبيل
شركة تنظيف خزانات بالقطيف
شركة تنظيف خزانات بالخبر
شركة تنظيف خزانات بالاحساء
شركة تنظيف خزانات بالدمام
شركة الصفرات للتنظيف بالرياض
شركة مكافحة حشرات بجازان
سائق عربى فى ميلانو
سائق عربى فى ايطاليا
سائق عربى فى ميلانو
سائق عربى فى ايطاليا
سائق عربى فى روما
شركة مكافحة حشرات بالظهران
شركة تنظيف استراحات بالظهران
شركة تنظيف منازل بالظهران
شركة تنظيف مكيفات بالظهران
شركة تنظيف مكيفات بالرياض
شركة تنظيف خزانات بالظهران
شركة شمس المملكة
شركة تنظيف مطاعم بالرياض
شركة تنظيف مكيفات بالدمام
شركة تنظيف مجالس بالرياض
شركة تنظيف استراحات بحي الامل بالدمام
شركة تنظيف مجالس بحي الحزام الذهبي بالخبر
شركة تنظيف مجالس بحي الشاطئ بالدمام
شركة تنظيف استراحات بحي النور بالدمام
شركة تنظيف مجالس بحي السوق بالدمام
شركة تنظيف خزانات بحي الروضة بالدمام
شركة ترميم بالرياض
معلم كهربائي بالرياض
معلم جبس بورد بالرياض
شركة عزل خزانات بالرياض
شركة كشف تسربات المياه بالرياض
شركة تنظيف مكيفات بالرياض
شركة تنظيف مكيفات بالدمام
معلم دهانات بالرياض
شركة ليلى نقل اثاث دبي هي شركة تقدم خدمات المنزلية و أثاث المكاتب
و الفنادق داخل الإمارات المتحدة في أي وقت و في كل مكان.
نقل اثاث دبي
نقل اثاث الشارقة
نقل اثاث عجمان
نقل اثاث الفجيرة
نقل اثاث العين
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
شركة نقل اثاث في دبي اسرع خدمة نقل الاثاث باحترافية عالية من خلال فريق من خبراء نقل وتخزين الاثاث
نوفر لعملائنا خدمات نقل الاثاث من الباب للباب تخزين تغليف فك وتركيب الاثاث
نقل عفش بسعر رخيص
نقل اثاث دبي
شركة نقل اثاث دبي
نقل اثاث الشارقة
نقل اثاث ابوظبي
نقل اثاث العين
نقل اثاث الفجيرة
شركة شحن من دبي الى الكويت البحرين السعودية لبنان العراق من اهم شركات الشحن في اللامارات شحن سيارات اثاث عفش فرش معدات ثقيلة امتعه حقائب ملابس
خدمة شحن بري جوي بحري رخيصة واحترافية
شحن من الامارات الى العراق
شحن من الامارات الى لبنان
شحن من الامارات الى السعودية
شحن من الامارات الى الكويت
شحن من الامارات الى البحرين
Post a Comment