001: /*
002: * Copyright 2003-2005 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.velocity.tools.generic;
018:
019: import java.lang.reflect.Array;
020: import java.util.List;
021:
022: /**
023: * Tool for working with Lists and arrays in Velocity templates.
024: * It provides a method to get and set specified elements.
025: * Also provides methods to perform the following actions to Lists and arrays:
026: * <ul>
027: * <li>Check if it is empty.</li>
028: * <li>Check if it contains a certain element.</li>
029: * </ul>
030: * <p/>
031: * <p><pre>
032: * Example uses:
033: * $primes -> new int[] {2, 3, 5, 7}
034: * $list.size($primes) -> 4
035: * $list.get($primes, 2) -> 5
036: * $list.set($primes, 2, 1) -> (primes[2] becomes 1)
037: * $list.get($primes, 2) -> 1
038: * $list.isEmpty($primes) -> false
039: * $list.contains($primes, 7) -> true
040: * <p/>
041: * Example toolbox.xml config (if you want to use this with VelocityView):
042: * <tool>
043: * <key>list</key>
044: * <scope>application</scope>
045: * <class>org.apache.velocity.tools.generic.ListTool</class>
046: * </tool>
047: * </pre></p>
048: * <p/>
049: * <p>This tool is entirely threadsafe, and has no instance members.
050: * It may be used in any scope (request, session, or application).
051: * </p>
052: *
053: * @author <a href="mailto:shinobu@ieee.org">Shinobu Kawai</a>
054: * @version $Id: ListTool.java,v 1.1 2006/03/23 06:36:11 czarneckid Exp $
055: */
056: public class ListTool {
057:
058: /**
059: * Default constructor.
060: */
061: public ListTool() {
062: }
063:
064: /**
065: * Gets the specified element of a List/array.
066: * It will return null under the following conditions:
067: * <ul>
068: * <li><code>list</code> is null.</li>
069: * <li><code>list</code> is not a List/array.</li>
070: * <li><code>list</code> doesn't have an <code>index</code>th value.</li>
071: * </ul>
072: *
073: * @param list the List/array object.
074: * @param index the index of the List/array to get.
075: * @return the specified element of the List/array.
076: */
077: public Object get(Object list, int index) {
078: if (this .isArray(list)) {
079: return this .getFromArray(list, index);
080: }
081: if (!this .isList(list)) {
082: return null;
083: }
084:
085: try {
086: return ((List) list).get(index);
087: } catch (IndexOutOfBoundsException e) {
088: // The index was wrong.
089: return null;
090: }
091: }
092:
093: /**
094: * Gets the specified element of an array.
095: *
096: * @param array the array object.
097: * @param index the index of the array to get.
098: * @return the specified element of the array.
099: */
100: private Object getFromArray(Object array, int index) {
101: try {
102: return Array.get(array, index);
103: } catch (IndexOutOfBoundsException e) {
104: // The index was wrong.
105: return null;
106: }
107: }
108:
109: /**
110: * Sets the specified element of a List/array.
111: * It will return null under the following conditions:
112: * <ul>
113: * <li><code>list</code> is null.</li>
114: * <li><code>list</code> is not a List/array.</li>
115: * <li><code>list</code> doesn't have an <code>index</code>th value.</li>
116: * </ul>
117: *
118: * @param list the List/array object.
119: * @param index the index of the List/array to set.
120: * @param value the element to set.
121: * @return blank if set, null if not set.
122: */
123: public Object set(Object list, int index, Object value) {
124: if (this .isArray(list)) {
125: return this .setToArray(list, index, value);
126: }
127: if (!this .isList(list)) {
128: return null;
129: }
130:
131: try {
132: ((List) list).set(index, value);
133: return "";
134: } catch (IndexOutOfBoundsException e) {
135: // The index was wrong.
136: return null;
137: }
138: }
139:
140: /**
141: * Sets the specified element of an array.
142: *
143: * @param array the array object.
144: * @param index the index of the array to set.
145: * @param value the element to set.
146: * @return blank if set, null if not set.
147: */
148: private Object setToArray(Object array, int index, Object value) {
149: try {
150: Array.set(array, index, value);
151: return "";
152: } catch (IndexOutOfBoundsException e) {
153: // The index was wrong.
154: return null;
155: }
156: }
157:
158: /**
159: * Gets the size of a List/array.
160: * It will return null under the following conditions:
161: * <ul>
162: * <li><code>list</code> is null.</li>
163: * <li><code>list</code> is not a List/array.</li>
164: * </ul>
165: * The result will be same as the {@link #length(Object)} method.
166: *
167: * @param list the List object.
168: * @return the size of the List.
169: * @see #length(Object)
170: */
171: public Integer size(Object list) {
172: if (this .isArray(list)) {
173: // Thanks to Eric Fixler for this refactor.
174: return new Integer(Array.getLength(list));
175: }
176: if (!this .isList(list)) {
177: return null;
178: }
179:
180: return new Integer(((List) list).size());
181: }
182:
183: /**
184: * Checks if an object is an array.
185: *
186: * @param object the object to check.
187: * @return <code>true</code> if the object is an array.
188: */
189: public boolean isArray(Object object) {
190: if (object == null) {
191: return false;
192: }
193: return object.getClass().isArray();
194: }
195:
196: /**
197: * Checks if an object is a List.
198: *
199: * @param object the object to check.
200: * @return <code>true</code> if the object is a List.
201: */
202: public boolean isList(Object object) {
203: return object instanceof List;
204: }
205:
206: /**
207: * Checks if a List/array is empty.
208: *
209: * @param list the List/array to check.
210: * @return <code>true</code> if the List/array is empty.
211: */
212: public Boolean isEmpty(Object list) {
213: Integer size = this .size(list);
214: if (size == null) {
215: return null;
216: }
217:
218: return new Boolean(size.intValue() == 0);
219: }
220:
221: /**
222: * Checks if a List/array contains a certain element.
223: *
224: * @param list the List/array to check.
225: * @param element the element to check.
226: * @return <code>true</code> if the List/array contains the element.
227: */
228: public Boolean contains(Object list, Object element) {
229: if (this .isArray(list)) {
230: return this .arrayContains(list, element);
231: }
232: if (!this .isList(list)) {
233: return null;
234: }
235:
236: return new Boolean(((List) list).contains(element));
237: }
238:
239: /**
240: * Checks if an array contains a certain element.
241: *
242: * @param array the array to check.
243: * @param element the element to check.
244: * @return <code>true</code> if the array contains the element.
245: */
246: private Boolean arrayContains(Object array, Object element) {
247: int size = this .size(array).intValue();
248:
249: for (int index = 0; index < size; ++index) {
250: if (this .equals(element, this .getFromArray(array, index))) {
251: return Boolean.TRUE;
252: }
253: }
254: return Boolean.FALSE;
255: }
256:
257: /**
258: * Check if two objects are equal.
259: *
260: * @param what an object
261: * @param with another object.
262: * @return <code>true</code> if the two objects are equal.
263: */
264: private boolean equals(Object what, Object with) {
265: if (what == null) {
266: return with == null;
267: }
268:
269: return what.equals(with);
270: }
271:
272: }
|