blob: e6546ef7809e038c13682a94462d82dfa3750f6d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2008 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.tasks.core;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.internal.tasks.core.deprecated.AbstractAttributeFactory;
import org.eclipse.mylyn.internal.tasks.core.deprecated.AbstractLegacyRepositoryConnector;
import org.eclipse.mylyn.internal.tasks.core.deprecated.RepositoryTaskAttribute;
import org.eclipse.mylyn.internal.tasks.core.deprecated.RepositoryTaskData;
import org.eclipse.mylyn.tasks.core.IRepositoryManager;
/**
* @deprecated Do not use. This class is pending for removal: see bug 237552.
*/
@Deprecated
public class TaskDataStorageManager {
private final IRepositoryManager taskRepositoryManager;
private final ITaskDataStorage storage;
private int nextNewId = 1;
public TaskDataStorageManager(IRepositoryManager taskRepositoryManager, ITaskDataStorage storage) {
this.taskRepositoryManager = taskRepositoryManager;
this.storage = storage;
}
/**
* Add a RepositoryTaskData to the offline reports file.
*/
public void setNewTaskData(RepositoryTaskData data) {
if (data == null || data.getRepositoryUrl() == null || data.getTaskId() == null) {
return;
}
TaskDataState state = retrieveState(data);
if (state != null) {
state.setNewTaskData(data);
} else {
state = new TaskDataState(data.getRepositoryUrl(), data.getTaskId());
state.setNewTaskData(data);
}
saveState(state);
}
/**
* @since 2.3
*/
public void setNewTaskData(String repositoryUrl, String taskId, RepositoryTaskData data) {
TaskDataState state = retrieveState(repositoryUrl, taskId);
if (state != null) {
state.setNewTaskData(data);
} else {
state = new TaskDataState(repositoryUrl, taskId);
state.setNewTaskData(data);
}
saveState(state);
}
public void setOldTaskData(RepositoryTaskData data) {
if (data == null || data.getRepositoryUrl() == null || data.getTaskId() == null) {
return;
}
TaskDataState state = retrieveState(data);
if (state != null) {
state.setOldTaskData(data);
} else {
StatusHandler.log(new Status(IStatus.WARNING, ITasksCoreConstants.ID_PLUGIN,
"Attempt to save old data when no new data exists", new Exception()));
}
saveState(state);
}
/**
* Returns the most recent copy of the task data.
*
* @return offline task data, null if no data found
*/
public RepositoryTaskData getNewTaskData(String repositoryUrl, String id) {
if (repositoryUrl == null || id == null) {
return null;
}
TaskDataState state = retrieveState(repositoryUrl, id);
if (state != null) {
return state.getNewTaskData();
}
return null;
}
/**
* Returns the old copy if exists, null otherwise.
*/
public RepositoryTaskData getOldTaskData(String repositoryUrl, String id) {
if (repositoryUrl == null || id == null) {
return null;
}
TaskDataState state = retrieveState(repositoryUrl, id);
if (state != null) {
return state.getOldTaskData();
}
return null;
}
/**
* @return Get the next available temporary taskId. This taskId is given to new unsubmitted repository tasks.
* Incremented each time this method is called.
*/
public synchronized String getNewRepositoryTaskId() {
// TODO: generate based on values of unsubmitted offline report ids
nextNewId++;
if (nextNewId == Integer.MAX_VALUE) {
nextNewId = 1;
}
return "" + nextNewId;
}
/**
*
* @return editable copy of task data with any edits applied
*/
public RepositoryTaskData getEditableCopy(String repositoryUrl, String id) {
if (repositoryUrl == null || id == null) {
return null;
}
TaskDataState state = retrieveState(repositoryUrl, id);
RepositoryTaskData clone = null;
if (state != null) {
if (state.getNewTaskData() != null) {
try {
clone = (RepositoryTaskData) ObjectCloner.deepCopy(state.getNewTaskData());
updateAttributeFactory(clone);
} catch (Exception e) {
StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN,
"Error constructing modifiable task", e));
return null;
}
}
if (clone != null) {
for (RepositoryTaskAttribute attribute : state.getEdits()) {
if (attribute == null) {
continue;
}
RepositoryTaskAttribute existing = clone.getAttribute(attribute.getId());
if (existing != null) {
existing.clearValues();
List<String> options = existing.getOptions();
for (String value : attribute.getValues()) {
if (options.size() > 0) {
if (options.contains(value)) {
existing.addValue(value);
}
} else {
existing.addValue(value);
}
}
} else {
clone.addAttribute(attribute.getId(), attribute);
}
}
}
}
return clone;
}
// TODO review: the state of the elements of changedAttribues could change between this call and the time state is written to disk, might need to make a full copy
public void saveEdits(String repositoryUrl, String id, Set<RepositoryTaskAttribute> changedAttributes) {
TaskDataState state = retrieveState(repositoryUrl, id);
if (state != null) {
Set<RepositoryTaskAttribute> edits = state.getEdits();
if (edits == null) {
// Copy here?
state.setEdits(changedAttributes);
} else {
edits.removeAll(changedAttributes);
edits.addAll(changedAttributes);
}
try {
storage.put(state);
} catch (Exception e) {
// FIXME what exception is caught here?
StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Error saving edits", e));
}
}
}
public Set<RepositoryTaskAttribute> getEdits(String repositoryUrl, String id) {
if (repositoryUrl == null || id == null) {
return Collections.emptySet();
}
TaskDataState state = retrieveState(repositoryUrl, id);
if (state != null) {
if (state.getEdits() != null) {
return Collections.unmodifiableSet(state.getEdits());
}
}
return Collections.emptySet();
}
public void discardEdits(String repositoryUrl, String id) {
if (repositoryUrl == null || id == null) {
return;
}
TaskDataState state = retrieveState(repositoryUrl, id);
if (state != null) {
state.discardEdits();
try {
storage.put(state);
} catch (Exception e) {
// FIXME what exception is caught here?
StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Error discarding edits", e));
}
}
}
public void remove(String repositoryUrl, String id) {
if (repositoryUrl == null || id == null) {
return;
}
storage.remove(repositoryUrl, id);
}
/**
* DESTROY ALL OFFLINE TASK DATA Public for testing only Forces a reset of all data maps Does not signal data
* changed (doesn't request save)
*/
public void clear() {
nextNewId = 0;
storage.clear();
}
/**
* After deserialization process the attributeFactory needs to be reset on each RepositoryTaskData.
*/
private void updateAttributeFactory(RepositoryTaskData taskData) {
if (taskData == null) {
return;
}
taskData.refresh();
AbstractLegacyRepositoryConnector connector = (AbstractLegacyRepositoryConnector) taskRepositoryManager.getRepositoryConnector(taskData.getConnectorKind());
if (connector != null && connector.getLegacyTaskDataHandler() != null) {
AbstractAttributeFactory factory = connector.getLegacyTaskDataHandler().getAttributeFactory(taskData);
if (factory != null) {
taskData.setAttributeFactory(factory);
}
}
}
// XXX: review if task data cloning can be done without using serialization
// Reference:
// http://www.javaworld.com/javaworld/javatips/jw-javatip76.html?page=2
public static class ObjectCloner {
private ObjectCloner() {
// can not instantiate
}
static public Object deepCopy(Object oldObj) throws Exception {
ObjectOutputStream outputStream = null;
ObjectInputStream inputStream = null;
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
outputStream = new ObjectOutputStream(byteArrayOutputStream);
outputStream.writeObject(oldObj);
outputStream.flush();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
inputStream = new ObjectInputStream(byteArrayInputStream);
return inputStream.readObject();
} catch (Exception e) {
throw (e);
} finally {
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
}
}
}
public void start() {
try {
storage.start();
} catch (Exception e) {
StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Offline storage start failed",
e));
}
}
public void stop() {
try {
storage.stop();
} catch (Exception e) {
StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Offline storage stop failed", e));
}
}
public void saveNow() {
storage.flush();
}
private TaskDataState retrieveState(RepositoryTaskData data) {
return retrieveState(data.getRepositoryUrl(), data.getTaskId());
}
private TaskDataState retrieveState(String repositoryUrl, String id) {
TaskDataState state = null;
try {
state = storage.get(repositoryUrl, id);
if (state != null) {
// TODO: Get rid of attribute factory on containers!!!
if (state.getNewTaskData() != null) {
updateAttributeFactory(state.getNewTaskData());
}
if (state.getOldTaskData() != null) {
updateAttributeFactory(state.getOldTaskData());
}
}
} catch (Exception e) {
// FIXME what Exception is caught here?
StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Error saving offline data", e));
}
return state;
}
private void saveState(TaskDataState state) {
storage.put(state);
}
}