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.lang.reflect.Method;
021: import java.util.ArrayList;
022: import java.util.List;
023:
024: /**
025: * Tool for working with Lists and arrays in Velocity templates.
026: * In addition to the features ListTool provides,
027: * it provides the function to retrieve the length,
028: * and create clones of a list or an array object.
029: * Also provides a method to convert arrays into Lists and
030: * Lists into arrays.
031: * <p/>
032: * <p><pre>
033: * Example uses:
034: * $primes -> new int[] {2, 3, 5, 7}
035: * $list.length($primes) -> 4
036: * $list.get($primes, 2) -> 5
037: * $list.clone($primes) -> int[] {2, 3, 5, 7}, != $primes
038: * $list.set($primes, 2, 1) -> (primes[2] becomes 1)
039: * $list.get($primes, 2) -> 1
040: * $list.get($clone, 2) -> 5
041: * <p/>
042: * Example toolbox.xml config (if you want to use this with VelocityView):
043: * <tool>
044: * <key>list</key>
045: * <scope>application</scope>
046: * <class>org.apache.velocity.tools.generic.ExtendedListTool</class>
047: * </tool>
048: * </pre></p>
049: * <p/>
050: * <p>This tool is entirely threadsafe, and has no instance members.
051: * It may be used in any scope (request, session, or application).
052: * </p>
053: *
054: * @author <a href="mailto:shinobu@ieee.org">Shinobu Kawai</a>
055: * @version $Id: ExtendedListTool.java,v 1.1 2006/03/23 06:36:11 czarneckid Exp $
056: */
057: public class ExtendedListTool extends ListTool {
058:
059: /**
060: * Default constructor.
061: */
062: public ExtendedListTool() {
063: }
064:
065: /**
066: * Converts an array object into a List.
067: * <ul>
068: * <li>
069: * If the object is already a List,
070: * it will return the object itself.
071: * </li>
072: * <li>
073: * If the object is an array of an Object,
074: * it will return a List of the elements.
075: * </li>
076: * <li>
077: * If the object is an array of a primitive type,
078: * it will return a List of the elements wrapped in their wrapper class.
079: * </li>
080: * <li>
081: * If the object is none of the above, it will return null.
082: * </li>
083: * </ul>
084: *
085: * @param array an array object.
086: * @return the converted java.util.List.
087: */
088: public List toList(Object array) {
089: if (this .isList(array)) {
090: return (List) array;
091: }
092: if (!this .isArray(array)) {
093: return null;
094: }
095:
096: // Thanks to Eric Fixler for this refactor.
097: int length = Array.getLength(array);
098: List asList = new ArrayList(length);
099: for (int index = 0; index < length; ++index) {
100: asList.add(Array.get(array, index));
101: }
102: return asList;
103: }
104:
105: /**
106: * Converts a List object into an array.
107: * <ul>
108: * <li>
109: * If the object is already an array,
110: * it will return the object itself.
111: * </li>
112: * <li>
113: * If the object is a List,
114: * it will return an array according to the object's
115: * <code>toArray()</code> method.
116: * </li>
117: * <li>
118: * If the object is none of the above, it will return null.
119: * </li>
120: * </ul>
121: *
122: * @param list a List object.
123: * @return the converted array.
124: */
125: public Object toArray(Object list) {
126: if (this .isArray(list)) {
127: return list;
128: }
129: if (!this .isList(list)) {
130: return null;
131: }
132:
133: List asList = (List) list;
134: return asList.toArray(new Object[asList.size()]);
135: }
136:
137: /**
138: * Gets the length of an array/List.
139: * It will return null under the following conditions:
140: * <ul>
141: * <li><code>array</code> is null.</li>
142: * <li><code>array</code> is not an array/List.</li>
143: * </ul>
144: * The result will be same as the {@link #size(Object)} method.
145: *
146: * @param array the array object.
147: * @return the length of the array.
148: * @see #size(Object)
149: */
150: public Integer length(Object array) {
151: if (this .isList(array)) {
152: return this .size(array);
153: }
154: if (!this .isArray(array)) {
155: return null;
156: }
157:
158: // Thanks to Eric Fixler for this refactor.
159: return new Integer(Array.getLength(array));
160: }
161:
162: /**
163: * Gets the clone of a List/array.
164: * It will return null under the following conditions:
165: * <ul>
166: * <li><code>list</code> is null.</li>
167: * <li><code>list</code> is not a List/array.</li>
168: * </ul>
169: *
170: * @param list the List/array object.
171: * @return the clone of the List/array.
172: */
173: public Object clone(Object list) {
174: if (this .isArray(list)) {
175: Class type = list.getClass().getComponentType();
176: int length = Array.getLength(list);
177: Object clone = Array.newInstance(type, length);
178: System.arraycopy(list, 0, clone, 0, length);
179: return clone;
180: }
181: if (!this .isList(list)) {
182: return null;
183: }
184:
185: // first, try the clone() method.
186: Class clazz = list.getClass();
187: try {
188: Method cloneMethod = clazz.getMethod("clone", new Class[0]);
189: return cloneMethod.invoke(list, null);
190: } catch (Exception ignoreAndTryTheNextStep) {
191: }
192:
193: // try to copy to a new instance.
194: try {
195: List clone = (List) clazz.newInstance();
196: clone.addAll(((List) list));
197: return clone;
198: } catch (Exception ignoreAndTryTheNextStep) {
199: }
200:
201: // last resort.
202: return new ArrayList(((List) list));
203: }
204:
205: }
|