SlideShare uma empresa Scribd logo
1 de 167
Case Study:
                             The Next Generation
                             Online Travel Platform




Michael Alford, Mark Meeker, and Alex Antonov
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
Project Context
Tech History
3 years of Spring
Framework usage
Spring MVC
experiments
Travel Commerce
    Platform
Increase developer
    productivity
Technology
Architecture
Direct Connections




   Booking Services




                           Distributed Business
Travel Business Services
                              Session Cache


Thin Presentation Layer      Distributed Web
 (Tomcat, Spring, SWF)        Session Cache
Deals    Shop      Book        Care
(REST)   (REST)   (not REST)   (mixed)
Spring and the
   UI Layer
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
<spring:bind />

<spring:bind path=”mymodel.myinput”>
<input name=”${status.expression}”
       value=”${status.value}” />
</spring:bind>
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 />
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
Error Display

• Custom Error custom tag
• Formats errors with correct styles
• Support for error tag debugging
• Error highlighting built into form inputs
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”
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
Flow listener with flow annotations to
         indicate flow’s security level



<action-state id=“purchase”>
   <attribute name=“permissions” value=“USER”/>
    …
</action-state>
http://blaugh.com/2006/08/21/ajax-makes-everything-better/
Universality

• Serve pages that will work on any and
  every device
• Fundamental basis for the web
• Goes hand-in-hand with Accessibility
Graded Browser Support




    http://developer.yahoo.com/yui/articles/gbs
Progressive
Enhancement
Plain
Old
Semantic
HTML
Progressive Enhancement


 HTML                CSS                JS



Content          Presentation        Behavior


       Frills”         s it Up”
                                         it Sing”
“ No             “D res           “M ake
Progressive Enhancement


• Separation of Layers ( HTML / CSS / JS )
• Phased development
• Easier to define view model and flows
• And the “good stuff” too!
Progressive Enhancement

       1    2    3     4

HTML      
CSS       
 JS       
1

HTML
       
CSS
       
 JS
       
<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>
2

HTML
       
CSS
       
 JS
       
3

HTML
       
CSS
       
 JS
       
4

HTML
       
CSS
       
 JS
       
Select from known list:




Free form input:
2

HTML   
CSS    
 JS    

                4

       HTML     
       CSS      
           JS   
2

HTML   
CSS    
 JS    

                4

       HTML     
       CSS      
           JS   
XHR
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
Header



           Module 1



Rail



           Module 2




       Footer
Header

                                 Login Module
         Module 1   JS-Enabled

Rail                   XHR

         Module 2


                     noscript
       Footer
                                       Login
                       page           Module
                    transition
JS-Enabled
     XHR



no-script
   page
transition
4

HTML
       
CSS
       
 JS
       
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
Componentization
Webapp Multi-Model

• Webflow definition
• Reusable components
• Form
Reusable Component

• View Module (JSP)
• Model
• Validator [optional]
• Executor (Component Action) [optional]
• Tests
Model = POJO
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);
	   }
}
/**
 * @spring.bean id=quot;shipperSelectionExecutorquot;
 *
 */
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;
	       }
}
/**
 * @spring.bean id=quot;shipperSelectionValidatorquot;
 *
 */
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(quot;countryquot;, quot;1535quot;);
       }
    }
}
<bean id=quot;shipperSelectionExecutorquot;
    class=quot;com.orbitz.wl.web.book.air.action.ShipperSelectionExecutorquot; />

<bean id=quot;shipperSelectionValidatorquot;
  class=quot;com.orbitz.wl.web.book.air.validator.ShipperSelectionValidatorquot; />

<bean id=quot;shipperSelectionComponentquot;
        class=quot;com.orbitz.webframework.component.ComponentFactoryBeanquot;>

    <property name=quot;singletonquot; value=quot;falsequot; />
    <property name=quot;idquot; value=quot;WL_UBP310.110quot; />
    <property name=quot;namequot; value=quot;shipperSelectionquot; />
    <property name=quot;modelClassquot;
value=quot;com.orbitz.wl.web.book.air.model.ShipperSelectionquot; />
    <property name=quot;executorquot; ref=quot;shipperSelectionExecutorquot;/>
    <property name=”validator” ref=”shipperSelectionValidator” />
