6 Replies Latest reply on Aug 5, 2009 11:51 AM by mole

    Concurrency issues using SEAM-Wicket for facebook app

    mole

      We build a quite successfull facebook prototype based on the example
      from the wicket wiki (http://cwiki.apache.org/WICKET/facebook-integration.html)
      and factored out the fetching of facebook session parameters to a separate
      SEAM component witch uses a SEAM @Observer(org.jboss.seam.wicket.beforeRequest).


      Essentially, we just grab the Facebook Credentials (session key and/or authtoken)
      and store it in EVENT Scope inside a custom FacebookRequestContext Bean (a POJO, not a SEAM Bean) which we use to instantiate a com.google.code.facebookapi.IFacebookRestClient later on.



      @Name("facebookRequestContextManager")
      @Scope(ScopeType.EVENT)
      @AutoCreate
      public class FacebookRequestContextManager {
              
              /** this member holds the facebook session id for this request */
              @Out(scope=ScopeType.EVENT)
              private FacebookRequestContext facebookRequestContext;
              
              @Observer("org.jboss.seam.wicket.beforeRequest")
              public void onBeforeWebRequest(){
      
                      // did facebook send us the sessionId?
                      String fbSessionParamName = FacebookParam.SESSION_KEY.toString();
                      String fbAuthTokenParamName = "auth_token";
                      
                      HttpServletRequest wicketHttpServletRequest = ((ServletWebRequest)WebRequestCycle.get().getRequest()).getHttpServletRequest();
      
                      String fbAuthToken = wicketHttpServletRequest.getParameter(fbAuthTokenParamName);
                      String fbSessionId = wicketHttpServletRequest.getParameter(fbSessionParamName);
                      
                      Session.get().setLocale(Locale.US);
                              
                      if( StringUtils.isEmpty(fbSessionId) ){
                              // we have no facebook session, so we need one!
                              if( !StringUtils.isEmpty(fbAuthToken)){
                                      // let the facebook service convert this authtoken into a valid session id:
                                      FacebookFacade facebookFacade = (FacebookFacade) Component.getInstance("FacebookFacade");
                                      try {
                                              fbSessionId = facebookFacade.authenticateSession( fbAuthToken );
                                      } catch (RuntimeException _e) {
                                              //ignore this: we'll throw the exception down there.... 
                                      }
                              }
                      }
                      if( fbSessionId==null ){
                              // send user to facebook login to initiate a new fb session
                              throw new FacebookAuthenticationException("auth failed");
                      }
                      facebookRequestContext = new FacebookRequestContext( fbSessionId );
              }
              
      }



      Things worked fine until we started serving several thousand customers
      per day. Under pressure, unfriendly things started to happen: Instead
      of giving each request Scope a separate FacebookRequestContext object, all our users
      got the same single instance (holding the very same session key) assigned. A rather
      puzzling customer experience ...


      Assuming a concurrency issue: Any clues what might be not thread safe with this construct?

        • 1. Re: Concurrency issues using SEAM-Wicket for facebook app
          bengrimm

          I've got the same problem. Anyone any ideas?

          • 2. Re: Concurrency issues using SEAM-Wicket for facebook app
            obfuscator

            have you disabled debug mode? I'm asking since this can cause concurrency problems.

            • 3. Re: Concurrency issues using SEAM-Wicket for facebook app
              asookazian

              This statement needs to be more specific and/or provide examples (from Seam ref doc):



              You may see errors if the system is placed under any load and debug is enabled.
              • 4. Re: Concurrency issues using SEAM-Wicket for facebook app
                asookazian
                • 5. Re: Concurrency issues using SEAM-Wicket for facebook app
                  swd847

                  Are you sure the FacebookRequestContext is the same object, or was it two separate objects with the same fbSessionId assigned to then (an easy way to check this is to create an int field in the object and assign it a random value on creation)?


                  The code that you posted should work fine, could you post the code for FacebookFacade?

                  • 6. Re: Concurrency issues using SEAM-Wicket for facebook app
                    mole

                    the issue turned out to be a custom Wicket UrlCodingStrategy missing thread safety.




                    public class FacebookQueryStringUrlCodingStrategy extends QueryStringUrlCodingStrategy {
                              
                         @In(required=false)
                         private FacebookRequestContext facebookRequestContext;
                    
                         public FacebookQueryStringUrlCodingStrategy(String _mountPath,
                                   Class<?> _bookmarkablePageClass) {
                              super(_mountPath, _bookmarkablePageClass);
                         }
                         
                         @Override
                         protected void appendParameters(AppendingStringBuffer _url, Map _parameters) {
                              if( facebookRequestContext!=null ){ 
                                   _parameters.putAll( facebookRequestContext.getAdditionalParameters());
                              }
                              super.appendParameters(_url, _parameters);
                         }     
                    }




                    point is that FacebookQueryStringUrlCodingStrategy is a shared object (instanciated with new) and method appendParameters is not thread safe in combination with dependency injection. adding synchronized to the method declaration made the race condition vanish (hm, well, and it triggered some certain thoughts about re-design...) .


                    thanks for your help and attention!



                    @Pierre: any chances you have a custom UrlCodingStrategy, too? If not, I've learned to recommend checking thread-safety of shared wicket components using some sort of bijection ...