/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.client.ui.rcp.businessprocess;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jubula.client.core.events.DataChangedEvent;
import org.eclipse.jubula.client.core.events.DataEventDispatcher;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.AutState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IAutStateListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IDataChangedListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IProjectLoadedListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IProjectStateListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.IServerConnectionListener;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.ProjectState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.ServerState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.UpdateState;
import org.eclipse.jubula.client.core.model.IAUTConfigPO;
import org.eclipse.jubula.client.core.model.IAUTMainPO;
import org.eclipse.jubula.client.core.model.IPersistentObject;
import org.eclipse.jubula.client.core.model.IProjectPO;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.internal.AutAgentConnection;
import org.eclipse.jubula.client.internal.exceptions.ConnectionException;
import org.eclipse.jubula.client.ui.rcp.i18n.Messages;
import org.eclipse.jubula.client.ui.utils.JobUtils;
import org.eclipse.jubula.tools.internal.constants.EnvConstants;
import org.eclipse.jubula.tools.internal.exception.Assert;
/**
* @author BREDEX GmbH
* @created 13.07.2006
*/
public class StartAutBP {
/** single instance of StartAutBP */
private static StartAutBP instance = null;
/** last used AUT */
private IAUTMainPO m_lastUsedAut;
/** last used AutConfiguration */
private IAUTConfigPO m_lastUsedConf;
/** describes, if a project is loaded or not */
private boolean m_isProjectLoaded = false;
/** describes the state of server connection */
private boolean m_isServerConnected = false;
/** describes the state of AUT */
private AutState m_autState = AutState.notRunning;
/** flag to signal if at least one aut is available */
private boolean m_atLeastOneAutAvailable = false;
/** flag to signal that the AUTStartButton was clicked
* it doesn't mean that the AUT is really running (see m_autState)
*/
private boolean m_autStarted = false;
/**
* <code>m_hostNameCache</code>
*/
private Map<String, String> m_hostNameCache = new HashMap<String, String>();
/** listener for loading of project */
private IProjectLoadedListener m_projLoadedListener =
new IProjectLoadedListener() {
/**
* {@inheritDoc}
*/
@SuppressWarnings("synthetic-access")
public void handleProjectLoaded() {
m_isProjectLoaded = true;
m_lastUsedAut = null;
m_lastUsedConf = null;
m_autState = AutState.notRunning;
m_autStarted = false;
m_atLeastOneAutAvailable = false;
fireAUTButtonStateCouldBeChanged();
}
};
/**
* <code>m_currentProjDeletedListener</code>listener for deletion of current project
*/
private IDataChangedListener m_currentProjDeletedListener =
new IDataChangedListener() {
/** {@inheritDoc} */
public void handleDataChanged(DataChangedEvent... events) {
for (DataChangedEvent e : events) {
handleDataChanged(e.getPo(), e.getDataState(),
e.getUpdateState());
}
}
@SuppressWarnings("synthetic-access")
public void handleDataChanged(IPersistentObject po,
DataState dataState,
UpdateState updateState) {
if (updateState == UpdateState.onlyInEditor) {
return;
}
if (dataState == DataState.Deleted && po instanceof IProjectPO
&& GeneralStorage.getInstance().getProject() == null) {
m_isProjectLoaded = false;
m_lastUsedAut = null;
m_lastUsedConf = null;
m_autState = AutState.notRunning;
m_autStarted = false;
m_atLeastOneAutAvailable = false;
}
}
};
/**
* <code>m_serverConnectListener</code>listener for modification of server connection
*/
private IServerConnectionListener m_serverConnectListener =
new IServerConnectionListener() {
@SuppressWarnings("synthetic-access")
public void handleServerConnStateChanged(ServerState state) {
switch (state) {
case Connected:
m_isServerConnected = true;
break;
case Disconnected:
case Connecting:
m_isServerConnected = false;
m_autState = AutState.notRunning;
m_autStarted = false;
break;
default:
Assert.notReached(Messages
.UnhandledConnectionStateForServer);
}
fireAUTButtonStateCouldBeChanged();
}
};
/**
* <code>m_autStateListener</code> listener for modification of aut state
*/
private IAutStateListener m_autStateListener = new IAutStateListener() {
/**
* @param state state from AUT
*/
@SuppressWarnings("synthetic-access")
public void handleAutStateChanged(AutState state) {
switch (state) {
case running:
m_autState = AutState.running;
break;
case notRunning:
m_autState = AutState.notRunning;
m_autStarted = false;
break;
default:
Assert.notReached(Messages.UnhandledAutState);
}
fireAUTButtonStateCouldBeChanged();
}
};
/**
* <code>m_projPropModifyListener</code> listener for modification of project properties
*/
private IProjectStateListener m_projPropModifyListener =
new IProjectStateListener() {
/** {@inheritDoc} */
public void handleProjectStateChanged(ProjectState state) {
if (ProjectState.prop_modified.equals(state)) {
if (getLastUsedAut() == null || getLastUsedConf() == null) {
fireAUTButtonStateCouldBeChanged();
return;
}
String autName = getLastUsedAut().getName();
String confName = getLastUsedConf().getName();
for (IAUTMainPO aut : GeneralStorage.getInstance()
.getProject().getAutMainList()) {
if (autName.equals(aut.getName())) {
for (IAUTConfigPO conf : aut.getAutConfigSet()) {
if (confName.equals(conf.getName())) {
setLastUsedAut(aut);
setLastUsedAutConf(conf);
return;
}
}
}
}
fireAUTButtonStateCouldBeChanged();
}
}
};
/**
* private constructor
*/
private StartAutBP() {
init();
}
/**
* init this BP instance
*/
private void init() {
final DataEventDispatcher ded = DataEventDispatcher.getInstance();
ded.addProjectLoadedListener(m_projLoadedListener, true);
ded.addDataChangedListener(m_currentProjDeletedListener, true);
ded.addAutAgentConnectionListener(m_serverConnectListener, true);
ded.addAutStateListener(m_autStateListener, true);
ded.addProjectStateListener(m_projPropModifyListener);
}
/**
* get single instance
* @return single instance of StartAutBP
*/
public static StartAutBP getInstance() {
if (instance == null) {
instance = new StartAutBP();
}
return instance;
}
/**
* @return all AUTs for connected aut agent
*/
public SortedMap<IAUTMainPO, SortedSet<IAUTConfigPO>> getAllAUTs() {
if (GeneralStorage.getInstance().getProject() != null) {
Set<IAUTMainPO> autsForLang = getAUTs();
return getAutsForAutAgent(autsForLang);
}
return new TreeMap<IAUTMainPO, SortedSet<IAUTConfigPO>>();
}
/**
* @param auts
* all auts
* @return map with all auts applicable for given
* configurations for started server
*/
private SortedMap<IAUTMainPO, SortedSet<IAUTConfigPO>>
getAutsForAutAgent(Set<IAUTMainPO> auts) {
SortedMap<IAUTMainPO, SortedSet<IAUTConfigPO>> autMap =
new TreeMap<IAUTMainPO, SortedSet<IAUTConfigPO>>();
String agentHostname = resolveAUTAgentHostName();
if (agentHostname != null) {
agentHostname = agentHostname.toLowerCase();
String agentIp = resolveIpUsingCache(agentHostname);
Set<String> validHosts = new HashSet<String>();
validHosts.add(agentIp);
validHosts.add(agentHostname);
final InetAddress lh = EnvConstants.LOCALHOST;
if (isConnectedToLocalhost(agentIp, agentHostname, lh)) {
validHosts.add(EnvConstants.LOCALHOST_ALIAS);
validHosts.add(EnvConstants.LOCALHOST_IP_ALIAS);
validHosts.add(lh.getHostAddress());
validHosts.add(lh.getHostName().toLowerCase());
validHosts.add(EnvConstants.LOCALHOST_FQDN.toLowerCase());
}
for (IAUTMainPO autForLang : auts) {
Set<IAUTConfigPO> confs = autForLang.getAutConfigSet();
SortedSet<IAUTConfigPO> validConfs =
new TreeSet<IAUTConfigPO>();
for (IAUTConfigPO conf : confs) {
String confAgentName = conf.getConfiguredAUTAgentHostName()
.toLowerCase();
String confAgentIp = resolveIpUsingCache(confAgentName);
if (validHosts.contains(confAgentIp)
|| validHosts.contains(confAgentName)) {
validConfs.add(conf);
}
}
if (!validConfs.isEmpty()) {
autMap.put(autForLang, validConfs);
}
}
}
return autMap;
}
/**
* @param agentIp
* the agent IP address
* @param agentHostname
* the agent host name
* @param localhost
* the local host
* @return whether the current connection is a connection to the local host
*/
private boolean isConnectedToLocalhost(String agentIp,
String agentHostname, InetAddress localhost) {
if (agentIp.equals(EnvConstants.LOCALHOST_IP_ALIAS)
|| agentHostname.equals(EnvConstants.LOCALHOST_ALIAS)) {
return true;
}
if (localhost == null) {
return false;
}
final String hostAddress = localhost.getHostAddress();
final String hostName = localhost.getHostName().toLowerCase();
final String fqHostName = localhost.getCanonicalHostName()
.toLowerCase();
return hostAddress.equals(agentIp) || hostName.equals(agentHostname)
|| fqHostName.equals(agentHostname);
}
/**
* @return the server host name
*/
private String resolveAUTAgentHostName() {
String serverHostName = null;
try {
AutAgentConnection serverConn = AutAgentConnection.getInstance();
if (serverConn.isConnected()
&& serverConn.getCommunicator() != null) {
serverHostName = serverConn.getCommunicator().getHostName();
}
} catch (ConnectionException ce) {
// Indicates that no connection has yet been established
}
return serverHostName;
}
/**
* @param hostname
* the hostname to resolve the ip for
* @return the corresponding ip adress; if not resolvable --> null
*/
private String resolveIpUsingCache(String hostname) {
String ip = null;
if (!m_hostNameCache.containsKey(hostname)) {
try {
ip = InetAddress.getByName(hostname).getHostAddress();
} catch (UnknownHostException e) {
// ignore
}
m_hostNameCache.put(hostname, ip);
} else {
ip = m_hostNameCache.get(hostname);
}
return ip;
}
/**
* @return AUTs, which support working language
*/
private Set<IAUTMainPO> getAUTs() {
return GeneralStorage.getInstance().getProject().getAutMainList();
}
/**
* @return last used AUT
*/
public IAUTMainPO getLastUsedAut() {
return m_lastUsedAut;
}
/**
* @param lastUsedAut The lastUsedAut to set.
*/
public void setLastUsedAut(IAUTMainPO lastUsedAut) {
m_lastUsedAut = lastUsedAut;
}
/**
* @param conf last used AutConfiguration
*/
public void setLastUsedAutConf(IAUTConfigPO conf) {
m_lastUsedConf = conf;
}
/**
* @return Returns the lastUsedConf.
*/
public IAUTConfigPO getLastUsedConf() {
return m_lastUsedConf;
}
/**
* {@inheritDoc}
*/
public boolean isEnabled() {
return m_isProjectLoaded
&& m_isServerConnected
&& m_autState == AutState.notRunning
&& !m_autStarted
&& m_atLeastOneAutAvailable;
}
/**
*
*/
protected void validateNumberOfAuts() {
final SortedMap<IAUTMainPO, SortedSet<IAUTConfigPO>> allAUTs =
getAllAUTs();
if (allAUTs.size() < 1) {
m_atLeastOneAutAvailable = false;
} else {
m_atLeastOneAutAvailable = true;
if (m_lastUsedAut != null && m_lastUsedConf != null) {
validateLastUsedAut(allAUTs);
}
}
}
/**
* validates, if the current last used AUT is still available
* @param allAUTs all available AUTs
*/
private void validateLastUsedAut(
SortedMap<IAUTMainPO, SortedSet<IAUTConfigPO>> allAUTs) {
if (!(allAUTs.containsKey(m_lastUsedAut)
&& allAUTs.get(m_lastUsedAut).contains(m_lastUsedConf))) {
m_lastUsedAut = null;
m_lastUsedConf = null;
}
}
/**
* signals, that at least one parameter for computing of enabled state of
* start aut button is changed
*/
private void fireAUTButtonStateCouldBeChanged() {
final String jobName = Messages.UIJobUpdatingRecentlyUsedAuts;
Job resolveStartableAUTs = new Job(jobName) {
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask(jobName, IProgressMonitor.UNKNOWN);
validateNumberOfAuts();
monitor.done();
return Status.OK_STATUS;
}
};
JobUtils.executeJob(resolveStartableAUTs, null);
}
/**
* invoke this method to signal, that the AUTStartButton was clicked
*/
public void fireAutStarted() {
m_autStarted = true;
}
}