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

rombert pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit d1d2508be01ee99c78d666c3419c4b96c359859f
Author: Stefan Seifert <[email protected]>
AuthorDate: Tue Jun 2 16:17:06 2015 +0000

    SLING-4381 keep Calendar and byte[] types in ValueMap, and convert it from 
and back when passing over to NoSql adapter
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1683132 
13f79535-47bb-0310-9956-ffa450edef68
---
 .../resource/impl/NoSqlResourceProvider.java       |   2 +-
 .../nosql/generic/resource/impl/NoSqlValueMap.java |  63 ++------
 .../impl/ValueMapConvertingNoSqlAdapter.java       | 170 +++++++++++++++++++++
 .../impl/AbstractNoSqlResourceProviderTest.java    |   2 +-
 4 files changed, 188 insertions(+), 49 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
 
b/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
index acad8b4..056c03e 100644
--- 
a/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
+++ 
b/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
@@ -60,7 +60,7 @@ public class NoSqlResourceProvider implements 
ResourceProvider, ModifyingResourc
     private final Set<String> deletedResources = new HashSet<String>();
     
     public NoSqlResourceProvider(NoSqlAdapter adapter, EventAdmin eventAdmin) {
-        this.adapter = adapter;
+        this.adapter = new ValueMapConvertingNoSqlAdapter(adapter);
         this.eventAdmin = eventAdmin;
     }
 
diff --git 
a/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java 
b/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
index 42e07f9..6f7fcf4 100644
--- 
a/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
+++ 
b/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
@@ -21,16 +21,10 @@ package org.apache.sling.nosql.generic.resource.impl;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
-import java.util.Locale;
 import java.util.Map;
 
-import javax.xml.bind.DatatypeConverter;
-
 import org.apache.commons.io.IOUtils;
 import org.apache.sling.api.resource.ModifiableValueMap;
 import org.apache.sling.api.resource.Resource;