</bean>
/**
 * @spring.bean id=quot;travelerInfoActionquot;
 * @spring.property name=quot;formObjectNamequot; value=quot;travelerInfoFormquot;
 * @spring.property name=quot;formObjectClassquot; *value=quot;com.orbitz.webframework.component.Formquot;
 * @spring.property name=quot;formObjectScopequot; value=quot;FLOWquot;
 * @spring.property name=quot;validatorquot; ref=quot;formValidatorquot;
 * @spring.property name=quot;propertyEditorRegistratorsquot; ref=quot;propertyEditorRegistratorsquot;
*/
public class TravelerInfoAction extends Action {
    private static final String SHIPPER_SELECTION = quot;shipperSelectionquot;;
    private static final String TRAVELERS_INPUT = quot;travelersInputquot;;

    @Override
    protected String[] getComponentIds() {
        return new String[] { SHIPPER_SELECTION + quot;Componentquot;, TRAVELERS_INPUT + quot;Componentquot;,};
    }
    @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();
    }
}
URLs and REST
Fundamental
nature of the web
RESTful URL
represents all the state necessary to reference a
               particular resource
long-lived
backwards compatible
benefits?
usability
agility and
runtime isolation
Cache:
performance and
hardware savings
exponential growth
of network effects
diffusion of innovation
search engine
 optimization
implementation?
Spring Webflow
     versus
  Spring MVC
one framework
to rule them all
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()
RESTful stateless
     flows
Deals    Shop      Book        Care
(REST)   (REST)   (not REST)   (mixed)
<flow …>
	 <attribute name=”stateless” value=”true”/>
      …
</flow>
no view state
          no pause
       no continuation

enforce with customization at XMLFlowBuilder level
            & made easier by SWF-310
separate model
 from the URL
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
input mapper
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>
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.
re-use flows as
subflows without
changing the URL
State Management
infinite memory
used smallest scope
      possible
avoided session and
conversation usage
request scope
 not for redirect-after-post
flow and flash scopes
continuation limits

<flow:executor id=quot;flowExecutorquot; registry-ref=quot;flowRegistryquot;>
    <flow:repository type=quot;continuationquot;
        max-conversations=quot;1quot;
        max-continuations=quot;30quot;/>
</flow:executor>
stateless flows,
continuations, and
form value history
no-cache
no-store
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, quot;No-cachequot;);
        if (this.useExpiresHeader) {
                 // HTTP 1.0 header
                 response.setDateHeader(HEADER_EXPIRES, 1L);
         }
         if (this.useCacheControlHeader) {
                  // HTTP 1.1 header: quot;no-cachequot; is the standard value,
                  // quot;no-storequot; is necessary to prevent caching on FireFox

                response.setHeader(HEADER_CACHE_CONTROL, quot;no-cachequot;);
                response.addHeader(HEADER_CACHE_CONTROL, quot;no-storequot;);
        }
}
workaround #1

<bean name=quot;dealsFlowControllerquot;
	 class=quot;org.springframework.webflow.…quot;>

    …

    <property name=quot;cacheSecondsquot; value=quot;1quot;/>
</bean>
workaround #2

<bean name=quot;dealsFlowControllerquot;
	 class=quot;org.springframework.webflow.…quot;>
    …

    <property name=“useCacheControlHeaderquot; value=“falsequot;/>
    <property name=quot;cacheSecondsquot; value=“0quot;/>
</bean>
Internationalization
third-party libraries
Joda-time
(what JDK Date/Calendar/DateFormat should be)
International
Components for Unicode
        (ICU)
JScience’s Units
      JSR-275
immutable /
   thread-safe
domain models &
   formatters
point-of-sale and locale
   parameterization
URL pattern   POS
POS   defaultLocale
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>
locale selection
<property name=quot;interceptorsquot;>
    <list>
        …
        <bean id=quot;localeChangeInterceptorquot;
      	 class=“        localeChangeInterceptorquot;>
               org.springframework.web.i18n.




            <property name=quot;paramNamequot;>
                <value>locale</value>
            </property>
        </bean>
        …
    </list>
<property>
locale persistence

<bean id=quot;localeResolverquot;
   class=quot;org.springframework.web.servlet.i18n.cookieLocaleResolverquot;/>


                                   OR


