org.chromium.sdk/src/org/chromium/sdk/internal/JsArrayImpl.java
changeset 2 e4420d2515f1
child 52 f577ea64429e
equal deleted inserted replaced
1:ef76fc2ac88c 2:e4420d2515f1
       
     1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style license that can be
       
     3 // found in the LICENSE file.
       
     4 
       
     5 package org.chromium.sdk.internal;
       
     6 
       
     7 import java.util.Collections;
       
     8 import java.util.Comparator;
       
     9 import java.util.List;
       
    10 import java.util.Map;
       
    11 import java.util.SortedMap;
       
    12 import java.util.TreeMap;
       
    13 
       
    14 import org.chromium.sdk.JsArray;
       
    15 import org.chromium.sdk.JsVariable;
       
    16 import org.chromium.sdk.internal.tools.v8.MethodIsBlockingException;
       
    17 
       
    18 /**
       
    19  * A generic implementation of the JsArray interface.
       
    20  */
       
    21 class JsArrayImpl extends JsObjectImpl implements JsArray {
       
    22 
       
    23   /**
       
    24    * An indexed sparse array of elements. Keys are indices, values are elements.
       
    25    */
       
    26   private SortedMap<Integer, JsVariableImpl> indexToElementMap;
       
    27 
       
    28   /**
       
    29    * This constructor implies lazy resolution of object properties.
       
    30    *
       
    31    * @param callFrame this array belongs in
       
    32    * @param parentFqn the fully qualified name of this array parent
       
    33    * @param valueState the mirror corresponding to this array
       
    34    */
       
    35   JsArrayImpl(CallFrameImpl callFrame, String parentFqn, ValueMirror valueState) {
       
    36     super(callFrame, parentFqn, valueState);
       
    37   }
       
    38 
       
    39   private synchronized void ensureElementsMap() throws MethodIsBlockingException {
       
    40     if (indexToElementMap != null) {
       
    41       return;
       
    42     }
       
    43     SortedMap<Integer, JsVariableImpl> map =
       
    44       // TODO(peter.rybin): do we need this comparator at all?
       
    45         new TreeMap<Integer, JsVariableImpl>(new Comparator<Integer>() {
       
    46           public int compare(Integer o1, Integer o2) {
       
    47             return o1 - o2;
       
    48           }
       
    49         });
       
    50 
       
    51     for (JsVariableImpl prop : getProperties()) {
       
    52       String name = prop.getRawName();
       
    53       Integer index = getAsArrayIndex(name);
       
    54       if (index == null) {
       
    55         continue;
       
    56       }
       
    57       map.put(index, prop);
       
    58     }
       
    59     indexToElementMap = Collections.unmodifiableSortedMap(map);
       
    60   }
       
    61 
       
    62   public JsVariable get(int index) throws MethodIsBlockingException {
       
    63     ensureElementsMap();
       
    64     return indexToElementMap.get(index);
       
    65   }
       
    66 
       
    67   public SortedMap<Integer, ? extends JsVariable> toSparseArray() throws MethodIsBlockingException {
       
    68     ensureElementsMap();
       
    69     return indexToElementMap;
       
    70   }
       
    71 
       
    72   public int length() {
       
    73     // TODO(peter.rybin) optimize it: either read "length" from remote or count PropertyReference
       
    74     // rather than JsVariableImpl
       
    75     int lastIndex = -1;
       
    76     List<JsVariableImpl> properties = getSubpropertiesHelper().getPropertiesLazily();
       
    77     // TODO(peter.rybin): rename propRefs
       
    78     for (JsVariableImpl prop : properties) {
       
    79       String name = prop.getRawName();
       
    80       Integer index = getAsArrayIndex(name);
       
    81       if (index == null) {
       
    82         continue;
       
    83       }
       
    84       if (index > lastIndex) {
       
    85         lastIndex = index;
       
    86       }
       
    87     }
       
    88     return lastIndex + 1;
       
    89   }
       
    90 
       
    91   @Override
       
    92   public String toString() {
       
    93     SortedMap<Integer, ? extends JsVariable> elements;
       
    94     try {
       
    95       elements = toSparseArray();
       
    96     } catch (MethodIsBlockingException e) {
       
    97       return "[JsArray: Exception in retrieving data]";
       
    98     }
       
    99     StringBuilder result = new StringBuilder();
       
   100     result.append("[JsArray: length=").append(elements.size());
       
   101     for (Map.Entry<Integer, ? extends JsVariable> entry : elements.entrySet()) {
       
   102       result.append(',').append(entry.getKey()).append('=').append(entry.getValue());
       
   103     }
       
   104     result.append(']');
       
   105     return result.toString();
       
   106   }
       
   107 
       
   108   @Override
       
   109   public JsArrayImpl asArray() {
       
   110     return this;
       
   111   }
       
   112 
       
   113   @Override
       
   114   protected JsVariableImpl.NameDecorator getChildPropertyNameDecorator() {
       
   115     return ARRAY_ELEMENT_DECORATOR;
       
   116   }
       
   117 
       
   118   /**
       
   119    * @return integer representation of the index or null if it is not an integer
       
   120    */
       
   121   static Integer getAsArrayIndex(String varName) {
       
   122     if (!JsonUtil.isInteger(varName)) {
       
   123       return null;
       
   124     }
       
   125     try {
       
   126       int index = Integer.parseInt(varName);
       
   127       return index;
       
   128     } catch (NumberFormatException e) {
       
   129       return null;
       
   130     }
       
   131   }
       
   132 
       
   133   private final static JsVariableImpl.NameDecorator ARRAY_ELEMENT_DECORATOR =
       
   134       new JsVariableImpl.NameDecorator() {
       
   135     @Override
       
   136     String decorateVarName(String rawName) {
       
   137       Integer index = getAsArrayIndex(rawName);
       
   138       if (index == null) {
       
   139         return rawName;
       
   140       }
       
   141       // Fix array element indices
       
   142       return OPEN_BRACKET + rawName + CLOSE_BRACKET;
       
   143     }
       
   144     @Override
       
   145     String buildAccessSuffix(String rawName) {
       
   146       Integer index = getAsArrayIndex(rawName);
       
   147       if (index == null) {
       
   148         return NOOP.buildAccessSuffix(rawName);
       
   149       }
       
   150       return OPEN_BRACKET + rawName + CLOSE_BRACKET;
       
   151     }
       
   152     private static final String OPEN_BRACKET = "[";
       
   153     private static final String CLOSE_BRACKET = "]";
       
   154   };
       
   155 }