Skip to content

Content of file ECPProjectManagerImpl.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 and changes
 *******************************************************************************/
package org.eclipse.emf.ecp.internal.core;

import java.io.File;
import java.io.IOException;
import java.io.ObjectInput;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecp.core.ECPProject;
import org.eclipse.emf.ecp.core.ECPProjectManager;
import org.eclipse.emf.ecp.core.ECPProvider;
import org.eclipse.emf.ecp.core.ECPRepository;
import org.eclipse.emf.ecp.core.exceptions.ECPProjectWithNameExistsException;
import org.eclipse.emf.ecp.core.util.ECPContainer;
import org.eclipse.emf.ecp.core.util.ECPProjectAware;
import org.eclipse.emf.ecp.core.util.ECPProperties;
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.ECPObserverBus;
import org.eclipse.emf.ecp.core.util.observer.ECPProjectContentChangedObserver;
import org.eclipse.emf.ecp.core.util.observer.ECPProjectContentTouchedObserver;
import org.eclipse.emf.ecp.core.util.observer.ECPProjectOpenClosedObserver;
import org.eclipse.emf.ecp.core.util.observer.ECPProjectsChangedObserver;
import org.eclipse.emf.ecp.core.util.observer.ECPRepositoriesChangedObserver;
import org.eclipse.emf.ecp.internal.core.util.InternalUtil;
import org.eclipse.emf.ecp.internal.core.util.PropertiesStore;
import org.eclipse.emf.ecp.spi.core.InternalProject;
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;

/**
 * This class manages the available {@link ECPProject ECPProjects}.
 *
 * @author Eike Stepper
 * @author Eugen Neufeld
 */
