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
17package com.google.clearsilver.jsilver.data;
18
19import com.google.clearsilver.jsilver.autoescape.EscapeMode;
20
21import java.io.IOException;
22import java.util.Iterator;
23import java.util.Map;
24
25/**
26 * Class that wraps a Data object and exports the same interface. Useful for extending the
27 * capabilities of an existing implementation.
28 */
29public class DelegatedData implements Data {
30
31  private final Data delegate;
32
33  public DelegatedData(Data delegate) {
34    if (delegate == null) {
35      throw new NullPointerException("Delegate Data must not be null.");
36    }
37    this.delegate = delegate;
38  }
39
40  /**
41   * Subclasses will want to override this method to return a Data object of their specific type.
42   *
43   * @param newDelegate the Data object to wrap with a new delegator
44   * @return a DelegateData type or subclass.
45   */
46  protected DelegatedData newInstance(Data newDelegate) {
47    return newDelegate == null ? null : new DelegatedData(newDelegate);
48  }
49
50  protected Data getDelegate() {
51    return delegate;
52  }
53
54  protected static Data unwrap(Data data) {
55    if (data instanceof DelegatedData) {
56      data = ((DelegatedData) data).getDelegate();
57    }
58    return data;
59  }
60
61  @Override
62  public String getName() {
63    return getDelegate().getName();
64  }
65
66  @Override
67  public String getValue() {
68    return getDelegate().getValue();
69  }
70
71  @Override
72  public int getIntValue() {
73    return getDelegate().getIntValue();
74  }
75
76  @Override
77  public boolean getBooleanValue() {
78    return getDelegate().getBooleanValue();
79  }
80
81  @Override
82  public void setValue(String value) {
83    getDelegate().setValue(value);
84  }
85
86  @Override
87  public String getFullPath() {
88    return getDelegate().getFullPath();
89  }
90
91  @Override
92  public void setAttribute(String key, String value) {
93    getDelegate().setAttribute(key, value);
94  }
95
96  @Override
97  public String getAttribute(String key) {
98    return getDelegate().getAttribute(key);
99  }
100
101  @Override
102  public boolean hasAttribute(String key) {
103    return getDelegate().hasAttribute(key);
104  }
105
106  @Override
107  public int getAttributeCount() {
108    return getDelegate().getAttributeCount();
109  }
110
111  @Override
112  public Iterable<Map.Entry<String, String>> getAttributes() {
113    return getDelegate().getAttributes();
114  }
115
116  @Override
117  public Data getRoot() {
118    return newInstance(getDelegate().getRoot());
119  }
120
121  @Override
122  public Data getParent() {
123    return newInstance(getDelegate().getParent());
124  }
125
126  @Override
127  public boolean isFirstSibling() {
128    return getDelegate().isFirstSibling();
129  }
130
131  @Override
132  public boolean isLastSibling() {
133    return getDelegate().isLastSibling();
134  }
135
136  @Override
137  public Data getNextSibling() {
138    return newInstance(getDelegate().getNextSibling());
139  }
140
141  @Override
142  public int getChildCount() {
143    return getDelegate().getChildCount();
144  }
145
146  /**
147   * Wrapping implementation of iterator that makes sure any Data object returned by the underlying
148   * iterator is wrapped with the right DelegatedData type.
149   */
150  protected class DelegatedIterator implements Iterator<DelegatedData> {
151    private final Iterator<? extends Data> iterator;
152
153    DelegatedIterator(Iterator<? extends Data> iterator) {
154      this.iterator = iterator;
155    }
156
157    public boolean hasNext() {
158      return iterator.hasNext();
159    }
160
161    public DelegatedData next() {
162      return newInstance(iterator.next());
163    }
164
165    public void remove() {
166      iterator.remove();
167    }
168  }
169
170  /**
171   * Subclasses can override this method to return specialized child iterators. For example, if they
172   * don't want to support the remove() operation.
173   *
174   * @return Iterator of children of delegate Data object that returns wrapped Data nodes.
175   */
176  protected Iterator<DelegatedData> newChildIterator() {
177    return new DelegatedIterator(getDelegate().getChildren().iterator());
178  }
179
180  /**
181   * Single Iterable object for each node. All it does is return a DelegatedIterator when asked for
182   * iterator.
183   */
184  private final Iterable<DelegatedData> delegatedIterable = new Iterable<DelegatedData>() {
185    public Iterator<DelegatedData> iterator() {
186      return newChildIterator();
187    }
188  };
189
190  @Override
191  public Iterable<? extends Data> getChildren() {
192    return delegatedIterable;
193  }
194
195  @Override
196  public Data getChild(String path) {
197    return newInstance(getDelegate().getChild(path));
198  }
199
200  @Override
201  public Data createChild(String path) {
202    return newInstance(getDelegate().createChild(path));
203  }
204
205  @Override
206  public void removeTree(String path) {
207    getDelegate().removeTree(path);
208  }
209
210  @Override
211  public void setSymlink(String sourcePath, String destinationPath) {
212    getDelegate().setSymlink(sourcePath, destinationPath);
213  }
214
215  @Override
216  public void setSymlink(String sourcePath, Data destination) {
217    destination = unwrap(destination);
218    getDelegate().setSymlink(sourcePath, destination);
219  }
220
221  @Override
222  public void setSymlink(Data symLink) {
223    symLink = unwrap(symLink);
224    getDelegate().setSymlink(symLink);
225  }
226
227  @Override
228  public Data getSymlink() {
229    return newInstance(getDelegate().getSymlink());
230  }
231
232  @Override
233  public void copy(String toPath, Data from) {
234    from = unwrap(from);
235    getDelegate().copy(toPath, from);
236  }
237
238  @Override
239  public void copy(Data from) {
240    from = unwrap(from);
241    getDelegate().copy(from);
242  }
243
244  @Override
245  public String getValue(String path, String defaultValue) {
246    return getDelegate().getValue(path, defaultValue);
247  }
248
249  @Override
250  public int getIntValue(String path, int defaultValue) {
251    return getDelegate().getIntValue(path, defaultValue);
252  }
253
254  @Override
255  public String getValue(String path) {
256    return getDelegate().getValue(path);
257  }
258
259  @Override
260  public int getIntValue(String path) {
261    return getDelegate().getIntValue(path);
262  }
263
264  @Override
265  public boolean getBooleanValue(String path) {
266    return getDelegate().getBooleanValue(path);
267  }
268
269  @Override
270  public void setValue(String path, String value) {
271    getDelegate().setValue(path, value);
272  }
273
274  @Override
275  public String toString() {
276    return getDelegate().toString();
277  }
278
279  @Override
280  public void toString(StringBuilder out, int indent) {
281    getDelegate().toString(out, indent);
282  }
283
284  @Override
285  public void write(Appendable out, int indent) throws IOException {
286    getDelegate().write(out, indent);
287  }
288
289  @Override
290  public void optimize() {
291    getDelegate().optimize();
292  }
293
294  @Override
295  public void setEscapeMode(EscapeMode mode) {
296    getDelegate().setEscapeMode(mode);
297  }
298
299  @Override
300  public EscapeMode getEscapeMode() {
301    return getDelegate().getEscapeMode();
302  }
303}
304