<bean id=quot;localeResolverquot;
   class=quot;org.springframework.web.servlet.i18n.sessionLocaleResolverquot;/>
<spring:bind />
    versus
  <format />
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));
…
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
content access
MessageSource

<bean id=quot;messageSource“
    class=quot;com.orbitz.webframework.ContentMessageSourcequot;>

    <constructor-arg>
      <ref bean=quot;contentMessageConfigquot;/>
    </constructor-arg>
    <property name=quot;useCodeAsDefaultMessagequot; value=quot;truequot;/>
</bean>
content access


• <format:message />
 • supports tokens of custom type
Spring’s dependency on
 JDK’s MessageFormat
open-source
performance
    and
concurrency
good performance from
       Spring &
   Spring Web Flow
lock contention

quot;http-8585-Processor39quot; 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)
cached results of
Spring’s getBeansOfType
              (circa March 2007 –
  Juergen says it may be fixed in Spring v2.0.5)
SWF,
registerCustomEditors,
 PropertyEditor issues
Other lock contentions
• JDK RMIClassLoaderSpi
• JDK java.security.*
• Tomcat
   • 3000 tag invocations in search results page view
• Log4j
• ICU
ConcurrentHashMap
            JDK 1.5
   Emory backport for JDK 1.4
concurrency is hard
(see Rob Harrop’s “Practical Enterprise Concurrency”
                   presentation)
Scala: JVM language
   Erlang-style message passing
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
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

Mais conteúdo relacionado

Mais procurados

High Performance Ajax Applications
High Performance Ajax ApplicationsHigh Performance Ajax Applications
High Performance Ajax Applications
Julien Lecomte
 
JavaScript and jQuery Fundamentals
JavaScript and jQuery FundamentalsJavaScript and jQuery Fundamentals
JavaScript and jQuery Fundamentals
BG Java EE Course
 

Mais procurados (20)

Basics of Rich Internet Applications
Basics of Rich Internet ApplicationsBasics of Rich Internet Applications
Basics of Rich Internet Applications
 
High Performance Ajax Applications
High Performance Ajax ApplicationsHigh Performance Ajax Applications
High Performance Ajax Applications
 
Wt unit 5 client &amp; server side framework
Wt unit 5 client &amp; server side frameworkWt unit 5 client &amp; server side framework
Wt unit 5 client &amp; server side framework
 
JavaScript and jQuery Fundamentals
JavaScript and jQuery FundamentalsJavaScript and jQuery Fundamentals
JavaScript and jQuery Fundamentals
 
Wt unit 2 ppts client side technology
Wt unit 2 ppts client side technologyWt unit 2 ppts client side technology
Wt unit 2 ppts client side technology
 
Riding Apache Camel
Riding Apache CamelRiding Apache Camel
Riding Apache Camel
 
HTML5: friend or foe (to Flash)?
HTML5: friend or foe (to Flash)?HTML5: friend or foe (to Flash)?
HTML5: friend or foe (to Flash)?
 
Java script Session No 1
Java script Session No 1Java script Session No 1
Java script Session No 1
 
High-Quality JavaScript
High-Quality JavaScriptHigh-Quality JavaScript
High-Quality JavaScript
 
Keypoints html5
Keypoints html5Keypoints html5
Keypoints html5
 
Wt unit 4 server side technology-2
Wt unit 4 server side technology-2Wt unit 4 server side technology-2
Wt unit 4 server side technology-2
 
Java script
Java scriptJava script
Java script
 
How to make Ajax work for you
How to make Ajax work for youHow to make Ajax work for you
How to make Ajax work for you
 
Java scipt
Java sciptJava scipt
Java scipt
 
JavaScripts & jQuery
JavaScripts & jQueryJavaScripts & jQuery
JavaScripts & jQuery
 
Html 5 in a big nutshell
Html 5 in a big nutshellHtml 5 in a big nutshell
Html 5 in a big nutshell
 
Visage Android Hands-on Lab (OSCON)
Visage Android Hands-on Lab (OSCON)Visage Android Hands-on Lab (OSCON)
Visage Android Hands-on Lab (OSCON)
 
Rails + Webpack
Rails + WebpackRails + Webpack
Rails + Webpack
 
Optaros Surf Code Camp Dispatcher
Optaros Surf Code Camp DispatcherOptaros Surf Code Camp Dispatcher
Optaros Surf Code Camp Dispatcher
 
