blob: a024c6b2cab10021480aa95c55c5b521d9a837ba [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2009 Tasktop Technologies and others.
* 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.context.core;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipOutputStream;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.context.core.ContextCore;
import org.eclipse.mylyn.context.core.IContextStore;
import org.eclipse.mylyn.context.core.IInteractionContext;
import org.eclipse.mylyn.context.core.IInteractionContextScaling;
/**
* @author Mik Kersten
* @author Steffen Pingel
*/
public class LocalContextStore implements IContextStore {
private File contextDirectory;
/**
* Cache of available context files.
*/
private Set<File> contextFiles;
private final InteractionContextExternalizer externalizer = new InteractionContextExternalizer();
private final IInteractionContextScaling commonContextScaling;
private final List<IContextStoreListener> listeners = new ArrayList<IContextStoreListener>();
public LocalContextStore(IInteractionContextScaling commonContextScaling) {
this.commonContextScaling = commonContextScaling;
}
public synchronized void setContextDirectory(File directory) {
this.contextDirectory = directory;
this.contextFiles = null;
for (IContextStoreListener listener : listeners) {
listener.contextStoreMoved(directory);
}
// rootDirectory = new File(TasksUiPlugin.getDefault().getDataDirectory());
// if (!rootDirectory.exists()) {
// rootDirectory.mkdir();
// }
//
// contextDirectory = new File(rootDirectory, ITasksCoreConstants.CONTEXTS_DIRECTORY);
// if (!contextDirectory.exists()) {
// contextDirectory.mkdir();
// }
}
public File getContextDirectory() {
return contextDirectory;
}
/**
* @return false if the map could not be read for any reason
*/
public IInteractionContext loadContext(String handleIdentifier) {
return loadContext(handleIdentifier, getFileForContext(handleIdentifier), commonContextScaling);
}
public IInteractionContext importContext(String handleIdentifier, File fromFile) throws CoreException {
InteractionContext context;
String handleToImportFrom;
handleToImportFrom = InteractionContextExternalizer.getFirstContextHandle(fromFile);
context = (InteractionContext) loadContext(handleToImportFrom, fromFile, commonContextScaling);
context.setHandleIdentifier(handleIdentifier);
saveContext(context);
return context;
}
/**
* @return The loaded context, or a newly created one.
*/
public IInteractionContext loadContext(String handleIdentifier, File fromFile,
IInteractionContextScaling contextScaling) {
IInteractionContext loadedContext = externalizer.readContextFromXml(handleIdentifier, fromFile, contextScaling);
if (loadedContext == null) {
return new InteractionContext(handleIdentifier, contextScaling);
} else {
return loadedContext;
}
}
// TODO: interaction activity capture should be locked or queued for the duration of this and other saves
public void saveActiveContext() {
// FIXME this should not reference the context manager
IInteractionContext context = ContextCore.getContextManager().getActiveContext();
if (context != null && context.getHandleIdentifier() != null) {
saveContext(context);
}
}
public void saveContext(IInteractionContext context, String fileName) {
try {
externalizer.writeContextToXml(context, getFileForContext(fileName));
} catch (IOException e) {
StatusHandler.log(new Status(IStatus.ERROR, ContextCorePlugin.ID_PLUGIN, "Failed to write context " //$NON-NLS-1$
+ context.getHandleIdentifier(), e));
}
}
public void saveContext(IInteractionContext context) {
// FIXME this should not reference the context manager
boolean wasPaused = ContextCore.getContextManager().isContextCapturePaused();
try {
// TODO: make this asynchronous by creating a copy
if (!wasPaused) {
// FIXME this should not reference the context manager
ContextCore.getContextManager().setContextCapturePaused(true);
}
if (context instanceof InteractionContext) {
((InteractionContext) context).collapse();
}
externalizer.writeContextToXml(context, getFileForContext(context.getHandleIdentifier()));
if (context.getAllElements().size() == 0) {
removeFromCache(context);
} else {
addToCache(context);
}
} catch (Throwable t) {
StatusHandler.log(new Status(IStatus.ERROR, ContextCorePlugin.ID_PLUGIN, "could not save context", t)); //$NON-NLS-1$
} finally {
if (!wasPaused) {
// FIXME this should not reference the context manager
ContextCore.getContextManager().setContextCapturePaused(false);
}
}
}
private boolean addToCache(IInteractionContext context) {
initCache();
return contextFiles.add(getFileForContext(context.getHandleIdentifier()));
}
private void initCache() {
if (contextFiles == null) {
contextFiles = new HashSet<File>();
File[] files = contextDirectory.listFiles();
for (File file : files) {
contextFiles.add(file);
}
}
}
private boolean removeFromCache(IInteractionContext context) {
if (contextFiles != null) {
return contextFiles.remove(getFileForContext(context.getHandleIdentifier()));
} else {
return false;
}
}
public IInteractionContext cloneContext(String sourceContextHandle, String destinationContextHandle) {
InteractionContext readContext = (InteractionContext) externalizer.readContextFromXml(sourceContextHandle,
getFileForContext(sourceContextHandle), commonContextScaling);
if (readContext == null) {
return new InteractionContext(destinationContextHandle, commonContextScaling);
} else {
readContext.setHandleIdentifier(destinationContextHandle);
saveContext(readContext);
}
// IInteractionContext context = importContext(destinationContextHandle, getFileForContext(sourceContextHandle));
// if (context != null) {
// saveContext(context);
// } else {
// StatusHandler.log(new Status(IStatus.WARNING, ContextCorePlugin.ID_PLUGIN, "Could not copy context from: "
// + sourceContextHandle));
// }
return readContext;
}
public boolean hasContext(String handleIdentifier) {
Assert.isNotNull(handleIdentifier);
File file = getFileForContext(handleIdentifier);
initCache();
return contextFiles.contains(file);
}
public File getFileForContext(String handleIdentifier) {
String encoded;
try {
encoded = URLEncoder.encode(handleIdentifier, InteractionContextManager.CONTEXT_FILENAME_ENCODING);
File contextDirectory = getContextDirectory();
File contextFile = new File(contextDirectory, encoded + InteractionContextManager.CONTEXT_FILE_EXTENSION);
return contextFile;
} catch (UnsupportedEncodingException e) {
StatusHandler.log(new Status(IStatus.ERROR, ContextCorePlugin.ID_PLUGIN,
"Could not determine path for context", e)); //$NON-NLS-1$
}
return null;
}
public void deleteContext(String handleIdentifier) {
try {
File file = getFileForContext(handleIdentifier);
if (file.exists()) {
file.delete();
}
if (contextFiles != null) {
contextFiles.remove(getFileForContext(handleIdentifier));
}
} catch (SecurityException e) {
StatusHandler.log(new Status(IStatus.ERROR, ContextCorePlugin.ID_PLUGIN,
"Could not delete context file, insufficient permissions.", e)); //$NON-NLS-1$
}
}
/**
* Can consider making this API, but it should not expose a zip stream.
*/
public void export(String handleIdentifier, ZipOutputStream outputStream) throws IOException {
IInteractionContext context = loadContext(handleIdentifier);
externalizer.writeContext(context, outputStream);
}
@Deprecated
public void addListener(IContextStoreListener listener) {
listeners.add(listener);
}
@Deprecated
public void removeListener(IContextStoreListener listener) {
listeners.remove(listener);
}
}