156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/*
256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc.
356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License");
556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License.
656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at
756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0
956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software
1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS,
1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and
1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License.
1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.data;
1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.ArrayList;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.List;
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.logging.Logger;
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Implementation of Data that allows for multiple underlying Data objects and checks each one in
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * order for a value before giving up. Behaves like local HDF and global HDF in the JNI
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * implementation of Clearsilver. This is only meant to be a root Data object and hardcodes that
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * fact.
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p>
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Note: If you have elements foo.1, foo.2, foo.3 in first Data object and foo.4, foo.5, foo.6 in
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * second Data object, then fetching children of foo will return only foo.1 foo.2 foo.3 from first
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Data object.
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class ChainedData extends DelegatedData {
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final Logger logger = Logger.getLogger(ChainedData.class.getName());
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  // This mode allows developers to locate occurrences where they set the same HDF
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  // variable in multiple Data objects in the chain, which usually indicates
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  // bad planning or misuse.
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final boolean DEBUG_MULTIPLE_ASSIGNMENTS = false;
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  Data[] dataList;
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Optmization for case of single item.
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param data a single data object to wrap.
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public ChainedData(Data data) {
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    super(data);
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.dataList = new Data[] {data};
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public ChainedData(Data... dataList) {
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    super(getFirstData(dataList));
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.dataList = dataList;
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public ChainedData(List<Data> dataList) {
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    super(getFirstData(dataList));
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.dataList = dataList.toArray(new Data[dataList.size()]);
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  protected DelegatedData newInstance(Data newDelegate) {
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return newDelegate == null ? null : new ChainedData(newDelegate);
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static Data getFirstData(Data[] dataList) {
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (dataList.length == 0) {
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new IllegalArgumentException("Must pass in at least one Data object to ChainedData.");
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data first = dataList[0];
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (first == null) {
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new IllegalArgumentException("ChainedData does not accept null Data objects.");
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return first;
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static Data getFirstData(List<Data> dataList) {
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (dataList.size() == 0) {
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new IllegalArgumentException("Must pass in at least one Data object to ChainedData.");
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data first = dataList.get(0);
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (first == null) {
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new IllegalArgumentException("ChainedData does not accept null Data objects.");
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return first;
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Data getChild(String path) {
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    ArrayList<Data> children = null;
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data first = null;
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (Data d : dataList) {
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      Data child = d.getChild(path);
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (child != null) {
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        if (!DEBUG_MULTIPLE_ASSIGNMENTS) {
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // If not in debug mode just return the first match. This assumes we are using the new
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // style of VariableLocator that does not iteratively ask for each HDF path element
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // separately.
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          return child;
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        }
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        if (first == null) {
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // First match found
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          first = child;
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        } else if (children == null) {
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // Second match found
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          children = new ArrayList<Data>(dataList.length);
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          children.add(first);
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          children.add(child);
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        } else {
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // Third or more match found
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          children.add(child);
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        }
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (children == null) {
11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // 0 or 1 matches. Return first which is null or Data.
12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return first;
12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Multiple matches. Pass back the first item found. This is only hit when
12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // DEBUG_MULTIPLE_ASSIGNMENTS is true.
12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      logger.info("Found " + children.size() + " matches for path " + path);
12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return first;
12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Data createChild(String path) {
13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data child = getChild(path);
13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (child != null) {
13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return child;
13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // We don't call super because we don't want to wrap the result in DelegatedData.
13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return dataList[0].createChild(path);
13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public String getValue(String path, String defaultValue) {
14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data child = getChild(path);
14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (child != null && child.getValue() != null) {
14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return child.getValue();
14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return defaultValue;
14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public int getIntValue(String path, int defaultValue) {
15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data child = getChild(path);
15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (child != null) {
15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String value = child.getValue();
15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      try {
15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        return value == null ? defaultValue : TypeConverter.parseNumber(value);
15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } catch (NumberFormatException e) {
15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        return defaultValue;
15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return defaultValue;
16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public String getValue(String path) {
16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data child = getChild(path);
16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (child != null) {
16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return child.getValue();
17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return null;
17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public int getIntValue(String path) {
17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data child = getChild(path);
17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (child != null) {
17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return child.getIntValue();
18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return 0;
18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public boolean getBooleanValue(String path) {
18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Data child = getChild(path);
18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (child != null) {
18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return child.getBooleanValue();
19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return false;
19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void toString(StringBuilder out, int indent) {
19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (Data d : dataList) {
19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      d.toString(out, indent);
19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void write(Appendable out, int indent) throws IOException {
20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (Data d : dataList) {
20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      d.write(out, indent);
20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void optimize() {
21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (Data d : dataList) {
21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      d.optimize();
21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
216