Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Pingel2012-02-24 00:29:07 +0000
committerSteffen Pingel2012-02-24 00:29:07 +0000
commit8c46405ded77db1f6fd71f4de6da24d24f988d5d (patch)
tree2d702c7cec6b87327b1501dc04d8d988416c17e4
parenta847c34384fe171d9dcadcbc34b50e58579a8889 (diff)
downloadorg.eclipse.mylyn.commons-8c46405ded77db1f6fd71f4de6da24d24f988d5d.tar.gz
org.eclipse.mylyn.commons-8c46405ded77db1f6fd71f4de6da24d24f988d5d.tar.xz
org.eclipse.mylyn.commons-8c46405ded77db1f6fd71f4de6da24d24f988d5d.zip
NEW - bug 371984: [api] provide a generic storage API
https://bugs.eclipse.org/bugs/show_bug.cgi?id=371984 Change-Id: I25a6b48962d68b40c5702d9100f92eed60165350
-rw-r--r--org.eclipse.mylyn.commons.core/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CoreUtil.java18
-rw-r--r--org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/CommonStorable.java85
-rw-r--r--org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/CommonStore.java135
-rw-r--r--org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/ICommonStorable.java36
-rw-r--r--org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/CommonTestUtil.java8
-rw-r--r--org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java2
-rw-r--r--org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CoreUtilTest.java16
-rw-r--r--org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/storage/CommonStoreTest.java132
9 files changed, 433 insertions, 0 deletions
diff --git a/org.eclipse.mylyn.commons.core/META-INF/MANIFEST.MF b/org.eclipse.mylyn.commons.core/META-INF/MANIFEST.MF
index 6a3e5567..f0b38801 100644
--- a/org.eclipse.mylyn.commons.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.mylyn.commons.core/META-INF/MANIFEST.MF
@@ -9,6 +9,7 @@ Export-Package: org.eclipse.mylyn.commons.core,
org.eclipse.mylyn.commons.core.io,
org.eclipse.mylyn.commons.core.net,
org.eclipse.mylyn.commons.core.operations,
+ org.eclipse.mylyn.commons.core.storage;x-internal:=true,
org.eclipse.mylyn.internal.commons.core;x-internal:=true,
org.eclipse.mylyn.internal.commons.core.operations;x-internal:=true,
org.eclipse.mylyn.internal.provisional.commons.core;x-internal:=true
diff --git a/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CoreUtil.java b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CoreUtil.java
index 96c26ec3..cfc56ce5 100644
--- a/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CoreUtil.java
+++ b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CoreUtil.java
@@ -219,4 +219,22 @@ public class CoreUtil {
return new Version(FRAMEWORK_VERSION);
}
+ /**
+ * Returns a representation of <code>name</code> that is a valid file name.
+ *
+ * @since 3.7
+ */
+ public static String asFileName(String name) {
+ StringBuffer sb = new StringBuffer(name.length());
+ char[] chars = name.toCharArray();
+ for (char c : chars) {
+ if (c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '.') {
+ sb.append(c);
+ } else {
+ sb.append("%" + Integer.toHexString(c).toUpperCase()); //$NON-NLS-1$
+ }
+ }
+ return sb.toString();
+ }
+
}
diff --git a/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/CommonStorable.java b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/CommonStorable.java
new file mode 100644
index 00000000..ae14eed0
--- /dev/null
+++ b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/CommonStorable.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * @author Steffen Pingel
+ */
+class CommonStorable implements ICommonStorable {
+
+ private final File path;
+
+ private final CommonStore store;
+
+ public CommonStorable(CommonStore store, File path) {
+ this.store = store;
+ this.path = path;
+ }
+
+ public void delete(String item) throws CoreException {
+ getFile(item).delete();
+ }
+
+ public boolean exists(String handle) {
+ if (!path.exists()) {
+ return false;
+ }
+ return getFile(handle).exists();
+ }
+
+ public IStatus flush() {
+ return Status.OK_STATUS;
+ }
+
+ public File getPath() {
+ return path;
+ }
+
+ public boolean isDirty() {
+ return false;
+ }
+
+ public InputStream read(String item, IProgressMonitor monitor) throws IOException {
+ File file = getFile(item);
+ return new FileInputStream(file);
+ }
+
+ public void release() {
+ store.release(this);
+ }
+
+ public OutputStream write(String item, IProgressMonitor monitor) throws IOException {
+ File file = getFile(item);
+ return new FileOutputStream(file);
+ }
+
+ private File getFile(String item) {
+ File file = new File(path, item);
+ if (!file.getParentFile().exists()) {
+ file.getParentFile().mkdirs();
+ }
+ return file;
+ }
+
+}
diff --git a/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/CommonStore.java b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/CommonStore.java
new file mode 100644
index 00000000..3b7f09f2
--- /dev/null
+++ b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/CommonStore.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.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;
+
+/**
+ * @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 synchronized void copy(IPath source, IPath target, boolean overwrite) {
+ // FIXME
+ }
+
+ 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) {
+ File file = new File(location, path.toOSString());
+ if (!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());
+ }
+
+}
diff --git a/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/ICommonStorable.java b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/ICommonStorable.java
new file mode 100644
index 00000000..dc5bedbe
--- /dev/null
+++ b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/storage/ICommonStorable.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * @author Steffen Pingel
+ */
+public interface ICommonStorable {
+
+ public void delete(String handle) throws CoreException;
+
+ public boolean exists(String handle);
+
+ public InputStream read(String handle, IProgressMonitor monitor) throws IOException, CoreException;
+
+ public OutputStream write(String handle, IProgressMonitor monitor) throws IOException, CoreException;
+
+ public void release();
+
+}
diff --git a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/CommonTestUtil.java b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/CommonTestUtil.java
index 41e10861..bb52cc00 100644
--- a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/CommonTestUtil.java
+++ b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/CommonTestUtil.java
@@ -122,6 +122,13 @@ public class CommonTestUtil {
return stateLocation.toFile();
}
+ public static File createTempFolder(String prefix) throws IOException {
+ File location = File.createTempFile(prefix, null);
+ location.delete();
+ location.mkdirs();
+ return location;
+ }
+
public static void delete(File file) {
if (file.exists()) {
for (int i = 0; i < MAX_RETRY; i++) {
@@ -158,6 +165,7 @@ public class CommonTestUtil {
}
}
}
+ path.delete();
}
public static CertificateCredentials getCertificateCredentials() {
diff --git a/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java
index 1f4210df..9eb53986 100644
--- a/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java
+++ b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java
@@ -18,6 +18,7 @@ import org.eclipse.mylyn.commons.tests.core.AuthenticatedProxyTest;
import org.eclipse.mylyn.commons.tests.core.CommonListenerListTest;
import org.eclipse.mylyn.commons.tests.core.CoreUtilTest;
import org.eclipse.mylyn.commons.tests.core.ExtensionPointReaderTest;
+import org.eclipse.mylyn.commons.tests.core.storage.CommonStoreTest;
import org.eclipse.mylyn.commons.tests.net.NetUtilTest;
import org.eclipse.mylyn.commons.tests.net.SslProtocolSocketFactoryTest;
import org.eclipse.mylyn.commons.tests.net.TimeoutInputStreamTest;
@@ -42,6 +43,7 @@ public class AllCommonsTests {
suite.addTestSuite(BrowserUtilTest.class);
suite.addTestSuite(ExtensionPointReaderTest.class);
suite.addTestSuite(CommonListenerListTest.class);
+ suite.addTestSuite(CommonStoreTest.class);
return suite;
}
diff --git a/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CoreUtilTest.java b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CoreUtilTest.java
index a729f9b3..aec0326b 100644
--- a/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CoreUtilTest.java
+++ b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CoreUtilTest.java
@@ -184,4 +184,20 @@ public class CoreUtilTest extends TestCase {
}
}
+ public void testAsFileName() {
+ assertEquals("abc", CoreUtil.asFileName("abc"));
+ assertEquals("a.b.c", CoreUtil.asFileName("a.b.c"));
+ assertEquals("", CoreUtil.asFileName(""));
+ }
+
+ public void testAsFileNameSpaces() {
+ assertEquals("%20%20", CoreUtil.asFileName(" "));
+ assertEquals(".%20", CoreUtil.asFileName(". "));
+ }
+
+ public void testAsFileNamePercent() {
+ assertEquals("%25abc", CoreUtil.asFileName("%abc"));
+ assertEquals("%2525abc", CoreUtil.asFileName("%25abc"));
+ }
+
}
diff --git a/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/storage/CommonStoreTest.java b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/storage/CommonStoreTest.java
new file mode 100644
index 00000000..eb11e304
--- /dev/null
+++ b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/storage/CommonStoreTest.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2012 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.tests.core.storage;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.mylyn.commons.core.storage.CommonStore;
+import org.eclipse.mylyn.commons.core.storage.ICommonStorable;
+import org.eclipse.mylyn.commons.sdk.util.CommonTestUtil;
+
+/**
+ * @author Steffen Pingel
+ */
+public class CommonStoreTest extends TestCase {
+
+ private File location;
+
+ private CommonStore store;
+
+ public void testDelete() throws Exception {
+ ICommonStorable storable = store.get(Path.EMPTY);
+ assertFalse(storable.exists("handle"));
+
+ OutputStream out = storable.write("handle", null);
+ out.close();
+ assertTrue(storable.exists("handle"));
+ assertEquals(Collections.singletonList(new File(location, "handle")), Arrays.asList(location.listFiles()));
+
+ storable.delete("handle");
+ assertFalse(storable.exists("handle"));
+ assertEquals(Collections.emptyList(), Arrays.asList(location.listFiles()));
+ }
+
+ public void testExists() throws Exception {
+ ICommonStorable storable = store.get(Path.EMPTY);
+ assertFalse(storable.exists("handle"));
+
+ OutputStream out = storable.write("handle", null);
+ out.close();
+ assertTrue(storable.exists("handle"));
+ }
+
+ public void testGetPathWrite() throws Exception {
+ ICommonStorable storable = store.get(new Path("sub"));
+ writeHello(storable, "handle");
+ File subFile = new File(location, "sub");
+ assertEquals(Collections.singletonList(subFile), Arrays.asList(location.listFiles()));
+ assertEquals(Collections.singletonList(new File(subFile, "handle")), Arrays.asList(subFile.listFiles()));
+ }
+
+ public void testGet() throws Exception {
+ ICommonStorable storable = store.get(Path.EMPTY);
+ ICommonStorable storable2 = store.get(Path.EMPTY);
+ assertSame(storable, storable2);
+ }
+
+ public void testGetPath() {
+ ICommonStorable storable = store.get(new Path("sub"));
+ ICommonStorable storable2 = store.get(Path.EMPTY);
+ assertNotSame(storable, storable2);
+ storable2 = store.get(new Path("sub"));
+ assertSame(storable, storable2);
+ }
+
+ public void testGetPathLazyCreate() {
+ ICommonStorable storable = store.get(new Path("sub"));
+ assertEquals(Collections.emptyList(), Arrays.asList(location.listFiles()));
+ assertFalse(storable.exists("handle"));
+ assertEquals(Collections.emptyList(), Arrays.asList(location.listFiles()));
+ }
+
+ public void testRelease() throws Exception {
+ ICommonStorable storable = store.get(Path.EMPTY);
+ storable.release();
+ ICommonStorable storable2 = store.get(Path.EMPTY);
+ assertNotSame(storable, storable2);
+ }
+
+ public void testWriteRead() throws Exception {
+ ICommonStorable storable = store.get(Path.EMPTY);
+ writeHello(storable, "handle");
+ assertTrue(storable.exists("handle"));
+
+ InputStream in = storable.read("handle", null);
+ try {
+ byte[] buffer = new byte[5];
+ in.read(buffer);
+ assertEquals("hello", new String(buffer));
+ } finally {
+ in.close();
+ }
+ }
+
+ private void writeHello(ICommonStorable storable, String handle) throws IOException, CoreException {
+ OutputStream out = storable.write(handle, null);
+ try {
+ out.write("hello".getBytes());
+ } finally {
+ out.close();
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ location = CommonTestUtil.createTempFolder(CommonStoreTest.class.getName());
+ store = new CommonStore(location);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ CommonTestUtil.deleteFolderRecursively(location);
+ }
+
+}

Back to the top