Keep your Wicket application in production

6,334 views

Published on

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

No Downloads
Views
Total views
6,334
On SlideShare
0
From Embeds
0
Number of Embeds
54
Actions
Shares
0
Downloads
138
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Keep your Wicket application in production

  1. 1. Get your application in production... ...and keep your weekends free Martijn Dashorst Topicus
  2. 2. 6 WAYS TO KEEP YOUR JOB OUT OF YOUR WEEKEND
  3. 3. 1. USE WICKET TESTER
  4. 4. WICKETTESTER • Test components directly, or their markup • Runs tests without starting server • Ajax testing (server side) • Runs in IDE, ant, maven builds • Achieves high code coverage
  5. 5. HELLOWORLD TEST @Test public void labelContainsHelloWorld() { }
  6. 6. HELLOWORLD TEST @Test public void labelContainsHelloWorld() { WicketTester tester = new WicketTester(); }
  7. 7. HELLOWORLD TEST @Test public void labelContainsHelloWorld() { WicketTester tester = new WicketTester(); tester.startPage(HelloWorld.class); }
  8. 8. HELLOWORLD TEST @Test public void labelContainsHelloWorld() { WicketTester tester = new WicketTester(); tester.startPage(HelloWorld.class); tester.assertLabel(quot;messagequot;, quot;Hello, World!quot;); }
  9. 9. LINK TEST @Test public void countingLinkClickTest() { }
  10. 10. LINK TEST @Test public void countingLinkClickTest() { WicketTester tester = new WicketTester(); }
  11. 11. LINK TEST @Test public void countingLinkClickTest() { WicketTester tester = new WicketTester(); tester.startPage(LinkCounter.class); }
  12. 12. LINK TEST @Test public void countingLinkClickTest() { WicketTester tester = new WicketTester(); tester.startPage(LinkCounter.class); tester.assertModelValue(quot;labelquot;, 0); }
  13. 13. LINK TEST @Test public void countingLinkClickTest() { WicketTester tester = new WicketTester(); tester.startPage(LinkCounter.class); tester.assertModelValue(quot;labelquot;, 0); tester.clickLink(quot;linkquot;); }
  14. 14. LINK TEST @Test public void countingLinkClickTest() { WicketTester tester = new WicketTester(); tester.startPage(LinkCounter.class); tester.assertModelValue(quot;labelquot;, 0); tester.clickLink(quot;linkquot;); tester.assertModelValue(quot;labelquot;, 1); }
  15. 15. NAVIGATION TEST @Test public void navigateToSecondPage() { }
  16. 16. NAVIGATION TEST @Test public void navigateToSecondPage() { WicketTester tester = new WicketTester(); tester.startPage(new FirstPage()); }
  17. 17. NAVIGATION TEST @Test public void navigateToSecondPage() { WicketTester tester = new WicketTester(); tester.startPage(new FirstPage()); tester.clickLink(quot;linkquot;); }
  18. 18. NAVIGATION TEST @Test public void navigateToSecondPage() { WicketTester tester = new WicketTester(); tester.startPage(new FirstPage()); tester.clickLink(quot;linkquot;); tester.assertRenderedPage(SecondPage.class); }
  19. 19. 2. PAGE CHECK
  20. 20. PAGES IN EDUARTE • Pages must have @PageInfo annotation • Policy file must contain existing pages • All secure pages must be in the policy file
  21. 21. PAGE INFO ANNOTATION @PageInfo( title = quot;Intake stap 1 van 4quot;, menu = {quot;Deelnemer > intakequot;} ) public class IntakePersonalia extends IntakeWizardPage { ... }
  22. 22. Our build fails for any of these problems...
  23. 23. 3. ENTITY CHECKER
  24. 24. Storing Hibernate entities in your pages is bad... ...mkay
  25. 25. WICKET SERIALIZABLE CHECKER • Runs when page is serialized • Tries to find non-serializable objects attached to page • Helpful stacktraces
  26. 26. EXAMPLE STACKTRACE Unable to serialize class: nl.topicus.project.entities.personen.Persoon Field hierarchy is: 2 [class=nl.topicus.project.SomePage, path=2] nl.topicus.project.entities.personen.Persoon nl.topicus.project.SomePage.persoon <----- Entity
  27. 27. WICKET SERIALIZER CHECK public class TopicusRequestCycle extends WebRequestCycle { public void onEndRequest() { Page requestPage = getRequest().getPage(); testDetachedObjects(requestPage); if (getRequestTarget() instanceof IPageRequestTarget) { Page responsePage = getRequestTarget().getPage(); if (responsePage != requestPage) { testDetachedObjects(responsePage); } } } }
  28. 28. WICKET SERIALIZER CHECK if (page == null || page.isErrorPage()) { return; } try { checker = new EntityAndSerializableChecker( new NotSerializableException()); checker.writeObject(page); } catch (Exception e) { log.error(quot;Couldn't serialize: quot; + page + quot;, error: quot; + ex); }
  29. 29. WICKET SERIALIZER CHECK private void check(Object obj) { Class cls = obj.getClass(); nameStack.add(simpleName); traceStack.add(new TraceSlot(obj, fieldDescription)); if (!(obj instanceof Serializable) && (!Proxy.isProxyClass(cls))) { throw new WicketNotSerializableException(/* ... */); } ... complicated stuff ... }
  30. 30. WICKET SERIALIZER CHECK if (!(obj instanceof Serializable) && (!Proxy.isProxyClass(cls))) { throw new WicketNotSerializableException(/* .. */) .toString(), exception); } if (obj instanceof IdObject) { Serializable id = ((IdObject) obj).getIdAsSerializable(); if (id != null && !(id instanceof Long && ((Long) id) <= 0)) { throw new WicketContainsEntityException(/* ... */); } } ... complicated stuff ...
  31. 31. To ensure developers have to fix it immediately... ...an Ajax callback checks for these errors and renders an ErrorPage
  32. 32. 4. MARKUP VALIDATOR
  33. 33. VALID MARKUP... • Nobody cares about valid markup • XHTML is dead
  34. 34. INVALID MARKUP... do care • Browsers • Subtle differences between browser DOM handling • Ajax becomes a pain
  35. 35. WICKET STUFF HTML VALIDATOR • http://github.com/dashorst/wicket-stuff-markup-validator • Based on: http://tuckey.org/validation
  36. 36. ADD DEPENDENCY TO POM <dependency> <groupId>org.wicketstuff</groupId> <artifactId>htmlvalidator</artifactId> <version>1.0</version> <scope>test</scope> </dependency>
  37. 37. ADD FILTER TO WEBAPP public class MyApplication extends WebApplication { // ... @Override protected void init() { // only enable the markup filter in DEVELOPMENT mode if(DEVELOPMENT.equals(getConfigurationType())) { getRequestCycleSettings() .addResponseFilter(new HtmlValidationResponseFilter()); } } }
  38. 38. DEFINE PROPER DOCTYPE <!DOCTYPE html PUBLIC quot;-//W3C//DTD XHTML 1.0 Transitional//EN quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtdquot;> <html xmlns=quot;http://www.w3.org/1999/xhtmlquot;> <head> <title>Foo</title> </head> <body> </body> </html>
  39. 39. ... AND ENDURE THE HORRORS OF VALID MARKUP
  40. 40. 5. REQUESTLOGGER
  41. 41. REQUEST LOGGER • HTTPD logs are (mostly) useless for Wicket applications • POST /vocus/app?wicket:interface=:4:lijst::IBehaviorListener... • GET /vocus/app?wicket:interface=:1084:: • RequestLogger provides decoded information: • Page, Listener, RequestTarget, SessionID, etc.
  42. 42. 14:00:19 time=101, event=Interface[ target:DefaultMenuLink(menu:personalia:dropitem page: nl.topicus.gui.student.ToonPersonaliaPage(4) interface: ILinkListener:onLinkClicked], response=PageRequest[ nl.topicus.gui.student.ToonLeerlingRelatiesPage(6)] sessioninfo=[ sessionId=D574D35FF49C047E4F290FE clientInfo=ClientProperties{ remoteAddress=192.0.2.50, browserVersionMajor=7, browserInternetExplorer=true}, organization=Demo School username=administrator], sessionstart=Fri Dec 14 13:59:14 CET 2008, requests=14, totaltime=3314
  43. 43. REQUEST LOST PARSER
  44. 44. 6. RABID MONITORING
  45. 45. NABAZTAG • Availability of production applications • Performance of production applications • Hudson builds • Issue tracker
  46. 46. THANK YOU!

×