/******************************************************************************* * Copyright (c) 2012-2014 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.openshift.common.core.connection; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.osgi.util.NLS; import org.jboss.tools.common.databinding.ObservablePojo; import org.jboss.tools.openshift.common.core.OpenShiftCoreException; /** * @author Rob Stryker * @author Andre Dietisheim * @author Jeff Cantrill */ public class ConnectionsRegistry { /** event that a connection was added */ private static final int ADDED = 0; /** event that a connection was removed */ private static final int REMOVED = 1; /** event that a connection was changed */ private static final int CHANGED = 2; /** The most recent user connected on OpenShift. */ private IConnection recentConnection = null; private Map<ConnectionURL, IConnection> connectionsByUrl = new HashMap<>(); private List<IConnectionsRegistryListener> listeners = new ArrayList<>(); private PropertyChangeListener connectionListener = new ConnectionListener(); public ConnectionsRegistry() { } public synchronized void addListener(IConnectionsRegistryListener listener) { listeners.add(listener); } public synchronized void removeListener(IConnectionsRegistryListener listener) { listeners.remove(listener); } /** * @return independent copy of listeners to fire changes. */ private synchronized List<IConnectionsRegistryListener> getListeners() { return new ArrayList<>(listeners); } public void clear() { IConnection[] connections = connectionsByUrl.values().toArray(new IConnection[connectionsByUrl.size()]); for (IConnection connection : connections) { remove(connection); } } public boolean add(IConnection connection) { try { ConnectionURL connectionUrl = ConnectionURL.forConnection(connection); return add(connectionUrl, connection); } catch (UnsupportedEncodingException e) { throw new OpenShiftCoreException(e, "Could not add connection {0}", connection.getHost()); } catch (MalformedURLException e) { throw new OpenShiftCoreException(e, "Could not add connection {0}", connection.getHost()); } } public void addAll(Collection<? extends IConnection> connections) { for (IConnection connection : connections) { add(connection); } } protected boolean add(ConnectionURL connectionUrl, IConnection connection) { if (connectionsByUrl.containsKey(connectionUrl)) { return false; } addPropertyChangeListener(connection); connectionsByUrl.put(connectionUrl, connection); this.recentConnection = connection; fireChange(connection, ADDED); return true; } public boolean has(IConnection connection) { try { ConnectionURL connectionUrl = ConnectionURL.forConnection(connection); return getByUrl(connectionUrl) != null; } catch (UnsupportedEncodingException e) { throw new OpenShiftCoreException(e, NLS.bind("Could not get url for connection {0}", connection.getHost())); } catch (MalformedURLException e) { throw new OpenShiftCoreException(e, NLS.bind("Could not get url for connection {0}", connection.getHost())); } } // TODO: dont allow/require external trigger to changer notification public void fireConnectionChanged(IConnection connection) { fireConnectionChanged(connection, null, null, null); } // TODO: dont allow/require external trigger to changer notification public void fireConnectionChanged(IConnection connection, String property, Object oldValue, Object newValue) { if (connection == null) { return; } fireChange(connection, CHANGED, property, oldValue, newValue); } public boolean remove(IConnection connection) { try { ConnectionURL connectionUrl = ConnectionURL.forConnection(connection); if (!connectionsByUrl.containsKey(connectionUrl)) { return false; } connectionsByUrl.remove(connectionUrl); removePropertyChangeListener(connection); if (this.recentConnection == connection) { this.recentConnection = null; } fireChange(connection, REMOVED); return true; } catch (UnsupportedEncodingException e) { throw new OpenShiftCoreException(e, NLS.bind("Could not remove connection {0}", connection.getHost())); } catch (MalformedURLException e) { throw new OpenShiftCoreException(e, NLS.bind("Could not remove connection {0}", connection.getHost())); } } private void fireChange(IConnection connection, int event) { fireChange(connection, event, null, null, null); } private void fireChange(IConnection connection, int event, String property, Object oldValue, Object newValue) { if (connection == null) { return; } for (IConnectionsRegistryListener l : getListeners()) { switch (event) { case ADDED: l.connectionAdded(connection); break; case REMOVED: l.connectionRemoved(connection); break; case CHANGED: l.connectionChanged(connection, property, oldValue, newValue); break; } } } public IConnection getRecentConnection() { return recentConnection; } @SuppressWarnings("unchecked") public <T extends IConnection> T getRecentConnection(Class<T> clazz) { if (recentConnection == null || clazz == null || !clazz.isAssignableFrom(recentConnection.getClass())) { return null; } return (T) recentConnection; } public IConnection getByUrl(ConnectionURL connectionUrl) { if (connectionUrl == null) { return null; } return connectionsByUrl.get(connectionUrl); } @SuppressWarnings("unchecked") public <T extends IConnection> T getByUrl(ConnectionURL connectionUrl, Class<T> clazz) { IConnection connection = getByUrl(connectionUrl); if (connection != null && !clazz.isAssignableFrom(connection.getClass())) { return null; } return (T) connection; } /** * Return a list of connections that are of the given type * * @return */ @SuppressWarnings("unchecked") public <T extends IConnection> Collection<T> getAll(Class<T> clazz) { List<T> connections = new ArrayList<>(); for (IConnection connection : connectionsByUrl.values()) { if (connection != null && clazz.isAssignableFrom(connection.getClass())) { connections.add((T) connection); } } return connections; } public Collection<IConnection> getAll() { return connectionsByUrl.values(); } public int size() { return connectionsByUrl.size(); } public IConnection setRecent(IConnection connection) { return this.recentConnection = connection; } private void addPropertyChangeListener(IConnection connection) { if (!(connection instanceof ObservablePojo)) { return; } ((ObservablePojo) connection).addPropertyChangeListener(connectionListener); ; } private void removePropertyChangeListener(IConnection connection) { if (!(connection instanceof ObservablePojo)) { return; } ((ObservablePojo) connection).removePropertyChangeListener(connectionListener); ; } private class ConnectionListener implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent event) { if (!(event.getSource() instanceof IConnection)) { return; } fireConnectionChanged((IConnection) event.getSource(), event.getPropertyName(), event.getOldValue(), event.getNewValue()); } } public void update(IConnection currentConnection, IConnection updatedConnection) { ConnectionURL updatedConnectionUrl = null; try { updatedConnectionUrl = ConnectionURL.forConnection(updatedConnection); } catch (UnsupportedEncodingException | MalformedURLException e) { throw new OpenShiftCoreException(e, NLS.bind("Could not update connection {0}", updatedConnection.getHost())); } ConnectionURL oldConnectionUrl = null; try { oldConnectionUrl = ConnectionURL.forConnection(currentConnection); } catch (UnsupportedEncodingException | MalformedURLException e) { throw new OpenShiftCoreException(e, NLS.bind("Could not update connection {0}", currentConnection.getHost())); } if (!oldConnectionUrl.equals(updatedConnectionUrl)) { connectionsByUrl.remove(oldConnectionUrl); } // serious change = username changed boolean seriousChange = !updatedConnection.equals(currentConnection); // change requiring refresh = password or token changed boolean credentialsChange = !updatedConnection.credentialsEqual(currentConnection); // in case of a serious change, we perform remove+add instead of just // updating+emitting change event // because the connection hashcode will change, refreshing it in the // treeview will cause `widget is disposed` errors if (seriousChange) { remove(currentConnection); } currentConnection.update(updatedConnection); if (seriousChange) { add(currentConnection); } else if (credentialsChange) { // Property is defined in // org.jboss.tools.openshift.core.connection.ConnectionProperties fireChange(currentConnection, CHANGED, "openshift.resource.refresh", currentConnection, currentConnection); } this.recentConnection = currentConnection; } }