/*******************************************************************************
* Copyright (C) 2013, Robin Stocker <robin@nibor.org>
*
* 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
*******************************************************************************/
package org.eclipse.egit.ui.internal.revision;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.egit.ui.Activator;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.team.core.history.IFileRevision;
/**
* Editable revision backed by a file outside of the workspace (just IPath).
* <p>
* Use {@link ResourceEditableRevision} if you have a resource.
*/
public class LocationEditableRevision extends EditableRevision {
private final IPath location;
private final IRunnableContext runnableContext;
/**
* @param fileRevision
* @param location
* @param runnableContext
*/
public LocationEditableRevision(IFileRevision fileRevision, IPath location,
IRunnableContext runnableContext) {
super(fileRevision, null);
this.location = location;
Assert.isNotNull(runnableContext);
this.runnableContext = runnableContext;
}
@Override
public void setContent(final byte[] newContent) {
try {
// Don't fork: if we are called from a thread which locked
// workspace our *forked* operation will never complete because it
// requires file lock which cannot be acquired from another thread
ISchedulingRule rule = Job.getJobManager().currentRule();
boolean fork = true;
if (rule instanceof IResource) {
IFile ourFile = ResourcesPlugin.getWorkspace().getRoot()
.getFile(location);
if (ourFile.exists()
&& ((IResource) rule).isConflicting(ourFile))
fork = false;
}
runnableContext.run(fork, false, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
IFileStore store = EFS.getLocalFileSystem().getStore(
location);
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(store.openOutputStream(
0, monitor));
out.write(newContent);
} catch (CoreException e) {
throw new InvocationTargetException(e);
} catch (IOException e) {
throw new InvocationTargetException(e);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
// Ignore this one
}
}
}
}
});
} catch (InvocationTargetException e) {
Activator.handleError(e.getTargetException().getMessage(),
e.getTargetException(), true);
} catch (InterruptedException e) {
// ignore here
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result
+ ((location == null) ? 0 : location.hashCode());
result = prime * result
+ ((runnableContext == null) ? 0 : runnableContext.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
LocationEditableRevision other = (LocationEditableRevision) obj;
if (location == null) {
if (other.location != null)
return false;
} else if (!location.equals(other.location))
return false;
if (runnableContext == null) {
if (other.runnableContext != null)
return false;
} else if (!runnableContext.equals(other.runnableContext))
return false;
return true;
}
}