You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2018/01/05 17:18:36 UTC

[isis] branch dev/2.0.0-M1 updated: ISIS-1809: adds new implementations of UrlEncodingService

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch dev/2.0.0-M1
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/dev/2.0.0-M1 by this push:
     new d727de1  ISIS-1809: adds new implementations of UrlEncodingService
     new e97fa3c  Merge branch 'ISIS-1809-url-encoding-service' into dev/2.0.0-M1
d727de1 is described below

commit d727de10bfd011e9c1d1a4f835dc6fe0dd381b4c
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Jan 5 17:17:24 2018 +0000

    ISIS-1809: adds new implementations of UrlEncodingService
---
 .../UrlEncodingServiceUsingBaseEncoding.java       | 10 +++-
 ...aseEncodingWithSupportForLargeUrlsAbstract.java | 69 ++++++++++++++++++++++
 .../UrlEncodingServiceWithCompressionAbstract.java | 66 +++++++++++++++++++++
 ...codingServiceWithCompression_Abstract_Test.java | 35 +++++++++++
 4 files changed, 179 insertions(+), 1 deletion(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceUsingBaseEncoding.java b/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceUsingBaseEncoding.java
index b81e919..6d30288 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceUsingBaseEncoding.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceUsingBaseEncoding.java
@@ -46,13 +46,21 @@ public class UrlEncodingServiceUsingBaseEncoding implements UrlEncodingService {
     @Programmatic
     public String encode(final String str) {
         byte[] bytes = str.getBytes(charset);
+        return encodeToBase64(bytes);
+    }
+
+    String encodeToBase64(final byte[] bytes) {
         return baseEncoding.encode(bytes);
     }
 
     @Programmatic
     public String decode(String str) {
-        final byte[] bytes = baseEncoding.decode(str);
+        final byte[] bytes = decodeBase64(str);
         return new String(bytes, Charset.forName("UTF-8"));
     }
 
+    byte[] decodeBase64(final String str) {
+        return baseEncoding.decode(str);
+    }
+
 }
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceUsingBaseEncodingWithSupportForLargeUrlsAbstract.java b/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceUsingBaseEncodingWithSupportForLargeUrlsAbstract.java
new file mode 100644
index 0000000..c0d7689
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceUsingBaseEncodingWithSupportForLargeUrlsAbstract.java
@@ -0,0 +1,69 @@
+package org.apache.isis.applib.services.urlencoding;
+
+import java.util.UUID;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.Maps;
+
+/**
+ * to use, subclass and annotated with:
+ * <pre>
+ * &#064;DomainService(nature=DOMAIN, menuOrder="100")
+ * </pre>
+ */
+public abstract class UrlEncodingServiceUsingBaseEncodingWithSupportForLargeUrlsAbstract extends UrlEncodingServiceUsingBaseEncoding {
+
+    /**
+     * Strings under this length are not cached, just returned as is.
+     */
+    private static final int MIN_LENGTH_TO_CACHE = 500;
+    /**
+     * Used to distinguish which strings represent keys in the cache, versus those not cached.
+     */
+    private static final String KEY_PREFIX = "______";
+
+    private static final int EXPECTED_SIZE = 1000;
+
+    // this is a naive implementation that will leak memory
+    private final BiMap<String, String> cachedValueByKey =
+            Maps.synchronizedBiMap(HashBiMap.<String, String>create(EXPECTED_SIZE));
+
+    @Override
+    public String encode(final String value) {
+        if(!canCache(value)) {
+            return super.encode(value);
+        }
+
+        synchronized (cachedValueByKey) {
+            String key = cachedValueByKey.inverse().get(value);
+            if (key == null) {
+                key = newKey();
+                cachedValueByKey.put(key, value);
+            }
+            return KEY_PREFIX + key;
+        }
+    }
+
+    @Override
+    public String decode(final String key) {
+        if(key == null || !key.startsWith(KEY_PREFIX)) {
+            return super.decode(key);
+        }
+        String keySuffix = key.substring(KEY_PREFIX.length());
+        return cachedValueByKey.get(keySuffix);
+    }
+
+    /**
+     * Factored out to allow easy subclassing.
+     */
+    protected String newKey() {
+        return UUID.randomUUID().toString();
+    }
+
+    private boolean canCache(final String key) {
+        return key != null && key.length() > MIN_LENGTH_TO_CACHE;
+    }
+
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceWithCompressionAbstract.java b/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceWithCompressionAbstract.java
new file mode 100644
index 0000000..892f24d
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceWithCompressionAbstract.java
@@ -0,0 +1,66 @@
+package org.apache.isis.applib.services.urlencoding;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import javax.inject.Inject;
+
+/**
+ * to use, subclass and annotated with:
+ * <pre>
+ * &#064;DomainService(nature=DOMAIN, menuOrder="100")
+ * </pre>
+ */
+public abstract class UrlEncodingServiceWithCompressionAbstract implements UrlEncodingService {
+
+    @Override
+    public String encode(final String str) {
+        try {
+            final byte[] compressed = compress(str);
+            return base64Encoder.encodeToBase64(compressed);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    @Override
+    public String decode(final String str) {
+        final byte[] bytes = base64Encoder.decodeBase64(str);
+        try {
+            return decompress(bytes);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    private static byte[] compress(String string) throws IOException {
+        ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
+        GZIPOutputStream gos = new GZIPOutputStream(os);
+        gos.write(string.getBytes());
+        gos.close();
+        byte[] compressed = os.toByteArray();
+        os.close();
+        return compressed;
+    }
+
+    private static String decompress(byte[] compressed) throws IOException {
+        final int BUFFER_SIZE = 32;
+        ByteArrayInputStream is = new ByteArrayInputStream(compressed);
+        GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] data = new byte[BUFFER_SIZE];
+        int bytesRead;
+        while ((bytesRead = gis.read(data)) != -1) {
+            baos.write(data, 0, bytesRead);
+        }
+        gis.close();
+        return baos.toString("UTF-8");
+    }
+
+    @Inject
+    UrlEncodingServiceUsingBaseEncoding base64Encoder;
+
+}
diff --git a/core/applib/src/test/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceWithCompression_Abstract_Test.java b/core/applib/src/test/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceWithCompression_Abstract_Test.java
new file mode 100644
index 0000000..1667983
--- /dev/null
+++ b/core/applib/src/test/java/org/apache/isis/applib/services/urlencoding/UrlEncodingServiceWithCompression_Abstract_Test.java
@@ -0,0 +1,35 @@
+package org.apache.isis.applib.services.urlencoding;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.greaterThan;
+
+public class UrlEncodingServiceWithCompression_Abstract_Test {
+
+    UrlEncodingServiceWithCompressionAbstract service;
+
+    @Before
+    public void setUp() throws Exception {
+        service = new UrlEncodingServiceWithCompressionAbstract(){};
+        service.base64Encoder = new UrlEncodingServiceUsingBaseEncoding();
+    }
+
+    @Test
+    public void roundtrip() throws Exception {
+
+        final String original = "0-theme-entityPageContainer-entity-rows-2-rowContents-1-col-tabGroups-1-panel-tabPanel-rows-1-rowContents-1-col-fieldSets-1-memberGroup-properties-1-property-scalarTypeContainer-scalarIfRegular-associatedActionLinksBelow-additionalLinkList-additionalLinkItem-0-additionalLink";
+
+        final String encoded = service.encode(original);
+        final String decoded = service.decode(encoded);
+
+        Assert.assertThat(decoded, is(equalTo(original)));
+
+        Assert.assertThat(original.length(), is(greaterThan(encoded.length())));
+    }
+
+
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
['"commits@isis.apache.org" <co...@isis.apache.org>'].