/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* 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:
******************************************************************************/
package org.eclipse.emf.emfstore.server.core.subinterfaces;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.emfstore.common.model.Project;
import org.eclipse.emf.emfstore.common.model.util.FileUtil;
import org.eclipse.emf.emfstore.common.model.util.ModelUtil;
import org.eclipse.emf.emfstore.server.connection.xmlrpc.util.StaticOperationFactory;
import org.eclipse.emf.emfstore.server.core.AbstractEmfstoreInterface;
import org.eclipse.emf.emfstore.server.core.AbstractSubEmfstoreInterface;
import org.eclipse.emf.emfstore.server.exceptions.AccessControlException;
import org.eclipse.emf.emfstore.server.exceptions.EmfStoreException;
import org.eclipse.emf.emfstore.server.exceptions.FatalEmfStoreException;
import org.eclipse.emf.emfstore.server.exceptions.InvalidProjectIdException;
import org.eclipse.emf.emfstore.server.exceptions.StorageException;
import org.eclipse.emf.emfstore.server.model.ModelFactory;
import org.eclipse.emf.emfstore.server.model.ProjectHistory;
import org.eclipse.emf.emfstore.server.model.ProjectId;
import org.eclipse.emf.emfstore.server.model.ProjectInfo;
import org.eclipse.emf.emfstore.server.model.SessionId;
import org.eclipse.emf.emfstore.server.model.versioning.LogMessage;
import org.eclipse.emf.emfstore.server.model.versioning.PrimaryVersionSpec;
import org.eclipse.emf.emfstore.server.model.versioning.Version;
import org.eclipse.emf.emfstore.server.model.versioning.VersionSpec;
import org.eclipse.emf.emfstore.server.model.versioning.VersioningFactory;
/**
* This subinterfaces implements all project related functionality for the
* {@link org.eclipse.emf.emfstore.server.core.EmfStoreImpl} interface.
*
* @author wesendon
*/
public class ProjectSubInterfaceImpl extends AbstractSubEmfstoreInterface {
/**
* Default constructor.
*
* @param parentInterface
* parent interface
* @throws FatalEmfStoreException
* in case of failure
*/
public ProjectSubInterfaceImpl(AbstractEmfstoreInterface parentInterface) throws FatalEmfStoreException {
super(parentInterface);
}
/**
* Returns the corresponding project.
*
* @param projectId
* project id
* @return a project or throws exception
* @throws EmfStoreException
* if project couldn't be found
*/
protected ProjectHistory getProject(ProjectId projectId) throws EmfStoreException {
ProjectHistory projectHistory = getProjectOrNull(projectId);
if (projectHistory != null) {
return projectHistory;
}
throw new InvalidProjectIdException("Project with the id:" + ((projectId == null) ? "null" : projectId)
+ " doesn't exist.");
}
private ProjectHistory getProjectOrNull(ProjectId projectId) {
for (ProjectHistory project : getServerSpace().getProjects()) {
if (project.getProjectId().equals(projectId)) {
return project;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public Project getProject(ProjectId projectId, VersionSpec versionSpec) throws EmfStoreException {
synchronized (getMonitor()) {
PrimaryVersionSpec resolvedVersion = getSubInterface(VersionSubInterfaceImpl.class).resolveVersionSpec(
projectId, versionSpec);
Version version = getSubInterface(VersionSubInterfaceImpl.class).getVersion(projectId, resolvedVersion);
if (version.getProjectState() == null) {
while (version.getProjectState() == null && version.getPreviousVersion() != null) {
version = version.getPreviousVersion();
}
if (version.getProjectState() == null) {
// TODO: nicer exception.
// is this null check necessary anyway? (there were problems
// in past, because
// the xml files were inconsistent.
throw new EmfStoreException("Couldn't find project state.");
}
Project projectState = ModelUtil.clone(version.getProjectState());
for (Version next = version.getNextVersion(); next != null
&& next.getPrimarySpec().compareTo(resolvedVersion) < 1; next = next.getNextVersion()) {
next.getChanges().apply(projectState);
}
return projectState;
}
return version.getProjectState();
}
}
/**
* {@inheritDoc}
*
* @throws EmfStoreException
* @throws AccessControlException
*/
public List<ProjectInfo> getProjectList(SessionId sessionId) throws EmfStoreException {
synchronized (getMonitor()) {
List<ProjectInfo> result = new ArrayList<ProjectInfo>();
for (ProjectHistory projectHistory : getServerSpace().getProjects()) {
if (getAuthorizationControl().hasPermissions(sessionId,
StaticOperationFactory.createReadProjectOperation(projectHistory.getProjectId(), null))) {
result.add(createProjectInfo(projectHistory));
}
}
return result;
}
}
/**
* {@inheritDoc}
*/
public ProjectInfo createProject(String name, String description, LogMessage logMessage) throws EmfStoreException {
synchronized (getMonitor()) {
ProjectHistory projectHistory = null;
try {
logMessage.setDate(new Date());
projectHistory = createEmptyProject(name, description, logMessage);
} catch (FatalEmfStoreException e) {
throw new StorageException(StorageException.NOSAVE);
}
return createProjectInfo(projectHistory);
}
}
/**
* {@inheritDoc}
*/
public ProjectInfo createProject(String name, String description, LogMessage logMessage, Project project)
throws EmfStoreException {
synchronized (getMonitor()) {
ProjectHistory projectHistory = null;
try {
logMessage.setDate(new Date());
projectHistory = createEmptyProject(name, description, logMessage);
Version lastVersion = projectHistory.getLastVersion();
lastVersion.setProjectState(project);
getResourceHelper().createResourceForProject(project, lastVersion.getPrimarySpec(),
projectHistory.getProjectId());
saveWithProject(lastVersion, project);// lastVersion.getProjectState());
} catch (FatalEmfStoreException e) {
throw new StorageException(StorageException.NOSAVE);
}
return createProjectInfo(projectHistory);
}
}
/**
* {@inheritDoc}
*/
public void deleteProject(ProjectId projectId, boolean deleteFiles) throws EmfStoreException {
deleteProject2(projectId, deleteFiles, true);
}
/**
* Implemenation of {@link #deleteProject(ProjectId, boolean)} with
* additional possibility of not throwing an invalid id exception.
*
* @param projectId
* project id
* @param deleteFiles
* boolean, whether to delete files in file system
* @param throwInvalidIdException
* boolean
* @throws EmfStoreException
* in case of failure
*/
protected void deleteProject2(ProjectId projectId, boolean deleteFiles, boolean throwInvalidIdException)
throws EmfStoreException {
synchronized (getMonitor()) {
try {
try {
ProjectHistory project = getProject(projectId);
getServerSpace().getProjects().remove(project);
save(getServerSpace());
} catch (InvalidProjectIdException e) {
if (throwInvalidIdException) {
throw e;
}
}
if (deleteFiles) {
File projectFolder = new File(getResourceHelper().getProjectFolder(projectId));
try {
FileUtil.deleteFolder(projectFolder);
} catch (IOException e) {
throw new StorageException(
"Project files couldn't be deleted, but it was deleted from containment tree.", e);
}
}
} catch (FatalEmfStoreException e) {
throw new StorageException(StorageException.NOSAVE);
}
}
}
/**
* {@inheritDoc}
*/
public ProjectId importProjectHistoryToServer(ProjectHistory projectHistory) throws EmfStoreException {
synchronized (getMonitor()) {
ProjectHistory projectOrNull = getProjectOrNull(projectHistory.getProjectId());
if (projectOrNull != null) {
// if project with same id exists, create a new id.
projectHistory.setProjectId(ModelFactory.eINSTANCE.createProjectId());
}
try {
getResourceHelper().createResourceForProjectHistory(projectHistory);
getServerSpace().getProjects().add(projectHistory);
getResourceHelper().save(getServerSpace());
for (Version version : projectHistory.getVersions()) {
if (version.getChanges() != null) {
getResourceHelper().createResourceForChangePackage(version.getChanges(),
version.getPrimarySpec(), projectHistory.getProjectId());
}
if (version.getProjectState() != null) {
getResourceHelper().createResourceForProject(version.getProjectState(),
version.getPrimarySpec(), projectHistory.getProjectId());
}
getResourceHelper().createResourceForVersion(version, projectHistory.getProjectId());
}
getResourceHelper().save(projectHistory);
getResourceHelper().saveAll();
} catch (FatalEmfStoreException e) {
// roll back
deleteProject2(projectHistory.getProjectId(), true, false);
throw new StorageException(StorageException.NOSAVE);
}
return EcoreUtil.copy(projectHistory.getProjectId());
}
}
/**
* {@inheritDoc}
*/
public ProjectHistory exportProjectHistoryFromServer(ProjectId projectId) throws EmfStoreException {
synchronized (getMonitor()) {
return EcoreUtil.copy(getProject(projectId));
}
}
private ProjectHistory createEmptyProject(String name, String description, LogMessage logMessage)
throws FatalEmfStoreException {
// create initial ProjectHistory
ProjectHistory projectHistory = ModelFactory.eINSTANCE.createProjectHistory();
projectHistory.setProjectName(name);
projectHistory.setProjectDescription(description);
projectHistory.setProjectId(ModelFactory.eINSTANCE.createProjectId());
// create a initial version without previous and change package
Version firstVersion = VersioningFactory.eINSTANCE.createVersion();
firstVersion.setLogMessage(logMessage);
PrimaryVersionSpec primary = VersioningFactory.eINSTANCE.createPrimaryVersionSpec();
primary.setIdentifier(0);
firstVersion.setPrimarySpec(primary);
// create initial project
Project project = org.eclipse.emf.emfstore.common.model.ModelFactory.eINSTANCE.createProject();
firstVersion.setProjectState(project);
getResourceHelper().createResourceForProject(project, firstVersion.getPrimarySpec(),
projectHistory.getProjectId());
projectHistory.getVersions().add(firstVersion);
// add to serverspace and saved
getResourceHelper().createResourceForVersion(firstVersion, projectHistory.getProjectId());
getResourceHelper().createResourceForProjectHistory(projectHistory);
getServerSpace().getProjects().add(projectHistory);
save(getServerSpace());
return projectHistory;
}
private ProjectInfo createProjectInfo(ProjectHistory project) {
ProjectInfo info = ModelFactory.eINSTANCE.createProjectInfo();
info.setName(project.getProjectName());
info.setDescription(project.getProjectDescription());
info.setProjectId(EcoreUtil.copy(project.getProjectId()));
info.setVersion(EcoreUtil.copy(project.getLastVersion().getPrimarySpec()));
return info;
}
}