Skip to content

Content of file ECPRepositoryManagerImpl.java

/*******************************************************************************
 * Copyright (c) 2011-2012 EclipseSource Muenchen GmbH and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 * Eike Stepper - initial API and implementation
 * Eugen Neufeld - JavaDoc
 *******************************************************************************/

package org.eclipse.emf.ecp.internal.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.emf.ecp.core.ECPProvider;
import org.eclipse.emf.ecp.core.ECPRepository;
import org.eclipse.emf.ecp.core.ECPRepositoryManager;
import org.eclipse.emf.ecp.core.util.ECPProperties;
import org.eclipse.emf.ecp.core.util.ECPRepositoryAware;
import org.eclipse.emf.ecp.core.util.ECPUtil;
import org.eclipse.emf.ecp.core.util.observer.ECPObserver;
import org.eclipse.emf.ecp.core.util.observer.ECPPropertiesObserver;
import org.eclipse.emf.ecp.core.util.observer.ECPProvidersChangedObserver;
import org.eclipse.emf.ecp.core.util.observer.ECPRepositoriesChangedObserver;
import org.eclipse.emf.ecp.core.util.observer.ECPRepositoryContentChangedObserver;
import org.eclipse.emf.ecp.internal.core.util.ExtensionParser;
import org.eclipse.emf.ecp.internal.core.util.ExtensionParser.ExtensionDescriptor;
import org.eclipse.emf.ecp.internal.core.util.InternalUtil;
import org.eclipse.emf.ecp.internal.core.util.Properties;
import org.eclipse.emf.ecp.internal.core.util.PropertiesStore;
import org.eclipse.emf.ecp.spi.core.InternalProvider;
import org.eclipse.emf.ecp.spi.core.InternalProvider.LifecycleEvent;
import org.eclipse.emf.ecp.spi.core.InternalRepository;
import org.eclipse.net4j.util.AdapterUtil;
import org.eclipse.net4j.util.io.IOUtil;

/**
 * This class manages the repositories.
 *
 * @author Eike Stepper
 * @author Eugen Neufeld
 */
