| /* |
| * Copyright (c) 2015 Eike Stepper (Berlin, Germany) 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: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.userstorage.internal; |
| |
| import org.eclipse.userstorage.IStorageService; |
| import org.eclipse.userstorage.internal.StorageService.DynamicService; |
| import org.eclipse.userstorage.internal.util.StringUtil; |
| |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IExtensionRegistry; |
| import org.eclipse.core.runtime.IRegistryEventListener; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.equinox.security.storage.ISecurePreferences; |
| import org.eclipse.equinox.security.storage.StorageException; |
| |
| import java.lang.ref.WeakReference; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.CopyOnWriteArrayList; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public final class StorageServiceRegistry implements IStorageService.Registry |
| { |
| public static final StorageServiceRegistry INSTANCE = new StorageServiceRegistry(); |
| |
| private static final ExtensionPointHandler HANDLER = new ExtensionPointHandler(); |
| |
| private static final String PREFIX = "org.eclipse.userstorage."; |
| |
| private static final String SERVICE_LABEL = "serviceLabel"; |
| |
| private static final String SERVICE_URI = "serviceURI"; |
| |
| private static final String CREATE_ACCOUNT_URI = "createAccountURI"; |
| |
| private static final String EDIT_ACCOUNT_URI = "editAccountURI"; |
| |
| private static final String RECOVER_PASSWORD_URI = "recoverPasswordURI"; |
| |
| private static final String TERMS_OF_USE_LINK = "termsOfUseLink"; |
| |
| private static final String DEFAULT_SERVICE_LABEL = "Eclipse.org"; |
| |
| private static final String DEFAULT_SERVICE_URI = "https://api.eclipse.org/"; |
| |
| private static final String STAGING_SERVICE_URI = "https://api-staging.eclipse.org/"; |
| |
| private final List<Listener> listeners = new CopyOnWriteArrayList<Listener>(); |
| |
| private final Set<WeakReference<Storage>> storages = new HashSet<WeakReference<Storage>>(); |
| |
| private final Map<URI, IStorageService> services = new LinkedHashMap<URI, IStorageService>(); |
| |
| private boolean running; |
| |
| private StorageServiceRegistry() |
| { |
| } |
| |
| @Override |
| public IStorageService[] getServices() |
| { |
| synchronized (services) |
| { |
| start(); |
| return services.values().toArray(new IStorageService[services.size()]); |
| } |
| } |
| |
| @Override |
| public StorageService getService(URI serviceURI) |
| { |
| synchronized (services) |
| { |
| start(); |
| return (StorageService)services.get(serviceURI); |
| } |
| } |
| |
| public StorageService getFirstService() |
| { |
| synchronized (services) |
| { |
| start(); |
| |
| if (services.isEmpty()) |
| { |
| return null; |
| } |
| |
| return (StorageService)services.values().iterator().next(); |
| } |
| } |
| |
| @Override |
| public IStorageService.Dynamic addService(String serviceLabel, URI serviceURI, URI createAccountURI, URI editAccountURI, URI recoverPasswordURI, |
| String termsOfUseLink) throws IllegalStateException |
| { |
| DynamicService service = new DynamicService(serviceLabel, serviceURI, createAccountURI, editAccountURI, recoverPasswordURI, termsOfUseLink); |
| addService(service); |
| |
| ISecurePreferences securePreferences = service.getSecurePreferences(); |
| if (securePreferences != null) |
| { |
| try |
| { |
| securePreferences.put(SERVICE_LABEL, serviceLabel, false); |
| securePreferences.put(SERVICE_URI, serviceURI.toString(), false); |
| setSecurePreference(securePreferences, CREATE_ACCOUNT_URI, createAccountURI); |
| setSecurePreference(securePreferences, EDIT_ACCOUNT_URI, editAccountURI); |
| setSecurePreference(securePreferences, RECOVER_PASSWORD_URI, recoverPasswordURI); |
| securePreferences.flush(); |
| } |
| catch (Exception ex) |
| { |
| Activator.log(ex); |
| } |
| } |
| |
| return service; |
| } |
| |
| @Override |
| public IStorageService.Dynamic addService(String serviceLabel, URI serviceURI) throws IllegalStateException |
| { |
| return addService(serviceLabel, serviceURI, null, null, null, null); |
| } |
| |
| @Override |
| public IStorageService.Dynamic[] refresh() |
| { |
| List<IStorageService.Dynamic> result = new ArrayList<IStorageService.Dynamic>(); |
| |
| ISecurePreferences securePreferences = Activator.getSecurePreferences(); |
| if (securePreferences != null) |
| { |
| for (String name : securePreferences.childrenNames()) |
| { |
| try |
| { |
| ISecurePreferences child = securePreferences.node(name); |
| |
| String serviceLabel = child.get(SERVICE_LABEL, null); |
| if (StringUtil.isEmpty(serviceLabel)) |
| { |
| continue; |
| } |
| |
| URI serviceURI = StringUtil.newURI(child.get(SERVICE_URI, null)); |
| if (serviceURI == null || !StringUtil.encodeURI(serviceURI).equals(name)) |
| { |
| continue; |
| } |
| |
| URI createAccountURI = StringUtil.newURI(child.get(CREATE_ACCOUNT_URI, null)); |
| URI editAccountURI = StringUtil.newURI(child.get(EDIT_ACCOUNT_URI, null)); |
| URI recoverPasswordURI = StringUtil.newURI(child.get(RECOVER_PASSWORD_URI, null)); |
| String termsOfUseLink = child.get(TERMS_OF_USE_LINK, null); |
| |
| IStorageService.Dynamic service = new DynamicService(serviceLabel, serviceURI, createAccountURI, editAccountURI, recoverPasswordURI, termsOfUseLink); |
| addService(service); |
| result.add(service); |
| } |
| catch (Exception ex) |
| { |
| //$FALL-THROUGH$ |
| } |
| } |
| } |
| |
| return result.toArray(new IStorageService.Dynamic[result.size()]); |
| } |
| |
| @Override |
| public void addListener(Listener listener) |
| { |
| listeners.add(listener); |
| } |
| |
| @Override |
| public void removeListener(Listener listener) |
| { |
| listeners.remove(listener); |
| } |
| |
| void addStorage(Storage storage) |
| { |
| synchronized (storages) |
| { |
| storages.add(new WeakReference<Storage>(storage)); |
| } |
| } |
| |
| void addService(IStorageService service) throws IllegalStateException |
| { |
| URI serviceURI = service.getServiceURI(); |
| |
| synchronized (services) |
| { |
| start(); |
| |
| IStorageService registered = services.get(serviceURI); |
| if (registered != null) |
| { |
| throw new IllegalStateException("Service already registered: " + registered); |
| } |
| |
| services.put(serviceURI, service); |
| } |
| |
| for (Listener listener : listeners) |
| { |
| try |
| { |
| listener.serviceAdded(service); |
| } |
| catch (Exception ex) |
| { |
| Activator.log(ex); |
| } |
| } |
| } |
| |
| void removeService(IStorageService service) |
| { |
| URI serviceURI = service.getServiceURI(); |
| |
| synchronized (services) |
| { |
| start(); |
| services.remove(serviceURI); |
| } |
| |
| for (Listener listener : listeners) |
| { |
| try |
| { |
| listener.serviceRemoved(service); |
| } |
| catch (Exception ex) |
| { |
| Activator.log(ex); |
| } |
| } |
| |
| List<Storage> storagesToNotify = new ArrayList<Storage>(); |
| synchronized (storages) |
| { |
| for (Iterator<WeakReference<Storage>> it = storages.iterator(); it.hasNext();) |
| { |
| WeakReference<Storage> ref = it.next(); |
| Storage storage = ref.get(); |
| if (storage != null) |
| { |
| storagesToNotify.add(storage); |
| } |
| else |
| { |
| it.remove(); |
| } |
| } |
| } |
| |
| for (Storage storage : storagesToNotify) |
| { |
| storage.serviceRemoved(service); |
| } |
| } |
| |
| public void start() |
| { |
| synchronized (services) |
| { |
| if (!running) |
| { |
| running = true; |
| |
| try |
| { |
| URI serviceURI = StringUtil.newURI(System.getProperty(PREFIX + SERVICE_URI, null)); |
| if (serviceURI == null) |
| { |
| if (Boolean.getBoolean(PREFIX + "staging")) |
| { |
| serviceURI = StringUtil.newURI(STAGING_SERVICE_URI); |
| } |
| else |
| { |
| serviceURI = StringUtil.newURI(DEFAULT_SERVICE_URI); |
| } |
| } |
| |
| if (serviceURI != null) |
| { |
| String serviceLabel = System.getProperty(PREFIX + SERVICE_LABEL, DEFAULT_SERVICE_LABEL); |
| URI createAccountURI = StringUtil.newURI(getValue(serviceURI, CREATE_ACCOUNT_URI, "https://dev.eclipse.org/site_login/")); |
| URI editAccountURI = StringUtil.newURI(getValue(serviceURI, EDIT_ACCOUNT_URI, "https://dev.eclipse.org/site_login/myaccount.php")); |
| URI recoverPasswordURI = StringUtil.newURI(getValue(serviceURI, RECOVER_PASSWORD_URI, "https://dev.eclipse.org/site_login/password_recovery.php")); |
| String termsOfUseLink = getValue(serviceURI, TERMS_OF_USE_LINK, |
| "I agree the use of this beta service is governed by the Eclipse Foundation <a href='http://www.eclipse.org/legal/termsofuse.php'>Terms of Use</a> and the Eclipse Foundation <a href='http://www.eclipse.org/legal/privacy.php'>Privacy Policy</a>."); |
| |
| StorageService eclipseStorage = new StorageService(serviceLabel, serviceURI, createAccountURI, editAccountURI, recoverPasswordURI, termsOfUseLink); |
| services.put(eclipseStorage.getServiceURI(), eclipseStorage); |
| } |
| |
| if (Activator.PLATFORM_RUNNING) |
| { |
| HANDLER.start(); |
| } |
| |
| refresh(); |
| } |
| catch (Exception ex) |
| { |
| Activator.log(ex); |
| } |
| } |
| } |
| } |
| |
| public void stop() throws Exception |
| { |
| synchronized (services) |
| { |
| if (running) |
| { |
| running = false; |
| |
| try |
| { |
| if (Activator.PLATFORM_RUNNING) |
| { |
| HANDLER.stop(); |
| } |
| |
| services.clear(); |
| } |
| catch (Exception ex) |
| { |
| Activator.log(ex); |
| } |
| } |
| } |
| } |
| |
| private static String getValue(URI serviceURI, String property, String defaultValue) |
| { |
| String value = System.getProperty(PREFIX + property); |
| if (StringUtil.isEmpty(value)) |
| { |
| String authority = serviceURI.getAuthority(); |
| if (authority != null && authority.endsWith(".eclipse.org")) |
| { |
| value = defaultValue; |
| } |
| } |
| |
| return value; |
| } |
| |
| private static void setSecurePreference(ISecurePreferences securePreferences, String key, URI uri) throws StorageException |
| { |
| if (uri != null) |
| { |
| securePreferences.put(key, uri.toString(), false); |
| } |
| else |
| { |
| securePreferences.remove(key); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private static final class ExtensionPointHandler implements IRegistryEventListener |
| { |
| private static final String EXTENSION_POINT = Activator.PLUGIN_ID + ".storages"; |
| |
| public ExtensionPointHandler() |
| { |
| } |
| |
| public void start() throws Exception |
| { |
| IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); |
| for (IConfigurationElement configurationElement : extensionRegistry.getConfigurationElementsFor(EXTENSION_POINT)) |
| { |
| added(configurationElement); |
| } |
| |
| extensionRegistry.addListener(this, EXTENSION_POINT); |
| } |
| |
| public void stop() throws Exception |
| { |
| Platform.getExtensionRegistry().removeListener(this); |
| } |
| |
| @Override |
| public void added(IExtensionPoint[] extensionPoints) |
| { |
| // Do nothing |
| } |
| |
| @Override |
| public void removed(IExtensionPoint[] extensionPoints) |
| { |
| // Do nothing |
| } |
| |
| @Override |
| public void added(IExtension[] extensions) |
| { |
| for (IExtension extension : extensions) |
| { |
| for (IConfigurationElement configurationElement : extension.getConfigurationElements()) |
| { |
| added(configurationElement); |
| } |
| } |
| } |
| |
| @Override |
| public void removed(IExtension[] extensions) |
| { |
| for (IExtension extension : extensions) |
| { |
| for (IConfigurationElement configurationElement : extension.getConfigurationElements()) |
| { |
| removed(configurationElement); |
| } |
| } |
| } |
| |
| private void added(IConfigurationElement configurationElement) |
| { |
| try |
| { |
| StorageService storage = createStorage(configurationElement); |
| INSTANCE.addService(storage); |
| } |
| catch (Exception ex) |
| { |
| Activator.log(ex); |
| } |
| } |
| |
| private void removed(IConfigurationElement configurationElement) |
| { |
| try |
| { |
| StorageService storage = createStorage(configurationElement); |
| INSTANCE.removeService(storage); |
| } |
| catch (Exception ex) |
| { |
| Activator.log(ex); |
| } |
| } |
| |
| private StorageService createStorage(IConfigurationElement configurationElement) |
| { |
| String serviceLabel = configurationElement.getAttribute(SERVICE_LABEL); |
| URI serviceURI = StringUtil.newURI(configurationElement.getAttribute(SERVICE_URI)); |
| URI createAccountURI = StringUtil.newURI(configurationElement.getAttribute(CREATE_ACCOUNT_URI)); |
| URI editAccountURI = StringUtil.newURI(configurationElement.getAttribute(EDIT_ACCOUNT_URI)); |
| URI recoverPasswordURI = StringUtil.newURI(configurationElement.getAttribute(RECOVER_PASSWORD_URI)); |
| String termsOfUseLink = configurationElement.getAttribute(TERMS_OF_USE_LINK); |
| |
| return new StorageService(serviceLabel, serviceURI, createAccountURI, editAccountURI, recoverPasswordURI, termsOfUseLink); |
| } |
| } |
| } |