]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.document.server/src/org/simantics/document/server/JSONObject.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.document.server / src / org / simantics / document / server / JSONObject.java
diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/JSONObject.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/JSONObject.java
new file mode 100644 (file)
index 0000000..b43a98d
--- /dev/null
@@ -0,0 +1,561 @@
+package org.simantics.document.server;\r
+\r
+import java.io.IOException;\r
+import java.util.Arrays;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.Set;\r
+import java.util.TreeMap;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.adapter.Adapter;\r
+import org.simantics.databoard.adapter.AdapterConstructionException;\r
+import org.simantics.databoard.binding.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.MapBinding;\r
+import org.simantics.databoard.binding.OptionalBinding;\r
+import org.simantics.databoard.binding.RecordBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.parser.repository.DataValueRepository;\r
+import org.simantics.databoard.type.Component;\r
+import org.simantics.databoard.type.RecordType;\r
+import org.simantics.databoard.util.Bean;\r
+import org.simantics.document.server.io.IJSONObject;\r
+import org.simantics.scl.runtime.tuple.Tuple;\r
+\r
+final public class JSONObject extends Bean implements IJSONObject {\r
+\r
+       final public String id;\r
+       final public TreeMap<String, Object> fields = new TreeMap<String, Object>();\r
+       private int hashCode = 0;\r
+\r
+       public JSONObject(Binding binding, String id) {\r
+               super(binding);\r
+               assert (binding != null);\r
+               assert (id != null);\r
+               this.id = id.intern();\r
+       }\r
+\r
+       public JSONObject(String id) {\r
+               assert (id != null);\r
+               this.id = id.intern();\r
+       }\r
+\r
+       public JSONObject clone() {\r
+               JSONObject result = new JSONObject(binding, id);\r
+               for (Map.Entry<String, Object> e : fields.entrySet())\r
+                       result.addJSONField(e.getKey(), e.getValue());\r
+               return result;\r
+       }\r
+\r
+       public void add(Map<String, Object> fields) {\r
+               for (Map.Entry<String, Object> e : fields.entrySet())\r
+                       addJSONField(e.getKey(), e.getValue());\r
+       }\r
+\r
+       @Override\r
+       public int hashCode() {\r
+               \r
+               if(hashCode == 0) {\r
+                       int result = id.hashCode();\r
+                       Iterator<Entry<String,Object>> i = fields.entrySet().iterator();\r
+                       while (i.hasNext()) {\r
+                               Entry<String,Object> entry = i.next();\r
+                               String key = entry.getKey();\r
+                               Object value = entry.getValue();\r
+                               if(value != null) {\r
+                                       if(value.getClass().isArray())\r
+                                               result += objectHashCode(key) ^ arrayHashCode(value);\r
+                                       else \r
+                                               result += objectHashCode(key) ^ objectHashCode(value);\r
+                               } else {\r
+                                       result += objectHashCode(key);\r
+                               }\r
+                       }\r
+                       hashCode = result;\r
+               }\r
+               return hashCode;\r
+\r
+       }\r
+\r
+    /**\r
+     * Returns the hash code of a non-{@code null} argument and 0 for\r
+     * a {@code null} argument.\r
+     *\r
+     * @param o an object\r
+     * @return the hash code of a non-{@code null} argument and 0 for\r
+     * a {@code null} argument\r
+     * @see Object#hashCode\r
+     */\r
+    private static int objectHashCode(Object o) {\r
+        return o != null ? o.hashCode() : 0;\r
+    }\r
+\r
+       private final boolean arrayEquals(Object av1, Object av2) {\r
+               if (av2 == null)\r
+                       return false;\r
+               Class<?> c1 = av1.getClass().getComponentType();\r
+               Class<?> c2 = av2.getClass().getComponentType();\r
+               if (c2 == null || !c1.equals(c2))\r
+                       return false;\r
+               boolean p1 = c1.isPrimitive();\r
+               boolean p2 = c2.isPrimitive();\r
+               if (p1 != p2)\r
+                       return false;\r
+               if (!p1)\r
+                       return Arrays.equals((Object[]) av1, (Object[]) av2);\r
+               if (boolean.class.equals(c1))\r
+                       return Arrays.equals((boolean[]) av1, (boolean[]) av2);\r
+               else if (byte.class.equals(c1))\r
+                       return Arrays.equals((byte[]) av1, (byte[]) av2);\r
+               else if (int.class.equals(c1))\r
+                       return Arrays.equals((int[]) av1, (int[]) av2);\r
+               else if (long.class.equals(c1))\r
+                       return Arrays.equals((long[]) av1, (long[]) av2);\r
+               else if (float.class.equals(c1))\r
+                       return Arrays.equals((float[]) av1, (float[]) av2);\r
+               else if (double.class.equals(c1))\r
+                       return Arrays.equals((double[]) av1, (double[]) av2);\r
+               throw new RuntimeException("??? Contact application querySupport.");\r
+       }\r
+\r
+       private final int arrayHashCode(Object av) {\r
+               if (av == null)\r
+                       return 0;\r
+               Class<?> c1 = av.getClass().getComponentType();\r
+               boolean p1 = c1.isPrimitive();\r
+               if (!p1)\r
+                       return Arrays.hashCode((Object[]) av);\r
+               if (boolean.class.equals(c1))\r
+                       return Arrays.hashCode((boolean[]) av);\r
+               else if (byte.class.equals(c1))\r
+                       return Arrays.hashCode((byte[]) av);\r
+               else if (int.class.equals(c1))\r
+                       return Arrays.hashCode((int[]) av);\r
+               else if (long.class.equals(c1))\r
+                       return Arrays.hashCode((long[]) av);\r
+               else if (float.class.equals(c1))\r
+                       return Arrays.hashCode((float[]) av);\r
+               else if (double.class.equals(c1))\r
+                       return Arrays.hashCode((double[]) av);\r
+               throw new RuntimeException("??? Contact application querySupport.");\r
+       }\r
+       \r
+       @Override\r
+       public boolean equals(Object object) {\r
+\r
+               if (this == object)\r
+                       return true;\r
+               else if (object == null)\r
+                       return false;\r
+               else if (!(object instanceof JSONObject))\r
+                       return false;\r
+               JSONObject o = (JSONObject) object;\r
+               \r
+               if (!id.equals(o.id))\r
+                       return false;\r
+\r
+               Set<String> keys = fields.keySet();\r
+               Set<String> otherKeys = o.fields.keySet();\r
+               \r
+               if (!keys.equals(otherKeys))\r
+                       return false;\r
+\r
+               for (String key : keys) {\r
+\r
+                       Object value = fields.get(key);\r
+                       Object otherValue = o.fields.get(key);\r
+\r
+                       if (otherValue != null) {\r
+                               if (otherValue.getClass().isArray()) {\r
+                                       if (!arrayEquals(otherValue, value)) {\r
+                                               return false;\r
+                                       }\r
+                               } else {\r
+                                       if (!otherValue.equals(value)) {\r
+                                               return false;\r
+                                       }\r
+                               }\r
+                       } else if (value != null)\r
+                               return false;\r
+\r
+               }\r
+\r
+               return true;\r
+\r
+       }\r
+\r
+       public void addJSONField(String key, Object content) {\r
+               fields.put(key, content);\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       public <T> T getJSONField(String key) {\r
+               return (T) fields.get(key);\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       public <T> T getJSONFieldDefault(String key, T defaultValue) {\r
+               T value = (T) fields.get(key);\r
+               if (value != null)\r
+                       return value;\r
+               else\r
+                       return defaultValue;\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       public <T> T getBeanJSONFieldDefault(String key, Binding target,\r
+                       T defaultValue) {\r
+               T value = (T) fields.get(key);\r
+               try {\r
+                       if (value != null) {\r
+//                             if (value instanceof Bean) {\r
+                                       Binding source = Bindings.getBinding(target.type());\r
+                                       Adapter adapter = Bindings.getAdapter(source, target);\r
+                                       return (T) adapter.adapt(value);\r
+//                             }\r
+//                             return value;\r
+                       }\r
+               } catch (AdapterConstructionException e) {\r
+               } catch (AdaptException e) {\r
+               }\r
+               return defaultValue;\r
+       }\r
+\r
+       public String getParent() {\r
+               return (String) fields.get("parent");\r
+       }\r
+\r
+       public String getParentOrd() {\r
+               return (String) fields.get("parentOrd");\r
+       }\r
+\r
+       public String getType() {\r
+               return (String) fields.get("type");\r
+       }\r
+\r
+       public String toString() {\r
+               StringBuilder b = new StringBuilder();\r
+               b.append("{");\r
+               boolean first = true;\r
+               for (Map.Entry<String, Object> entry : fields.entrySet()) {\r
+                       if (first)\r
+                               first = false;\r
+                       else\r
+                               b.append(",");\r
+                       String key = entry.getKey();\r
+                       String value = fieldJSON(entry.getValue());\r
+                       if (value == null) {\r
+                               first = true; // prevents ", ," when no key and value are given\r
+                               continue;\r
+                       }\r
+                       b.append('"');\r
+                       b.append(key);\r
+                       b.append('"');\r
+                       b.append(':');\r
+                       b.append(value);\r
+                       b.append("\n");\r
+               }\r
+               b.append("}");\r
+               return b.toString();\r
+       }\r
+\r
+       private void printValue(Object value, Binding binding_, StringBuilder sb)\r
+                       throws IOException {\r
+               try {\r
+                       if (binding_ instanceof RecordBinding) {\r
+                               RecordBinding binding = (RecordBinding) binding_;\r
+                               sb.append("{");\r
+                               RecordType type = binding.type();\r
+                               for (int i = 0, j = 0; i < type.getComponentCount(); i++) {\r
+\r
+                                       Component c = type.getComponent(i);\r
+\r
+                                       Object field = binding.getComponent(value, i);\r
+\r
+                                       Binding b = binding.getComponentBinding(i);\r
+                                       if (b instanceof OptionalBinding) {\r
+                                               OptionalBinding ob = (OptionalBinding) b;\r
+                                               if (!ob.hasValueUnchecked(field))\r
+                                                       continue;\r
+                                               b = ob.getComponentBinding();\r
+                                       }\r
+\r
+                                       if (j > 0)\r
+                                               sb.append(",");\r
+                                       sb.append("\n");\r
+                                       j++;\r
+\r
+                                       sb.append("\"");\r
+                                       sb.append(c.name);\r
+                                       sb.append("\" : ");\r
+                                       printValue(field, b, sb);\r
+                               }\r
+                               sb.append("}");\r
+                       } else if (binding_ instanceof ArrayBinding) {\r
+                               ArrayBinding binding = (ArrayBinding) binding_;\r
+                               Binding b = binding.getComponentBinding();\r
+                               sb.append("[");\r
+                               for (int i = 0; i < binding.size(value); i++) {\r
+                                       if (i > 0)\r
+                                               sb.append(",");\r
+                                       printValue(binding.get(value, i), b, sb);\r
+                               }\r
+                               sb.append("]");\r
+                       } else if (binding_ instanceof MapBinding) {\r
+                               sb.append("{");\r
+                               MapBinding binding = (MapBinding) binding_;\r
+                               int j = 0;\r
+                               for (Object key : binding.getKeys(value)) {\r
+                                       Object val = binding.get(value, key);\r
+                                       if (key instanceof String && val instanceof String) {\r
+\r
+                                               if (j > 0)\r
+                                                       sb.append(",");\r
+                                               sb.append("\n");\r
+                                               j++;\r
+\r
+                                               sb.append("\"");\r
+                                               sb.append((String) key);\r
+                                               sb.append("\" : \"");\r
+                                               sb.append((String) val);\r
+                                               sb.append("\"");\r
+\r
+                                       }\r
+                               }\r
+                               sb.append("}");\r
+                       } else {\r
+                               DataValueRepository rep = new DataValueRepository();\r
+                               binding_.printValue(value, sb, rep, false);\r
+                       }\r
+               } catch (BindingException e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+\r
+       private String printList(List<?> list) {\r
+               StringBuilder b = new StringBuilder();\r
+               b.append("[");\r
+               boolean first = true;\r
+               for (Object o : list) {\r
+                       if (first) {\r
+                               first = false;\r
+                       } else {\r
+                               b.append(",");\r
+                       }\r
+                       b.append(fieldJSON(o));\r
+               }\r
+               b.append("]");\r
+               return b.toString();\r
+       }\r
+\r
+       private String fieldJSON(Object field) {\r
+\r
+               if (field == null)\r
+                       return null;\r
+\r
+               String valueString = null;\r
+               if (field instanceof Bean) {\r
+                       // Try bean to JSON\r
+                       try {\r
+                               Bean bean = (Bean) field;\r
+                               StringBuilder sb = new StringBuilder();\r
+                               printValue(bean, bean.getBinding(), sb);\r
+                               valueString = sb.toString();\r
+                       } catch (IOException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               } else if (field instanceof List) {\r
+                       return printList((List<?>) field);\r
+               } else if (field instanceof Tuple) {\r
+                       Tuple t = (Tuple) field;\r
+                       if (t.length() == 2) {\r
+                               Object o1 = t.get(0);\r
+                               Object o2 = t.get(1);\r
+                               if (o1 instanceof String) {\r
+                                       return fieldJSON(o1) + " : " + fieldJSON(o2);\r
+                               } else {\r
+                                       return "{" + fieldJSON(o1) + " , " + fieldJSON(o2) + "}";\r
+                               }\r
+                       } else {\r
+                               StringBuilder b = new StringBuilder();\r
+                               b.append("{");\r
+                               for (int i = 0; i < t.length(); i++) {\r
+                                       if (i > 0)\r
+                                               b.append(",");\r
+                                       b.append(fieldJSON(t.get(i)));\r
+                               }\r
+                               b.append("}");\r
+                               return b.toString();\r
+                       }\r
+               } else {\r
+                       if (field.getClass().isArray()) {\r
+\r
+                               Object[] array;\r
+                               if (field instanceof float[]) {\r
+                                       array = new Float[((float[]) field).length];\r
+                                       for (int i = 0; i < array.length; i++) {\r
+                                               array[i] = ((float[]) field)[i];\r
+                                       }\r
+                               } else if (field instanceof int[]) {\r
+                    array = new Integer[((int[]) field).length];\r
+                    for (int i = 0; i < array.length; i++) {\r
+                        array[i] = ((int[]) field)[i];\r
+                    }\r
+                               } else\r
+                                       array = (Object[]) field;\r
+\r
+                               // Build a string of the value array. Format is: [ value, value,\r
+                               // value, ... ]\r
+                               StringBuilder arrayBuilder = new StringBuilder();\r
+                               arrayBuilder.append("[");\r
+                               for (int i = 0; i < array.length; i++) {\r
+                                       Object o = array[i];\r
+                                       if (i != 0)\r
+                                               arrayBuilder.append(",");\r
+\r
+                                       if (o instanceof String)\r
+                                               arrayBuilder.append("\"");\r
+\r
+                                       arrayBuilder.append(o.toString());\r
+\r
+                                       if (o instanceof String)\r
+                                               arrayBuilder.append("\"");\r
+                               }\r
+                               arrayBuilder.append("]");\r
+                               valueString = arrayBuilder.toString();\r
+                       } else {\r
+                               if (field instanceof String) {\r
+                                       // Use a string representation of the value\r
+                                       valueString = quote((String) field);\r
+                               } else {\r
+                                       // Use a string representation of the value\r
+                                       valueString = "\"" + field.toString() + "\"";\r
+                               }\r
+\r
+                       }\r
+               }\r
+\r
+               return valueString;\r
+\r
+       }\r
+       \r
+       /*\r
+        * Copied from org.json\r
+        * \r
+           Copyright (c) 2002 JSON.org\r
+\r
+           Permission is hereby granted, free of charge, to any person obtaining a copy\r
+           of this software and associated documentation files (the "Software"), to deal\r
+           in the Software without restriction, including without limitation the rights\r
+           to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+           copies of the Software, and to permit persons to whom the Software is\r
+           furnished to do so, subject to the following conditions:\r
+\r
+           The above copyright notice and this permission notice shall be included in all\r
+           copies or substantial portions of the Software.\r
+\r
+           The Software shall be used for Good, not Evil.\r
+\r
+           THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+           IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+           FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+           AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+           LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+           OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+           SOFTWARE.\r
+        */\r
+       /**\r
+     * Produce a string in double quotes with backslash sequences in all the\r
+     * right places. A backslash will be inserted within </, allowing JSON\r
+     * text to be delivered in HTML. In JSON text, a string cannot contain a\r
+     * control character or an unescaped quote or backslash.\r
+     * @param string A String\r
+     * @return  A String correctly formatted for insertion in a JSON text.\r
+     */\r
+    public static String quote(String string) {\r
+        if (string == null || string.length() == 0) {\r
+            return "\"\"";\r
+        }\r
+\r
+        char         b;\r
+        char         c = 0;\r
+        int          i;\r
+        int          len = string.length();\r
+        StringBuffer sb = new StringBuffer(len + 4);\r
+        String       t;\r
+\r
+        sb.append('"');\r
+        for (i = 0; i < len; i += 1) {\r
+            b = c;\r
+            c = string.charAt(i);\r
+            switch (c) {\r
+                case '\\':\r
+                case '"':\r
+                    sb.append('\\');\r
+                    sb.append(c);\r
+                    break;\r
+                case '/':\r
+                    if (b == '<') {\r
+                        sb.append('\\');\r
+                    }\r
+                    sb.append(c);\r
+                    break;\r
+                case '\b':\r
+                    sb.append("\\b");\r
+                    break;\r
+                case '\t':\r
+                    sb.append("\\t");\r
+                    break;\r
+                case '\n':\r
+                    sb.append("\\n");\r
+                    break;\r
+                case '\f':\r
+                    sb.append("\\f");\r
+                    break;\r
+                case '\r':\r
+                    sb.append("\\r");\r
+                    break;\r
+                default:\r
+                    if (c < ' ' || (c >= '\u0080' && c < '\u00a0') ||\r
+                            (c >= '\u2000' && c < '\u2100')) {\r
+                        t = "000" + Integer.toHexString(c);\r
+                        sb.append("\\u" + t.substring(t.length() - 4));\r
+                    } else {\r
+                        sb.append(c);\r
+                    }\r
+            }\r
+        }\r
+        sb.append('"');\r
+        return sb.toString();\r
+    }  \r
+       \r
+       public String getId() {\r
+               return id;\r
+       }\r
+\r
+    @SuppressWarnings("unchecked")\r
+       @Override\r
+    public <T> T getValue(String key) {\r
+        return (T)fields.get(key);\r
+    }\r
+\r
+    @Override\r
+    public Iterator<String> keys() {\r
+        return fields.keySet().iterator();\r
+    }\r
+\r
+    @Override\r
+    public IJSONObject clone(Map<String, Object> newObjects) {\r
+        JSONObject result = new JSONObject(binding, id);\r
+        for (Map.Entry<String, Object> e : fields.entrySet())\r
+            result.addJSONField(e.getKey(), e.getValue());\r
+        \r
+        for (Map.Entry<String, Object> e : newObjects.entrySet())\r
+            result.addJSONField(e.getKey(), e.getValue());\r
+        return result;\r
+    }\r
+}
\ No newline at end of file