1 /**
2 * Copyright 2007 Art Technology Group, Inc (ATG)
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 *
7 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and limitations under the License.
13 */
14
15 package atg.taglib.json;
16
17
18 import atg.taglib.json.util.JSONArray;
19
20 import java.io.IOException;
21 import java.io.StringWriter;
22 import java.lang.reflect.Array;
23 import java.text.MessageFormat;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.Map;
29
30 import javax.servlet.jsp.JspException;
31 import javax.servlet.jsp.tagext.JspFragment;
32
33
34 /**
35 * Tag to represent a JSON array. The body of this tag should declare the template that will
36 * be used to represent each element in the array. Each element in the 'items' collection will
37 * be iterated over, and the body of the tag used to render each item in the array.
38 * <br/>
39 * This tag should contain a single json:object element if each array element is an object,
40 * otherwise it should contain textual content, which will create an array of Strings
41 *
42 * @author James Wiltshire
43 * @version $Id$
44 */
45
46 public class JsonArrayTag extends JsonBaseTag
47 {
48 protected String mVar;
49
50 /**
51 * Gets the Var
52 * @return the Var
53 */
54 public String getVar()
55 {
56 return mVar;
57 }
58
59 /**
60 * Sets the Var
61 *
62 * @param pVar The Var to set
63 */
64 public void setVar(String pVar)
65 {
66 mVar = pVar;
67 }
68
69 protected Object mItems;
70
71 /**
72 * Gets the Items
73 * @return the Items
74 */
75 public Object getItems()
76 {
77 return mItems;
78 }
79
80 /**
81 * Sets the Items
82 *
83 * @param pItems The Items to set
84 */
85 public void setItems(Object pItems)
86 {
87 mItems = pItems;
88 mItemsPropertySet=true;
89 }
90
91 /**
92 * Raw items coerced to a Collection
93 */
94 protected Collection mItemsCollection;
95
96 /**
97 * Flag to signify whether the items property was explicitly set
98 */
99 protected boolean mItemsPropertySet=false;
100
101
102 /**
103 * Process the tag
104 * @see javax.servlet.jsp.tagext.SimpleTagSupport#doTag()
105 *
106 * @throws JspException
107 */
108 public void doTag() throws JspException{
109 JspFragment body = getJspBody();
110
111
112 if (mItemsPropertySet && getVar()==null && body !=null){
113 throw new JspException(Messages.getString("atg.taglib.json.error.array.1"));
114 }
115
116 try{
117
118 JSONArray array = new JSONArray();
119 JsonEntity entity = new JsonEntity(array);
120 getEntityStack().push(entity);
121
122 if (mItemsPropertySet){
123 coerceItemsToCollection();
124
125
126 if (!mItemsCollection.isEmpty()){
127 iterateOverItems(array);
128 }
129 }
130 else {
131
132
133 if (body!=null){
134 StringWriter writer = new StringWriter();
135 body.invoke(writer);
136 }
137 }
138
139
140 getEntityStack().pop();
141
142
143 processTagEnd(entity);
144 }
145 catch (JspException e){
146
147
148 throw e;
149 }
150 catch (Exception e){
151 throw new JspException(Messages.getString("atg.taglib.json.error.array.0"),e);
152 }
153 }
154
155 /**
156 * Iterate over the items collection, adding each item to the array either directly or
157 * by invoking the tag body.
158 *
159 * @param pArray The JSON array to add each item to
160 * @throws JspException
161 * @throws IOException
162 */
163 private void iterateOverItems(JSONArray pArray) throws JspException, IOException
164 {
165 JspFragment body = getJspBody();
166
167
168 Iterator it = mItemsCollection.iterator();
169 while (it.hasNext()){
170 Object currentItem=it.next();
171
172 if (body==null){
173
174
175 pArray.add(currentItem);
176 }
177 else{
178
179
180
181 getJspContext().setAttribute(getVar(), currentItem);
182 int arraySizeBeforeInvokingBody = pArray.size();
183
184
185 StringWriter writer = new StringWriter();
186 body.invoke(writer);
187
188
189
190
191 if (pArray.size() == arraySizeBeforeInvokingBody){
192
193
194 Object value=writer.toString();
195
196
197 value=trimAndEscapeValue(value);
198
199
200 pArray.add(value);
201 }
202
203
204 getJspContext().removeAttribute(getVar());
205 }
206 }
207 }
208
209 /**
210 * Coerce the raw items object that has been set to a Collection that we
211 * can subsequently iterate over
212 *
213 * @throws JspException If unable to coerce the raw items to a Collection
214 *
215 */
216 private void coerceItemsToCollection() throws JspException
217 {
218 Object o = getItems();
219 Collection result;
220 if (o==null){
221
222
223 result = new ArrayList();
224 }
225 else if (
226
227 (o instanceof boolean[]) ||
228 (o instanceof byte[]) ||
229 (o instanceof char[]) ||
230 (o instanceof short[]) ||
231 (o instanceof int[]) ||
232 (o instanceof long[]) ||
233 (o instanceof float[]) ||
234 (o instanceof double[])) {
235 result = convertArrayToList(o);
236 }
237 else if (o instanceof Object[]){
238 result = Arrays.asList((Object[])o);
239 }
240 else if (o instanceof Collection){
241 result = (Collection)o;
242 }
243 else if (o instanceof Map){
244
245 result = ((Map)o).values();
246 }
247 else if (o instanceof String){
248
249 result = Arrays.asList(((String)o).split(","));
250 }
251 else {
252 String msg=MessageFormat.format(Messages.getString("atg.taglib.json.error.array.2"),
253 new Object[]{o.getClass()});
254 throw new JspException(msg);
255 }
256
257 mItemsCollection=result;
258 }
259
260 /**
261 * Convert a primitive array to a Collection
262 *
263 * @param pArray The primitive array to convert
264 * @return A Collection containing wrapper objects of all the primitive array elements
265 */
266 private Collection convertArrayToList(Object pArray){
267 if (pArray==null){
268
269 return new ArrayList();
270 }
271 int length = Array.getLength(pArray);
272 if (length == 0) {
273
274 return new ArrayList();
275 }
276 Class wrapperType = Array.get(pArray, 0).getClass();
277 Object[] newArray = (Object[]) Array.newInstance(wrapperType, length);
278 for (int i = 0; i < length; i++) {
279 newArray[i] = Array.get(pArray, i);
280 }
281 return Arrays.asList(newArray);
282 }
283 }
284