blob: 7ad58638da65a9316cf50f7e3f469f31657d0c31 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 QNX Software Systems and others.
* 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:
* QNX - initial API and implementation
*******************************************************************************/
package org.eclipse.remote.internal.core;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.equinox.security.storage.ISecurePreferences;
import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteConnectionType;
import org.eclipse.remote.core.IRemoteConnectionWorkingCopy;
import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.IRemoteServicesManager;
import org.eclipse.remote.core.RemoteConnectionChangeEvent;
import org.eclipse.remote.core.exception.ConnectionExistsException;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
/**
* The implementation for a given remote services collection.n
*/
public class RemoteConnectionType implements IRemoteConnectionType {
private final RemoteServicesManager remoteServicesManager;
private final String id;
private final String name;
private final String scheme;
private final boolean canAdd;
private final boolean canEdit;
private final boolean canRemove;
private final Map<Class<? extends Service>, Object> serviceMap = new HashMap<>();
private final Map<String, IConfigurationElement> serviceDefinitionMap = new HashMap<>();
private final Map<String, IConfigurationElement> connectionServiceDefinitionMap = new HashMap<>();
private final Map<String, IConfigurationElement> processServiceDefinitionMap = new HashMap<>();
private final Map<String, RemoteConnection> connections = new HashMap<>();
public RemoteConnectionType(IConfigurationElement ce, RemoteServicesManager manager) {
this.remoteServicesManager = manager;
id = ce.getAttribute("id"); //$NON-NLS-1$
name = ce.getAttribute("name"); //$NON-NLS-1$
scheme = ce.getAttribute("scheme"); //$NON-NLS-1$
// capabilities, default is true for all of these
String canAddStr = ce.getAttribute("canAdd"); //$NON-NLS-1$
canAdd = canAddStr != null ? Boolean.parseBoolean(canAddStr) : true;
String canEditStr = ce.getAttribute("canEdit"); //$NON-NLS-1$
canEdit = canEditStr != null ? Boolean.parseBoolean(canEditStr) : true;
String canRemoveStr = ce.getAttribute("canRemove"); //$NON-NLS-1$
canRemove = canRemoveStr != null ? Boolean.parseBoolean(canRemoveStr) : true;
// load up existing connections
try {
for (String nodeName : getPreferenceNode().childrenNames()) {
String connectionName = URLDecoder.decode(nodeName, "UTF-8");
connections.put(connectionName, new RemoteConnection(this, connectionName));
}
} catch (BackingStoreException | UnsupportedEncodingException e) {
RemoteCorePlugin.log(e);
}
}
Preferences getPreferenceNode() {
return remoteServicesManager.getPreferenceNode().node(id);
}
ISecurePreferences getSecurePreferencesNode() {
return remoteServicesManager.getSecurePreferenceNode().node(id);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#getRemoteServicesManager()
*/
@Override
public IRemoteServicesManager getRemoteServicesManager() {
return remoteServicesManager;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#getId()
*/
@Override
public String getId() {
return id;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#getName()
*/
@Override
public String getName() {
return name;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#getScheme()
*/
@Override
public String getScheme() {
return scheme;
}
@Override
public boolean canAdd() {
return canAdd;
}
@Override
public boolean canEdit() {
return canEdit;
}
@Override
public boolean canRemove() {
return canRemove;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#getService(java.lang.Class)
*/
@Override
public <T extends Service> T getService(Class<T> service) {
@SuppressWarnings("unchecked")
T obj = (T) serviceMap.get(service);
if (obj == null) {
IConfigurationElement ce = serviceDefinitionMap.get(service.getName());
if (ce != null) {
try {
Service.Factory factory = (Service.Factory) ce.createExecutableExtension("factory"); //$NON-NLS-1$
if (factory != null) {
obj = factory.getService(this, service);
serviceMap.put(service, obj);
}
} catch (CoreException e) {
RemoteCorePlugin.log(e.getStatus());
}
}
}
return obj;
}
@Override
public List<String> getServices() {
return new ArrayList<>(serviceDefinitionMap.keySet());
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#hasService(java.lang.Class)
*/
@Override
public <T extends Service> boolean hasService(Class<T> service) {
return serviceDefinitionMap.get(service.getName()) != null;
}
/**
* Called from the connection to get a service object for that connection.
*
* @param connection
* the connection to which the service applies
* @param service
* the interface the service must implement
* @return the service object
* @throws CoreException
*/
public <T extends IRemoteConnection.Service> T getConnectionService(IRemoteConnection connection, Class<T> service) {
IConfigurationElement ce = connectionServiceDefinitionMap.get(service.getName());
if (ce != null) {
try {
IRemoteConnection.Service.Factory factory = (IRemoteConnection.Service.Factory) ce
.createExecutableExtension("factory"); //$NON-NLS-1$
if (factory != null) {
return factory.getService(connection, service);
}
} catch (CoreException e) {
RemoteCorePlugin.log(e.getStatus());
}
}
return null;
}
@Override
public List<String> getConnectionServices() {
return new ArrayList<>(connectionServiceDefinitionMap.keySet());
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#hasConnectionService(java.lang.Class)
*/
@Override
public <T extends IRemoteConnection.Service> boolean hasConnectionService(Class<T> service) {
return connectionServiceDefinitionMap.get(service.getName()) != null;
}
/**
* Called from the remote process to get a service object for that process.
*
* @param process
* the process to which the service applies
* @param service
* the interface the service must implement
* @return the service object
* @throws CoreException
*/
public <T extends IRemoteProcess.Service> T getProcessService(IRemoteProcess process, Class<T> service) {
IConfigurationElement ce = processServiceDefinitionMap.get(service.getName());
if (ce != null) {
try {
IRemoteProcess.Service.Factory factory = (IRemoteProcess.Service.Factory) ce.createExecutableExtension("factory"); //$NON-NLS-1$
if (factory != null) {
return factory.getService(process, service);
}
} catch (CoreException e) {
RemoteCorePlugin.log(e.getStatus());
}
}
return null;
}
@Override
public List<String> getProcessServices() {
return new ArrayList<>(processServiceDefinitionMap.keySet());
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#hasProcessService(java.lang.Class)
*/
@Override
public <T extends IRemoteProcess.Service> boolean hasProcessService(Class<T> service) {
return processServiceDefinitionMap.get(service.getName()) != null;
}
/**
* Called from the remote service manager to register a service extension for
* this remote services implementation
*
* @param ce
* the extension element defining the service
*/
public void addService(IConfigurationElement ce) {
String serviceName = ce.getAttribute("service"); //$NON-NLS-1$
String name = ce.getName();
switch (name) {
case "connectionTypeService": //$NON-NLS-1$
serviceDefinitionMap.put(serviceName, ce);
break;
case "connectionService": //$NON-NLS-1$
connectionServiceDefinitionMap.put(serviceName, ce);
break;
case "processService": //$NON-NLS-1$
processServiceDefinitionMap.put(serviceName, ce);
break;
}
}
/**
* Signal connection has been added.
*
* @since 2.0
*/
protected void connectionAdded(final IRemoteConnection connection) {
RemoteConnectionChangeEvent event = new RemoteConnectionChangeEvent(connection,
RemoteConnectionChangeEvent.CONNECTION_ADDED);
remoteServicesManager.fireRemoteConnectionChangeEvent(event);
}
/**
* Signal a connnection is about to be removed.
*
* @since 2.0
*/
protected void connectionRemoved(final IRemoteConnection connection) {
RemoteConnectionChangeEvent event = new RemoteConnectionChangeEvent(connection,
RemoteConnectionChangeEvent.CONNECTION_REMOVED);
remoteServicesManager.fireRemoteConnectionChangeEvent(event);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#getConnection(java.lang.String)
*/
@Override
public IRemoteConnection getConnection(String name) {
synchronized (connections) {
return connections.get(name);
}
}
@Override
public IRemoteConnection getConnection(URI uri) {
synchronized (connections) {
IRemoteConnection connection = connections.get(uri.getAuthority());
if (connection != null) {
return connection;
}
// If it's a file: scheme we must be the local connection type, just return our
// hopefully one connection, the Local connection.
if (uri.getScheme().equals("file") && !connections.isEmpty()) { //$NON-NLS-1$
return connections.values().iterator().next();
}
return null;
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#getConnections()
*/
@Override
public List<IRemoteConnection> getConnections() {
synchronized (connections) {
return new ArrayList<IRemoteConnection>(connections.values());
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#newConnection(java.lang.String)
*/
@Override
public IRemoteConnectionWorkingCopy newConnection(String name) throws RemoteConnectionException {
synchronized (connections) {
if (connections.containsKey(name)) {
throw new ConnectionExistsException(name);
}
return new RemoteConnectionWorkingCopy(this, name);
}
}
void addConnection(RemoteConnection remoteConnection) {
synchronized (connections) {
connections.put(remoteConnection.getName(), remoteConnection);
}
}
void removeConnection(String name) {
synchronized (connections) {
connections.remove(name);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.remote.core.IRemoteConnectionType#removeConnection(org.eclipse.remote.core.IRemoteConnection)
*/
@Override
public void removeConnection(IRemoteConnection connection) throws RemoteConnectionException {
synchronized (connections) {
if (connection instanceof RemoteConnection) {
connection.close();
RemoteConnection conn = (RemoteConnection) connection;
try {
conn.getPreferences().removeNode();
} catch (BackingStoreException e) {
throw new RemoteConnectionException(e);
}
conn.getSecurePreferences().removeNode();
connections.remove(conn.getName());
connection.fireConnectionChangeEvent(RemoteConnectionChangeEvent.CONNECTION_REMOVED);
} else {
RemoteCorePlugin.log("Wrong class for " + connection.getName() + ", was " + connection.getClass().getName()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}