/*
* org.openmicroscopy.shoola.env.data.login.LoginService
*
*------------------------------------------------------------------------------
* Copyright (C) 2006 University of Dundee. All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.env.data.login;
//Java imports
//Third-party libraries
//Application-internal dependencies
import org.openmicroscopy.shoola.env.event.AgentEvent;
import org.openmicroscopy.shoola.env.event.AgentEventListener;
/**
* Defines the high-level functionality required to log onto <i>OMERO</i>.
* <p>The Login Service provides an abstraction over the process of logging
* onto <i>OMERO</i>. This service is only used directly by the Container
* either during initialization or when an invalid link is detected to try and
* reestablish it this could happen because the connection went down,
* the session expired, or the user has an invalid login. In fact, during the
* initialization procedure the user is asked to enter their credentials, which
* the Initializer then passes along to the Login Service so to establish the
* initial link to the server. Then whenever a method in the Data Services
* raises an exception due to an invalid link, the Data Services throw a <code>
* DSOutOfServiceException</code> to inform the caller (typically an Agent) and
* ask the Login Service to reestablish the broken link. At which point, the
* Login Service attempts to reconnect to <i>OMERO</i> using the current user's
* credentials that is, the credentials that the user entered during the
* initialization procedure. So many attempts are made as specified in the
* Container's configuration file. If all attempts fail, then a dialog is
* brought up on screen to allow the user to reenter their credentials (which
* now become the current credentials) and a last attempt is made. If this
* fails too, then the Login Service gives up and informs the user through an
* error dialog.</p>
* <p>Because the Container, through the Login Service, transparently manages
* the connection to <i>OMERO</i>, Agents never need to make an explicit call
* to the Login Service. However, a mechanism is provided so that Agents can
* be notified if the link to <i>OMERO</i> is reestablished. This allows an
* Agent to gracefully recover from a <code>DSOutOfServiceException</code>.
* It works as follows. The Agent registers with the <code>Event Bus</code>
* for <code>ServiceActivationResponse</code>s and then catches a <code>
* DSOutOfServiceException</code> to post a <code>ServiceActivationRequest.
* </code> This will be responded by the Login Service with a <code>
* ServiceActivationResponse</code>, whose <code>isActivationSuccessful</code>
* method can be used to find out if the link has been reestablished. If so,
* the Agent can retry the original call to the Data Services. Note that if
* the Agent implements this for more than one Data Services method, then
* upon receipt of a <code>ServiceActivationResponse</code> some sort of
* de-multiplexing could be required to find out what was the method that
* originally raised the <code>DSOutOfServiceException</code> assuming
* the Agent wants to retry that call. Instead of writing endless <code>if-
* else</code> or <code>switch</code> blocks, you may want to consider the
* fact that a <code>ServiceActivationResponse</code> works like an Asynchronous
* Completion Token (ACT). Here's a code example that illustrates a possible
* recovery strategy implemented by a fictitious Agent and how to take advantage
* of ACTs:</p>
* <p><code><pre>
* public class MyAgent
* implements Agent, AgentEventListener
* {
* private Registry context;
*
* public void setContext(Registry ctx)
* {
* this.context = ctx;
*
* //Register with the Event Bus for ServiceActivationResponses
* EventBus bus = ctx.getEventBus();
* bus.register(this, ServiceActivationResponse.class);
* }
*
* public void displayProjects()
* {
* DataManagementService dms = context.getDataManagementService();
* try {
* List projects = dms.retrieveUserProjects();
*
* //Display the projects in some UI widget...
*
* } catch (DSOutOfServiceException e) {
* //For some reason our link to OMEDS is not valid at the moment.
* //The Container is working under the hood to reestablish a valid
* //link, but we want to know when and if the Container succeeds.
* //So we're going to post a ServiceActivationRequest.
* ServiceActivationRequest req = new ServiceActivationRequest(
* ServiceActivationRequest.DATA_SERVICES);
* req.setSource(this);
*
* //Because we want to retry the call in the case the Container
* //manages to reestablish a valid link, we set a CompletionHanlder
* //which will be dispatched when we receive the response.
* //(See eventFired below.)
* req.setCompletionHandler(new CompletionHandler() {
* public void handle(RequestEvent request,
* ResponseEvent response)
* {
* ServiceActivationResponse sar =
* (ServiceActivationResponse) response;
* if (sar.isActivationSuccessful())
* //We have a valid link to OMEDS. Retry the call.
* displayProjects();
* }
* });
*
* //Now we can post the request. The Container will notify us of
* //the outcome of its attempts to reestablish a link with a
* //ServiceActivationResponse. (See eventFired below.)
* EventBus bus = context.getEventBus();
* bus.post(req);
*
* } catch (DSAccessException e) {
* //Tell the user to retry...
* }
* }
*
* public void displayDatasets()
* {
* //Similar to displayProjects...
* }
*
* public void eventFired(AgentEvent ae)
* {
* if (ae instanceof ServiceActivationResponse) {
* ServiceActivationResponse sar = (ServiceActivationResponse) ae;
* if (sar.getSource() == this) //This was our request.
* sar.complete();
* }
* //The complete method will eventually invoke the CompletionHandler.
* //Note how we hanlde *all* cases (displayProjects, displayDatasets,
* //etc.) with a *single* statement.
* //Also note that we make sure we only hanlde requests that this
* //Agent posted. In fact, multiple ServiceActivationResponses could
* //be travelling on the Event Bus if more than one Agent posted
* //ServiceActivationRequests.
* }
*
*
* //Other methods...
*
* } //End of MyAgent.
* </pre></code></p>
* <p>The Login Service is thread-safe. If multiple threads attempt to login
* at the same time, then only one is allowed to proceed as all the others will
* have to wait for the outcome of the login attempt. (Note that because a
* <code>DataServiceView</code> usually runs asynchronously with respect to the
* UI, it's possible that two or more concurrent calls to the Data Services fail
* at approximately the same time, which would result in concurrent calls to the
* Login Service.)</p>
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author <br>Andrea Falconi
* <a href="mailto:a.falconi@dundee.ac.uk">
* a.falconi@dundee.ac.uk</a>
* @version 2.2
* <small>
* (<b>Internal version:</b> $Revision$ $Date$)
* </small>
* @since OME2.2
*/
public interface LoginService
extends AgentEventListener
{
/**
* Indicates that the client couldn't connect b/c a
* <code>DNSException</code> was thrown by the server.
*/
public static final int DNS_INDEX = 100;
/**
* Indicates that the client couldn't connect b/c a
* <code>PermissionException</code> was thrown by the server.
*/
public static final int PERMISSION_INDEX = 101;
/**
* Indicates that the client couldn't connect b/c a
* <code>ConnectionException</code> was thrown by the server.
*/
public static final int CONNECTION_INDEX = 102;
/**
* Indicates that the client couldn't connect b/c the user is no longer
* active
*/
public static final int ACTIVE_INDEX = 103;
/**
* Indicates that the client couldn't connect b/c a
* <code>Ice.FileException</code> was thrown by the server.
*/
public static final int CONFIGURATION_INDEX = 104;
/** Indicates that a failure occurred preventing the client to start.*/
public static final int SYSTEM_FAILURE_INDEX = 105;
/**
* Flag to denote the Idle state.
* While in this state, the Login Service is waiting for a login request.
*/
public static final int IDLE = 0;
/**
* Flag to denote the Attempting Login state.
* While in this state, the Login Service is carrying out a login request.
*/
public static final int ATTEMPTING_LOGIN = 1;
/** Flag indicating that the client is connected to the server. */
public static final int CONNECTED = 1;
/** Flag indicating that the client is not connected to the server. */
public static final int NOT_CONNECTED = 0;
/** Flag indicating that the connection's attempt's has time out. */
public static final int TIMEOUT = 2;
/** Flag indicating that the client and server are not compatible.*/
public static final int INCOMPATIBLE = 3;
/**
* Returns the current state of the Login Service.
*
* @return One of the state flags defined by this interface.
*/
public int getState();
/**
* Attempts to login using the current user's credentials.
* If the user hasn't entered their login credentials yet, then this method
* just returns without attempting a connection to <i>OMEDS</i>.
* Otherwise, the most recently entered user's credentials are used to
* attempt establishing a valid link to the server.
* Upon failure, this method retries for how many times as specified by the
* Container's configuration. (The time interval between each attempt is
* also specified by the Container's configuration.) If all attempts fail,
* then a dialog is brought up on screen to allow the user to reenter their
* credentials (which now become the current credentials) and a last attempt
* is made. If this fails too, then this method gives up and informs the
* user through an error dialog.
*/
public void login();
/**
* Attempts to login using the specified user's credentials.
* If <code>uc</code> is <code>null</code>, then then this method just
* returns without attempting a connection to <i>OMEDS</i>. Otherwise,
* <code>uc</code> becomes the current user's credentials and an attempt
* is made to establish a link to the server. If the attempt fails, the
* user is informed through an error dialog.
*
* @param uc The new user's credentials.
* @return <code>true</code> upon success, <code>false</code> in the case
* of failure.
*/
public int login(UserCredentials uc);
/**
* Implemented to receive notification of a <code>ServiceActivationRequest
* </code> coming from an Agent.
* A <code>ServiceActivationResponse</code> is posted back to inform the
* Agent about the current login state. That is, if there's a valid link
* to the server.
*
* @param serviceActivationRequest A <code>ServiceActivationRequest</code>
* posted by an Agent.
*/
public void eventFired(AgentEvent serviceActivationRequest);
/** Updates the view when failed to log in. */
public void notifyLoginFailure();
/** Updates the view when failed to log in. */
public void notifyLoginTimeout();
}