• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.clearsilver.jsilver.data;
18 
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.logging.Logger;
23 
24 /**
25  * Implementation of Data that allows for multiple underlying Data objects and checks each one in
26  * order for a value before giving up. Behaves like local HDF and global HDF in the JNI
27  * implementation of Clearsilver. This is only meant to be a root Data object and hardcodes that
28  * fact.
29  * <p>
30  * Note: If you have elements foo.1, foo.2, foo.3 in first Data object and foo.4, foo.5, foo.6 in
31  * second Data object, then fetching children of foo will return only foo.1 foo.2 foo.3 from first
32  * Data object.
33  */
34 public class ChainedData extends DelegatedData {
35   public static final Logger logger = Logger.getLogger(ChainedData.class.getName());
36 
37   // This mode allows developers to locate occurrences where they set the same HDF
38   // variable in multiple Data objects in the chain, which usually indicates
39   // bad planning or misuse.
40   public static final boolean DEBUG_MULTIPLE_ASSIGNMENTS = false;
41 
42   Data[] dataList;
43 
44   /**
45    * Optmization for case of single item.
46    *
47    * @param data a single data object to wrap.
48    */
ChainedData(Data data)49   public ChainedData(Data data) {
50     super(data);
51     this.dataList = new Data[] {data};
52   }
53 
ChainedData(Data... dataList)54   public ChainedData(Data... dataList) {
55     super(getFirstData(dataList));
56     this.dataList = dataList;
57   }
58 
ChainedData(List<Data> dataList)59   public ChainedData(List<Data> dataList) {
60     super(getFirstData(dataList));
61     this.dataList = dataList.toArray(new Data[dataList.size()]);
62   }
63 
64   @Override
newInstance(Data newDelegate)65   protected DelegatedData newInstance(Data newDelegate) {
66     return newDelegate == null ? null : new ChainedData(newDelegate);
67   }
68 
getFirstData(Data[] dataList)69   private static Data getFirstData(Data[] dataList) {
70     if (dataList.length == 0) {
71       throw new IllegalArgumentException("Must pass in at least one Data object to ChainedData.");
72     }
73     Data first = dataList[0];
74     if (first == null) {
75       throw new IllegalArgumentException("ChainedData does not accept null Data objects.");
76     }
77     return first;
78   }
79 
getFirstData(List<Data> dataList)80   private static Data getFirstData(List<Data> dataList) {
81     if (dataList.size() == 0) {
82       throw new IllegalArgumentException("Must pass in at least one Data object to ChainedData.");
83     }
84     Data first = dataList.get(0);
85     if (first == null) {
86       throw new IllegalArgumentException("ChainedData does not accept null Data objects.");
87     }
88     return first;
89   }
90 
91   @Override
getChild(String path)92   public Data getChild(String path) {
93     ArrayList<Data> children = null;
94     Data first = null;
95     for (Data d : dataList) {
96       Data child = d.getChild(path);
97       if (child != null) {
98         if (!DEBUG_MULTIPLE_ASSIGNMENTS) {
99           // If not in debug mode just return the first match. This assumes we are using the new
100           // style of VariableLocator that does not iteratively ask for each HDF path element
101           // separately.
102           return child;
103         }
104         if (first == null) {
105           // First match found
106           first = child;
107         } else if (children == null) {
108           // Second match found
109           children = new ArrayList<Data>(dataList.length);
110           children.add(first);
111           children.add(child);
112         } else {
113           // Third or more match found
114           children.add(child);
115         }
116       }
117     }
118     if (children == null) {
119       // 0 or 1 matches. Return first which is null or Data.
120       return first;
121     } else {
122       // Multiple matches. Pass back the first item found. This is only hit when
123       // DEBUG_MULTIPLE_ASSIGNMENTS is true.
124       logger.info("Found " + children.size() + " matches for path " + path);
125       return first;
126     }
127   }
128 
129   @Override
createChild(String path)130   public Data createChild(String path) {
131     Data child = getChild(path);
132     if (child != null) {
133       return child;
134     } else {
135       // We don't call super because we don't want to wrap the result in DelegatedData.
136       return dataList[0].createChild(path);
137     }
138   }
139 
140   @Override
getValue(String path, String defaultValue)141   public String getValue(String path, String defaultValue) {
142     Data child = getChild(path);
143     if (child != null && child.getValue() != null) {
144       return child.getValue();
145     } else {
146       return defaultValue;
147     }
148   }
149 
150   @Override
getIntValue(String path, int defaultValue)151   public int getIntValue(String path, int defaultValue) {
152     Data child = getChild(path);
153     if (child != null) {
154       String value = child.getValue();
155       try {
156         return value == null ? defaultValue : TypeConverter.parseNumber(value);
157       } catch (NumberFormatException e) {
158         return defaultValue;
159       }
160     } else {
161       return defaultValue;
162     }
163   }
164 
165   @Override
getValue(String path)166   public String getValue(String path) {
167     Data child = getChild(path);
168     if (child != null) {
169       return child.getValue();
170     } else {
171       return null;
172     }
173   }
174 
175   @Override
getIntValue(String path)176   public int getIntValue(String path) {
177     Data child = getChild(path);
178     if (child != null) {
179       return child.getIntValue();
180     } else {
181       return 0;
182     }
183   }
184 
185   @Override
getBooleanValue(String path)186   public boolean getBooleanValue(String path) {
187     Data child = getChild(path);
188     if (child != null) {
189       return child.getBooleanValue();
190     } else {
191       return false;
192     }
193   }
194 
195   @Override
toString(StringBuilder out, int indent)196   public void toString(StringBuilder out, int indent) {
197     for (Data d : dataList) {
198       d.toString(out, indent);
199     }
200   }
201 
202   @Override
write(Appendable out, int indent)203   public void write(Appendable out, int indent) throws IOException {
204     for (Data d : dataList) {
205       d.write(out, indent);
206     }
207   }
208 
209   @Override
optimize()210   public void optimize() {
211     for (Data d : dataList) {
212       d.optimize();
213     }
214   }
215 }
216