%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.turbine.services.intake.model.Group$GroupFactory |
|
|
1 | package org.apache.turbine.services.intake.model; |
|
2 | ||
3 | /* |
|
4 | * Copyright 2001-2005 The Apache Software Foundation. |
|
5 | * |
|
6 | * Licensed under the Apache License, Version 2.0 (the "License") |
|
7 | * you may not use this file except in compliance with the License. |
|
8 | * You may obtain a copy of the License at |
|
9 | * |
|
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
11 | * |
|
12 | * Unless required by applicable law or agreed to in writing, software |
|
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
15 | * See the License for the specific language governing permissions and |
|
16 | * limitations under the License. |
|
17 | */ |
|
18 | ||
19 | import java.util.ArrayList; |
|
20 | import java.util.HashMap; |
|
21 | import java.util.Iterator; |
|
22 | import java.util.List; |
|
23 | import java.util.Map; |
|
24 | ||
25 | import org.apache.commons.logging.Log; |
|
26 | import org.apache.commons.logging.LogFactory; |
|
27 | ||
28 | import org.apache.commons.pool.BaseKeyedPoolableObjectFactory; |
|
29 | ||
30 | import org.apache.turbine.om.Retrievable; |
|
31 | import org.apache.turbine.services.intake.IntakeException; |
|
32 | import org.apache.turbine.services.intake.TurbineIntake; |
|
33 | import org.apache.turbine.services.intake.xmlmodel.AppData; |
|
34 | import org.apache.turbine.services.intake.xmlmodel.XmlField; |
|
35 | import org.apache.turbine.services.intake.xmlmodel.XmlGroup; |
|
36 | import org.apache.turbine.util.TurbineException; |
|
37 | import org.apache.turbine.util.parser.ValueParser; |
|
38 | ||
39 | /** |
|
40 | * Holds a group of Fields |
|
41 | * |
|
42 | * @author <a href="mailto:jmcnally@collab.net">John McNally</a> |
|
43 | * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> |
|
44 | * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> |
|
45 | * @version $Id: Group.java 264148 2005-08-29 14:21:04Z henning $ |
|
46 | */ |
|
47 | public class Group |
|
48 | { |
|
49 | public static final String EMPTY = ""; |
|
50 | ||
51 | /* |
|
52 | * An id representing a new object. |
|
53 | */ |
|
54 | public static final String NEW = "_0"; |
|
55 | ||
56 | private static final Log log; |
|
57 | private static final boolean isDebugEnabled; |
|
58 | ||
59 | static |
|
60 | { |
|
61 | log = LogFactory.getLog(Group.class); |
|
62 | isDebugEnabled = log.isDebugEnabled(); |
|
63 | } |
|
64 | ||
65 | /** |
|
66 | * The key used to represent this group in a parameter. |
|
67 | * This key is usually a prefix as part of a field key. |
|
68 | */ |
|
69 | protected final String gid; |
|
70 | ||
71 | /** |
|
72 | * The name used in templates and java code to refer to this group. |
|
73 | */ |
|
74 | protected final String name; |
|
75 | ||
76 | /** |
|
77 | * The number of Groups with the same name that will be pooled. |
|
78 | */ |
|
79 | private final int poolCapacity; |
|
80 | ||
81 | /** |
|
82 | * A map of the fields in this group mapped by field name. |
|
83 | */ |
|
84 | protected Map fields; |
|
85 | ||
86 | /** |
|
87 | * Map of the fields by mapToObject |
|
88 | */ |
|
89 | protected Map mapToObjectFields; |
|
90 | ||
91 | /** |
|
92 | * An array of fields in this group. |
|
93 | */ |
|
94 | protected Field[] fieldsArray; |
|
95 | ||
96 | /** |
|
97 | * The object id used to associate this group to a bean |
|
98 | * for one request cycle |
|
99 | */ |
|
100 | protected String oid; |
|
101 | ||
102 | /** |
|
103 | * The object containing the request data |
|
104 | */ |
|
105 | protected ValueParser pp; |
|
106 | ||
107 | /** |
|
108 | * A flag to help prevent duplicate hidden fields declaring this group. |
|
109 | */ |
|
110 | protected boolean isDeclared; |
|
111 | ||
112 | /** |
|
113 | * Constructs a new Group based on the xml specification. Groups are |
|
114 | * instantiated and pooled by the IntakeService and should not |
|
115 | * be instantiated otherwise. |
|
116 | * |
|
117 | * @param group a <code>XmlGroup</code> value |
|
118 | * @exception IntakeException if an error occurs in other classes |
|
119 | */ |
|
120 | public Group(XmlGroup group) throws IntakeException |
|
121 | { |
|
122 | gid = group.getKey(); |
|
123 | name = group.getName(); |
|
124 | poolCapacity = Integer.parseInt(group.getPoolCapacity()); |
|
125 | ||
126 | List inputFields = group.getFields(); |
|
127 | int size = inputFields.size(); |
|
128 | fields = new HashMap((int) (1.25 * size + 1)); |
|
129 | mapToObjectFields = new HashMap((int) (1.25 * size + 1)); |
|
130 | fieldsArray = new Field[size]; |
|
131 | for (int i = size - 1; i >= 0; i--) |
|
132 | { |
|
133 | XmlField f = (XmlField) inputFields.get(i); |
|
134 | Field field = FieldFactory.getInstance(f, this); |
|
135 | fieldsArray[i] = field; |
|
136 | fields.put(f.getName(), field); |
|
137 | ||
138 | // map fields by their mapToObject |
|
139 | List tmpFields = (List) mapToObjectFields.get(f.getMapToObject()); |
|
140 | if (tmpFields == null) |
|
141 | { |
|
142 | tmpFields = new ArrayList(size); |
|
143 | mapToObjectFields.put(f.getMapToObject(), tmpFields); |
|
144 | } |
|
145 | tmpFields.add(field); |
|
146 | } |
|
147 | ||
148 | // Change the mapToObjectFields values to Field[] |
|
149 | for (Iterator keys = mapToObjectFields.keySet().iterator(); keys.hasNext();) |
|
150 | { |
|
151 | Object key = keys.next(); |
|
152 | List tmpFields = (List) mapToObjectFields.get(key); |
|
153 | mapToObjectFields.put(key, |
|
154 | tmpFields.toArray(new Field[tmpFields.size()])); |
|
155 | } |
|
156 | } |
|
157 | ||
158 | /** |
|
159 | * Initializes the default Group using parameters. |
|
160 | * |
|
161 | * @param pp a <code>ValueParser</code> value |
|
162 | * @return this Group |
|
163 | */ |
|
164 | public Group init(ValueParser pp) throws TurbineException |
|
165 | { |
|
166 | return init(NEW, pp); |
|
167 | } |
|
168 | ||
169 | /** |
|
170 | * Initializes the Group with parameters from RunData |
|
171 | * corresponding to key. |
|
172 | * |
|
173 | * @param pp a <code>ValueParser</code> value |
|
174 | * @return this Group |
|
175 | */ |
|
176 | public Group init(String key, ValueParser pp) throws IntakeException |
|
177 | { |
|
178 | this.oid = key; |
|
179 | this.pp = pp; |
|
180 | for (int i = fieldsArray.length - 1; i >= 0; i--) |
|
181 | { |
|
182 | fieldsArray[i].init(pp); |
|
183 | } |
|
184 | return this; |
|
185 | } |
|
186 | ||
187 | /** |
|
188 | * Initializes the group with properties from an object. |
|
189 | * |
|
190 | * @param obj a <code>Persistent</code> value |
|
191 | * @return a <code>Group</code> value |
|
192 | */ |
|
193 | public Group init(Retrievable obj) |
|
194 | { |
|
195 | this.oid = obj.getQueryKey(); |
|
196 | ||
197 | Class cls = obj.getClass(); |
|
198 | while (cls != null) |
|
199 | { |
|
200 | Field[] flds = (Field[]) mapToObjectFields.get(cls.getName()); |
|
201 | if (flds != null) |
|
202 | { |
|
203 | for (int i = flds.length - 1; i >= 0; i--) |
|
204 | { |
|
205 | flds[i].init(obj); |
|
206 | } |
|
207 | } |
|
208 | ||
209 | cls = cls.getSuperclass(); |
|
210 | } |
|
211 | ||
212 | return this; |
|
213 | } |
|
214 | ||
215 | /** |
|
216 | * Gets a list of the names of the fields stored in this object. |
|
217 | * |
|
218 | * @return A String array containing the list of names. |
|
219 | */ |
|
220 | public String[] getFieldNames() |
|
221 | { |
|
222 | String nameList[] = new String[fieldsArray.length]; |
|
223 | for (int i = 0; i < nameList.length; i++) |
|
224 | { |
|
225 | nameList[i] = fieldsArray[i].name; |
|
226 | } |
|
227 | return nameList; |
|
228 | } |
|
229 | ||
230 | /** |
|
231 | * Return the name given to this group. The long name is to |
|
232 | * avoid conflicts with the get(String key) method. |
|
233 | * |
|
234 | * @return a <code>String</code> value |
|
235 | */ |
|
236 | public String getIntakeGroupName() |
|
237 | { |
|
238 | return name; |
|
239 | } |
|
240 | ||
241 | /** |
|
242 | * Get the number of Group objects that will be pooled. |
|
243 | * |
|
244 | * @return an <code>int</code> value |
|
245 | */ |
|
246 | public int getPoolCapacity() |
|
247 | { |
|
248 | return poolCapacity; |
|
249 | } |
|
250 | ||
251 | /** |
|
252 | * Get the part of the key used to specify the group. |
|
253 | * This is specified in the key attribute in the xml file. |
|
254 | * |
|
255 | * @return a <code>String</code> value |
|
256 | */ |
|
257 | public String getGID() |
|
258 | { |
|
259 | return gid; |
|
260 | } |
|
261 | ||
262 | /** |
|
263 | * Get the part of the key that distinguishes a group |
|
264 | * from others of the same name. |
|
265 | * |
|
266 | * @return a <code>String</code> value |
|
267 | */ |
|
268 | public String getOID() |
|
269 | { |
|
270 | return oid; |
|
271 | } |
|
272 | ||
273 | /** |
|
274 | * Concatenation of gid and oid. |
|
275 | * |
|
276 | * @return a <code>String</code> value |
|
277 | */ |
|
278 | public String getObjectKey() |
|
279 | { |
|
280 | return gid + oid; |
|
281 | } |
|
282 | ||
283 | /** |
|
284 | * Describe <code>getObjects</code> method here. |
|
285 | * |
|
286 | * @param pp a <code>ValueParser</code> value |
|
287 | * @return an <code>ArrayList</code> value |
|
288 | * @exception IntakeException if an error occurs |
|
289 | */ |
|
290 | public ArrayList getObjects(ValueParser pp) throws IntakeException |
|
291 | { |
|
292 | ArrayList objs = null; |
|
293 | String[] oids = pp.getStrings(gid); |
|
294 | if (oids != null) |
|
295 | { |
|
296 | objs = new ArrayList(oids.length); |
|
297 | for (int i = oids.length - 1; i >= 0; i--) |
|
298 | { |
|
299 | objs.add(TurbineIntake.getGroup(name).init(oids[i], pp)); |
|
300 | } |
|
301 | } |
|
302 | return objs; |
|
303 | } |
|
304 | ||
305 | /** |
|
306 | * Get the Field . |
|
307 | * @return Field. |
|
308 | * @throws IntakeException indicates the field could not be found. |
|
309 | */ |
|
310 | public Field get(String fieldName) |
|
311 | throws IntakeException |
|
312 | { |
|
313 | if (fields.containsKey(fieldName)) |
|
314 | { |
|
315 | return (Field) fields.get(fieldName); |
|
316 | } |
|
317 | else |
|
318 | { |
|
319 | throw new IntakeException("Intake Field name: " + fieldName + |
|
320 | " not found!"); |
|
321 | } |
|
322 | } |
|
323 | ||
324 | /** |
|
325 | * Performs an AND between all the fields in this group. |
|
326 | * |
|
327 | * @return a <code>boolean</code> value |
|
328 | */ |
|
329 | public boolean isAllValid() |
|
330 | { |
|
331 | boolean valid = true; |
|
332 | for (int i = fieldsArray.length - 1; i >= 0; i--) |
|
333 | { |
|
334 | valid &= fieldsArray[i].isValid(); |
|
335 | if (isDebugEnabled && !fieldsArray[i].isValid()) |
|
336 | { |
|
337 | log.debug("Group(" + oid + "): " + name + "; Field: " |
|
338 | + fieldsArray[i].name + "; value=" + |
|
339 | fieldsArray[i].getValue() + " is invalid!"); |
|
340 | } |
|
341 | } |
|
342 | return valid; |
|
343 | } |
|
344 | ||
345 | /** |
|
346 | * Calls a setter methods on obj, for fields which have been set. |
|
347 | * |
|
348 | * @param obj Object to be set with the values from the group. |
|
349 | * @throws IntakeException indicates that a failure occurred while |
|
350 | * executing the setter methods of the mapped object. |
|
351 | */ |
|
352 | public void setProperties(Object obj) throws IntakeException |
|
353 | { |
|
354 | Class cls = obj.getClass(); |
|
355 | ||
356 | while (cls != null) |
|
357 | { |
|
358 | if (isDebugEnabled) |
|
359 | { |
|
360 | log.debug("setProperties(" + cls.getName() + ")"); |
|
361 | } |
|
362 | ||
363 | Field[] flds = (Field[]) mapToObjectFields.get(cls.getName()); |
|
364 | if (flds != null) |
|
365 | { |
|
366 | for (int i = flds.length - 1; i >= 0; i--) |
|
367 | { |
|
368 | flds[i].setProperty(obj); |
|
369 | } |
|
370 | } |
|
371 | ||
372 | cls = cls.getSuperclass(); |
|
373 | } |
|
374 | log.debug("setProperties() finished"); |
|
375 | } |
|
376 | ||
377 | /** |
|
378 | * Calls a setter methods on obj, for fields which pass validity tests. |
|
379 | * In most cases one should call Intake.isAllValid() and then if that |
|
380 | * test passes call setProperties. Use this method when some data is |
|
381 | * known to be invalid, but you still want to set the object properties |
|
382 | * that are valid. |
|
383 | */ |
|
384 | public void setValidProperties(Object obj) |
|
385 | { |
|
386 | Class cls = obj.getClass(); |
|
387 | while (cls != null) |
|
388 | { |
|
389 | Field[] flds = (Field[]) mapToObjectFields.get(cls.getName()); |
|
390 | if (flds != null) |
|
391 | { |
|
392 | for (int i = flds.length - 1; i >= 0; i--) |
|
393 | { |
|
394 | try |
|
395 | { |
|
396 | flds[i].setProperty(obj); |
|
397 | } |
|
398 | catch (Exception e) |
|
399 | { |
|
400 | // just move on to next field |
|
401 | } |
|
402 | } |
|
403 | } |
|
404 | ||
405 | cls = cls.getSuperclass(); |
|
406 | } |
|
407 | } |
|
408 | ||
409 | /** |
|
410 | * Calls getter methods on objects that are known to Intake |
|
411 | * so that field values in forms can be initialized from |
|
412 | * the values contained in the intake tool. |
|
413 | * |
|
414 | * @param obj Object that will be used to as a source of data for |
|
415 | * setting the values of the fields within the group. |
|
416 | * @throws IntakeException indicates that a failure occurred while |
|
417 | * executing the setter methods of the mapped object. |
|
418 | */ |
|
419 | public void getProperties(Object obj) throws IntakeException |
|
420 | { |
|
421 | Class cls = obj.getClass(); |
|
422 | while (cls != null) |
|
423 | { |
|
424 | Field[] flds = (Field[]) mapToObjectFields.get(cls.getName()); |
|
425 | if (flds != null) |
|
426 | { |
|
427 | for (int i = flds.length - 1; i >= 0; i--) |
|
428 | { |
|
429 | flds[i].getProperty(obj); |
|
430 | } |
|
431 | } |
|
432 | ||
433 | cls = cls.getSuperclass(); |
|
434 | } |
|
435 | } |
|
436 | ||
437 | /** |
|
438 | * Removes references to this group and its fields from the |
|
439 | * query parameters |
|
440 | */ |
|
441 | public void removeFromRequest() |
|
442 | { |
|
443 | if (pp != null) |
|
444 | { |
|
445 | String[] groups = pp.getStrings(gid); |
|
446 | if (groups != null) |
|
447 | { |
|
448 | pp.remove(gid); |
|
449 | for (int i = 0; i < groups.length; i++) |
|
450 | { |
|
451 | if (groups[i] != null && !groups[i].equals(oid)) |
|
452 | { |
|
453 | pp.add(gid, groups[i]); |
|
454 | } |
|
455 | } |
|
456 | for (int i = fieldsArray.length - 1; i >= 0; i--) |
|
457 | { |
|
458 | fieldsArray[i].removeFromRequest(); |
|
459 | } |
|
460 | } |
|
461 | } |
|
462 | } |
|
463 | ||
464 | /** |
|
465 | * To be used in the event this group is used within multiple |
|
466 | * forms within the same template. |
|
467 | */ |
|
468 | public void resetDeclared() |
|
469 | { |
|
470 | isDeclared = false; |
|
471 | } |
|
472 | ||
473 | /** |
|
474 | * A xhtml valid hidden input field that notifies intake of the |
|
475 | * group's presence. |
|
476 | * |
|
477 | * @return a <code>String</code> value |
|
478 | */ |
|
479 | public String getHtmlFormInput() |
|
480 | { |
|
481 | StringBuffer sb = new StringBuffer(64); |
|
482 | appendHtmlFormInput(sb); |
|
483 | return sb.toString(); |
|
484 | } |
|
485 | ||
486 | /** |
|
487 | * A xhtml valid hidden input field that notifies intake of the |
|
488 | * group's presence. |
|
489 | */ |
|
490 | public void appendHtmlFormInput(StringBuffer sb) |
|
491 | { |
|
492 | if (!isDeclared) |
|
493 | { |
|
494 | isDeclared = true; |
|
495 | sb.append("<input type=\"hidden\" name=\"") |
|
496 | .append(gid) |
|
497 | .append("\" value=\"") |
|
498 | .append(oid) |
|
499 | .append("\"/>\n"); |
|
500 | } |
|
501 | } |
|
502 | ||
503 | // ********** PoolableObjectFactory implementation ****************** |
|
504 | ||
505 | public static class GroupFactory |
|
506 | extends BaseKeyedPoolableObjectFactory |
|
507 | { |
|
508 | private AppData appData; |
|
509 | ||
510 | public GroupFactory(AppData appData) |
|
511 | 0 | { |
512 | 0 | this.appData = appData; |
513 | 0 | } |
514 | ||
515 | /** |
|
516 | * Creates an instance that can be returned by the pool. |
|
517 | * @return an instance that can be returned by the pool. |
|
518 | * @throws IntakeException indicates that the group could not be retreived |
|
519 | */ |
|
520 | public Object makeObject(Object key) throws IntakeException |
|
521 | { |
|
522 | 0 | return new Group(appData.getGroup((String) key)); |
523 | } |
|
524 | ||
525 | /** |
|
526 | * Uninitialize an instance to be returned to the pool. |
|
527 | * @param obj the instance to be passivated |
|
528 | */ |
|
529 | public void passivateObject(Object key, Object obj) |
|
530 | { |
|
531 | 0 | Group group = (Group) obj; |
532 | 0 | group.oid = null; |
533 | 0 | group.pp = null; |
534 | 0 | for (int i = group.fieldsArray.length - 1; i >= 0; i--) |
535 | { |
|
536 | 0 | group.fieldsArray[i].dispose(); |
537 | } |
|
538 | 0 | group.isDeclared = false; |
539 | 0 | } |
540 | } |
|
541 | } |
|
542 | ||
543 |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |