The State of Wicket

37,978 views

Published on

The current state of the Apache Wicket framework in 2014 as presented at the DEVdev meetup held in Deventer, the Netherlands.

- A critique of ThoughtWorks' Technology Review 2014 where they slam JSF (jay) as a concept (nay)
- A look back at 10 years of Wicket
- A review of the current Wicket versions
- An outlook and roadmap for Wicket 7 and Wicket 8

The DEVdev (Deventer Developers) is a new meetup for any developer in the eastern part of the Netherlands (the right side of the IJssel river). This presentation was delivered at the first meetup, and was kindly sponsored by Topicus B.V.

Published in: Technology, Education
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
37,978
On SlideShare
0
From Embeds
0
Number of Embeds
31,433
Actions
Shares
0
Downloads
63
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide

The State of Wicket

  1. 1. State of 
 Apache Wicket
  2. 2. presented at: DEVELOPERS DEV ENTER powered by Topicus
  3. 3. sponsored by topicus
  4. 4. “We continue to see teams run into trouble using JSF -- JavaServer Faces -- and are recommending you avoid this technology.” –ThoughtWorks Technology Radar January 2014 Wicket Developers Rejoice! ! Our archenemy has been de nounced!! ! Or is there more to this stor y?
  5. 5. “We continue to see teams run into trouble using JSF -- JavaServer Faces -- and are recommending you avoid this technology. Teams seem to choose JSF because it is a J2EE standard without really evaluating whether the programming model suits them. We think JSF is flawed because it tries to abstract away HTML, CSS and HTTP, exactly the reverse of what modern web frameworks orks from ThoughtW do. JSF, he full webforms, attempts to create are TASP.NET quote like . stateless od bits HTTP gy Radthe The go protocol echnolo top of ar T statefulness on next s ide .. the a whole lhost.of problems on and ends up causing involving shared server-side state. We are aware of the improvements in JSF 2.0, but think the model is fundamentally broken. We recommend teams use simple frameworks and embrace and understand web technologies including HTTP, HTML and CSS.” –ThoughtWorks Technology Radar January 2014
  6. 6. “We continue to see teams run into trouble using JSF and are recommending you avoid this technology. We think JSF is flawed because it tries to abstract away HTML, CSS and HTTP. JSF, like ASP.NET webforms, attempts to create statefulness on top of the stateless protocol HTTP. We think the model is fundamentally broken.” –ThoughtWorks Technology Radar January 2014 This is not a critique of JSF in part icular but (server side) component framework s. The grunt of the critique is that JSF att empts to create state fullness on top of the stateless protocol–which is precisely what J SF, .Net, Wicket and Tapestry are doing.
  7. 7. “We recommend teams use simple frameworks and embrace and understand web technologies including HTTP, HTML and CSS.” –ThoughtWorks Technology Radar January 2014 with this assessment:! I don’t agree managing frameworks were server side, state solution for problems created to provide a ifficult to solve with “simple that are d frameworks”. ! 2004 is not the solution! Going back to
  8. 8. A typical screen in one of our 1000+ pag e multi-tenant SaaS applications.! Would a“simple framework” make it po ssible to maintain 3 of these 1M lines of code applications with just 30 developers?
  9. 9. 10 years of Apache Wicket
  10. 10. 2004
  11. 11. 2004 Wicket is presented to the w or ! ld.! Raise your hand if you still r ead TheServerside.com?
  12. 12. 2004 The Server Side
  13. 13. 2004 The orig The Server Side inal Wicket website. We have seen several different stylings ov er the years...
  14. 14. 2004 2005 codehaus.org The Server Side
  15. 15. 2004 2005 codehaus.org The Server Side icket meetup in 2005 in The first W r at the Topicus offices. Devente
  16. 16. 2004 2005 codehaus.org The Server Side
  17. 17. 2004 2005 JSF Wicket Tapestry codehaus.org The Server Side Struts 2 (originally Webwork) The web framework sh oot-out at JavaOne 2005. Now th at was fun! Shale
  18. 18. 2004 2005 codehaus.org The Server Side JavaOne
  19. 19. 2004 2005 codehaus.org 1.0 The Server Side JavaOne
  20. 20. 2004 2005 codehaus.org The Server Side 1.0 1.1 JavaOne
  21. 21. 2004 2005 codehaus.org The Server Side 1.0 1.1 JavaOne 2006 1.2
  22. 22. 2007
  23. 23. 2007 Wicket joins ! The Apache Software Foundation!
  24. 24. 2007 ket meetups in One of 3 Wic rganised by Arjé Amsterdam o hn (Hippo CMS) Ca
  25. 25. 2007
  26. 26. 2007 2008 1.3
  27. 27. 2007 2008 1.3
  28. 28. 2007 2008 1.3
  29. 29. 2007 2008 2009 1.3 1.4
  30. 30. 2007 2008 2009 2010 1.3 1.4
  31. 31. 2007 2008 2009 2010 2011 1.3 1.4 1.5
  32. 32. 2012 2013 2014
  33. 33. 2012 2013 6.0 2014
  34. 34. 2012 2013 2014 6.2 6.6 6.10 6.0 6.4 6.8 6.12 6.1 6.5 6.9 6.13 6.3 6.7 6.11
  35. 35. State of Apache Wicket
  36. 36. 1. core 2. extensions 3. spring 4. datetime 5. auth-roles
  37. 37. Mailinglist traffic
  38. 38. Commit activity Wicket in Action Wicket Cookbook
  39. 39. Commit activity Wicket in Action Wicket Cookbook e a dent used quit ng has ca tivities:! book writi related ac ur Wicket in o ajor part. plays a m burn-out
  40. 40. In a Nutshell, Wicket... – Ohloh report for Wicket
  41. 41. In a Nutshell, Wicket... … has had 17,645 commits made by 52 contributors representing 314,959 lines of code – Ohloh report for Wicket
  42. 42. In a Nutshell, Wicket... … has had 17,645 commits made by 52 contributors representing 314,959 lines of code … is mostly written in Java with
 a well-commented source code – Ohloh report for Wicket
  43. 43. In a Nutshell, Wicket... … has had 17,645 commits made by 52 contributors representing 314,959 lines of code … is mostly written in Java with
 a well-commented source code … has a well established, mature codebase maintained by a large development team with stable Y-O-Y commits – Ohloh report for Wicket
  44. 44. In a Nutshell, Wicket... … has had 17,645 commits made by 52 contributors representing 314,959 lines of code … is mostly written in Java with
 a well-commented source code … has a well established, mature codebase maintained by a large development team with stable Y-O-Y commits … took an estimated 83 years of effort (COCOMO model)
 starting with its first commit in September, 2004
 ending with its most recent commit 2 days ago – Ohloh report for Wicket
  45. 45. Wicket 1.4 rity fixes only secu
  46. 46. Wicket 1.5 rity fixes only secu
  47. 47. Wicket 6 released along continues to be , monthlies will side Wicket 7 onthlies when nsform into bi-m tra resolved tickets number of subsides.
  48. 48. Java 6
  49. 49. semantic versioning Works wonderful for us. Only snag: JQuery updates.
  50. 50. Monthly releases also wonderful: no longer waiting for a long time for a fixed bug.
  51. 51. Wicket 7 ch to say about Wicket 7: not mu no major API changes.
  52. 52. Java 7
  53. 53. Servlet 3
  54. 54. Minor API breaks
  55. 55. Wicket 8 Anything written here is just speculation from my side. This is not set in stone, this is not how e are going to implement things, w or quite reasonably at all.
  56. 56. Java 8
  57. 57. PROJECT LAMBDA “functional” programming in Java
  58. 58. @FunctionalInterface public interface ILinkListener { void onLickClicked(); }
  59. 59. ILinkListener l = new ILinkListener() { @Override public void onLinkClicked() { System.out.println("Klik"); } }
  60. 60. ILinkListener l = () -> { System.out.println("Klik"); }
  61. 61. ILinkListener l = new ILinkListener() { @Override public void onLinkClicked() { System.out.println("Klik"); } } -of! ILinkListener l = () -> { System.out.println("Klik"); }
  62. 62. add(new Link<Void>("save") { @Override public void onClick() { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()) } });
  63. 63. add(new Link<Void>("save") { @Override public void onClick() { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()) } });
  64. 64. add(new Link<>("save").onClick(()-> { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()); });
  65. 65. private void onSave() { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()) } ! ! ! ! ! !
  66. 66. private void onSave() { dao.save(object); getSession().info("Saved."); setResponsePage(new OtherPage()) } ! ! add(new Link<Void>("save") .onClick(this::onSave); ! !
  67. 67. A link with onclick, visibility and body
  68. 68. add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));
  69. 69. add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));
  70. 70. add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));
  71. 71. add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));
  72. 72. add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));
  73. 73. add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));
  74. 74. add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } }));
  75. 75. A link with onclick, visibility and body
  76. 76. add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );
  77. 77. add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );
  78. 78. add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );
  79. 79. add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );
  80. 80. add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );
  81. 81. add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) );
  82. 82. add(new Link<Void>("like") { @Override public void onClick() { person.likedBy(me); } @Override public boolean isVisible() { return person.isNotLiked(); } }.setBody(new AbstractReadOnlyModel<String>() { @Override public String getObject() { StringBuilder sb = new StringBuilder("Like "); sb.append(person.getFirstName()); return sb.toString(); } })); add(new Link<>("like") .visible(() -> person.isNotLiked()) .onClick(() -> person.likedBy(me)) .body(() -> { StringBuilder sb = new StringBuilder("L sb.append(person.getFirstName()); return sb.toString(); }) ); ! ! ! ! ! ! ! ! Anon inner classes: 17 lines Java 8 lambdas: 9 lines
  83. 83. nashorn
  84. 84. JavaScript validation
  85. 85. ScriptEngineManager m = new ScriptEngineManager(); ! ScriptEngine nashorn = m.getEngineByName("nashorn"); ! nashorn.put("age", validatable.getValue()); String js = "age >= 18"; ! try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }
  86. 86. ScriptEngineManager m = new ScriptEngineManager(); ! ScriptEngine nashorn = m.getEngineByName("nashorn"); ! nashorn.put("age", validatable.getValue()); String js = "age >= 18"; ! try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }
  87. 87. ScriptEngineManager m = new ScriptEngineManager(); ! ScriptEngine nashorn = m.getEngineByName("nashorn"); ! nashorn.put("age", validatable.getValue()); String js = "age >= 18"; ! try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }
  88. 88. ScriptEngineManager m = new ScriptEngineManager(); ! ScriptEngine nashorn = m.getEngineByName("nashorn"); ! nashorn.put("age", validatable.getValue()); String js = "age >= 18"; ! try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }
  89. 89. ScriptEngineManager m = new ScriptEngineManager(); ! ScriptEngine nashorn = m.getEngineByName("nashorn"); ! nashorn.put("age", validatable.getValue()); String js = "age >= 18"; ! Object result = nashorn.eval(js); try { if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch(Exception e) { }
  90. 90. ScriptEngineManager m = new ScriptEngineManager(); ! ScriptEngine nashorn = m.getEngineByName("nashorn"); ! nashorn.put("age", validatable.getValue()); String js = "age >= 18"; ! Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } try { } catch(Exception e) { }
  91. 91. ScriptEngineManager m = new ScriptEngineManager(); ! ScriptEngine nashorn = m.getEngineByName("nashorn"); ! nashorn.put("age", validatable.getValue()); String js = "age >= 18"; ! try { Object result = nashorn.eval(js); if(!((Boolean)result) { ValidationError e = new ValidationError(); validatable.error(e); } } catch (Exception e) { }
  92. 92. ScriptEngineManager m = ! ScriptEngine nashorn = m.getEngineByName( ! nashorn.put( was only a proof-of-concept This . String js =is probably won Th ’t ever fly due ! to business entities residing on try server, and difficult to share those Object result = nashorn.eval(js); in browser, including I18N m e = new ValidationErroressages. ValidationError() } } } validatable.error(e);
  93. 93. java.time support for this will be for converters, validations and possibly wicket-datetime
  94. 94. Roadmap Anything written here is just speculation from my side. This is not set in stone. Dates are mere guidelines.
  95. 95. Monthly releases
  96. 96. 2014 feb mar may 6.1 4 6.1 6.1 -M 7.0 7.0 1 5 -M 2 jun 8 7.0 6.1 9 7.1
  97. 97. 2015 feb mar 7.1 7.9 8.0 -M 1 may 7.1 8.0 0 -M 2 jun 2 8.0 7.1 3 8.1
  98. 98. git organization
  99. 99. master wicket-1.0.x wicket-1.1.x wicket-1.2.x wicket-1.3.x wicket-1.4.x wicket-1.5.x wicket-6.x ! Current organisation of our repository: master is new development, rest is maintenance.
  100. 100. master wicket-1.0.x wicket-1.1.x wicket-1.2.x wicket-1.3.x wicket-1.4.x wicket-1.5.x wicket-6.x ! x! cket 7. wi Current organisation of our repository: master is new development, rest is maintenance.
  101. 101. master wicket-1.0.x wicket-1.1.x wicket-1.2.x wicket-1.3.x wicket-1.4.x wicket-1.5.x wicket-6.x wicket-7.x wicket-8.x proposed layout: no more master, but just product branches.
  102. 102. experimental modules Jay! Many exper imental modules have been upgra ded to core modules! beanva lidation, CDI-1.1, web sockets will be part of Wicket core from 6.14 an d onwards.
  103. 103. org.apache.wicket.experimental.wicket-6.x wicket-atmosphere wicket-bootstrap wicket-new-examples ! org.apache.wicket.experimental.wicket-7.x Remaining wicket-atmosphere experimental modules wicket-cdi-1.1
  104. 104. org.apache.wicket.experimental.wicket-6.x wicket-atmosphere wicket-bootstrap wicket-new-examples ! tstrap: bootstrap is No more boo org.apache.wicket.experimental.wicket-7.x new examples: ource reference to no just a res wicket-atmosphere r time to do anyth CSS. Write you t and ing JavaScrip wicket-cdi-1.1 use useful with them 0 lines of code) or . own (~1 ’s bootstrap wicket L0rdn1kk0n component library.
  105. 105. Wicket 6.x org.apache.wicket.experimental.wicket-6.x wicket-atmosphere ! Wicket 7.x ! org.apache.wicket.experimental.wicket-7.x wicket-atmosphere ! How to separate the same experimental modules in multiple product lines?
  106. 106. Wicket 6.x org.apache.wicket.experimental.wicket-6.x wicket-atmosphere ! Wicket 7.x ! org.apache.wicket.experimental.wicket-7.x wicket-atmosphere ! Make the groupId specific to the product line, keep code as sim ilar as possible.
  107. 107. The state of Apache Wicket:
  108. 108. The state of Apache Wicket: HEALTHY
  109. 109. DEVELOPERS DEV ENTER powered by Topicus

×