@@ -56,25 +50,10 @@ class NoSqlValueMap extends ValueMapDecorator implements 
ModifiableValueMap {
     @Override
     public <T> T get(String name, Class<T> type) {
         
-        if (type == Calendar.class) {
-            Date date = get(name, Date.class);
-            if (date != null) {
-                Calendar calendar = Calendar.getInstance();
-                calendar.setTime(date);
-                return (T)calendar;
-            }
-            else {
-                return null;
-            }
-        }
-        else if (type == Date.class) {
-            Object value = get(name);
-            if (value instanceof String) {
-                try {
-                    return (T)getISO8601Format().parse((String)value);
-                } catch (ParseException e) {
-                    return null;
-                }
+        if (type == Date.class) {
+            Calendar value = get(name, Calendar.class);
+            if (value != null) {
+                return (T)value.getTime();
             }
         }
         else if (type == InputStream.class) {
@@ -87,13 +66,6 @@ class NoSqlValueMap extends ValueMapDecorator implements 
ModifiableValueMap {
                 return null;
             }
         }
-        else if (type == byte[].class) {
-            // Support conversion from base64 string to byte array
-            Object value = get(name);
-            if (value instanceof String) {
-                return (T)DatatypeConverter.parseBase64Binary((String)value);
-            }
-        }
         else if ( type == null ) {
             return (T) super.get(name);
         }
@@ -128,11 +100,10 @@ class NoSqlValueMap extends ValueMapDecorator implements 
ModifiableValueMap {
     }
 
     private static Object convertForWrite(Object value) {
-        if (value instanceof Calendar) {
-            value = getISO8601Format().format(((Calendar)value).getTime());
-        }
         if (value instanceof Date) {
-            value = getISO8601Format().format((Date)value);
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime((Date)value);
+            value = calendar;
         }
         else if (value instanceof InputStream) {
             // Store InputStream values as byte array
@@ -142,25 +113,27 @@ class NoSqlValueMap extends ValueMapDecorator implements 
ModifiableValueMap {
                 throw new RuntimeException("Unable to convert input stream to 
byte array.");
             }
         }
-        else if (value instanceof byte[]) {
-            value = DatatypeConverter.printBase64Binary((byte[])value);
-        }
-        else if (value != null && !isValidPrimitveType(value.getClass())) {
+        else if (value != null && !isValidType(value.getClass())) {
             throw new IllegalArgumentException("Data type not supported for 
NoSqlValueMap: " + value.getClass());
         }
         return value;
     }
     
-    static boolean isValidPrimitveType(Class clazz) {
+    static boolean isValidType(Class clazz) {
         if (clazz.isArray()) {
-            return isValidPrimitveType(clazz.getComponentType());
+            if (clazz.getComponentType() == byte.class) {
+                // byte only supported as array
+                return true;
+            }
+            return isValidType(clazz.getComponentType());
         }
         else {
             return clazz == String.class
                     || clazz == Integer.class
                     || clazz == Long.class
                     || clazz == Double.class
-                    || clazz == Boolean.class;
+                    || clazz == Boolean.class
+                    || Calendar.class.isAssignableFrom(clazz);
         }
     }
     
@@ -171,8 +144,4 @@ class NoSqlValueMap extends ValueMapDecorator implements 
ModifiableValueMap {
         return map;
     }
 
-    private static DateFormat getISO8601Format() {
-        return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
-    }
-
 }
diff --git 
a/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
 
b/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
new file mode 100644
index 0000000..62974f0
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.nosql.generic.resource.impl;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
+import org.apache.sling.nosql.generic.adapter.NoSqlData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Special adapter wrapper that converts all Calendar and byte[] values in 
ValueMap to String values
+ * when passing to the underlying NoSql adapter and back to typed values when 
reading from it.
+ * This is required because too many implementations access ValueMap without 
type specifier so
+ * we cannot only rely on the type conversion in the typed get methods of a 
ValueMap.
+ */
+class ValueMapConvertingNoSqlAdapter implements NoSqlAdapter {
+    
+    private static final String PREFIX_CALENDAR = "{{calendar}}";
+    private static final String PREFIX_BYTE_ARRAY = "{{bytes}}";
+
+    private final NoSqlAdapter delegate;
+    
+    private static final Logger log = 
LoggerFactory.getLogger(ValueMapConvertingNoSqlAdapter.class);
+
+    public ValueMapConvertingNoSqlAdapter(NoSqlAdapter delegate) {
+        this.delegate = delegate;
+    }
+
+    public boolean validPath(String path) {
+        return delegate.validPath(path);
+    }
+
+    public NoSqlData get(String path) {
+        return deserializeUnsupportedTypes(delegate.get(path));
+    }
+
+    public Iterator<NoSqlData> getChildren(String parentPath) {
+        return deserializeUnsupportedTypes(delegate.getChildren(parentPath));
+    }
+
+    public boolean store(NoSqlData data) {
+        return delegate.store(serializeUnsupportedTypes(data));
+    }
+
+    public boolean deleteRecursive(String path) {
+        return delegate.deleteRecursive(path);
+    }
+
+    public Iterator<NoSqlData> query(String query, String language) {
+        return deserializeUnsupportedTypes(delegate.query(query, language));
+    }
+    
+    private Iterator<NoSqlData> deserializeUnsupportedTypes(final 
Iterator<NoSqlData> source) {
+        if (source == null) {
+            return null;
+        }
+        return new Iterator<NoSqlData>() {
+            @Override
+            public boolean hasNext() {
+                return source.hasNext();
+            }
+            @Override
+            public NoSqlData next() {
+                return deserializeUnsupportedTypes(source.next());
+            }
+            @Override
+            public void remove() {
+                source.remove();
+            }
+        };
+    }
+    
+    private NoSqlData serializeUnsupportedTypes(NoSqlData data) {
+        if (data == null) {
+            return null;
+        }
+        
+        Map<String,Object> serializedMap = new HashMap<String, Object>();
+        
+        for (Map.Entry<String, Object> entry : 
data.getProperties().entrySet()) {
+            Object serializedValue = entry.getValue();
+            
+            // Calendar.class
+            if (entry.getValue() instanceof Calendar) {
+                serializedValue = PREFIX_CALENDAR + 
getISO8601Format().format(((Calendar)entry.getValue()).getTime());
+            }
+            
+            // byte[].class
+            else if (entry.getValue() instanceof byte[]) {
+                serializedValue = PREFIX_BYTE_ARRAY + 
DatatypeConverter.printBase64Binary((byte[])entry.getValue());
+            }
+            
+            serializedMap.put(entry.getKey(), serializedValue);
+        }
+        
+        return new NoSqlData(data.getPath(), serializedMap);
+    }
+    
+    private NoSqlData deserializeUnsupportedTypes(NoSqlData data) {
+        if (data == null) {
+            return null;
+        }
+        
+        Map<String,Object> deserializedMap = new HashMap<String, Object>();
+
+        for (Map.Entry<String, Object> entry : 
data.getProperties().entrySet()) {
+            Object deserializedValue = entry.getValue();
+            if (entry.getValue() instanceof String) {
+                String value = (String)entry.getValue();
+                
+                // Calendar.class
+                if (value.indexOf(PREFIX_CALENDAR) == 0) {
+                    String calendarValue = 
value.substring(PREFIX_CALENDAR.length());
+                    try {
+                        Date date = 
getISO8601Format().parse((String)calendarValue);
+                        Calendar calendar = Calendar.getInstance();
+                        calendar.setTime(date);
+                        deserializedValue = calendar;
+                    }
+                    catch (ParseException ex) {
+                        log.warn("Unable to parse serialized calendar value: " 
+ entry.getValue(), ex);
+                    }
+                }
+                
+                // byte[].class
+                else if (value.indexOf(PREFIX_BYTE_ARRAY) == 0) {
+                    String byteArrayValue = 
value.substring(PREFIX_BYTE_ARRAY.length());
+                    deserializedValue = 
DatatypeConverter.parseBase64Binary(byteArrayValue);
+                }
+                
+            }
+            deserializedMap.put(entry.getKey(), deserializedValue);
+        }
+        
+        return new NoSqlData(data.getPath(), deserializedMap);
+    }
+    
+    private static DateFormat getISO8601Format() {
+        return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
 
b/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
index fde5152..fa3a82e 100644
--- 
a/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
+++ 
b/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
@@ -198,7 +198,7 @@ public abstract class AbstractNoSqlResourceProviderTest {
         // ensure that value map has only supported primitive types (all other 
supported types converted to string)
         ValueMap valueMap = resource1.getValueMap();
         for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
-            
assertTrue(NoSqlValueMap.isValidPrimitveType(entry.getValue().getClass()));
+            assertTrue(NoSqlValueMap.isValidType(entry.getValue().getClass()));
         }
     }
 

-- 
To stop receiving notification emails like this one, please contact
"[email protected]" <[email protected]>.

Reply via email to