Orbitz and Spring Webflow Case Study

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    Favorites, Groups & Events

    Orbitz and Spring Webflow Case Study - Presentation Transcript

    1. Case Study: The Next Generation Online Travel Platform Michael Alford, Mark Meeker, and Alex Antonov
    2. Agenda • Project context • Technology architecture • Building UI forms • Interesting Flows • Security and SSL • Progressive Enhancement • Composite View Pattern • Componentization • URLs and REST • State management and HTTP browser caching headers • Internationalization • Performance and concurrency • Summary • Q&A
    3. Project Context
    4. Tech History
    5. 3 years of Spring Framework usage
    6. Spring MVC experiments
    7. Travel Commerce Platform
    8. Increase developer productivity
    9. Technology Architecture
    10. Direct Connections Booking Services Distributed Business Travel Business Services Session Cache Thin Presentation Layer Distributed Web (Tomcat, Spring, SWF) Session Cache
    11. Deals Shop Book Care (REST) (REST) (not REST) (mixed)
    12. Spring and the UI Layer
    13. Dear Java Developers, Whatever you do, don’t choose a web framework that generates its own XHTML (or worse, non- validating @#$% HTML that we wouldn’t be caught dead near). Your friends, The UI Team
    14. <spring:bind /> <spring:bind path=”mymodel.myinput”> <input name=”${status.expression}” value=”${status.value}” /> </spring:bind>
    15. Form Custom Tags • Started pre- spring-form.tld • Full control of mark-up • Abstracts concept of binding • Limit attributes available to be set • type, maxlength, class, autocomplete • Extended scope to include <label />
    16. Form Custom Tags • Additional values for inputs • label-key, label-state, required, read-only • Build in hook for JavaScript • Turn-off running against live model • Augment error handling
    17. Error Display • Custom Error custom tag • Formats errors with correct styles • Support for error tag debugging • Error highlighting built into form inputs
    18. Interesting Flows • Leverage framework for page navigation • Large number of special conditions in booking path • Informational pop-up flows need data from flow, but don’t affect it • “Helper” flows for RESTful Ajax calls • Requirement for a “wait page”
    19. Security and SSL • Browser security alerts are bad for business! • HTTP vs. HTTPS based on URL pattern • Spring Security channel filter to enforce SSL • Custom link tag insures correct protocol • Single source of truth
    20. Flow listener with flow annotations to indicate flow’s security level <action-state id=“purchase”> <attribute name=“permissions” value=“USER”/> … </action-state>
    21. http://blaugh.com/2006/08/21/ajax-makes-everything-better/
    22. Universality • Serve pages that will work on any and every device • Fundamental basis for the web • Goes hand-in-hand with Accessibility
    23. Graded Browser Support http://developer.yahoo.com/yui/articles/gbs
    24. Progressive Enhancement
    25. Plain Old Semantic HTML
    26. Progressive Enhancement HTML CSS JS Content Presentation Behavior Frills” s it Up” it Sing” “ No “D res “M ake
    27. Progressive Enhancement • Separation of Layers ( HTML / CSS / JS ) • Phased development • Easier to define view model and flows • And the “good stuff” too!
    28. Progressive Enhancement 1 2 3 4 HTML     CSS     JS    
    29. 1 HTML  CSS  JS 
    30. <img src=”/map/image” /> <ul> <li><a href=”/map/move?dir=n”>North</a></li> <li><a href=”/map/move?dir=e”>East</a></li> <li><a href=”/map/move?dir=s”>South</a></li> <li><a href=”/map/move?dir=w”>West</a></li> ... </ul> <ul> <li><a href=”/map/zoom?level=1”>Zoom Level 1</a></li> <li><a href=”/map/zoom?level=2”>Zoom Level 2</a></li> <li><a href=”/map/zoom?level=3”>Zoom Level 3</a></li> ... </ul>
    31. 2 HTML  CSS  JS 
    32. 3 HTML  CSS  JS 
    33. 4 HTML  CSS  JS 
    34. Select from known list: Free form input:
    35. 2 HTML  CSS  JS  4 HTML  CSS  JS 
    36. 2 HTML  CSS  JS  4 HTML  CSS  JS 
    37. XHR
    38. Hijax • Term coined by Jeremy Keith • Bulletproof Ajax (http://bulletproofajax.com/) • Pull in portion of page via Ajax when XHR is supported • Re-use same portion when a full page refresh is required • Requires UI Componentization
    39. Header Module 1 Rail Module 2 Footer
    40. Header Login Module Module 1 JS-Enabled Rail XHR Module 2 noscript Footer Login page Module transition
    41. JS-Enabled XHR no-script page transition
    42. 4 HTML  CSS  JS 
    43. Composite View Pattern • Separates “layout” of page from content • Allows to plug in different modules into page • Used in Apache Tiles • Leverage in-house framework • Try and gain as much re-use of JSP code
    44. Componentization
    45. Webapp Multi-Model • Webflow definition • Reusable components • Form
    46. Reusable Component • View Module (JSP) • Model • Validator [optional] • Executor (Component Action) [optional] • Tests
    47. Model = POJO
    48. public class ShipperSelection implements Serializable { private List<ShipperOption> shipperOptions; private ShipperOption shipperOption; private COUNTRY country; public COUNTRY getCountry() { return country; } public void setCountry(COUNTRY country) { this.country = country; } public ShipperOption getShipperOption() { return shipperOption; } public void setShipperOption(ShipperOption shipperOption) { this.shipperOption = shipperOption; } public List<ShipperOption> getShipperOptions() { return shipperOptions; } public void setShipperOptions(List<ShipperOption> shipperOptions) { this.shipperOptions = shipperOptions; } public void addShipperOption(ShipperOption shipperOption) { this.shipperOptions.add(shipperOption); } }
    49. /** * @spring.bean id=\"shipperSelectionExecutor\" * */ public class ShipperSelectionExecutor { private static PRODUCT_TYPE[] productTypes = {PRODUCT_TYPE.AIR}; public PRODUCT_TYPE[] getApplicableProductTypes() { return productTypes; } public boolean supports(Class clazz) { return ClassUtils.isAssignable(ShipperSelection.class, clazz); } public void setupBookComponent(ShipperSelection shipperSelection, BookState newParam) { List<ShipperOption> shipperOptions = getShipperOptions(); shipperSelection.setShipperOptions(shipperOptions); } private List<ShipperOption> getShipperOptions() { … return shipperOptions; } }
    50. /** * @spring.bean id=\"shipperSelectionValidator\" * */ public class ShipperSelectionValidator implements Validator { private List<COUNTRY> restrictedCountries; public ShipperSelectionValidator(List<COUNTRY> restrictedCountries) { this.restrictedCountries = restrictedCountries; } public boolean supports(Class clazz) { return ClassUtils.isAssignable(ShipperSelection.class, clazz); } public void validate(Object obj, Errors errors) { ShipperSelection c = (ShipperSelection) obj; if (restrictedCountries.contains(c.getCountry()) { errors.rejectValue(\"country\", \"1535\"); } } }
    51. <bean id=\"shipperSelectionExecutor\" class=\"com.orbitz.wl.web.book.air.action.ShipperSelectionExecutor\" /> <bean id=\"shipperSelectionValidator\" class=\"com.orbitz.wl.web.book.air.validator.ShipperSelectionValidator\" /> <bean id=\"shipperSelectionComponent\" class=\"com.orbitz.webframework.component.ComponentFactoryBean\"> <property name=\"singleton\" value=\"false\" /> <property name=\"id\" value=\"WL_UBP310.110\" /> <property name=\"name\" value=\"shipperSelection\" /> <property name=\"modelClass\" value=\"com.orbitz.wl.web.book.air.model.ShipperSelection\" /> <property name=\"executor\" ref=\"shipperSelectionExecutor\"/> <property name=”validator” ref=”shipperSelectionValidator” /> </bean>
    52. /** * @spring.bean id=\"travelerInfoAction\" * @spring.property name=\"formObjectName\" value=\"travelerInfoForm\" * @spring.property name=\"formObjectClass\" *value=\"com.orbitz.webframework.component.Form\" * @spring.property name=\"formObjectScope\" value=\"FLOW\" * @spring.property name=\"validator\" ref=\"formValidator\" * @spring.property name=\"propertyEditorRegistrators\" ref=\"propertyEditorRegistrators\" */ public class TravelerInfoAction extends Action { private static final String SHIPPER_SELECTION = \"shipperSelection\"; private static final String TRAVELERS_INPUT = \"travelersInput\"; @Override protected String[] getComponentIds() { return new String[] { SHIPPER_SELECTION + \"Component\", TRAVELERS_INPUT + \"Component\",}; } @Override public Event setupComponents(RequestContext context) { ShipperSelectionExecutor flightTicketExecutor = getComponentExecutor(context, SHIPPER_SELECTION); flightTicketExecutor.setupComponent(shipperSelection.getModel(), getBookState(context)); return success(); } public Event postProcess(RequestContext context) { TravelersInput travelersInput = getComponentModel(context, TRAVELERS_INPUT); TravelersInputExecutor whosTravelingExecutor = getComponentExecutor(context, TRAVELERS_INPUT); whosTravelingExecutor.executePostProcess(travelersInput, getBookState(context)); return success(); } }
    53. URLs and REST
    54. Fundamental nature of the web
    55. RESTful URL represents all the state necessary to reference a particular resource
    56. long-lived backwards compatible
    57. benefits?
    58. usability
    59. agility and runtime isolation
    60. Cache: performance and hardware savings
    61. exponential growth of network effects
    62. diffusion of innovation
    63. search engine optimization
    64. implementation?
    65. Spring Webflow versus Spring MVC
    66. one framework to rule them all
    67. Session scope obfuscated public interface Action { public Event execute(RequestContext context) throws Exception; } public interface RequestContext { public MutableAttributeMap getRequestScope(); public MutableAttributeMap getFlashScope(); public MutableAttributeMap getFlowScope(); public MutableAttributeMap getConversationScope(); … } requestContext.getExternalContext().getSessionMap()
    68. RESTful stateless flows
    69. Deals Shop Book Care (REST) (REST) (not REST) (mixed)
    70. <flow …> <attribute name=”stateless” value=”true”/> … </flow>
    71. no view state no pause no continuation enforce with customization at XMLFlowBuilder level & made easier by SWF-310
    72. separate model from the URL
    73. http://www.ebookers.com/shop/home? type=air&ar.type=roundTrip&ar.rt.leaveSlice.orig.key=L HR&ar.rt.leaveSlice.dest.key=FLL&ar.rt.leaveSlice.date =12%2F12%2F07&ar.rt.leaveSlice.time=Anytime&ar.rt.retu rnSlice.date=15%2F12%2F07&ar.rt.returnSlice.time=Anyti me&ar.rt.numAdult=1&ar.rt.numSenior=0&ar.rt.numChild=0 &ar.rt.child%5B0%5D=&ar.rt.child%5B1%5D=&ar.rt.child %5B2%5D=&ar.rt.child%5B3%5D=&ar.rt.child %5B4%5D=&ar.rt.child%5B5%5D=&ar.rt.child %5B6%5D=&ar.rt.child%5B7%5D=&search=Search+Flights Internet Explorer’s URL limit: 2083 characters source: Source: http://support.microsoft.com/kb/208427
    74. input mapper
    75. AttributeMapper config <flow …> … <subflow-state id=”executeSearch” flow=”search”/> <attribute-mapper> <input-mapper> <input-attribute name=”dealsModel.searchAttr1”/> <input-attribute name=”dealsModel.searchAttr2”/> </input-mapper> </attribute-mapper> <transition on=”someOutcome” to=”someView”/> </subflow-state> </flow>
    76. SWF-297 will also allow the input-mapper to also record validation error messages, providing a better alternative to the FormAction generally used for this purpose now.
    77. re-use flows as subflows without changing the URL
    78. State Management
    79. infinite memory
    80. used smallest scope possible
    81. avoided session and conversation usage
    82. request scope not for redirect-after-post
    83. flow and flash scopes
    84. continuation limits <flow:executor id=\"flowExecutor\" registry-ref=\"flowRegistry\"> <flow:repository type=\"continuation\" max-conversations=\"1\" max-continuations=\"30\"/> </flow:executor>
    85. stateless flows, continuations, and form value history
    86. no-cache no-store
    87. Spring source when cacheSeconds == 0 /** * Prevent the response from being cached. * See www.mnot.net.cache docs. */ protected final void preventCaching(HttpServletResponse response) { response.setHeader(HEADER_PRAGMA, \"No-cache\"); if (this.useExpiresHeader) { // HTTP 1.0 header response.setDateHeader(HEADER_EXPIRES, 1L); } if (this.useCacheControlHeader) { // HTTP 1.1 header: \"no-cache\" is the standard value, // \"no-store\" is necessary to prevent caching on FireFox response.setHeader(HEADER_CACHE_CONTROL, \"no-cache\"); response.addHeader(HEADER_CACHE_CONTROL, \"no-store\"); } }
    88. workaround #1 <bean name=\"dealsFlowController\" class=\"org.springframework.webflow.…\"> … <property name=\"cacheSeconds\" value=\"1\"/> </bean>
    89. workaround #2 <bean name=\"dealsFlowController\" class=\"org.springframework.webflow.…\"> … <property name=“useCacheControlHeader\" value=“false\"/> <property name=\"cacheSeconds\" value=“0\"/> </bean>
    90. Internationalization
    91. third-party libraries
    92. Joda-time (what JDK Date/Calendar/DateFormat should be)
    93. International Components for Unicode (ICU)
    94. JScience’s Units JSR-275
    95. immutable / thread-safe domain models & formatters
    96. point-of-sale and locale parameterization
    97. URL pattern POS
    98. POS defaultLocale
    99. POS config <pos> <posCode>EBCH</posCode> <description>Ebookers Switzerland Point of Sale</description> … <supportedLocales> <defaultLocale>de_CH</defaultLocale> <locale>de_CH</locale> <locale>fr_CH</locale> … </supportedLocales> … </pos>
    100. locale selection
    101. <property name=\"interceptors\"> <list> … <bean id=\"localeChangeInterceptor\" class=“ localeChangeInterceptor\"> org.springframework.web.i18n. <property name=\"paramName\"> <value>locale</value> </property> </bean> … </list> <property>
    102. locale persistence <bean id=\"localeResolver\" class=\"org.springframework.web.servlet.i18n.cookieLocaleResolver\"/> OR <bean id=\"localeResolver\" class=\"org.springframework.web.servlet.i18n.sessionLocaleResolver\"/>
    103. <spring:bind /> versus <format />
    104. register PropertyEditors editors.put(Currency.class, new CurrencyEditor()); editors.put(Scalar.class, new ScalarEditor()); editors.put(DateTime.class, new JodaDateTimeEditor(true)); editors.put(YearMonthDay.class, new JodaYearMonthDayEditor(true)); editors.put(LocalDate.class, new JodaLocalDateEditor(true)); …
    105. format tags for data types format:dateTime format:distance format:distanceVector format:interval format:money format:number format:period format:address format:creditCard format:emailAddress format:location format:name format:phoneNumber
    106. content access
    107. MessageSource <bean id=\"messageSource“ class=\"com.orbitz.webframework.ContentMessageSource\"> <constructor-arg> <ref bean=\"contentMessageConfig\"/> </constructor-arg> <property name=\"useCodeAsDefaultMessage\" value=\"true\"/> </bean>
    108. content access • <format:message /> • supports tokens of custom type
    109. Spring’s dependency on JDK’s MessageFormat
    110. open-source
    111. performance and concurrency
    112. good performance from Spring & Spring Web Flow
    113. lock contention \"http-8585-Processor39\" daemon prio=1 tid=0x081634c8 nid=0x65b7 waiting for moni tor entry [0x9d41a000..0x9d41e0b0] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistr y.getSingleton(DefaultSingletonBeanRegistry.java:114) - waiting to lock <0xb0d85828> (a java.util.LinkedHashMap) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean (AbstractBeanFactory.java:187) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean (AbstractBeanFactory.java:156)
    114. cached results of Spring’s getBeansOfType (circa March 2007 – Juergen says it may be fixed in Spring v2.0.5)
    115. SWF, registerCustomEditors, PropertyEditor issues
    116. Other lock contentions • JDK RMIClassLoaderSpi • JDK java.security.* • Tomcat • 3000 tag invocations in search results page view • Log4j • ICU
    117. ConcurrentHashMap JDK 1.5 Emory backport for JDK 1.4
    118. concurrency is hard (see Rob Harrop’s “Practical Enterprise Concurrency” presentation)
    119. Scala: JVM language Erlang-style message passing
    120. Summary • Project context • Technology architecture • Building UI forms • Managing Flows • Security and SSL • Progressive Enhancement • Composite View Pattern • Componentization • URLs and REST • State management and HTTP browser caching headers • Internationalization • Performance and concurrency • Summary • Q&A
    121. Slides & Contact Slides: http://markmeeker.com/events/tse2007 Emails: Michael Alford - malford@orbitz.com Mark Meeker - mmeeker@orbitz.com We are Hiring: http://www.orbitz.com/startmycareer

    + Mark MeekerMark Meeker, 2 years ago

    custom

    3603 views, 0 favs, 0 embeds more stats

    In this session, Michael Alford and Mark Meeker wil more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 3603
      • 3603 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 0
    • Downloads 0
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories