package org.eclipse.dltk.core.internal.rse; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.Platform; import org.eclipse.dltk.utils.LazyExtensionManager; import org.eclipse.dltk.utils.LazyExtensionManager.Descriptor; import org.eclipse.rse.core.model.IHost; import org.eclipse.rse.core.subsystems.ISubSystem; import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem; /** * This class is designed to synchronize connections to RSE to display only one * connection dialog per time. * * @author haiodo * @since 2.0 * */ public class RSEConnectionQueryManager { /** * 5 minutes for connection to be established. */ private static final long CONNECTION_TIMEOUT = 1000 * 10; // ten seconds. private static RSEConnectionQueryManager queryManager = null; public static synchronized RSEConnectionQueryManager getInstance() { if (queryManager == null) { queryManager = new RSEConnectionQueryManager(); } return queryManager; } private static class ConnectionRequest { private IHost host; private boolean finished = false; public ConnectionRequest(IHost host, long id) { this.host = host; } public synchronized boolean isFinished() { return finished; } public synchronized void setFinished(boolean finished) { this.finished = finished; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((host == null) ? 0 : host.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ConnectionRequest other = (ConnectionRequest) obj; if (host == null) { if (other.host != null) return false; } else if (!host.equals(other.host)) return false; return true; } } public interface IConnector { void register(); boolean isDirectProcessingRequired(); void runDisplayRunnables(long connectionTimeout); } public void setConnectingStatus(boolean status) { synchronized (requests) { isConnecting = status; } } public boolean isConnecting() { synchronized (requests) { return isConnecting; } } public void markHostAsFinished(IHost host) { synchronized (requests) { List<ConnectionRequest> toRemove = new ArrayList<>(); for (ConnectionRequest request : requests) { if (request.host.equals(host)) { toRemove.add(request); request.setFinished(true); } } setConnectingStatus(false); if (!toRemove.isEmpty()) { requests.removeAll(toRemove); requests.notifyAll(); } } } /** * Get host and set state to isConnecting() * * @return */ public IHost getNextHost(boolean wait) { synchronized (requests) { if (wait) { while (isConnecting() || requests.isEmpty()) { try { requests.wait(100); } catch (InterruptedException e) { DLTKRSEPlugin.log(e); } } } if (!requests.isEmpty()) { ConnectionRequest request = requests.get(0); setConnectingStatus(true); return request.host; } return null; } } private LazyExtensionManager<IConnector> connectors = new LazyExtensionManager<>( DLTKRSEPlugin.PLUGIN_ID + ".rseConnector"); private List<ConnectionRequest> requests = new ArrayList<>(); private boolean isConnecting = false; private long currentId; public RSEConnectionQueryManager() { Descriptor<IConnector>[] descriptors = connectors.getDescriptors(); for (Descriptor<IConnector> descriptor : descriptors) { IConnector connector = descriptor.get(); connector.register(); } } public boolean connectTo(IHost host) { if (isConnected(host)) { return true; } ConnectionRequest request = new ConnectionRequest(host, currentId++); synchronized (requests) { requests.add(request); requests.notifyAll(); // Notify all connectors } // are in display thread. Descriptor<IConnector>[] descriptors = connectors.getDescriptors(); for (Descriptor<IConnector> descriptor : descriptors) { IConnector connector = descriptor.get(); if (connector.isDirectProcessingRequired()) { connector.runDisplayRunnables(CONNECTION_TIMEOUT); } } long endTime = System.currentTimeMillis() + CONNECTION_TIMEOUT; synchronized (requests) { while (!request.isFinished() && Platform.isRunning()) { try { requests.wait(100); long currentTime = System.currentTimeMillis(); if (currentTime > endTime) { // Just break // markHostAsFinished(host); break; } } catch (InterruptedException e) { DLTKRSEPlugin.log(e); } } } return isConnected(host); } private boolean isConnected(IHost host) { ISubSystem[] subSystems = host.getSubSystems(); for (ISubSystem subsystem : subSystems) { if (subsystem instanceof IRemoteFileSubSystem) { return subsystem.isConnected(); } } return false; } public boolean hasHosts() { synchronized (requests) { return !requests.isEmpty(); } } }