jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r1409467 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/kernel/ main/java/org/apache/jackrabbit/oak/plugins/memory/ test/java/org/apache/jackrabbit/oak/query/
Date Wed, 14 Nov 2012 22:00:21 GMT
Author: jukka
Date: Wed Nov 14 22:00:20 2012
New Revision: 1409467

URL: http://svn.apache.org/viewvc?rev=1409467&view=rev
Log:
OAK-445: Allow JSON strings to be reclaimed after they've been parsed

Add an internal StringCache for common strings in the JSON responses from the MK.

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/StringCache.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStates.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/JsopUtil.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java?rev=1409467&r1=1409466&r2=1409467&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
Wed Nov 14 22:00:20 2012
@@ -27,6 +27,7 @@ import java.util.Map.Entry;
 import java.util.concurrent.ExecutionException;
 
 import javax.annotation.Nonnull;
+import javax.jcr.PropertyType;
 
 import com.google.common.base.Function;
 import com.google.common.cache.LoadingCache;
@@ -37,7 +38,12 @@ import org.apache.jackrabbit.mk.api.Micr
 import org.apache.jackrabbit.mk.json.JsopReader;
 import org.apache.jackrabbit.mk.json.JsopTokenizer;
 import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.BinaryPropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.BooleanPropertyState;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
+import org.apache.jackrabbit.oak.plugins.memory.StringPropertyState;
+import org.apache.jackrabbit.oak.plugins.value.Conversions;
 import org.apache.jackrabbit.oak.spi.state.AbstractChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
