connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/internal/registry/Registry.java
changeset 0 fb279309251b
child 380 2c1483a2585f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/connectivity/com.nokia.carbide.remoteConnections/src/com/nokia/carbide/remoteconnections/internal/registry/Registry.java	Fri Apr 03 23:33:03 2009 +0100
@@ -0,0 +1,452 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+package com.nokia.carbide.remoteconnections.internal.registry;
+
+import com.nokia.carbide.remoteconnections.Messages;
+import com.nokia.carbide.remoteconnections.RemoteConnectionsActivator;
+import com.nokia.carbide.remoteconnections.interfaces.*;
+import com.nokia.carbide.remoteconnections.ui.ClientServiceSiteUI;
+import com.nokia.cpp.internal.api.utils.core.Check;
+import com.nokia.cpp.internal.api.utils.core.ListenerList;
+import com.nokia.cpp.internal.api.utils.core.Logging;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.viewers.IFilter;
+
+import java.io.*;
+import java.text.MessageFormat;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A registry of connection type and service extensions
+ */
+public class Registry implements IConnectionTypeProvider, IConnectionsManager {
+
+	private static final String FILTER_EXTENSION = RemoteConnectionsActivator.PLUGIN_ID + ".extensionFilter"; //$NON-NLS-1$
+	private static final String CONNECTION_TYPE_EXTENSION = RemoteConnectionsActivator.PLUGIN_ID + ".connectionType"; //$NON-NLS-1$
+	private static final String SERVICE_EXTENSION = RemoteConnectionsActivator.PLUGIN_ID + ".service"; //$NON-NLS-1$
+	private static final String CONNECTED_SERVICE_FACTORY_EXTENSION = RemoteConnectionsActivator.PLUGIN_ID + ".connectedServiceFactory"; //$NON-NLS-1$
+	private static final String CONNECTION_DATA_XML = "connectionData.xml"; //$NON-NLS-1$
+	private static final String NAME_SUFFIX_PATTERN = "(.+) \\((\\d+)\\)"; //$NON-NLS-1$
+	private static final String NAME_FMT = "{0} ({1})"; //$NON-NLS-1$
+	private static Registry instance;
+	
+	private List<IExtensionFilter> extensionFilters;
+	private Map<String, IConnectionType> connectionTypeIdMap;
+	private ArrayList<IService> services;
+	private Map<IConnectionType, Collection<IService>> connectionTypeToServices;
+	private Map<IConnection, List<IConnectedService>> connectionToConnectedServices;
+	private ListenerList<IConnectionsManagerListener> listeners;
+	private List<IConnectedServiceFactory> connectedServiceFactories;
+
+	public static Registry instance() {
+		if (instance == null) {
+			instance = new Registry();
+		}
+		
+		return instance;
+	}
+	
+	private Registry() {
+		// private because is singleton
+		connectionToConnectedServices = new HashMap<IConnection, List<IConnectedService>>();
+	}
+
+	public void loadExtensions() {
+		loadExtensionFilters();
+		loadConnectionTypeExtensions();
+		loadServiceExtensions();
+		loadConnectedServiceFactoryExtensions();
+		mapConnectionTypeToServices();
+	}
+
+	private void loadConnectedServiceFactoryExtensions() {
+		connectedServiceFactories = new ArrayList<IConnectedServiceFactory>();
+		String loadError = Messages.getString("Registry.ConnectedServiceFactoryExtensionLoadError"); //$NON-NLS-1$
+		loadExtensions(CONNECTED_SERVICE_FACTORY_EXTENSION, loadError, connectedServiceFactories, null);
+	}
+
+	private void loadExtensionFilters() {
+		extensionFilters = new ArrayList<IExtensionFilter>();
+		String loadError = Messages.getString("Registry.FilterExtensionLoadError"); //$NON-NLS-1$
+		loadExtensions(FILTER_EXTENSION, loadError, extensionFilters, null);
+	}
+
+	private void loadConnectionTypeExtensions() {
+		List<IConnectionType> connectionTypeExtensions = new ArrayList<IConnectionType>();
+		String loadError = Messages.getString("Registry.ConnectionTypeExtensionLoadError"); //$NON-NLS-1$
+		loadExtensions(CONNECTION_TYPE_EXTENSION, loadError, connectionTypeExtensions, new IFilter() {
+			public boolean select(Object toTest) {
+				return acceptConnectionType(((IConnectionType) toTest).getIdentifier());
+			}
+		});
+		
+		connectionTypeIdMap = new HashMap<String, IConnectionType>();
+		for (IConnectionType connectionType : connectionTypeExtensions) {
+			connectionTypeIdMap.put(connectionType.getIdentifier(), connectionType);
+		}
+	}
+	
+	private boolean acceptConnectionType(String connectionTypeId) {
+		for (IExtensionFilter extensionFilter : extensionFilters) {
+			if (!extensionFilter.acceptConnectionType(connectionTypeId))
+				return false;
+		}
+		return true;
+	}
+	
+	private void loadServiceExtensions() {
+		services = new ArrayList<IService>();
+		String loadError = Messages.getString("Registry.ServiceExtensionLoadError"); //$NON-NLS-1$
+		loadExtensions(SERVICE_EXTENSION, loadError, services, new IFilter() {
+			public boolean select(Object toTest) {
+				return acceptService(((IService) toTest).getIdentifier());
+			}
+		});
+	}
+	
+	private boolean acceptService(String serviceId) {
+		for (IExtensionFilter extensionFilter : extensionFilters) {
+			if (!extensionFilter.acceptService(serviceId))
+				return false;
+		}
+		return true;
+	}
+	
+	private <T> void loadExtensions(String extensionId, String loadError, Collection<T> extensionObjects, IFilter filter) {
+		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+		IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(extensionId);
+		IExtension[] extensions = extensionPoint.getExtensions();
+		
+		for (int i = 0; i < extensions.length; i++) {
+			IExtension extension = extensions[i];
+			IConfigurationElement[] elements = extension.getConfigurationElements();
+			Check.checkContract(elements.length == 1);
+			IConfigurationElement element = elements[0];
+			try {
+				T extObject = (T) element.createExecutableExtension("class"); //$NON-NLS-1$
+				if (filter == null || filter.select(extObject))
+					extensionObjects.add(extObject);
+			} 
+			catch (CoreException e) {
+				if (loadError != null)
+					log(loadError, e);
+			}
+		}
+	}
+	
+	private void mapConnectionTypeToServices() {
+		connectionTypeToServices = new HashMap<IConnectionType, Collection<IService>>();
+		Set<String> connectionTypeIds = connectionTypeIdMap.keySet();
+		for (IService service : services) {
+			Collection<String> compatibleConnectionTypeIds = getCompatibleConnectionTypeIds(service);
+			String serviceId = service.getIdentifier();
+			for (String connectionTypeId : compatibleConnectionTypeIds) {
+				if (connectionTypeIds.contains(connectionTypeId)) {
+					IConnectionType connectionType = connectionTypeIdMap.get(connectionTypeId);
+					if (!connectionTypeToServices.containsKey(connectionType)) {
+						connectionTypeToServices.put(connectionType, 
+								new TreeSet<IService>(new Comparator<IService>() {
+							public int compare(IService o1, IService o2) {
+								return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName());
+							}
+						}));
+					}
+					Set<IService> servicesForConnectionType = 
+						(Set<IService>) connectionTypeToServices.get(connectionType);
+					if (acceptConnectedService(serviceId, connectionTypeId))
+						servicesForConnectionType.add(service);
+				}
+			}
+		}
+	}
+
+	public Collection<String> getCompatibleConnectionTypeIds(IService service) {
+		Collection<String> compatibleConnectionTypeIds = new HashSet<String>();
+		for (IConnectedServiceFactory factory : connectedServiceFactories) {
+			compatibleConnectionTypeIds.addAll(factory.getCompatibleConnectionTypeIds(service));
+		}
+		return compatibleConnectionTypeIds;
+	}
+
+	private boolean acceptConnectedService(String serviceId, String connectionTypeId) {
+		boolean accept = true;
+		for (IExtensionFilter extensionFilter : extensionFilters) {
+			if (!extensionFilter.acceptConnectedService(connectionTypeId, serviceId)) {
+				accept = false;
+				break;
+			}
+		}
+		return accept;
+	}
+
+	private void log(String errorStr, Throwable t) {
+		RemoteConnectionsActivator p = RemoteConnectionsActivator.getDefault();
+		String error = errorStr;
+		if (t != null) {
+			error += " : " + t.getLocalizedMessage(); //$NON-NLS-1$
+		}
+		Logging.log(p, Logging.newStatus(p, IStatus.ERROR, error));
+		if (t instanceof CoreException)
+			Logging.log(p, ((CoreException) t).getStatus());
+	}
+	
+	/* (non-Javadoc)
+	 * @see com.nokia.carbide.remoteconnections.registry.IConnectionStore#loadConnections()
+	 */
+	public void loadConnections() {
+		File connectionStorageFile = getConnectionStorageFile();
+		if (!connectionStorageFile.exists())
+			return;
+		connectionToConnectedServices = new HashMap<IConnection, List<IConnectedService>>();
+		try {
+			List<IConnection> connections = Reader.readFromXML(this, new FileInputStream(connectionStorageFile));
+			for (IConnection connection : connections) {
+				List<IConnectedService> connectedServices = createConnectedServicesForConnection(connection);
+				connectionToConnectedServices.put(connection, connectedServices);
+			}
+			fireConnectionStoreChanged();
+		} 
+		catch (Exception e) {
+			log(Messages.getString("Registry.ConnectionLoadError"), e); //$NON-NLS-1$
+		}
+		
+	}
+
+	private List<IConnectedService> createConnectedServicesForConnection(IConnection connection) {
+		List<IConnectedService> connectedServices = new ArrayList<IConnectedService>();
+		for (IService service : getCompatibleServices(connection.getConnectionType())) {
+			IConnectedService connectedService = createConnectedService(service, connection);
+			connectedServices.add(connectedService);
+		}
+		return connectedServices;
+	}
+	
+	public IConnectedService createConnectedService(IService service, IConnection connection) {
+		// use first created connected service returned from a factory
+		for (IConnectedServiceFactory factory : connectedServiceFactories) {
+			IConnectedService connectedService = factory.createConnectedService(service, connection);
+			if (connectedService != null)
+				return connectedService;
+		}
+		log(MessageFormat.format(
+				Messages.getString("Registry.ConnectedServiceFactoryError"), //$NON-NLS-1$
+				service.getDisplayName(), connection.getConnectionType().getDisplayName()), null);
+		return null;
+	}
+
+	/* (non-Javadoc)
+	 * @see com.nokia.carbide.remoteconnections.registry.IConnectionStore#storeConnections()
+	 */
+	public void storeConnections() {
+		try {
+			OutputStream os = new FileOutputStream(getConnectionStorageFile());
+			Writer.writeToXML(os, connectionToConnectedServices.keySet());
+		} 
+		catch (Exception e) {
+			log(Messages.getString("Registry.ConnectionStoreError"), e); //$NON-NLS-1$
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see com.nokia.carbide.remoteconnections.registry.IConnectionStore#addConnectionStoreChangedListener(com.nokia.carbide.remoteconnections.registry.Registry.IConnectionStoreChangedListener)
+	 */
+	public void addConnectionStoreChangedListener(IConnectionsManagerListener listener) {
+		if (listeners == null)
+			listeners = new ListenerList<IConnectionsManagerListener>();
+		listeners.add(listener);
+	}
+
+	public void removeConnectionStoreChangedListener(IConnectionsManagerListener listener) {
+		if (listeners != null)
+			listeners.remove(listener);
+	}
+	
+	private void fireConnectionStoreChanged() {
+		if (listeners == null)
+			return;
+		for (IConnectionsManagerListener listener : listeners) {
+			listener.connectionStoreChanged();
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see com.nokia.carbide.remoteconnections.registry.IConnectionTypeProvider#getConnectionType(java.lang.String)
+	 */
+	public IConnectionType getConnectionType(String identifier) {
+		Check.checkContract(connectionTypeIdMap != null);
+		return connectionTypeIdMap.get(identifier);
+	}
+
+	public Collection<IConnectionType> getConnectionTypes() {
+		return connectionTypeIdMap.values();
+	}
+	
+	public Collection<IService> getCompatibleServices(IConnectionType connectionType) {
+		Check.checkContract(connectionTypeToServices != null);
+		Collection<IService> services = connectionTypeToServices.get(connectionType);
+		if (services != null)
+			return services;
+		return Collections.EMPTY_LIST;
+	}
+	
+	/* (non-Javadoc)
+	 * @see com.nokia.carbide.remoteconnections.registry.IConnectionStore#addConnection(com.nokia.carbide.remoteconnections.extensions.IConnection)
+	 */
+	public void addConnection(IConnection connection) {
+		ensureUniqueId(connection);
+		ensureUniqueName(connection);
+		List<IConnectedService> connectedServices = createConnectedServicesForConnection(connection);
+		connectionToConnectedServices.put(connection, connectedServices);
+		fireConnectionStoreChanged();
+	}
+	
+	private void ensureUniqueId(IConnection connection) {
+		String id = connection.getIdentifier();
+		if (id == null || id.length() == 0 || connectionIdInUse(id))
+			connection.setIdentifier(getUniqueConnectionId());
+	}
+	
+	public String getUniqueConnectionId() {
+		return UUID.randomUUID().toString();
+	}
+	
+	private boolean connectionIdInUse(String id) {
+		boolean used = false;
+		for (IConnection c : connectionToConnectedServices.keySet()) {
+			if (c.getIdentifier().equals(id)) {
+				used = true;
+				break;
+			}
+		}
+		return used;
+	}
+
+	private void ensureUniqueName(IConnection connection) {
+		String name = connection.getDisplayName();
+		if (name == null)
+			connection.setDisplayName(connection.getIdentifier());
+		if (connectionNameInUse(name)) {
+			// check if already has the suffix " (num)"
+			Pattern pattern = Pattern.compile(NAME_SUFFIX_PATTERN);
+			Matcher matcher = pattern.matcher(name);
+			boolean hasSuffix = matcher.matches();
+			String namePart;
+			int number;
+			if (hasSuffix) { // extract the name part and the number to increment
+				namePart = matcher.group(1);
+				String numberPart = matcher.group(2);
+				number = Integer.parseInt(numberPart); // all digits, so should not throw
+				number = (number <= 1) ? 2 : number++;
+			}
+			else { // just use the name and add the number starting with 2
+				namePart = name;
+				number = 2;
+			}
+			while (true) {
+				String newName = MessageFormat.format(NAME_FMT, new Object[] { namePart, number++ });
+				if (!connectionNameInUse(newName)) {
+					connection.setDisplayName(newName);
+					break;
+				}
+			}
+		}
+	}
+
+	public boolean connectionNameInUse(String name) {
+		boolean used = false;
+		for (IConnection c : connectionToConnectedServices.keySet()) {
+			if (c.getDisplayName().equals(name)) {
+				used = true;
+				break;
+			}
+		}
+		return used;
+	}
+
+	/* (non-Javadoc)
+	 * @see com.nokia.carbide.remoteconnections.registry.IConnectionStore#removeConnection(com.nokia.carbide.remoteconnections.extensions.IConnection)
+	 */
+	public void removeConnection(IConnection connection) {
+		disposeConnection(connection);
+		connectionToConnectedServices.remove(connection);
+		fireConnectionStoreChanged();
+	}
+
+	private void disposeConnection(IConnection connection) {
+		List<IConnectedService> connectedServices = connectionToConnectedServices.get(connection);
+		for (IConnectedService connectedService : connectedServices) {
+			connectedService.dispose();
+		}
+		connection.dispose();
+	}
+
+	/* (non-Javadoc)
+	 * @see com.nokia.carbide.remoteconnections.registry.IConnectionStore#getConnections()
+	 */
+	public Collection<IConnection> getConnections() {
+		return connectionToConnectedServices.keySet();
+	}
+	
+	public Collection<IConnectedService> getConnectedServices(IConnection connection) {
+		return connectionToConnectedServices.get(connection);
+	}
+
+	private File getConnectionStorageFile() {
+		IPath path = RemoteConnectionsActivator.getDefault().getStateLocation().append(CONNECTION_DATA_XML);
+		return path.toFile();
+	}
+
+	public void disposeConnections() {
+		for (IConnection connection : connectionToConnectedServices.keySet()) {
+			disposeConnection(connection);
+		}
+		connectionToConnectedServices.clear();
+	}
+
+	private void fireDisplayChanged() {
+		if (listeners == null)
+			return;
+		for (IConnectionsManagerListener listener : listeners) {
+			listener.displayChanged();
+		}
+	}
+	
+	public void updateDisplays() {
+		fireDisplayChanged();
+	}
+
+	public IClientServiceSiteUI getClientSiteUI(IService service) {
+		return new ClientServiceSiteUI(service);
+	}
+	
+	public Collection<IService> getServices() {
+		return services;
+	}
+
+	public IService findServiceByID(String id) {
+		for (IService service : services) {
+			if (service.getIdentifier().equals(id))
+				return service;
+		}
+		return null;
+	}
+}
\ No newline at end of file