public final class ECPProjectManagerImpl extends PropertiesStore<InternalProject, ECPObserver> implements
	ECPProjectManager, ECPRepositoriesChangedObserver {

	private static final String PROJECT_FOLDERNAME = "projects"; //$NON-NLS-1$

	/**
	 * This variable defines whether the projects where already initialized. Default value is false.
	 */
	private boolean initializedProjects;

	private ECPObserverBus ecpObserverBus;

	/**
	 * Should not be called directly, use service instead.
	 */
	public ECPProjectManagerImpl() {
		initializeFolder(null);
	}

	/**
	 * @param sessionId Will be appended to the folder name so that there are different folders for each session
	 */
	public ECPProjectManagerImpl(String sessionId) {
		initializeFolder(sessionId);
	}

	private void initializeFolder(String sessionId) {

		final File stateLocation = Activator.getInstance().getStateLocation().toFile();
		setFolder(new File(stateLocation, PROJECT_FOLDERNAME));
		String finalFolderName = PROJECT_FOLDERNAME;
		if (sessionId != null) {
			finalFolderName += "-" + sessionId; //$NON-NLS-1$
		}
		setFolder(new File(stateLocation, finalFolderName));
	}

	/**
	 * Bindes the ECPObserverBus.
	 *
	 * @param ecpObserverBus the bus
	 */
	public void setECPObserverBus(ECPObserverBus ecpObserverBus) {
		this.ecpObserverBus = ecpObserverBus;
	}

	/** {@inheritDoc} */
	@Override
	public ECPProject createProject(ECPProvider provider, String name) throws ECPProjectWithNameExistsException {
		return this.createProject(provider, name, ECPUtil.createProperties());
	}

	/** {@inheritDoc} */
	@Override
	public ECPProject createProject(ECPProvider provider, String name, ECPProperties properties)
		throws ECPProjectWithNameExistsException {
		if (projectExists(name)) {
			throw new ECPProjectWithNameExistsException("A project with name " + name + " already exists"); //$NON-NLS-1$ //$NON-NLS-2$
		}
		if (!provider.hasCreateProjectWithoutRepositorySupport()) {
			throw new UnsupportedOperationException("The provider " + provider.getLabel() //$NON-NLS-1$
				+ " doesn't support the creation of projects without an ECPRepository (aka offline project)."); //$NON-NLS-1$
		}
		final InternalProject project = new ECPProjectImpl((InternalProvider) provider, name, properties);
		return createProject(project);
	}

	/** {@inheritDoc} */
	@Override
	public ECPProject createProject(ECPRepository repository, String name, ECPProperties properties)
		throws ECPProjectWithNameExistsException {
		if (projectExists(name)) {
			throw new ECPProjectWithNameExistsException("A project with name " + name + " already exists"); //$NON-NLS-1$ //$NON-NLS-2$
		}
		final InternalProject project = new ECPProjectImpl(repository, name, properties);
		return createProject(project);
	}

	/** {@inheritDoc} */
	@Override
	public ECPProject createProject(ECPProject project, String name) {
		final InternalProject internalProject = (InternalProject) project;
		final InternalProject newProject = internalProject.clone(name);
		return createProject(newProject);
	}

	private boolean projectExists(String name) {
		return getProject(name) != null;
	}

	private ECPProject createProject(InternalProject project) {
		project.getProvider().handleLifecycle(project, LifecycleEvent.CREATE);
		changeElements(null, Collections.singleton(project));

		return project;
	}

	/** {@inheritDoc} */
	@Override
	public InternalProject getProject(Object adaptable) {
		if (adaptable instanceof ECPProjectAware) {
			final ECPProjectAware projectAware = (ECPProjectAware) adaptable;
			return (InternalProject) projectAware.getProject();
		}
		final InternalProject result = getInternalProject(adaptable);
		if (result != null) {
			return result;
		}
		return AdapterUtil.adapt(adaptable, InternalProject.class);
	}

	private InternalProject getInternalProject(Object object) {
		for (final ECPProvider provider : ECPUtil.getECPProviderRegistry().getProviders()) {
			final InternalProvider internalProvider = (InternalProvider) ECPUtil.getResolvedElement(provider);
			final ECPContainer modelContext = internalProvider.getModelContext(object);
			if (modelContext != null && InternalProject.class.isInstance(modelContext)) {
				return (InternalProject) modelContext;
			}
		}

		return null;
	}

	/** {@inheritDoc} */
	@Override
	public InternalProject getProject(String name) {
		return getElement(name);
	}

	/** {@inheritDoc} */
	@Override
	public Collection<ECPProject> getProjects() {
		initializeProjects();
		return (Collection) getElements();
} /** * @param projects */ private void initializeProjects() { if (!initializedProjects) { for (final InternalProject project : getElements()) { if (!project.getProvider().modelExists(project)) { project.close(); Activator.log(IStatus.ERROR, "Project Data was deleted since last start. Project is now closed."); //$NON-NLS-1$ continue; } project.notifyProvider(LifecycleEvent.INIT); } initializedProjects = true; } } /** * This is called by projects to notify observers if a project gets openes or closed. * * @param project the project that called this method * @param opened whether the project is open * @param store whether to store the change */ public void changeProject(ECPProject project, boolean opened, boolean store) { if (store) { storeElement((InternalProject) project); } try { ecpObserverBus.notify(ECPProjectOpenClosedObserver.class).projectChanged(project, opened); } catch (final RuntimeException ex) { Activator.log(ex); } } /** * This is called by projects to notify observers about object changes. * First the {@link ECPProjectContentChangedObserver IECPProjectObjectsChangedObservers} are notified then the * {@link ECPProjectsChangedObserver IECPProjectsChangedUIObservers}. * * @param project the project that called this method * @param objects the objects that changed * @param structural whether the changes where structural */ public void notifyObjectsChanged(ECPProject project, Collection<Object> objects, boolean structural) { final Collection<Object> affected = ecpObserverBus.notify(ECPProjectContentChangedObserver.class) .objectsChanged(project, objects); final Set<Object> toUpdate = new HashSet<Object>(objects); if (affected != null) { toUpdate.addAll(affected); } ecpObserverBus.notify(ECPProjectContentTouchedObserver.class) .contentTouched(project, toUpdate, structural); } /** {@inheritDoc} */ @Override public void repositoriesChanged(Collection<ECPRepository> oldRepositories, Collection<ECPRepository> newRepositories) { final Set<ECPRepository> addedRepositories = InternalUtil.getAddedElements(oldRepositories, newRepositories); final Collection<InternalProject> projects = getElements(); for (final ECPRepository repository : addedRepositories) { for (final InternalProject project : projects) { if (!project.isOpen() && project.getRepository() != null && repository.getName().equals(project.getRepository().getName())) { project.undispose((InternalRepository) repository); } } } } @Override protected void elementsChanged(Collection<InternalProject> oldElements, Collection<InternalProject> newElements) { super.elementsChanged(oldElements, newElements); } @Override protected void doActivate() throws Exception { super.doActivate(); ecpObserverBus.register(this); } @Override protected void doDeactivate() throws Exception { ecpObserverBus.unregister(this); super.doDeactivate(); } @Override protected InternalProject loadElement(ObjectInput in) throws IOException { return new ECPProjectImpl(in); } // @Override // protected InternalProject[] createElementArray(int size) { // return new InternalProject[size]; // } @Override protected void notifyObservers(Collection<InternalProject> oldElements, Collection<InternalProject> newElements) throws Exception { ecpObserverBus.notify(ECPProjectsChangedObserver.class) .projectsChanged((Collection) oldElements, (Collection) newElements); } @Override protected boolean isRemoveDisposedElements() { return false; } }