/******************************************************************************* * Copyright (c) 2012, 2013 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.commons.core.storage; import java.io.File; import java.util.HashMap; import java.util.Map; 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.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.commons.core.CommonsCorePlugin; import org.eclipse.osgi.util.NLS; /** * @author Steffen Pingel */ public class CommonStore { /** * Delays writing of mementos to avoid blocking UI thread. */ private class FlushJob extends Job { public FlushJob() { super("Flush context mementos"); //$NON-NLS-1$ setSystem(true); setPriority(Job.SHORT); } @Override protected IStatus run(IProgressMonitor monitor) { flushPending(); return Status.OK_STATUS; } } private static final long FLUSH_DELAY = 500; private boolean scheduled; private FlushJob flushJob; private final Map<File, CommonStorable> storableByLocation; private File location; public CommonStore(File location) { Assert.isNotNull(location); this.storableByLocation = new HashMap<File, CommonStorable>(); this.location = location; } public synchronized ICommonStorable get(IPath path) { File file = getFile(path); CommonStorable storable = storableByLocation.get(file); if (storable == null) { storable = new CommonStorable(this, file); storableByLocation.put(file, storable); } return storable; } public File getLocation() { return location; } public void setLocation(File location) { Assert.isNotNull(location); this.location = location; } public void stop() { synchronized (this) { if (flushJob != null) { flushJob.cancel(); flushJob = null; } } flushPending(); } private File getFile(IPath path) { return getFile(path, true); } private File getFile(IPath path, boolean create) { File file = new File(location, path.toOSString()); if (create && !file.getParentFile().exists()) { file.getParentFile().mkdirs(); } return file; } synchronized void schedule() { if (!scheduled) { if (flushJob == null) { flushJob = new FlushJob(); } flushJob.schedule(FLUSH_DELAY); } } synchronized void flushPending() { MultiStatus status = new MultiStatus(CommonsCorePlugin.ID_PLUGIN, 0, "Failed to save storable", null); //$NON-NLS-1$ for (CommonStorable memento : storableByLocation.values()) { if (memento.isDirty()) { IStatus result = memento.flush(); status.add(result); } } if (!status.isOK()) { StatusHandler.log(status); } } synchronized void release(CommonStorable storable) { storableByLocation.remove(storable.getPath()); } public void move(IPath oldPath, IPath newPath) throws CoreException { File oldFile = getFile(oldPath, false); // TODO lock hierarchy and throw an exception if oldFile is in use if (oldFile.exists()) { File newFile = getFile(newPath, false); newFile.getParentFile().mkdirs(); if (!oldFile.renameTo(newFile)) { throw new CoreException(new Status(IStatus.ERROR, CommonsCorePlugin.ID_PLUGIN, NLS.bind( "The target path ''{0}'' already exists", newPath))); //$NON-NLS-1$ } } } }