blob: 9b4b2e8f955e72ae1a6cb1b971973bf79d8829a3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2011 Obeo.
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.docs.intent.collab.ide.repository;
import com.google.common.base.Predicate;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.mylyn.docs.intent.collab.handlers.RepositoryClient;
import org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter;
import org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryStructurer;
import org.eclipse.mylyn.docs.intent.collab.ide.adapters.WorkspaceAdapter;
import org.eclipse.mylyn.docs.intent.collab.repository.Repository;
import org.eclipse.mylyn.docs.intent.collab.repository.RepositoryConnectionException;
/**
* Representation of a Workspace as a repository.
*
* @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a>
*/
public class WorkspaceRepository implements Repository {
/**
* The default extension for any element stored on the repository.
*/
private static final String WORKSPACE_RESOURCE_EXTENSION = "repomodel";
/**
* Represents this repository configuration.
*/
private WorkspaceConfig workspaceConfig;
/**
* Session that will notify any listening entities about changes on Workspace resources corresponding to
* repository resources.
*/
private WorkspaceSession session;
/**
* Indicates if the repository resource set has been initialized.
*/
private boolean isResourceSetLoaded;
/**
* The repository editing domain.
*/
private TransactionalEditingDomain editingDomain;
/**
* The repository structurer.
*/
private RepositoryStructurer repositoryStructurer;
/**
* Used to determine if a resource can be unloaded: if the root has one of this unloadableTypes, then it
* will be unloaded.
*/
private EClass[] unloadableTypes;
/**
* WorkspaceRepository constructor.
*
* @param workspaceConfig
* this repository configuration
* @param unloadableTypes
* the list of types which cannot be unloaded
*/
public WorkspaceRepository(WorkspaceConfig workspaceConfig, EClass... unloadableTypes) {
this.unloadableTypes = unloadableTypes;
this.workspaceConfig = workspaceConfig;
this.editingDomain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain();
isResourceSetLoaded = false;
}
/**
* Initializes the resource set using the repository content ; if the repository content is empty, creates
* all the declared indexes.
*
* @throws CoreException
* it the resourceSet cannot be initialized
*/
private void initializeResourceSet() throws CoreException {
// We first get the project on which the repository is defined
IProject project = workspaceConfig.getProject();
if (!project.exists()) {
project.create(null);
}
if (!project.isOpen()) {
project.open(null);
}
IFolder folder = project.getFolder(workspaceConfig.getRepositoryRelativePath());
// We created a WorkspaceRepositoryLoader using the indexPathList
WorkspaceRepositoryLoader loader = new WorkspaceRepositoryLoader(this, this.getWorkspaceConfig()
.getIndexesPathList());
// If the repository folder exists
if (folder.exists()) {
// We load the resourceSet
loader.loadResourceSet();
} else {
// If the repository folder doesn't exist
// We create it
folder.create(IResource.NONE, true, null);
// And use the RepositoryLoader to initialize the resource set with empty content
loader.loadResourceSet();
}
isResourceSetLoaded = true;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#register(org.eclipse.mylyn.docs.intent.collab.handlers.RepositoryClient)
*/
public void register(RepositoryClient client) {
// No need to register
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#unregister(org.eclipse.mylyn.docs.intent.collab.handlers.RepositoryClient)
*/
public void unregister(RepositoryClient client) {
// No need to unregister
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#getOrCreateSession()
*/
public synchronized Object getOrCreateSession() throws RepositoryConnectionException {
// We first initialize the resource set if needed
if (!isResourceSetLoaded) {
try {
initializeResourceSet();
} catch (CoreException e) {
throw new RepositoryConnectionException(e.getMessage());
}
}
if (this.session == null) {
// Creation of a Workspace session that will send notifications when the workspace's resources
// corresponding to repository resources change
this.session = new WorkspaceSession(this);
IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.addResourceChangeListener(session);
}
return this.session;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#closeSession()
*/
public synchronized void closeSession() throws RepositoryConnectionException {
if (this.session != null) {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(session);
this.session.close();
this.session = null;
}
// If a transaction is being executed, we abort it
if (((InternalTransactionalEditingDomain)this.editingDomain).getActiveTransaction() != null) {
((InternalTransactionalEditingDomain)this.editingDomain).getActiveTransaction().abort(
Status.CANCEL_STATUS);
}
this.editingDomain.dispose();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#getPackageRegistry()
*/
public Registry getPackageRegistry() throws RepositoryConnectionException {
// Return the resourceset's package registry
return getResourceSet().getPackageRegistry();
}
// ---- SPECIFIC BEHAVIORS
/**
* Indicates if the given path represents a location in the repository.
*
* @param path
* the path to study
* @return true if the given path represents a location in the repository, false otherwise
*/
public boolean isInRepositoryPath(String path) {
return path.startsWith(this.workspaceConfig.getRepositoryRelativePath());
}
/**
* Indicates if the given resource is included in the given path.
*
* @param path
* is the path
* @param resource
* the resource to determine if it's included in the given path
* @return true if the resource's associated path starts with or is equals to the given path, false
* otherwise
*/
public boolean isIncludedInPath(String path, Resource resource) {
// We first get the complete URI of the given path
URI uriPath = getURIMatchingPath(path);
// We compare the two URI
return resource.getURI().toString().startsWith(uriPath.toString());
}
/**
* Returns the Repository URI corresponding to the given path.
* <p>
* The complete path is calculated by prefixing the given path by this repository path and postfixing it
* by the default file extension.
* </p>
*
* @param path
* is the path
* @return the Repository URI corresponding to the given path
*/
public URI getURIMatchingPath(String path) {
String completePath = this.getWorkspaceConfig().getRepositoryAbsolutePath() + path;
// If the path don't ends with '/' (i.e isn't a folder), we add the file extension
if (shouldHaveWorkspaceResourceExtension(completePath)) {
completePath += "." + WORKSPACE_RESOURCE_EXTENSION;
}
completePath = completePath.trim();
URI uri = URI.createPlatformResourceURI(completePath, false);
return uri;
}
/**
* Indicates if the Repository resource located at the given path should be association with the
* {@link WorkspaceRepository#WORKSPACE_RESOURCE_EXTENSION} extension.
*
* @param path
* the path of the Repository resource
* @return true if the Repository resource located at the given path should be association with the
* {@link WorkspaceRepository#WORKSPACE_RESOURCE_EXTENSION} extension, false otherwise
*/
public boolean shouldHaveWorkspaceResourceExtension(String path) {
return !path.endsWith("/");
}
/**
* Returns the EMF ResourceSet of this Workspace repository.
* <p>
* It will handle resource creation, package registry management...
* </p>
*
* @return the resourceSet the EMF ResourceSet of this Workspace repository
*/
public ResourceSet getResourceSet() {
return editingDomain.getResourceSet();
}
/**
* Returns this repository configuration.
*
* @return this repository configuration
*/
public WorkspaceConfig getWorkspaceConfig() {
return workspaceConfig;
}
/**
* Returns the default extension for any element stored on the repository.
*
* @return the default extension for any element stored on the repository
*/
public static String getWorkspaceResourceExtension() {
return WORKSPACE_RESOURCE_EXTENSION;
}
public TransactionalEditingDomain getEditingDomain() {
return editingDomain;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#setRepositoryStructurer(org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryStructurer)
*/
public void setRepositoryStructurer(RepositoryStructurer structurer) {
this.repositoryStructurer = structurer;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#createRepositoryAdapter()
*/
public RepositoryAdapter createRepositoryAdapter() {
WorkspaceAdapter workspaceAdapter = new WorkspaceAdapter(this);
if (this.repositoryStructurer != null) {
workspaceAdapter.attachRepositoryStructurer(this.repositoryStructurer);
}
// We set a new unloadable Resource Predicate
workspaceAdapter.setUnloadableResourcePredicate(new Predicate<Resource>() {
public boolean apply(Resource resource) {
// The Intent index should never be unloaded
if (!resource.getContents().isEmpty()) {
boolean res = false;
EObject root = resource.getContents().iterator().next();
for (EClass unloadableType : unloadableTypes) {
if (root.eClass().equals(unloadableType)) {
res = true;
}
}
return res;
}
return false;
}
});
return workspaceAdapter;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#getIdentifier()
*/
public String getIdentifier() {
return workspaceConfig.getProject().getName();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#getRepositoryLocation()
*/
public String getRepositoryLocation() {
return ResourcesPlugin.getWorkspace().getRoot().getLocation().toPortableString()
+ getWorkspaceConfig().getRepositoryAbsolutePath().replace(".repository", "");
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.collab.repository.Repository#getRepositoryURI()
*/
public URI getRepositoryURI() {
return URI.createPlatformResourceURI(getIdentifier(), true);
}
}