Java script
Java scriptJava script
Java script
 

Semelhante a Orbitz and Spring Webflow Case Study

Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
Chris Alfano
 

Semelhante a Orbitz and Spring Webflow Case Study (20)

T5 Oli Aro
T5 Oli AroT5 Oli Aro
T5 Oli Aro
 
Jsf Ajax
Jsf AjaxJsf Ajax
Jsf Ajax
 
Plone Interactivity
Plone InteractivityPlone Interactivity
Plone Interactivity
 
Real-World AJAX with ASP.NET
Real-World AJAX with ASP.NETReal-World AJAX with ASP.NET
Real-World AJAX with ASP.NET
 
JSON Viewer XPATH Workbook
JSON Viewer XPATH WorkbookJSON Viewer XPATH Workbook
JSON Viewer XPATH Workbook
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentation
 
Service Oriented Integration With ServiceMix
Service Oriented Integration With ServiceMixService Oriented Integration With ServiceMix
Service Oriented Integration With ServiceMix
 
IE 8 et les standards du Web - Chris Wilson - Paris Web 2008
IE 8 et les standards du Web - Chris Wilson - Paris Web 2008IE 8 et les standards du Web - Chris Wilson - Paris Web 2008
IE 8 et les standards du Web - Chris Wilson - Paris Web 2008
 
CTS Conference Web 2.0 Tutorial Part 2
CTS Conference Web 2.0 Tutorial Part 2CTS Conference Web 2.0 Tutorial Part 2
CTS Conference Web 2.0 Tutorial Part 2
 
WordPress APIs
WordPress APIsWordPress APIs
WordPress APIs
 
Ajax Introduction
Ajax IntroductionAjax Introduction
Ajax Introduction
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
 
More Secrets of JavaScript Libraries
More Secrets of JavaScript LibrariesMore Secrets of JavaScript Libraries
More Secrets of JavaScript Libraries
 
Taking Apache Camel For A Ride
Taking Apache Camel For A RideTaking Apache Camel For A Ride
Taking Apache Camel For A Ride
 
IPhone Web Development With Grails from CodeMash 2009
IPhone Web Development With Grails from CodeMash 2009IPhone Web Development With Grails from CodeMash 2009
IPhone Web Development With Grails from CodeMash 2009
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
 

Mais de Mark Meeker

Modern Browser Support
Modern Browser SupportModern Browser Support
Modern Browser Support
Mark Meeker
 

Mais de Mark Meeker (8)

Simplifying Massive Changes with a Live Style Guide
Simplifying Massive Changes with a Live Style GuideSimplifying Massive Changes with a Live Style Guide
Simplifying Massive Changes with a Live Style Guide
 
Modern Browser Support
Modern Browser SupportModern Browser Support
Modern Browser Support
 
Flourish2011
Flourish2011Flourish2011
Flourish2011
 
Open and Accessible UI
Open and Accessible UIOpen and Accessible UI
Open and Accessible UI
 
Ajax and Accessibiity
Ajax and AccessibiityAjax and Accessibiity
Ajax and Accessibiity
 
Coding the UI
Coding the UICoding the UI
Coding the UI
 
Introduction to Front End Engineering
Introduction to Front End EngineeringIntroduction to Front End Engineering
Introduction to Front End Engineering
 
Microformats: The What, Where, Why and How
Microformats: The What, Where, Why and HowMicroformats: The What, Where, Why and How
Microformats: The What, Where, Why and How
 

Último

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 

Último (20)

Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 

