[JSDO v4.4] XmlHttpRequest InvalidStateError - Forum - Mobile - Progress Community

[JSDO v4.4] XmlHttpRequest InvalidStateError

 Forum

[JSDO v4.4] XmlHttpRequest InvalidStateError

  • When logging out and discarding a JSDO session and then creating a new one and logging in again, sometimes on the very next request (could be an addCatalog, a fill, etc.), the JSDO will throw an XmlHttpRequest InvalidStateException stating that the request's state must be OPENED. After some debugging I have found that in the following method: progress.data.AuthenticationProvider.prototype._openRequestAndAuthorize, there is a call made to hasClientCredentials() which returns false, even though this is happening after a successful form authentication. Because the hasClientCredentials() method returns false, the xhr.open method is never called and thus when calling xhr.send, the error is thrown.

    To reproduce this one needs to create a JSDO session, authenticate, add a catalog, create a JSDO and call the fill method at least once, logout, create a new session, authenticate again and attempt creating another JSDO and filling it with data.

    Is this a bug with the JSDO implementation, or are there API changes in v4.4 that I am not accounting for?

  • Hey! JSDOSession.login() and logout() are deprecated as of 4.4 (and will probably be removed in 4.5) so I tried replicating this using the new API.

    Here are the steps I used to test this out:

    1. Create an AuthenticationProvider

    2. Log in with the AP

    3. Create the JSDOSession and call addCatalog()

    4. Create a JSDO and call fill()

    5. Create another JSDOSession and call addCatalog()

    6. Create another JSDO and call fill()

    And I don't seem to be stumbling on this issue. I just want to clarify, is this with JSDOSession.login() and .logout()?

  • Hi Nicaragua,

    Please log a bug. We implemented a new interface and it looks like we might have broke something. We will try to provide a workaround once we get a chance to investigate.

    Thank you

    Shelley

  • Hello, is there an example with this authentication?

  • Shelley Chase

    Hi Nicaragua,

    Please log a bug. We implemented a new interface and it looks like we might have broke something. We will try to provide a workaround once we get a chance to investigate.

    Thank you

    Shelley

    Done.

    Architect of the SmartComponent Library and WinKit

    Consultingwerk Ltd.

  • In versions before 4.4, the JSDOSession object had too many responsibilities. It handled both authentication and session management. For clarity and maintainability, the JSDOSession was split.

    The AuthenticationProvider object was created to handle authentication of the user. All current authentication models are supported, with the potential of handling new ones like oauth.

    The JSDOSession now only manages the user’s session and will now require an AuthenticationProvider whenever it is being instantiated.

    Sample Code 

                var session,
                    auth;
    
                auth = new progress.data.AuthenticationProvider(
                {
                    authenticationModel: progress.data.Session.AUTH_TYPE_FORM,
                    uri: "http://1.1.1.1:8810/Customer/"
                });
                
                auth.login("user", "password")    
                    .then(function() { 
    
                        session = new progress.data.JSDOSession({
                            authenticationModel: progress.data.Session.AUTH_TYPE_FORM,
                            serviceURI: "http://1.1.1.1:8810/Customer/",
                            authProvider: auth
                       });
    
                        return session.isAuthorized();
                    })
                    .then(function (session, result, info) {
                        return session.addCatalog("1.1.1.1:8810/.../CustomerService.json");
                    })
                    .then(function (s, r, i) {
                        jsdo = new progress.data.JSDO({ name: 'Customer' });
                        jsdo.subscribe('AfterFill', onAfterFillCustomers, this);	
                        jsdo.fill();    
    
                        function onAfterFillCustomers(jsdo, success, request) {
                            jsdo.ttCustomer.foreach(function(customer) {
                                document.write(customer.data.CustNum + ' ' + customer.data.Name + '<br>');
                            });	
                        }
                    });

    Some extra things to note are that
    • JSDOSession.login() and logout() have been officially deprecated. We recommend the usage of the new AuthenticationProvider model or even getSession(), which will handle the creation of AuthenticationProviders for you.
      • Note that getSession() will now require two extra properties in the parameter object, authProviderAuthenticationModel which is the authenticationModel of the AuthProvider and the authenticationURI, which is the URI of where you are authenticating.
        • For form, anon, and basic, the serviceURI and the authenticationURI is usually the same. 

    • The Session object also has been deprecated. Please use the JSDOSession object instead.
    • An AuthenticationProvider can also be shared by multiple JSDOSessions, it's not limited to just one.
    • The official documentation is on the way.

     

    API

    AuthenticationProvider object

    • Constructor
    • login()
    • logout()
    • hasClientCredentials()

    1. Constructor

    Syntax:

    new AuthenticationProvider(options);

    Parameters: 

    • Options object that requires these two fields
      • uri
        • This is the uri of the webapp which this AP will login into
      • authenticationModel
        • Specifies what model this AP will use, currently supports:
          • progress.data.AuthProvider.AUTH_TYPE_ANON 
          • progress.data.AuthProvider.AUTH_TYPE_BASIC
          • progress.data.AuthProvider.AUTH_TYPE_FORM

    2. login()

    Syntax:

    authenticationProvider.login(username, password);

    Parameters:

    • username
      • A string of the username. Not required for anon.
    • password
      • A string of the password. Not required for anon.

    What it does:

    • This logs into the webapp of the URI given in the constructor. Paired with the JSDOSession, it should attach the credentials it has to requests that your JSDOSession makes.

    Returns:

    • JQuery promise
      • All promise handlers will be given the AP, the result, and more information about the result, e.g.:
        • ap.login(username, password).then(function(ap, result, info) {});
      • The result param will have one of these three values:
        • progress.data.Session.SUCCESS (its numeric value is 1)
        • progress.data.Session.AUTHENTICATION_FAILURE (2)
        • progress.data.Session.GENERAL_FAILURE (3)

    3. logout()

    Syntax:

    authProvider.logout()

    What it does:

    • It logs you out of the webapp you logged into.

    Returns:

    • JQuery promise
      • All promise handlers will be given the AP, the result, and more information about the result, e.g.:
        • ap.logout().then(function(ap, result, info) {});
      • Result will have one of these two values:
        • progress.data.Session.AUTHENTICATION_SUCCESS
        • progress.data.Session.GENERAL_FAILURE

    4. hasClientCredentials()

    Syntax:

    ap.hasClientCredentials()

    What it does:

    • If the AP is currently managing credentials (e.g. you successfully logged in via FORM and haven't logged out), then this'll return true. Else, it'll return false.

    Returns:

    • Boolean, will either be true or false.

    JSDOSession object

    • Constructor
    • login()
    • logout()
    • isAuthorized()

    1. Constructor

    Syntax:

    new JSDOSession(options);

    Parameters: 

    • Options object that requires these two fields
      • serviceURI
        • This is the uri of the webapp which this session will access
      • authenticationModel
        • Specifies what model this session will use, currently supports:
          • progress.data.Session.AUTH_TYPE_ANON 
          • progress.data.Session.AUTH_TYPE_BASIC
          • progress.data.Session.AUTH_TYPE_FORM
      • authProvider
        • An AuthProvider object that this JSDOSession will use

      2. login()

      This function is now deprecated, don't use it.

      3. logout()

      This function has now gone the way of the might Tyrannasaurus Rex and has been deprecated. Please do not use it.

      4. isAuthorized()

      Syntax:

      session.isAuthorized()

      Parameters:

      None

      What it does:

      • Checks if the credentials that the AuthProvider is valid or if the service is even accessible. Will trigger online/offline events in the session.

      Returns:

      • JQuery promise
        • All promise handlers will be given the JSDOSession, the result, and more information about the result, e.g.:
          • ap.logout().then(function(jsdosession, result, info) {});

        • Result will have one of these four values:
          • progress.data.Session.SUCCESS
          • progress.data.Session.AUTHENTICATION_FAILURE
          • progress.data.Session.LOGIN_AUTHENTICATION_REQUIRED
          • progress.data.Session.GENERAL_FAILURE

    • Hopefully, that previous post answered most of your questions. Let me know if you guys need any more information or have any more questions!

    • "The official documentation is on the way."

      -Is it here already?

    • Hey Ruben, I've updated the above post with the API of the AuthenticationProvider and the JSDOSession. Let me know if you need more information.

      And the official docs is not here yet unfortunately.

    • Thanks for the info Alan, much appreciated.

      Just to make sure: you will need to use the login function with the AP, even if you're using anonymous authentication?

    • Hi Ruben,
       
      Yes. For all supported authentication models (Anonymous, Basic and Form) it is recommended to use AuthenticationProvider.
       
      Thanks and Regards,
      Anil Kumar.
       
    • Thanks Anil, but that's not exactly what I meant though. I can create an authenticationProvider object just fine, but I need to call login on the authenticationProvider object to be able to i.e. add a catalog to the JSDOSession object.

      Otherwise the HasClientCredentials() function fails for the authenticationProvider object (even when client credentials are blanks).