Package com.google.template.soy.data.restricted

Source Code of com.google.template.soy.data.restricted.CollectionData

/*
* Copyright 2008 Google Inc.
*
* Licensed 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 com.google.template.soy.data.restricted;

import com.google.common.collect.Lists;
import com.google.template.soy.data.SoyData;
import com.google.template.soy.data.SoyDataException;
import com.google.template.soy.data.SoyListData;
import com.google.template.soy.data.SoyMapData;

import java.util.List;


/**
* Abstract superclass for a node in a Soy data tree that represents a collection of data (i.e. an
* internal node).
*
* <p> Important: This class may only be used in implementing plugins (e.g. functions, directives).
*
* @author Kai Huang
*/
public abstract class CollectionData extends SoyData {


  // ------------ put() ------------


  /**
   * Convenience function to put multiple mappings in one call.
   * @param data The mappings to put, as alternating keys/values. Indices 0, 2, 4, ... must be valid
   *     key strings. Indices 1, 3, 5, ... must be valid Soy data values.
   * @throws SoyDataException When attempting to add an invalid varargs list or a mapping containing
   *     an invalid key.
   */
  public void put(Object... data) {

    // TODO: Perhaps change to only convert varargs to Map, and do put(Map) elsewhere.
    if (data.length % 2 != 0) {
      throw new SoyDataException(
          "Varargs to put(...) must have an even number of arguments (key-value pairs).");
    }
    for (int i = 0; i < data.length; i += 2) {
      try {
        put((String) data[i], SoyData.createFromExistingData(data[i + 1]));
      } catch (ClassCastException cce) {
        throw new SoyDataException(
            "Attempting to add a mapping containing a non-string key (key type " +
            data[i].getClass().getName() + ").");
      }
    }
  }


  /**
   * Puts data into this data tree at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @param value The data to put at the specified location.
   */
  public void put(String keyStr, SoyData value) {

    List<String> keys = split(keyStr, '.');
    int numKeys = keys.size();

    CollectionData collectionData = this;
    for (int i = 0; i <= numKeys - 2; ++i) {

      SoyData nextSoyData = collectionData.getSingle(keys.get(i));
      if (nextSoyData != null && !(nextSoyData instanceof CollectionData)) {
        throw new SoyDataException(
            "Failed to evaluate key string \"" + keyStr + "\" for put().");
      }
      CollectionData nextCollectionData = (CollectionData) nextSoyData;

      if (nextCollectionData == null) {
        // Create the SoyData object that will be bound to keys.get(i). We need to check the first
        // part of keys[i+1] to know whether to create a SoyMapData or SoyListData (checking the
        // first char is sufficient).
        nextCollectionData =
            (Character.isDigit(keys.get(i + 1).charAt(0))) ? new SoyListData() : new SoyMapData();
        collectionData.putSingle(keys.get(i), nextCollectionData);
      }
      collectionData = nextCollectionData;
    }

    collectionData.putSingle(keys.get(numKeys - 1), ensureValidValue(value));
  }


  /**
   * Puts data into this data tree at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @param value The data to put at the specified location.
   */
  public void put(String keyStr, boolean value) {
    put(keyStr, BooleanData.forValue(value));
  }

  /**
   * Puts data into this data tree at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @param value The data to put at the specified location.
   */
  public void put(String keyStr, int value) {
    put(keyStr, IntegerData.forValue(value));
  }

  /**
   * Puts data into this data tree at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @param value The data to put at the specified location.
   */
  public void put(String keyStr, double value) {
    put(keyStr, FloatData.forValue(value));
  }

  /**
   * Puts data into this data tree at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @param value The data to put at the specified location.
   */
  public void put(String keyStr, String value) {
    put(keyStr, StringData.forValue(value));
  }


  // ------------ remove() ------------


  /**
   * Removes the data at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   */
  public void remove(String keyStr) {

    List<String> keys = split(keyStr, '.');
    int numKeys = keys.size();

    CollectionData collectionData = this;
    for (int i = 0; i <= numKeys - 2; ++i) {
      SoyData soyData = collectionData.getSingle(keys.get(i));
      if (soyData == null || !(soyData instanceof CollectionData)) {
        return;
      }
      collectionData = (CollectionData) soyData;
    }

    collectionData.removeSingle(keys.get(numKeys - 1));
  }


  // ------------ get*() ------------


  /**
   * Gets the data at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @return The data at the specified key string, or null if there's no data at the location.
   */
  public SoyData get(String keyStr) {

    List<String> keys = split(keyStr, '.');
    int numKeys = keys.size();

    CollectionData collectionData = this;
    for (int i = 0; i <= numKeys - 2; ++i) {
      SoyData soyData = collectionData.getSingle(keys.get(i));
      if (soyData == null || !(soyData instanceof CollectionData)) {
        return null;
      }
      collectionData = (CollectionData) soyData;
    }

    return collectionData.getSingle(keys.get(numKeys - 1));
  }


