GUI and GUI-less versions of a class

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

GUI and GUI-less versions of a class

Fernando Rodriguez
Hi,

I'm making a few modifications to the Url class hierarchy from Squeak.
The HttpUrl subclass has a method to retrieve whatever the url points
to.

Since it might need a username and password, it has a method for
asking the user for it, in case it gets an authentication error.

I'd like to change this behavior. In some cases, I'd like it not to
open any window (asking for the username and password) and just log an
error somewhere.

What do you recommend? Having a flag inside HttpUrl that indicates the
behavior in case of an authentication error, or having 2 separate
classes?

BTW, where should I log the error? O:-)

Thanks


Reply | Threaded
Open this post in threaded view
|

Re: GUI and GUI-less versions of a class

Chris Uppal-3
Fernando,

> BTW, where should I log the error? O:-)

Notification signal: 'a message' is a reasonable choice.  In a development
image the message gets written to the Transcript, in a deployed image (by
default) it is written to the Windows debug stream where it can be read with
tools like DebugView from www.sysinternals.com (highly recommended).


> What do you recommend? Having a flag inside HttpUrl that indicates the
> behavior in case of an authentication error, or having 2 separate
> classes?

Or you could pass a block to #connect, something like:

    anUrl connectAuthenticatingUsing: [:realm | Prompter promp: ... ]

where the block would be evaluated if authentication was required and not
otherwise.

There's another possibility that you might like.  You can make #connect throw a
/resumable/ exception.  The rough idea is that client code can catch that
exception, prompt the user for the password, and then resume it /if/ it wants
to.  The advantage is that the place where the user is prompted for a password
can be separated by several layers of code from the place where the connection
takes place. It doesn't have to be an exception hander immediately around
#connect, but could be at the very top-level of the GUI where a command that
might ultimately use '#connect was issued.  This allows you to decouple the
low-level networking code from the high-level GUI code, without having to pass
a load of extra data through all the intervening layers of software. (Unlike
the case of using a block as above, or a flag or separate classes.)

Create your own subclass of Exception, HttpAuthenticationRequiredException, add
an override of #isResumable that answers true, and add a few instvars to hold
the domain/URL/realm/whatever for which authentication is required, and user
name and password that client code may fill in if it wishes.

In the place where the "error" is discovered you can raise the exception with
HttpAuthenticationRequiredException signal or similar.


    [ex := (HttpAuthenticationRequiredException new)
                        realm: ...whatever...;
                        url: ... whatever...;
                        yourself.
    ex signal: 'Authentication required']
        whileTrue: [...re-try using info in ex..].

If that is handled by the client code (below) then #signal: should answer
either true or false.  If true then you can extract the supplied user-name and
password from the exception (that the client code has filled in) and attempt to
connect again.  If it answers false then the client code has handled the
exception but the user (or whatever) has decided that he/she/it does not want
to attempt authentication, so you can bomb out (without logging anything, since
it's all working according to how the user wants it to).  If the client code
does /not/ handle the exception, then (because it a subclass of Exception
rather than Notification) the normal default exception handling will kick in.
Unless you change it, the default is to abort the calling process and log an
error.

In the client code, if it wishes to be able to supply a username/password then
it should use an exception handler, something like:

    [connection := anURL connect]
        on: HttpAuthenticationRequiredException
        do: [:ex | ... handler... ].

In the handler code you can do three things.

You can prompt the user for username/password (using the information supplied
in 'ex'), if the user supplies some data then you can stuff that into the
exception and then do
        ex resume: true.
Which will return true to the place where the exception was raised.  That code
can then extract the username/password from the exception and use it to attempt
to make the connection.

Alternatively you could do
        ex resume: false.
which would return false to the place where the exception was raised.
Presumably you'd do that if the user didn't want to supply a password.

Or you could decide that the exception should be treated /as/ an exception,
aborting the current process and creating a log record.  To do that you can do
    ex pass
which, in effect, re-signals it for any containing signal handler to see, or
for its default behaviour to kick in if there is no such handler.

Of course, if you never want to handle such exceptions in one particular place
where you use #connect, then you wouldn't bother setting up an exception
handler at all.

Of course, there are other options...

    -- chris

P.S.  Having just written all that, I've just noticed/remembered that Steve
Waring's 'SW HTTPClient' package uses a similar exception-based technique; you
might like to take a look at it.


Reply | Threaded
Open this post in threaded view
|

Re: GUI and GUI-less versions of a class

Schwab,Wilhelm K
In reply to this post by Fernando Rodriguez
Fernando,

> I'm making a few modifications to the Url class hierarchy from Squeak.
> The HttpUrl subclass has a method to retrieve whatever the url points
> to.
>
> Since it might need a username and password, it has a method for
> asking the user for it, in case it gets an authentication error.
>
> I'd like to change this behavior. In some cases, I'd like it not to
> open any window (asking for the username and password) and just log an
> error somewhere.

FWIW, you are on the right track.  Inappropriate GUI interaction is a
problem in Squeak.  It is improving over time, but you are wise to
correct it in your port.

I will also second Chris' plug for Steve's HTTP client.  I have not
actually used it, but it appears to be well worth a look.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]