Orbitz and Spring Webflow Case Study

  • 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
  • 5. 3 years of Spring Framework usage
  • 6.
  • 8.
  • 9.
  • 10.
  • 11. Travel Commerce Platform
  • 12. Increase developer productivity
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 21. Direct Connections Booking Services Distributed Business Travel Business Services Session Cache Thin Presentation Layer Distributed Web (Tomcat, Spring, SWF) Session Cache
  • 22. Deals Shop Book Care (REST) (REST) (not REST) (mixed)
  • 23. Spring and the UI Layer
  • 24.
  • 25.
  • 26.
  • 27. 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
  • 28. <spring:bind /> <spring:bind path=”mymodel.myinput”> <input name=”${status.expression}” value=”${status.value}” /> </spring:bind>
  • 29. 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 />
  • 30. 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
  • 31. Error Display • Custom Error custom tag • Formats errors with correct styles • Support for error tag debugging • Error highlighting built into form inputs
  • 32.
  • 33.
  • 34. 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”
  • 35.
  • 36.
  • 37. 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
  • 38. Flow listener with flow annotations to indicate flow’s security level <action-state id=“purchase”> <attribute name=“permissions” value=“USER”/> … </action-state>
  • 40. Universality • Serve pages that will work on any and every device • Fundamental basis for the web • Goes hand-in-hand with Accessibility
  • 41. Graded Browser Support http://developer.yahoo.com/yui/articles/gbs
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 49. Progressive Enhancement HTML CSS JS Content Presentation Behavior Frills” s it Up” it Sing” “ No “D res “M ake
  • 50. Progressive Enhancement • Separation of Layers ( HTML / CSS / JS ) • Phased development • Easier to define view model and flows • And the “good stuff” too!
  • 51. Progressive Enhancement 1 2 3 4 HTML     CSS     JS    
  • 52.
  • 53. 1 HTML  CSS  JS 
  • 54. <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>
  • 55. 2 HTML  CSS  JS 
  • 56. 3 HTML  CSS  JS 
  • 57. 4 HTML  CSS  JS 
  • 58.
  • 59.
  • 60.
  • 61.
  • 62. Select from known list: Free form input:
  • 63.
  • 64. 2 HTML  CSS  JS  4 HTML  CSS  JS 
  • 65. 2 HTML  CSS  JS  4 HTML  CSS  JS 
  • 66. XHR
  • 67. 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
  • 68. Header Module 1 Rail Module 2 Footer
  • 69. Header Login Module Module 1 JS-Enabled Rail XHR Module 2 noscript Footer Login page Module transition
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75. JS-Enabled XHR no-script page transition
  • 76.
  • 77.
  • 78. 4 HTML  CSS  JS 
  • 79. 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
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 86. Webapp Multi-Model • Webflow definition • Reusable components • Form
  • 87. Reusable Component • View Module (JSP) • Model • Validator [optional] • Executor (Component Action) [optional] • Tests
  • 89. 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); } }
  • 90. /** * @spring.bean id=quot;shipperSelectionExecutorquot; * */ 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; } }
  • 91. /** * @spring.bean id=quot;shipperSelectionValidatorquot; * */ 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(quot;countryquot;, quot;1535quot;); } } }
  • 92. <bean id=quot;shipperSelectionExecutorquot; class=quot;com.orbitz.wl.web.book.air.action.ShipperSelectionExecutorquot; /> <bean id=quot;shipperSelectionValidatorquot; class=quot;com.orbitz.wl.web.book.air.validator.ShipperSelectionValidatorquot; /> <bean id=quot;shipperSelectionComponentquot; class=quot;com.orbitz.webframework.component.ComponentFactoryBeanquot;> <property name=quot;singletonquot; value=quot;falsequot; /> <property name=quot;idquot; value=quot;WL_UBP310.110quot; /> <property name=quot;namequot; value=quot;shipperSelectionquot; /> <property name=quot;modelClassquot; value=quot;com.orbitz.wl.web.book.air.model.ShipperSelectionquot; /> <property name=quot;executorquot; ref=quot;shipperSelectionExecutorquot;/> <property name=”validator” ref=”shipperSelectionValidator” /> </bean>
  • 93. /** * @spring.bean id=quot;travelerInfoActionquot; * @spring.property name=quot;formObjectNamequot; value=quot;travelerInfoFormquot; * @spring.property name=quot;formObjectClassquot; *value=quot;com.orbitz.webframework.component.Formquot; * @spring.property name=quot;formObjectScopequot; value=quot;FLOWquot; * @spring.property name=quot;validatorquot; ref=quot;formValidatorquot; * @spring.property name=quot;propertyEditorRegistratorsquot; ref=quot;propertyEditorRegistratorsquot; */ public class TravelerInfoAction extends Action { private static final String SHIPPER_SELECTION = quot;shipperSelectionquot;; private static final String TRAVELERS_INPUT = quot;travelersInputquot;; @Override protected String[] getComponentIds() { return new String[] { SHIPPER_SELECTION + quot;Componentquot;, TRAVELERS_INPUT + quot;Componentquot;,}; } @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(); } }
  • 96. RESTful URL represents all the state necessary to reference a particular resource
  • 106. Spring Webflow versus Spring MVC
  • 108.
  • 109. 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()
  • 110. RESTful stateless flows
  • 111. Deals Shop Book Care (REST) (REST) (not REST) (mixed)
  • 112. <flow …> <attribute name=”stateless” value=”true”/> … </flow>
  • 113. no view state no pause no continuation enforce with customization at XMLFlowBuilder level & made easier by SWF-310
  • 117. 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>
  • 118. 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.
  • 119. re-use flows as subflows without changing the URL
  • 120.
  • 123. used smallest scope possible
  • 125. request scope not for redirect-after-post
  • 126. flow and flash scopes
  • 127. continuation limits <flow:executor id=quot;flowExecutorquot; registry-ref=quot;flowRegistryquot;> <flow:repository type=quot;continuationquot; max-conversations=quot;1quot; max-continuations=quot;30quot;/> </flow:executor>
  • 129.
  • 131. 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, quot;No-cachequot;); if (this.useExpiresHeader) { // HTTP 1.0 header response.setDateHeader(HEADER_EXPIRES, 1L); } if (this.useCacheControlHeader) { // HTTP 1.1 header: quot;no-cachequot; is the standard value, // quot;no-storequot; is necessary to prevent caching on FireFox response.setHeader(HEADER_CACHE_CONTROL, quot;no-cachequot;); response.addHeader(HEADER_CACHE_CONTROL, quot;no-storequot;); } }
  • 132. workaround #1 <bean name=quot;dealsFlowControllerquot; class=quot;org.springframework.webflow.…quot;> … <property name=quot;cacheSecondsquot; value=quot;1quot;/> </bean>
  • 133. workaround #2 <bean name=quot;dealsFlowControllerquot; class=quot;org.springframework.webflow.…quot;> … <property name=“useCacheControlHeaderquot; value=“falsequot;/> <property name=quot;cacheSecondsquot; value=“0quot;/> </bean>
  • 138. JScience’s Units JSR-275
  • 139. immutable / thread-safe domain models & formatters
  • 140. point-of-sale and locale parameterization
  • 141. URL pattern POS
  • 142. POS defaultLocale
  • 143. 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>
  • 145. <property name=quot;interceptorsquot;> <list> … <bean id=quot;localeChangeInterceptorquot; class=“ localeChangeInterceptorquot;> org.springframework.web.i18n. <property name=quot;paramNamequot;> <value>locale</value> </property> </bean> … </list> <property>
  • 146. locale persistence <bean id=quot;localeResolverquot; class=quot;org.springframework.web.servlet.i18n.cookieLocaleResolverquot;/> OR <bean id=quot;localeResolverquot; class=quot;org.springframework.web.servlet.i18n.sessionLocaleResolverquot;/>
  • 147. <spring:bind /> versus <format />
  • 148. 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)); …
  • 149. 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
  • 151. MessageSource <bean id=quot;messageSource“ class=quot;com.orbitz.webframework.ContentMessageSourcequot;> <constructor-arg> <ref bean=quot;contentMessageConfigquot;/> </constructor-arg> <property name=quot;useCodeAsDefaultMessagequot; value=quot;truequot;/> </bean>
  • 152. content access • <format:message /> • supports tokens of custom type
  • 153. Spring’s dependency on JDK’s MessageFormat
  • 155. performance and concurrency
  • 156. good performance from Spring & Spring Web Flow
  • 157. lock contention quot;http-8585-Processor39quot; 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)
  • 158.
  • 159. cached results of Spring’s getBeansOfType (circa March 2007 – Juergen says it may be fixed in Spring v2.0.5)
  • 161.
  • 162. Other lock contentions • JDK RMIClassLoaderSpi • JDK java.security.* • Tomcat • 3000 tag invocations in search results page view • Log4j • ICU
  • 163. ConcurrentHashMap JDK 1.5 Emory backport for JDK 1.4
  • 164. concurrency is hard (see Rob Harrop’s “Practical Enterprise Concurrency” presentation)
  • 165. Scala: JVM language Erlang-style message passing
  • 166. 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
  • 167. 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