  /**
   * Precondition: The specified key string is the path to a SoyMapData object.
   * Gets the SoyMapData at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @return The SoyMapData at the specified key string, or null if no data is stored there.
   */
  public SoyMapData getMapData(String keyStr) {
    return (SoyMapData) get(keyStr);
  }

  /**
   * Precondition: The specified key string is the path to a SoyListData object.
   * Gets the SoyListData at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @return The SoyListData at the specified key string, or null if no data is stored there.
   */
  public SoyListData getListData(String keyStr) {
    return (SoyListData) get(keyStr);
  }

  /**
   * Precondition: The specified key string is the path to a boolean.
   * Gets the boolean at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @return The boolean at the specified key string.
   * @throws IllegalArgumentException If no data is stored at the specified key.
   */
  public boolean getBoolean(String keyStr) {
    SoyData valueData = get(keyStr);
    if (valueData == null) {
      throw new IllegalArgumentException("Missing key: " + keyStr);
    }
    return valueData.booleanValue();
  }

  /**
   * Precondition: The specified key string is the path to an integer.
   * Gets the integer at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @return The integer at the specified key string.
   * @throws IllegalArgumentException If no data is stored at the specified key.
   */
  public int getInteger(String keyStr) {
    SoyData valueData = get(keyStr);
    if (valueData == null) {
      throw new IllegalArgumentException("Missing key: " + keyStr);
    }
    return valueData.integerValue();
  }

  /**
   * Precondition: The specified key string is the path to a float.
   * Gets the float at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @return The float at the specified key string.
   * @throws IllegalArgumentException If no data is stored at the specified key.
   */
  public double getFloat(String keyStr) {
    SoyData valueData = get(keyStr);
    if (valueData == null) {
      throw new IllegalArgumentException("Missing key: " + keyStr);
    }
    return valueData.floatValue();
  }

  /**
   * Precondition: The specified key string is the path to a string.
   * Gets the string at the specified key string.
   * @param keyStr One or more map keys and/or list indices (separated by '.' if multiple parts).
   *     Indicates the path to the location within this data tree.
   * @return The string at the specified key string.
   * @throws IllegalArgumentException If no data is stored at the specified key.
   */
  public String getString(String keyStr) {
    SoyData valueData = get(keyStr);
    if (valueData == null) {
      throw new IllegalArgumentException("Missing key: " + keyStr);
    }
    return valueData.stringValue();
  }


  // -----------------------------------------------------------------------------------------------
  // Superpackage-private methods.


  /**
   * Important: Do not use outside of Soy code (treat as superpackage-private).
   *
   * Puts data into this data object at the specified key.
   * @param key An individual key.
   * @param value The data to put at the specified key.
   */
  public abstract void putSingle(String key, SoyData value);


  /**
   * Important: Do not use outside of Soy code (treat as superpackage-private).
   *
   * Removes the data at the specified key.
   * @param key An individual key.
   */
  public abstract void removeSingle(String key);


  /**
   * Important: Do not use outside of Soy code (treat as superpackage-private).
   *
   * Gets the data at the specified key.
   * @param key An individual key.
   * @return The data at the specified key, or null if the key is not defined.
   */
  public abstract SoyData getSingle(String key);


  // -----------------------------------------------------------------------------------------------
  // Protected/private helpers.


  /**
   * Ensures that the given value is valid for insertion into a Soy data tree. If the value is not
   * null, then simply returns it, else return NullData.
   * @param value The value to ensure validity for.
   * @return The given value if it's not null, or NullData if it is null.
   */
  protected static SoyData ensureValidValue(SoyData value) {
    return (value != null) ? value : NullData.INSTANCE;
  }


  /**
   * Splits a string into tokens at the specified delimiter.
   * @param str The string to split.  Must not be null.
   * @param delim The delimiter character.
   * @return A list of tokens. Will not return null.
   */
  private static List<String> split(String str, char delim) {

    List<String> result = Lists.newArrayList();

    int currPartStart = 0;
    while (true) {
      int currPartEnd = str.indexOf(delim, currPartStart);
      if (currPartEnd == -1) {
        result.add(str.substring(currPartStart));
        break;
      } else {
        result.add(str.substring(currPartStart, currPartEnd));
        currPartStart = currPartEnd + 1;
      }
    }

    return result;
  }

}
TOP

Related Classes of com.google.template.soy.data.restricted.CollectionData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.