blob: 3ebb5d83ccf10f400806ca6cac1c015afa30058f [file] [log] [blame]
/*******************************************************************************
* 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.client.model;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.emfstore.client.model.changeTracking.commands.EMFStoreBasicCommandStack;
import org.eclipse.emf.emfstore.client.model.connectionmanager.AdminConnectionManager;
import org.eclipse.emf.emfstore.client.model.connectionmanager.ConnectionManager;
import org.eclipse.emf.emfstore.client.model.connectionmanager.KeyStoreManager;
import org.eclipse.emf.emfstore.client.model.connectionmanager.xmlrpc.XmlRpcAdminConnectionManager;
import org.eclipse.emf.emfstore.client.model.connectionmanager.xmlrpc.XmlRpcConnectionManager;
import org.eclipse.emf.emfstore.client.model.util.EMFStoreCommand;
import org.eclipse.emf.emfstore.client.model.util.EditingDomainProvider;
import org.eclipse.emf.emfstore.client.model.util.WorkspaceUtil;
import org.eclipse.emf.emfstore.common.CommonUtil;
import org.eclipse.emf.emfstore.common.model.ModelVersion;
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.MalformedModelVersionException;
import org.eclipse.emf.emfstore.common.model.util.ModelUtil;
import org.eclipse.emf.emfstore.common.observer.ObserverBus;
import org.eclipse.emf.emfstore.migration.EMFStoreMigrationException;
import org.eclipse.emf.emfstore.migration.EMFStoreMigratorUtil;
/**
* Controller for workspaces. Workspace Manager is a singleton.
*
* @author Maximilian Koegel
* @generated NOT
*/
public final class WorkspaceManager {
private static WorkspaceManager instance;
private Workspace currentWorkspace;
private ConnectionManager connectionManager;
private AdminConnectionManager adminConnectionManager;
private ObserverBus observerBus;
/**
* Get an instance of the workspace manager. Will create an instance if no workspace manager is present.
*
* @return the workspace manager singleton
* @generated NOT
*/
public static synchronized WorkspaceManager getInstance() {
if (instance == null) {
try {
instance = new WorkspaceManager();
// BEGIN SUPRESS CATCH EXCEPTION
} catch (RuntimeException e) {
// END SURPRESS CATCH EXCEPTION
ModelUtil.logException("Workspace Initialization failed, shutting down", e);
throw e;
}
// init ecore packages
CommonUtil.getAllModelElementEClasses();
// notify post workspace observers
instance.notifyPostWorkspaceInitiators();
}
return instance;
}
/**
* Initialize the Workspace Manager singleton.
*/
public static synchronized void init() {
getInstance();
}
/**
* Default constructor.
*
* @generated NOT
*/
private WorkspaceManager() {
this.connectionManager = initConnectionManager();
this.adminConnectionManager = initAdminConnectionManager();
this.currentWorkspace = initWorkSpace();
this.observerBus = new ObserverBus();
}
private void notifyPostWorkspaceInitiators() {
IConfigurationElement[] workspaceObservers = Platform.getExtensionRegistry().getConfigurationElementsFor(
"org.eclipse.emf.emfstore.client.notify.postinit");
for (IConfigurationElement element : workspaceObservers) {
try {
PostWorkspaceInitiator workspaceObserver = (PostWorkspaceInitiator) element
.createExecutableExtension("class");
workspaceObserver.workspaceInitComplete(currentWorkspace);
} catch (CoreException e) {
WorkspaceUtil.logException(e.getMessage(), e);
}
}
}
/**
* Initialize the connection manager of the workspace. The connection manager connects the workspace with the emf
* store.
*
* @return the connection manager
* @generated NOT
*/
private ConnectionManager initConnectionManager() {
KeyStoreManager.getInstance().setupKeys();
// return new RMIConnectionManagerImpl();
return new XmlRpcConnectionManager();
}
/**
* Initialize the connection manager of the workspace. The connection manager connects the workspace with the emf
* store.
*
* @return the admin connection manager
* @generated NOT
*/
private AdminConnectionManager initAdminConnectionManager() {
// return new RMIAdminConnectionManagerImpl();
return new XmlRpcAdminConnectionManager();
}
/**
* Initialize the workspace. Loads workspace from persistent storage if present. There is always one current
* Workspace.
*
* @return the workspace
* @generated NOT
*/
private Workspace initWorkSpace() {
ResourceSet resourceSet = new ResourceSetImpl();
// register an editing domain on the ressource
Configuration.setEditingDomain(createEditingDomain(resourceSet));
URI fileURI = URI.createFileURI(Configuration.getWorkspacePath());
File workspaceFile = new File(Configuration.getWorkspacePath());
final Workspace workspace;
final Resource resource;
if (!workspaceFile.exists()) {
workspace = createNewWorkspace(resourceSet, fileURI);
} else {
// file exists load it
// check if a migration is needed
migrateModel(resourceSet);
// resource = resourceSet.getResource(fileURI, true);
resource = resourceSet.createResource(fileURI);
try {
resource.load(ModelUtil.getResourceLoadOptions());
} catch (IOException e) {
WorkspaceUtil.logException("Error while loading workspace.", e);
}
EList<EObject> directContents = resource.getContents();
// MK cast
workspace = (Workspace) directContents.get(0);
}
workspace.setConnectionManager(this.connectionManager);
workspace.setWorkspaceResourceSet(resourceSet);
new EMFStoreCommand() {
@Override
protected void doRun() {
workspace.init();
}
}.run(true);
return workspace;
}
private EditingDomain createEditingDomain(ResourceSet resourceSet) {
EditingDomainProvider domainProvider = getDomainProvider();
if (domainProvider != null) {
return domainProvider.getEditingDomain(resourceSet);
} else {
AdapterFactoryEditingDomain domain = new AdapterFactoryEditingDomain(new ComposedAdapterFactory(
ComposedAdapterFactory.Descriptor.Registry.INSTANCE), new EMFStoreBasicCommandStack(), resourceSet);
resourceSet.eAdapters().add(new AdapterFactoryEditingDomain.EditingDomainProvider(domain));
return domain;
}
}
private EditingDomainProvider getDomainProvider() {
IConfigurationElement[] rawExtensions = Platform.getExtensionRegistry().getConfigurationElementsFor(
"org.eclipse.emf.emfstore.client.editingDomainProvider");
for (IConfigurationElement extension : rawExtensions) {
try {
EditingDomainProvider provider = (EditingDomainProvider) extension.createExecutableExtension("class");
if (provider != null) {
return provider;
}
} catch (CoreException e) {
// fail silently
}
}
return null;
}
private Workspace createNewWorkspace(ResourceSet resourceSet, URI fileURI) {
final Workspace workspace;
final Resource resource;
// no workspace content found, create a workspace
resource = resourceSet.createResource(fileURI);
workspace = ModelFactory.eINSTANCE.createWorkspace();
workspace.getServerInfos().addAll(Configuration.getDefaultServerInfos());
EList<Usersession> usersessions = workspace.getUsersessions();
for (ServerInfo serverInfo : workspace.getServerInfos()) {
Usersession lastUsersession = serverInfo.getLastUsersession();
if (lastUsersession != null) {
usersessions.add(lastUsersession);
}
}
new EMFStoreCommand() {
@Override
protected void doRun() {
resource.getContents().add(workspace);
}
}.run(true);
try {
resource.save(Configuration.getResourceSaveOptions());
} catch (IOException e) {
WorkspaceUtil.logException(
"Creating new workspace failed! Delete workspace folder: " + Configuration.getWorkspaceDirectory(), e);
}
int modelVersionNumber;
try {
modelVersionNumber = ModelUtil.getModelVersionNumber();
stampCurrentVersionNumber(modelVersionNumber);
} catch (MalformedModelVersionException e1) {
WorkspaceUtil.logException("Loading model version failed!", e1);
}
return workspace;
}
private void stampCurrentVersionNumber(int modelReleaseNumber) {
URI versionFileUri = URI.createFileURI(Configuration.getModelReleaseNumberFileName());
Resource versionResource = new ResourceSetImpl().createResource(versionFileUri);
ModelVersion modelVersion = org.eclipse.emf.emfstore.common.model.ModelFactory.eINSTANCE.createModelVersion();
modelVersion.setReleaseNumber(modelReleaseNumber);
versionResource.getContents().add(modelVersion);
try {
versionResource.save(Configuration.getResourceSaveOptions());
} catch (IOException e) {
WorkspaceUtil.logException(
"Version stamping workspace failed! Delete workspace folder: " + Configuration.getWorkspaceDirectory(),
e);
}
}
private void migrateModel(ResourceSet resourceSet) {
ModelVersion workspaceModelVersion = getWorkspaceModelVersion();
int modelVersionNumber;
try {
modelVersionNumber = ModelUtil.getModelVersionNumber();
stampCurrentVersionNumber(modelVersionNumber);
} catch (MalformedModelVersionException e1) {
WorkspaceUtil.logException("Loading model version failed, migration skipped!", e1);
return;
}
if (workspaceModelVersion.getReleaseNumber() == modelVersionNumber) {
return;
} else if (workspaceModelVersion.getReleaseNumber() > modelVersionNumber) {
backupAndRecreateWorkspace(resourceSet);
WorkspaceUtil.logException("Model conforms to a newer version, update client! New workspace was backuped!",
new IllegalStateException());
return;
}
// we need to migrate
if (!EMFStoreMigratorUtil.isMigratorAvailable()) {
WorkspaceUtil.logException("Model requires migration, but no migrators are registered!",
new IllegalStateException());
return;
}
backupWorkspace(false);
File workspaceFile = new File(Configuration.getWorkspaceDirectory());
for (File file : workspaceFile.listFiles()) {
if (file.getName().startsWith(Configuration.getProjectSpaceDirectoryPrefix())) {
String projectFilePath = file.getAbsolutePath() + File.separatorChar
+ Configuration.getProjectFolderName() + File.separatorChar + 0
+ Configuration.getProjectFragmentFileExtension();
URI projectURI = URI.createFileURI(projectFilePath);
String operationsFilePath = null;
File[] listFiles = file.listFiles();
if (listFiles == null) {
WorkspaceUtil.logException("The migration of the project in projectspace at " + projectFilePath
+ " failed!", new IllegalStateException("Broken projectSpace!"));
continue;
}
for (File subDirFile : listFiles) {
if (subDirFile.getName().endsWith(Configuration.getOperationCompositeFileExtension())) {
operationsFilePath = subDirFile.getAbsolutePath();
}
}
if (operationsFilePath == null) {
WorkspaceUtil.logException("The migration of the project in projectspace at " + projectFilePath
+ " failed!", new IllegalStateException("Broken workspace!"));
backupAndRecreateWorkspace(resourceSet);
}
URI operationsURI = URI.createFileURI(operationsFilePath);
try {
migrate(projectURI, operationsURI, workspaceModelVersion.getReleaseNumber());
} catch (EMFStoreMigrationException e) {
WorkspaceUtil.logException("The migration of the project in projectspace at " + projectFilePath
+ " failed!", e);
backupAndRecreateWorkspace(resourceSet);
}
}
}
stampCurrentVersionNumber(modelVersionNumber);
}
public void migrate(String absoluteFilename) {
URI projectURI = URI.createFileURI(absoluteFilename);
List<URI> modelURIs = new ArrayList<URI>();
modelURIs.add(projectURI);
ModelVersion workspaceModelVersion = getWorkspaceModelVersion();
if (!EMFStoreMigratorUtil.isMigratorAvailable()) {
ModelUtil.logWarning("No Migrator available to migrate imported file");
return;
}
try {
EMFStoreMigratorUtil.getEMFStoreMigrator().migrate(modelURIs, workspaceModelVersion.getReleaseNumber() - 1,
new NullProgressMonitor());
} catch (EMFStoreMigrationException e) {
WorkspaceUtil.logWarning("The migration of the project in the file " + absoluteFilename + " failed!", e);
}
}
private void backupAndRecreateWorkspace(ResourceSet resourceSet) {
backupWorkspace(true);
URI fileURI = URI.createFileURI(Configuration.getWorkspacePath());
createNewWorkspace(resourceSet, fileURI);
}
private void backupWorkspace(boolean move) {
String workspaceDirectory = Configuration.getWorkspaceDirectory();
File workspacePath = new File(workspaceDirectory);
// TODO: if you want the date included in the backup folder you should change the format. the default format
// does not work with every os due to : and other characters.
String newWorkspaceDirectory = Configuration.getLocationProvider().getBackupDirectory() + "emfstore_backup_"
+ System.currentTimeMillis();
File workspacebackupPath = new File(newWorkspaceDirectory);
if (move) {
workspacePath.renameTo(workspacebackupPath);
} else {
try {
FileUtil.copyDirectory(workspacePath, workspacebackupPath);
} catch (IOException e) {
WorkspaceUtil.logException("Workspace backup failed!", e);
}
}
}
private ModelVersion getWorkspaceModelVersion() {
// check for legacy workspace
File versionFile = new File(Configuration.getModelReleaseNumberFileName());
if (!versionFile.exists()) {
int modelVersionNumber;
try {
modelVersionNumber = ModelUtil.getModelVersionNumber();
stampCurrentVersionNumber(modelVersionNumber);
} catch (MalformedModelVersionException e1) {
WorkspaceUtil.logException("Loading model version failed!", e1);
}
}
// check if we need to migrate
URI versionFileUri = URI.createFileURI(Configuration.getModelReleaseNumberFileName());
ResourceSet resourceSet = new ResourceSetImpl();
try {
Resource resource = resourceSet.getResource(versionFileUri, true);
EList<EObject> directContents = resource.getContents();
ModelVersion modelVersion = (ModelVersion) directContents.get(0);
return modelVersion;
// BEGIN SUPRESS CATCH EXCEPTION
} catch (RuntimeException e) {
// END SUPRESS CATCH EXCEPTION
// resource can not be loaded, assume version number before metamodel split
ModelVersion modelVersion = org.eclipse.emf.emfstore.common.model.ModelFactory.eINSTANCE
.createModelVersion();
modelVersion.setReleaseNumber(4);
return modelVersion;
}
}
/**
* Migrate the model instance if neccessary.
*
* @param projectURI the uri of the project state
* @param changesURI the uri of the local changes of the project state
* @param sourceModelReleaseNumber
* @throws EMFStoreMigrationException
*/
private void migrate(URI projectURI, URI changesURI, int sourceModelReleaseNumber)
throws EMFStoreMigrationException {
List<URI> modelURIs = new ArrayList<URI>();
modelURIs.add(projectURI);
modelURIs.add(changesURI);
EMFStoreMigratorUtil.getEMFStoreMigrator().migrate(modelURIs, sourceModelReleaseNumber,
new NullProgressMonitor());
}
/**
* Get the current workspace. There is always one current workspace.
*
* @return the workspace
*/
public Workspace getCurrentWorkspace() {
return currentWorkspace;
}
/**
* Get the connection manager. Return the connection manager for this workspace.
*
* @return the connectionManager
*/
public ConnectionManager getConnectionManager() {
return connectionManager;
}
/**
* Set the connectionmanager.
*
* @param manager connection manager.
*/
public void setConnectionManager(ConnectionManager manager) {
connectionManager = manager;
}
/**
* Get the admin connection manager. Return the admin connection manager for this workspace.
*
* @return the connectionManager
*/
public AdminConnectionManager getAdminConnectionManager() {
return adminConnectionManager;
}
/**
* Retrieve the project space for a model element.
*
* @param modelElement the model element
* @return the project space
*/
public static ProjectSpace getProjectSpace(EObject modelElement) {
if (modelElement == null) {
throw new IllegalArgumentException("The model element is null");
} else if (modelElement instanceof ProjectSpace) {
return (ProjectSpace) modelElement;
}
Project project = ModelUtil.getProject(modelElement);
if (project == null) {
throw new IllegalArgumentException("The model element " + modelElement + " has no project");
}
return getProjectSpace(project);
}
/**
* Retrieve the project space for a project.
*
* @param project the project
* @return the project space
*/
public static ProjectSpace getProjectSpace(Project project) {
if (project == null) {
throw new IllegalArgumentException("The project is null");
}
// check if my container is a project space
if (ModelPackage.eINSTANCE.getProjectSpace().isInstance(project.eContainer())) {
return (ProjectSpace) project.eContainer();
} else {
throw new IllegalStateException("Project is not contained by any project space");
}
}
/**
* Returns the {@link ObserverBus}.
*
* @return observer bus
*/
public static ObserverBus getObserverBus() {
return getInstance().observerBus;
}
}