macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Sweetening Your Xgrid with Cocoa
Pages: 1, 2, 3, 4, 5

Opening a Connection

We'll begin in the run method of Central Command's Controller class. This method, which is invoked when the user hits the Run button, attempts to open a connection with the host name and password entered.



// Setup a password authenticator, if necessary
XGTwoWayRandomAuthenticator *authenticator = nil;
if ( usePasswordAuthentication ) {
    authenticator = [[[XGTwoWayRandomAuthenticator alloc] init] autorelease];
    [authenticator setUsername:@"one-xgrid-client"];
    [authenticator setPassword:[self controllerPassword]];
}

// Make a connection to the Xgrid server. 
XGConnection *newConnection = 
    [[[XGConnection alloc] initWithHostname:[self controllerHostname] portnumber:0] autorelease];
[newConnection setAuthenticator:authenticator];
[newConnection setDelegate:self];
[[self connection] setDelegate:nil]; // Set delegate of previous connection to nil
[self setConnection:newConnection]; // This registers as the connection's delegate

// Open connection
[newConnection open];

First, an XGTwoWayRandomAuthenticator is created, if password authentication is being used. The password is set with the setPassword: method, which may not come as a surprise, but the call to setUsername: could have you a little perplexed. (I know it had me perplexed...still does.) The username you should use in this call is "one-xgrid-client," for reasons that I have been unable to ascertain. Just mark it down to idiosyncrasy, and move on. I did.

The XGConnection is initialized with the hostname, and a port number of 0. If you pass 0 for the port, the default port will be used, which is what we want in this case. The setAuthenticator: method is used to supply the authenticator to the XGConnection; if nil is passed to this method, no authentication is used.

The delegate of the XGConnection is set to Controller instance. Note that if an XGConnection is already stored in the Controller, its delegate is set to nil to prevent future calls to the delegate methods. This pattern repeats itself throughout Central Command: when initiating some form of observation, whether it involves delegation or KVO, the Controller first stops observing objects leftover from earlier runs.

The last method invoked is open. This asynchronous method attempts to contact the host specified, and authenticate. The XGConnection then calls back to its delegate, the Controller, to report success or failure. The delegate methods look like this:

-(void)connectionDidNotOpen:(XGConnection *)connection 
        withError:(NSError *)error {
    [self setRunning:NO];
    NSAlert *alert = [NSAlert alertWithMessageText:@"Could not open connection to Xgrid server." 
        defaultButton:@"OK" alternateButton:nil otherButton:nil
        informativeTextWithFormat:
            @"Check that controller host name was entered correctly, and that it is "
            @"available."];
    [alert runModal];
}

-(void)connectionDidClose:(XGConnection *)conn {
    if ( [conn error] ) {
        int errorCode = [[connection error] code];
        NSAlert *alert;
        if ( errorCode == 530 || errorCode == 535 ) { // Authentication error
            alert = [NSAlert alertWithMessageText:@"An authentication error occurred." 
                defaultButton:@"OK" alternateButton:nil otherButton:nil
                informativeTextWithFormat:
                    @"Check that you have entered the authentication details "
                    @"correctly, and that you have used the correct authentication method."];
            [alert runModal];
        }
        else {
            alert = [NSAlert alertWithMessageText:@"Could not open connection to Xgrid server." 
                defaultButton:@"OK" alternateButton:nil otherButton:nil
                informativeTextWithFormat:
                    @"Check that controller host name was entered correctly, and that the server is "
                    @"available."];
        }
        [self setRunning:NO];
        [alert runModal];
    }
}

-(void)connectionDidOpen:(XGConnection *)conn {
    // Create controller proxy
    XGController *newController = [[[XGController alloc] initWithConnection:conn] autorelease];
    [self beginMonitoringController:newController];
}

Much of this code simply deals with the errors that can arise. Authentication errors, such as a misspelled password, are quite common. Rather surprisingly, if an authentication error occurs, the connectionDidClose: method is called, not connectionDidNotOpen:. The XGConnection includes a method called error that returns an NSError explaining what went wrong. You can retrieve an error code from the NSError; a value of 530 or 535 indicates an authentication error.

If all goes well, the connectionDidOpen: delegate method is called. It creates an XGController, initializing it with the newly created XGConnection. It then calls the method beginMonitoringController, which stops observing any previously used XGController, and begins observing the state attribute of the new XGController with KVO.

-(void)beginMonitoringController:(XGController *)newController {
    [[self controller] removeObserver:self forKeyPath:@"state"];
    [newController addObserver:self forKeyPath:@"state" options:0 context:NULL];
    [self setController:newController];
}

Pages: 1, 2, 3, 4, 5

Next Pagearrow