Client Application Registration Recovery Example

After SAP Mobile Server is restored, the client application connection information might be lost if the registration was created after the database was backed up.

This client application calls startConnection to connect to SAP Mobile Server. The onConnectionStatusChanged callback returns error code 580 with the message authentication failed . The user can reregister the application using SUPApplicationCallback implementation by this error code . If SAP Mobile Server is restored to a point in time when the client application has registered, startConnection should be able to start without error or with other errors when communications to SAP Mobile Server failed.
Note: In these code examples lines following "MyApplicationCallback.h" indicates they should be in the MyApplicationCallback.h header file. Similarly, code lines following "MyApplicationCallback.m" indicates they should be in the MyApplicationCallback.m file.
  1. Automatic registration recover:
    - (void) startApplication
    
    
    {
        SUPApplication *app = [SUPApplication getInstance];
        MyApplicationCallback *cb = [[[MyApplicationCallback alloc] init] autorelease];
        [app setApplicationCallback:cb];
        
        @try
        {
            SUPConnectionProperties *connProperties = app.connectionProperties;
            connProperties.serverName = testServer;
            connProperties.portNumber = testPort;
            SUPLoginCredentials *login = [SUPLoginCredentials getInstance];
            login.username = testUser;
            login.password = testPassword;
            connProperties.loginCredentials = login;
            
            if (app.registrationStatus == SUPRegistrationStatus_UNREGISTERED)
            {
                [app registerApplication:100]; // or call app.RegisterApplication();
            }
            else
            {
                [app startConnection:100]; // or call app.StartConnection();
            }
        }
        @catch (SUPApplicationRuntimeException *ex)
        {
            NSLog(@"SUPApplicationRuntimeException(%d): %@", ex.errorCode, ex.reason);
        }
        @catch (SUPApplicationTimeoutException  *ex)
        {
            NSLog(@"SUPApplicationTimeoutException(%d): %@", ex.errorCode, ex.reason);
        }
        
        while (app.connectionStatus != SUPConnectionStatus_CONNECTED || app.registrationStatus != SUPRegistrationStatus_REGISTERED)
        {
            if (cb.reregisterException != nil)
            {
                // reregister hit exception
                @throw cb.reregisterException;
            }
            sleep(1);
        }
    }
    
    
    MyApplicationCallback.h
    
    #import "SUPApplicationDefaultCallback.h"
    
    @interface MyApplicationCallback : SUPApplicationDefaultCallback
    {
        
    }
    
    @property(readwrite, nonatomic, assign) BOOL callFlag;
    @property(readwrite, nonatomic, retain) NSException *reregisterException;
    
    @end
    
    MyApplicationCallback.m
    
    
    #import "MyApplicationCallback.h"
    
    #import "SUPApplication.h"
    #import "end2end_rdbEnd2end_rdbDB.h"
    
    @implementation MyApplicationCallback
    
    @synthesize callFlag;
    @synthesize reregisterException;
    
    - (id) init
    {
        [super init];
        callFlag = NO;
        reregisterException = nil;
        return self;
    }
    
    - (void)onConnectionStatusChanged:(SUPConnectionStatusType)connectionStatus :(int)errorCode :(NSString *)errorMessage
    {
        // error code 580 is COMMUNICATION_DEVICEVAL_INVALID_ACTIVE_CODE
        if (errorCode == COMMUNICATION_DEVICEVAL_INVALID_ACTIVE_CODE && !callFlag)
        {
            // this callback could be invoked multiple times when this error occures,
            // but we just call once to reregister, so set the callFlag to be true.
            callFlag = true;
            dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
            dispatch_async(queue, ^{
                [self reregister];
            });
                           
        }
    }
    
    - (void) reregister
    {
        // do not unregister application, because the application connection info
        // has been deleted from server side. We can call registerApplication directly.
        @try
        {
            // call disable sync for all packages in this application
            [end2end_rdbEnd2end_rdbDB disableSync];
    
            SUPApplication *app = [SUPApplication getInstance];
            [app registerApplication:100];
    
            // call enable sync for all packages in this application
            [end2end_rdbEnd2end_rdbDB enableSync];
    
            NSLog(@"Done reregister.");
        }
        @catch (NSException *exception)
        {
            NSLog(@"reregister hit exception(%@): %@", exception.name, exception.reason);
            self.reregisterException = exception;
        }
    
    }
    @end
    
  2. Manual registration recover - if error code 580 is encountered, register the application manually in SAP Control Center first, or else reregistering the application fails the first time. Manual registration requires an activation code be set:
    - (void) startApplication
    {
        SUPApplication *app = [SUPApplication getInstance];
        MyApplicationCallback *cb = [[[MyApplicationCallback alloc] init] autorelease];
        [app setApplicationCallback:cb];
        
        @try
        {
            SUPConnectionProperties *connProperties = app.connectionProperties;
            connProperties.serverName = testServer;
            connProperties.portNumber = testPort;
            connProperties.activationCode = @”100”;
            SUPLoginCredentials *login = [SUPLoginCredentials getInstance];
            login.username = testUser;
            login.password = nil;
            connProperties.loginCredentials = login;
            
            if (app.registrationStatus == SUPRegistrationStatus_UNREGISTERED)
            {
                [app registerApplication:100]; // or call app.RegisterApplication();
            }
            else
            {
                [app startConnection:100]; // or call app.StartConnection();
            }
        }
        @catch (SUPApplicationRuntimeException *ex)
        {
            NSLog(@"SUPApplicationRuntimeException(%d): %@", ex.errorCode, ex.reason);
        }
        @catch (SUPApplicationTimeoutException  *ex)
        {
            NSLog(@"SUPApplicationTimeoutException(%d): %@", ex.errorCode, ex.reason);
        }
        
        while (app.connectionStatus != SUPConnectionStatus_CONNECTED || app.registrationStatus != SUPRegistrationStatus_REGISTERED)
        {
            if (cb.reregisterException != nil)
            {
                // reregister hit exception
                @throw cb.reregisterException;
            }
            sleep(1);
        }
    }
    
    
    MyApplicationCallback.h
    
    #import "SUPApplicationDefaultCallback.h"
    
    @interface MyApplicationCallback : SUPApplicationDefaultCallback
    {
        
    }
    
    @property(readwrite, nonatomic, assign) BOOL callFlag;
    @property(readwrite, nonatomic, retain) NSException *reregisterException;
    
    @end
    
    MyApplicationCallback.m
    
    
    #import "MyApplicationCallback.h"
    
    #import "SUPApplication.h"
    #import "end2end_rdbEnd2end_rdbDB.h"
    
    @implementation MyApplicationCallback
    
    @synthesize callFlag;
    @synthesize reregisterException;
    
    - (id) init
    {
        [super init];
        callFlag = NO;
        reregisterException = nil;
        return self;
    }
    
    - (void) onConnectionStatusChanged: (SUPConnectionStatusType) connectionStatus :(int)errorCode :(NSString *)errorMessage
    {
        // error code 580 is COMMUNICATION_DEVICEVAL_INVALID_ACTIVE_CODE
        if (errorCode == COMMUNICATION_DEVICEVAL_INVALID_ACTIVE_CODE && !callFlag)
        {
            // this callback could be invoked multiple times when this error occures,
            // but we just call once to reregister, so set the callFlag to be true.
            callFlag = true;
            dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
            dispatch_async(queue, ^{
                [self reregister];
            });
                           
        }
    }
    
    - (void) reregister
    {
        // do not unregister application, because the application connection info
        // has been deleted from server side. We can call registerApplication directly.
        @try
        {
            // call disable sync for all packages in this application
            [end2end_rdbEnd2end_rdbDB disableSync];
    
            SUPApplication *app = [SUPApplication getInstance];
            [app registerApplication:100];
    
            // call enable sync for all packages in this application
            [end2end_rdbEnd2end_rdbDB enableSync];
    
            NSLog(@"Done reregister.");
        }
        @catch (NSException *exception)
        {
            NSLog(@"reregister hit exception(%@): %@", exception.name, exception.reason);
            self.reregisterException = exception;
        }
    
    }
    @end