public final class ECPRepositoryManagerImpl extends PropertiesStore<InternalRepository, ECPObserver> implements
	ECPRepositoryManager, ECPProvidersChangedObserver {

	/**
	 * The file extension that is used for dynamic properties of statically declared repositories.
	 */
	private static final String DYNAMIC_PROPERTIES_EXTENSION = ".dynamic_properties"; //$NON-NLS-1$

	private final RepositoryParser extensionParser = new RepositoryParser();

	/**
	 * Should not be called directly, use service instead.
	 */
	public ECPRepositoryManagerImpl() {

		final File stateLocation = Activator.getInstance().getStateLocation().toFile();
		setFolder(new File(stateLocation, "repositories")); //$NON-NLS-1$
	}

	/** {@inheritDoc} **/
	@Override
	public InternalRepository getRepository(Object adaptable) {
		if (adaptable instanceof ECPRepositoryAware) {
			final ECPRepositoryAware repositoryAware = (ECPRepositoryAware) adaptable;
			return (InternalRepository) repositoryAware.getRepository();
		}

		return AdapterUtil.adapt(adaptable, InternalRepository.class);
	}

	/** {@inheritDoc} **/
	@Override
	public InternalRepository getRepository(String name) {
		return getElement(name);
	}

	/** {@inheritDoc} **/
	@Override
	public Collection<ECPRepository> getRepositories() {
		return (Collection) getElements();
	}

	/**
	 * Checks whether any repositories are available.
	 *
	 * @return true if any repository is available, false otherwise
	 */
	public boolean hasRepositories() {
		return hasElements();
	}

	/** {@inheritDoc} **/
	@Override
	public ECPRepository addRepository(ECPProvider provider, String name, String label, String description,
		ECPProperties properties) {
		if (!provider.hasCreateRepositorySupport()) {
			throw new UnsupportedOperationException("The provider " + provider.getLabel() //$NON-NLS-1$
				+ " doesn't support the addition of new repositories."); //$NON-NLS-1$
		}
		final InternalRepository repository = new ECPRepositoryImpl(provider, name, properties);
		repository.setLabel(label);
		repository.setDescription(description);

		((InternalProvider) provider).handleLifecycle(repository, LifecycleEvent.CREATE);
		changeElements(null, Collections.singleton(repository));
		return repository;
	}

	/**
	 * This is called by the {@link ECPRepository} to notificate observers about chnages it its objects.
	 *
	 * @param repository the repository where the changes occured
	 * @param objects the changed objects
	 */
	public void notifyObjectsChanged(ECPRepository repository, Collection<Object> objects) {

		try {
			ECPUtil.getECPObserverBus().notify(ECPRepositoryContentChangedObserver.class)
				.contentChanged(repository, objects);
		} catch (final Exception ex) {
			Activator.log(ex);
		}
	}

	/** {@inheritDoc} **/
	@Override
	public void providersChanged(Collection<ECPProvider> oldProviders, Collection<ECPProvider> newProviders) {
		final Set<ECPProvider> addedProviders = InternalUtil.getAddedElements(oldProviders, newProviders);
		if (!addedProviders.isEmpty()) {
			load();
		}
	}

	@Override
	protected File getFile(InternalRepository element) {
		if (element instanceof RepositoryDescriptor) {
			return new File(getFolder(), element.getName() + DYNAMIC_PROPERTIES_EXTENSION);
		}
		return super.getFile(element);
	}

	@Override
	protected boolean isLoadableElement(File file) {
		return super.isLoadableElement(file) && !file.getName().endsWith(DYNAMIC_PROPERTIES_EXTENSION);
	}

	@Override
	protected InternalRepository loadElement(ObjectInput in) throws IOException {
		return new ECPRepositoryImpl(in);
	}

	// @Override
	// protected InternalRepository[] createElementArray(int size) {
	// return new InternalRepository[size];
	// }

	@Override
	protected void notifyObservers(Collection<InternalRepository> oldRepositories,
		Collection<InternalRepository> newRepositories) throws Exception {
		ECPUtil.getECPObserverBus().notify(ECPRepositoriesChangedObserver.class)
			.repositoriesChanged((Collection) oldRepositories, (Collection) newRepositories);
} @Override protected void doActivate() throws Exception { super.doActivate(); // 1. Load dynamic repositories extensionParser.activate(); // 2. Register static repositories ECPUtil.getECPObserverBus().register(this); } @Override protected void doDeactivate() throws Exception { ECPUtil.getECPObserverBus().unregister(this); extensionParser.deactivate(); super.doDeactivate(); } /** * @author Eike Stepper */ private final class RepositoryParser extends ExtensionParser<InternalRepository> { private static final String EXTENSION_POINT_NAME = "repositories"; //$NON-NLS-1$ RepositoryParser() { super(ECPRepositoryManagerImpl.this, Activator.PLUGIN_ID, EXTENSION_POINT_NAME); } @Override protected InternalRepository createElement(String name, IConfigurationElement configurationElement) { final RepositoryDescriptor descriptor = new RepositoryDescriptor(name, configurationElement); descriptor.setLabel(configurationElement.getDeclaringExtension().getLabel()); descriptor.setDescription(configurationElement.getAttribute("description")); //$NON-NLS-1$ return descriptor; } } /** * @author Eike Stepper */ private final class RepositoryDescriptor extends ExtensionDescriptor<InternalRepository> implements InternalRepository { private final Set<String> declaredPropertyKeys; private final ECPProperties properties = new Properties() { @Override public void addProperty(String key, String value) { excludeDeclaredProperties(key); super.addProperty(key, value); } @Override public void removeProperty(String key) { excludeDeclaredProperties(key); super.removeProperty(key); } private void excludeDeclaredProperties(String key) { if (declaredPropertyKeys != null && declaredPropertyKeys.contains(key)) { throw new IllegalArgumentException("Statically declared property can not be changed: " + key); //$NON-NLS-1$ } } @Override protected Collection<Map.Entry<String, String>> getElementsToWrite() { final List<Map.Entry<String, String>> elementsToWrite = new ArrayList<Map.Entry<String, String>>(); for (final Map.Entry<String, String> entry : getElements()) { if (!declaredPropertyKeys.contains(entry.getKey())) { elementsToWrite.add(entry); } } return elementsToWrite; } }; RepositoryDescriptor(String name, IConfigurationElement configurationElement) { super(ECPRepositoryManagerImpl.this, name, TYPE, configurationElement); for (final IConfigurationElement property : configurationElement.getChildren("property")) { //$NON-NLS-1$ final String key = property.getAttribute("key"); //$NON-NLS-1$ final String value = property.getAttribute("value"); //$NON-NLS-1$ properties.addProperty(key, value); } declaredPropertyKeys = new HashSet<String>(properties.getKeys()); InputStream stream = null; try { final File file = getFile(this); if (file.exists()) { stream = new FileInputStream(file); final ObjectInputStream in = new ObjectInputStream(stream); final Properties dynamicProperties = new Properties(in); for (final Entry<String, String> property : dynamicProperties.getProperties()) { properties.addProperty(property.getKey(), property.getValue()); } } } catch (final IOException ex) { Activator.log(ex); } finally { IOUtil.close(stream); } properties.addObserver(new ECPPropertiesObserver() { @Override public void propertiesChanged(ECPProperties properties, Collection<Entry<String, String>> oldProperties, Collection<Entry<String, String>> newProperties) { ((ECPRepositoryManagerImpl) ECPUtil.getECPRepositoryManager()) .storeElement(RepositoryDescriptor.this); } }); } /** {@inheritDoc} */ @Override public boolean isStorable() { return true; } /** {@inheritDoc} */ @Override public void write(ObjectOutput out) throws IOException { ((Properties) properties).write(out); } /** {@inheritDoc} */ @Override public InternalProvider getProvider() { final String providerName = getConfigurationElement().getAttribute("provider"); //$NON-NLS-1$ return (InternalProvider) ECPUtil.getECPProviderRegistry().getProvider(providerName); } /** {@inheritDoc} */ @Override public ECPProperties getProperties() { return properties; } /** {@inheritDoc} */ @Override public Object getProviderSpecificData() { return getResolvedElement().getProviderSpecificData(); } /** {@inheritDoc} */ @Override public void setProviderSpecificData(Object data) { getResolvedElement().setProviderSpecificData(data); } /** {@inheritDoc} */ @Override public boolean canDelete() { return false; } /** {@inheritDoc} */ @Override public void delete() { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ @Override public void notifyObjectsChanged(Collection<Object> objects) { getResolvedElement().notifyObjectsChanged(objects); } /** {@inheritDoc} */ @Override protected InternalRepository resolve() throws Exception { return new ECPRepositoryImpl(getProvider(), getName(), getProperties()); } } }