@@ -46,8 +52,7 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.readArrayProperty;
-import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.readProperty;
+import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
 
 /**
  * Basic {@link NodeState} implementation based on the {@link MicroKernel}
@@ -106,13 +111,13 @@ public final class KernelNodeState exten
             properties = new LinkedHashMap<String, PropertyState>();
             childPaths = new LinkedHashMap<String, String>();
             do {
-                String name = reader.readString();
+                String name = StringCache.get(reader.readString());
                 reader.read(':');
                 if (":childNodeCount".equals(name)) {
                     childNodeCount =
                             Long.valueOf(reader.read(JsopReader.NUMBER));
                 } else if (":hash".equals(name)) {
-                    hash = reader.read(JsopReader.STRING);
+                    hash = new String(reader.read(JsopReader.STRING));
                 } else if (reader.matches('{')) {
                     reader.read('}');
                     String childPath = path + '/' + name;
@@ -121,9 +126,9 @@ public final class KernelNodeState exten
                     }
                     childPaths.put(name, childPath);
                 } else if (reader.matches('[')) {
-                    properties.put(name, readArrayProperty(name, reader, kernel));
+                    properties.put(name, readArrayProperty(name, reader));
                 } else {
-                    properties.put(name, readProperty(name, reader, kernel));
+                    properties.put(name, readProperty(name, reader));
                 }
             } while (reader.matches(','));
             reader.read('}');
@@ -296,7 +301,7 @@ public final class KernelNodeState exten
                 JsopReader reader = new JsopTokenizer(json);
                 reader.read('{');
                 do {
-                    String name = reader.readString();
+                    String name = StringCache.get(reader.readString());
                     reader.read(':');
                     if (reader.matches('{')) {
                         reader.read('}');
@@ -381,4 +386,86 @@ public final class KernelNodeState exten
 
     }
 
+    /**
+     * Read a {@code PropertyState} from a {@link JsopReader}
+     * @param name  The name of the property state
+     * @param reader  The reader
+     * @return new property state
+     */
+    private PropertyState readProperty(String name, JsopReader reader) {
+        if (reader.matches(JsopReader.NUMBER)) {
+            String number = reader.getToken();
+            return createProperty(name, number, PropertyType.LONG);
+        } else if (reader.matches(JsopReader.TRUE)) {
+            return BooleanPropertyState.booleanProperty(name, true);
+        } else if (reader.matches(JsopReader.FALSE)) {
+            return BooleanPropertyState.booleanProperty(name, false);
+        } else if (reader.matches(JsopReader.STRING)) {
+            String jsonString = reader.getToken();
+            int split = TypeCodes.split(jsonString);
+            if (split != -1) {
+                int type = TypeCodes.decodeType(split, jsonString);
+                String value = TypeCodes.decodeName(split, jsonString);
+                if (type == PropertyType.BINARY) {
+                    return  BinaryPropertyState.binaryProperty(
+                            name, new KernelBlob(new String(value), kernel));
+                } else {
+                    return createProperty(name, StringCache.get(value), type);
+                }
+            } else {
+                return StringPropertyState.stringProperty(
+                        name, StringCache.get(jsonString));
+            }
+        } else {
+            throw new IllegalArgumentException("Unexpected token: " + reader.getToken());
+        }
+    }
+
+    /**
+     * Read a multi valued {@code PropertyState} from a {@link JsopReader}
+     * @param name  The name of the property state
+     * @param reader  The reader
+     * @return new property state
+     */
+    private PropertyState readArrayProperty(String name, JsopReader reader) {
+        int type = PropertyType.STRING;
+        List<Object> values = Lists.newArrayList();
+        while (!reader.matches(']')) {
+            if (reader.matches(JsopReader.NUMBER)) {
+                String number = reader.getToken();
+                type = PropertyType.LONG;
+                values.add(Conversions.convert(number).toLong());
+            } else if (reader.matches(JsopReader.TRUE)) {
+                type = PropertyType.BOOLEAN;
+                values.add(true);
+            } else if (reader.matches(JsopReader.FALSE)) {
+                type = PropertyType.BOOLEAN;
+                values.add(false);
+            } else if (reader.matches(JsopReader.STRING)) {
+                String jsonString = reader.getToken();
+                int split = TypeCodes.split(jsonString);
+                if (split != -1) {
+                    type = TypeCodes.decodeType(split, jsonString);
+                    String value = TypeCodes.decodeName(split, jsonString);
+                    if (type == PropertyType.BINARY) {
+                        values.add(new KernelBlob(new String(value), kernel));
+                    } else if(type == PropertyType.DOUBLE) {
+                        values.add(Conversions.convert(value).toDouble());
+                    } else if(type == PropertyType.DECIMAL) {
+                        values.add(Conversions.convert(value).toDecimal());
+                    } else {
+                        values.add(StringCache.get(value));
+                    }
+                } else {
+                    type = PropertyType.STRING;
+                    values.add(StringCache.get(jsonString));
+                }
+            } else {
+                throw new IllegalArgumentException("Unexpected token: " + reader.getToken());
+            }
+            reader.matches(',');
+        }
+        return createProperty(name, values, Type.fromTag(type, true));
+    }
+
 }

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/StringCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/StringCache.java?rev=1409467&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/StringCache.java
(added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/StringCache.java
Wed Nov 14 22:00:20 2012
@@ -0,0 +1,158 @@
+/*
+ * 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.jackrabbit.oak.kernel;
+
+import java.util.Map;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.version.VersionConstants;
+
+import com.google.common.collect.ImmutableMap;
+
+class StringCache {
+
+    private static final Map<String, String> CONSTANTS = createStringMap(
+            JcrConstants.JCR_AUTOCREATED,
+            JcrConstants.JCR_BASEVERSION,
+            JcrConstants.JCR_CHILD,
+            JcrConstants.JCR_CHILDNODEDEFINITION,
+            JcrConstants.JCR_CONTENT,
+            JcrConstants.JCR_CREATED,
+            JcrConstants.JCR_DATA,
+            JcrConstants.JCR_DEFAULTPRIMARYTYPE,
+            JcrConstants.JCR_DEFAULTVALUES,
+            JcrConstants.JCR_ENCODING,
+            JcrConstants.JCR_FROZENMIXINTYPES,
+            JcrConstants.JCR_FROZENNODE,
+            JcrConstants.JCR_FROZENPRIMARYTYPE,
+            JcrConstants.JCR_FROZENUUID,
+            JcrConstants.JCR_HASORDERABLECHILDNODES,
+            JcrConstants.JCR_ISCHECKEDOUT,
+            JcrConstants.JCR_ISMIXIN,
+            JcrConstants.JCR_LANGUAGE,
+            JcrConstants.JCR_LASTMODIFIED,
+            JcrConstants.JCR_LOCKISDEEP,
+            JcrConstants.JCR_LOCKOWNER,
+            JcrConstants.JCR_MANDATORY,
+            JcrConstants.JCR_MERGEFAILED,
+            JcrConstants.JCR_MIMETYPE,
+            JcrConstants.JCR_MIXINTYPES,
+            JcrConstants.JCR_MULTIPLE,
+            JcrConstants.JCR_NAME,
+            JcrConstants.JCR_NODETYPENAME,
+            JcrConstants.JCR_ONPARENTVERSION,
+            JcrConstants.JCR_PREDECESSORS,
+            JcrConstants.JCR_PRIMARYITEMNAME,
+            JcrConstants.JCR_PRIMARYTYPE,
+            JcrConstants.JCR_PROPERTYDEFINITION,
+            JcrConstants.JCR_PROTECTED,
+            JcrConstants.JCR_REQUIREDPRIMARYTYPES,
+            JcrConstants.JCR_REQUIREDTYPE,
+            JcrConstants.JCR_ROOTVERSION,
+            JcrConstants.JCR_SAMENAMESIBLINGS,
+            JcrConstants.JCR_STATEMENT,
+            JcrConstants.JCR_SUCCESSORS,
+            JcrConstants.JCR_SUPERTYPES,
+            JcrConstants.JCR_SYSTEM,
+            JcrConstants.JCR_UUID,
+            JcrConstants.JCR_VALUECONSTRAINTS,
+            JcrConstants.JCR_VERSIONHISTORY,
+            JcrConstants.JCR_VERSIONLABELS,
+            JcrConstants.JCR_VERSIONSTORAGE,
+            JcrConstants.JCR_VERSIONABLEUUID,
+            JcrConstants.JCR_PATH,
+            JcrConstants.JCR_SCORE,
+            JcrConstants.MIX_LOCKABLE,
+            JcrConstants.MIX_REFERENCEABLE,
+            JcrConstants.MIX_VERSIONABLE,
+            JcrConstants.MIX_SHAREABLE,
+            JcrConstants.NT_BASE,
+            JcrConstants.NT_CHILDNODEDEFINITION,
+            JcrConstants.NT_FILE,
+            JcrConstants.NT_FOLDER,
+            JcrConstants.NT_FROZENNODE,
+            JcrConstants.NT_HIERARCHYNODE,
+            JcrConstants.NT_LINKEDFILE,
+            JcrConstants.NT_NODETYPE,
+            JcrConstants.NT_PROPERTYDEFINITION,
+            JcrConstants.NT_QUERY,
+            JcrConstants.NT_RESOURCE,
+            JcrConstants.NT_UNSTRUCTURED,
+            JcrConstants.NT_VERSION,
+            JcrConstants.NT_VERSIONHISTORY,
+            JcrConstants.NT_VERSIONLABELS,
+            JcrConstants.NT_VERSIONEDCHILD,
+            NodeTypeConstants.JCR_NODE_TYPES,
+            NodeTypeConstants.JCR_IS_ABSTRACT,
+            NodeTypeConstants.JCR_IS_QUERYABLE,
+            NodeTypeConstants.JCR_IS_FULLTEXT_SEARCHABLE,
+            NodeTypeConstants.JCR_IS_QUERY_ORDERABLE,
+            NodeTypeConstants.JCR_AVAILABLE_QUERY_OPERATORS,
+            NodeTypeConstants.NT_REP_ROOT,
+            NodeTypeConstants.NT_REP_SYSTEM,
+            NodeTypeConstants.JCR_CREATEDBY,
+            NodeTypeConstants.JCR_LASTMODIFIEDBY,
+            NodeTypeConstants.MIX_CREATED,
+            NodeTypeConstants.MIX_LASTMODIFIED,
+            NodeTypeConstants.MIX_REP_MERGE_CONFLICT,
+            NodeTypeConstants.REP_OURS,
+            NodeTypeConstants.ADD_EXISTING,
+            NodeTypeConstants.CHANGE_DELETED,
+            NodeTypeConstants.CHANGE_CHANGED,
+            NodeTypeConstants.DELETE_CHANGED,
+            NodeTypeConstants.DELETE_DELETED,
+            VersionConstants.JCR_ACTIVITY,
+            VersionConstants.JCR_ACTIVITIES,
+            VersionConstants.JCR_ACTIVITY_TITLE,
+            VersionConstants.NT_ACTIVITY,
+            VersionConstants.REP_ACTIVITIES,
+            VersionConstants.JCR_CONFIGURATION,
+            VersionConstants.JCR_CONFIGURATIONS,
+            VersionConstants.JCR_ROOT,
+            VersionConstants.NT_CONFIGURATION,
+            VersionConstants.REP_CONFIGURATIONS);
+
+    private static Map<String, String> createStringMap(String... strings) {
+        ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+        for (String string : strings) {
+            builder.put(string, string);
+        }
+        return builder.build();
+    }
+
+    // must be a power of 2
+    private static final int STRING_CACHE_SIZE = 1024;
+
+    private static final String[] STRING_CACHE = new String[STRING_CACHE_SIZE];
+
+    public static String get(String s) {
+        String constant = CONSTANTS.get(s);
+        if (constant != null) {
+            return constant;
+        }
+
+        int index = s.hashCode() & (STRING_CACHE_SIZE - 1);
+        String cached = STRING_CACHE[index];
+        if (!s.equals(cached)) {
+            cached = new String(s); // avoid referring to 
+            STRING_CACHE[index] = cached;
+        }
+        return cached;
+    }
+
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStates.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStates.java?rev=1409467&r1=1409466&r2=1409467&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStates.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStates.java
Wed Nov 14 22:00:20 2012
@@ -28,13 +28,9 @@ import javax.jcr.Value;
 
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-import org.apache.jackrabbit.mk.api.MicroKernel;
-import org.apache.jackrabbit.mk.json.JsopReader;
 import org.apache.jackrabbit.oak.api.Blob;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.kernel.KernelBlob;
-import org.apache.jackrabbit.oak.kernel.TypeCodes;
 import org.apache.jackrabbit.oak.plugins.value.Conversions;
 
 import static org.apache.jackrabbit.oak.api.Type.STRINGS;
@@ -186,7 +182,7 @@ public final class PropertyStates {
      */
     @SuppressWarnings("unchecked")
     @Nonnull
-    public static <T> PropertyState createProperty(String name, T value, Type<T>
type) {
+    public static PropertyState createProperty(String name, Object value, Type<?> type)
{
         switch (type.tag()) {
             case PropertyType.STRING:
                 return type.isArray()
@@ -271,85 +267,4 @@ public final class PropertyStates {
         }
     }
 
-    /**
-     * Read a {@code PropertyState} from a {@link JsopReader}
-     * @param name  The name of the property state
-     * @param reader  The reader
-     * @param kernel  {@link MicroKernel} instance used to resolve binaries
-     * @return  The new property state of type {@link Type#DECIMALS}
-     */
-    public static PropertyState readProperty(String name, JsopReader reader, MicroKernel
kernel) {
-        if (reader.matches(JsopReader.NUMBER)) {
-            String number = reader.getToken();
-            return createProperty(name, number, PropertyType.LONG);
-        } else if (reader.matches(JsopReader.TRUE)) {
-            return BooleanPropertyState.booleanProperty(name, true);
-        } else if (reader.matches(JsopReader.FALSE)) {
-            return BooleanPropertyState.booleanProperty(name, false);
-        } else if (reader.matches(JsopReader.STRING)) {
-            String jsonString = reader.getToken();
-            int split = TypeCodes.split(jsonString);
-            if (split != -1) {
-                int type = TypeCodes.decodeType(split, jsonString);
-                String value = TypeCodes.decodeName(split, jsonString);
-                if (type == PropertyType.BINARY) {
-                    return  BinaryPropertyState.binaryProperty(name, new KernelBlob(value,
kernel));
-                } else {
-                    return createProperty(name, value, type);
-                }
-            } else {
-                return StringPropertyState.stringProperty(name, jsonString);
-            }
-        } else {
-            throw new IllegalArgumentException("Unexpected token: " + reader.getToken());
-        }
-    }
-
-    /**
-     * Read a multi valued {@code PropertyState} from a {@link JsopReader}
-     * @param name  The name of the property state
-     * @param reader  The reader
-     * @param kernel  {@link MicroKernel} instance used to resolve binaries
-     * @return  The new property state of type {@link Type#DECIMALS}
-     */
-    public static PropertyState readArrayProperty(String name, JsopReader reader, MicroKernel
kernel) {
-        int type = PropertyType.STRING;
-        List<Object> values = Lists.newArrayList();
-        while (!reader.matches(']')) {
-            if (reader.matches(JsopReader.NUMBER)) {
-                String number = reader.getToken();
-                type = PropertyType.LONG;
-                values.add(Conversions.convert(number).toLong());
-            } else if (reader.matches(JsopReader.TRUE)) {
-                type = PropertyType.BOOLEAN;
-                values.add(true);
-            } else if (reader.matches(JsopReader.FALSE)) {
-                type = PropertyType.BOOLEAN;
-                values.add(false);
-            } else if (reader.matches(JsopReader.STRING)) {
-                String jsonString = reader.getToken();
-                int split = TypeCodes.split(jsonString);
-                if (split != -1) {
-                    type = TypeCodes.decodeType(split, jsonString);
-                    String value = TypeCodes.decodeName(split, jsonString);
-                    if (type == PropertyType.BINARY) {
-                        values.add(new KernelBlob(value, kernel));
-                    } else if(type == PropertyType.DOUBLE) {
-                        values.add(Conversions.convert(value).toDouble());
-                    } else if(type == PropertyType.DECIMAL) {
-                        values.add(Conversions.convert(value).toDecimal());
-                    } else {
-                        values.add(value);
-                    }
-                } else {
-                    type = PropertyType.STRING;
-                    values.add(jsonString);
-                }
-            } else {
-                throw new IllegalArgumentException("Unexpected token: " + reader.getToken());
-            }
-            reader.matches(',');
-        }
-        return createProperty(name, values, (Type<Object>) Type.fromTag(type, true));
-    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/JsopUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/JsopUtil.java?rev=1409467&r1=1409466&r2=1409467&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/JsopUtil.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/JsopUtil.java
Wed Nov 14 22:00:20 2012
@@ -16,11 +16,25 @@
  */
 package org.apache.jackrabbit.oak.query;
 
+import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+
+import java.util.List;
+
+import javax.jcr.PropertyType;
+
+import org.apache.jackrabbit.mk.json.JsopReader;
 import org.apache.jackrabbit.mk.json.JsopTokenizer;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.kernel.TypeCodes;
+import org.apache.jackrabbit.oak.plugins.memory.BooleanPropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.StringPropertyState;
+import org.apache.jackrabbit.oak.plugins.value.Conversions;
+
+import com.google.common.collect.Lists;
 
 /**
  * Utility class for working with jsop string diffs
@@ -94,10 +108,91 @@ public class JsopUtil {
                     tokenizer.read('}');
                 }
             } else if (tokenizer.matches('[')) {
-                t.setProperty(PropertyStates.readArrayProperty(key, tokenizer, null));
+                t.setProperty(readArrayProperty(key, tokenizer));
             } else {
-                t.setProperty(PropertyStates.readProperty(key, tokenizer, null));
+                t.setProperty(readProperty(key, tokenizer));
             }
         } while (tokenizer.matches(','));
     }
+
+    /**
+     * Read a {@code PropertyState} from a {@link JsopReader}
+     * @param name  The name of the property state
+     * @param reader  The reader
+     * @return new property state
+     */
+    private static PropertyState readProperty(String name, JsopReader reader) {
+        if (reader.matches(JsopReader.NUMBER)) {
+            String number = reader.getToken();
+            return createProperty(name, number, PropertyType.LONG);
+        } else if (reader.matches(JsopReader.TRUE)) {
+            return BooleanPropertyState.booleanProperty(name, true);
+        } else if (reader.matches(JsopReader.FALSE)) {
+            return BooleanPropertyState.booleanProperty(name, false);
+        } else if (reader.matches(JsopReader.STRING)) {
+            String jsonString = reader.getToken();
+            int split = TypeCodes.split(jsonString);
+            if (split != -1) {
+                int type = TypeCodes.decodeType(split, jsonString);
+                String value = TypeCodes.decodeName(split, jsonString);
+                if (type == PropertyType.BINARY) {
+                    throw new UnsupportedOperationException();
+                } else {
+                    return createProperty(name, value, type);
+                }
+            } else {
+                return StringPropertyState.stringProperty(name, jsonString);
+            }
+        } else {
+            throw new IllegalArgumentException("Unexpected token: " + reader.getToken());
+        }
+    }
+
+    /**
+     * Read a multi valued {@code PropertyState} from a {@link JsopReader}
+     * @param name  The name of the property state
+     * @param reader  The reader
+     * @return new property state
+     */
+    private static PropertyState readArrayProperty(String name, JsopReader reader) {
+        int type = PropertyType.STRING;
+        List<Object> values = Lists.newArrayList();
+        while (!reader.matches(']')) {
+            if (reader.matches(JsopReader.NUMBER)) {
+                String number = reader.getToken();
+                type = PropertyType.LONG;
+                values.add(Conversions.convert(number).toLong());
+            } else if (reader.matches(JsopReader.TRUE)) {
+                type = PropertyType.BOOLEAN;
+                values.add(true);
+            } else if (reader.matches(JsopReader.FALSE)) {
+                type = PropertyType.BOOLEAN;
+                values.add(false);
+            } else if (reader.matches(JsopReader.STRING)) {
+                String jsonString = reader.getToken();
+                int split = TypeCodes.split(jsonString);
+                if (split != -1) {
+                    type = TypeCodes.decodeType(split, jsonString);
+                    String value = TypeCodes.decodeName(split, jsonString);
+                    if (type == PropertyType.BINARY) {
+                        throw new UnsupportedOperationException();
+                    } else if(type == PropertyType.DOUBLE) {
+                        values.add(Conversions.convert(value).toDouble());
+                    } else if(type == PropertyType.DECIMAL) {
+                        values.add(Conversions.convert(value).toDecimal());
+                    } else {
+                        values.add(value);
+                    }
+                } else {
+                    type = PropertyType.STRING;
+                    values.add(jsonString);
+                }
+            } else {
+                throw new IllegalArgumentException("Unexpected token: " + reader.getToken());
+            }
+            reader.matches(',');
+        }
+        return createProperty(name, values, Type.fromTag(type, true));
+    }
+
 }



Mime
View raw message