1 package org.apache.turbine.services.intake;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import org.apache.turbine.om.Retrievable;
28 import org.apache.turbine.services.intake.model.Group;
29 import org.apache.turbine.services.pull.ApplicationTool;
30 import org.apache.turbine.util.RunData;
31 import org.apache.turbine.util.TurbineException;
32 import org.apache.turbine.util.parser.ValueParser;
33 import org.apache.turbine.util.pool.Recyclable;
34
35 /***
36 * The main class through which Intake is accessed.
37 *
38 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
39 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
40 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
41 * @version $Id: IntakeTool.java 264148 2005-08-29 14:21:04Z henning $
42 */
43 public class IntakeTool
44 implements ApplicationTool, Recyclable
45 {
46 /*** Used for logging */
47 private static Log log = LogFactory.getLog(IntakeTool.class);
48
49 /*** Constant for default key */
50 public static final String DEFAULT_KEY = "_0";
51
52 /*** Constant for the hidden fieldname */
53 public static final String INTAKE_GRP = "intake-grp";
54
55 /*** Groups from intake.xml */
56 private HashMap groups;
57
58 /*** ValueParser instance */
59 private ValueParser pp;
60
61 HashMap declaredGroups = new HashMap();
62 StringBuffer allGroupsSB = new StringBuffer(256);
63 StringBuffer groupSB = new StringBuffer(128);
64
65 /*** The cache of PullHelpers. **/
66 private Map pullMap;
67
68 /***
69 * Constructor
70 */
71 public IntakeTool()
72 {
73 String[] groupNames = TurbineIntake.getGroupNames();
74 int groupCount = 0;
75 if (groupNames != null)
76 {
77 groupCount = groupNames.length;
78 }
79 groups = new HashMap((int) (1.25 * groupCount + 1));
80 pullMap = new HashMap((int) (1.25 * groupCount + 1));
81
82 for (int i = groupCount - 1; i >= 0; i--)
83 {
84 pullMap.put(groupNames[i], new PullHelper(groupNames[i]));
85 }
86 }
87
88 /***
89 * Prepares intake for a single request
90 */
91 public void init(Object runData)
92 {
93 this.pp = ((RunData) runData).getParameters();
94
95 String[] groupKeys = pp.getStrings(INTAKE_GRP);
96 String[] groupNames = null;
97 if (groupKeys == null || groupKeys.length == 0)
98 {
99 groupNames = TurbineIntake.getGroupNames();
100 }
101 else
102 {
103 groupNames = new String[groupKeys.length];
104 for (int i = groupKeys.length - 1; i >= 0; i--)
105 {
106 groupNames[i] = TurbineIntake.getGroupName(groupKeys[i]);
107 }
108
109 }
110
111 for (int i = groupNames.length - 1; i >= 0; i--)
112 {
113 try
114 {
115 List foundGroups = TurbineIntake.getGroup(groupNames[i])
116 .getObjects(pp);
117
118 if (foundGroups != null)
119 {
120 for (Iterator iter = foundGroups.iterator();
121 iter.hasNext();)
122 {
123 Group group = (Group) iter.next();
124 groups.put(group.getObjectKey(), group);
125 }
126 }
127 }
128 catch (Exception e)
129 {
130 log.error(e);
131 }
132 }
133 }
134
135 public void addGroupsToParameters(ValueParser vp)
136 {
137 for (Iterator i = groups.values().iterator(); i.hasNext();)
138 {
139 Group group = (Group) i.next();
140 if (!declaredGroups.containsKey(group.getIntakeGroupName()))
141 {
142 declaredGroups.put(group.getIntakeGroupName(), null);
143 vp.add("intake-grp", group.getGID());
144 }
145 vp.add(group.getGID(), group.getOID());
146 }
147 declaredGroups.clear();
148 }
149
150 /***
151 * A convenience method to write out the hidden form fields
152 * that notify intake of the relevant groups. It should be used
153 * only in templates with 1 form. In multiform templates, the groups
154 * that are relevant for each form need to be declared using
155 * $intake.newForm() and $intake.declareGroup($group) for the relevant
156 * groups in the form.
157 *
158 */
159 public String declareGroups()
160 {
161 allGroupsSB.setLength(0);
162 for (Iterator i = groups.values().iterator(); i.hasNext();)
163 {
164 declareGroup((Group) i.next(), allGroupsSB);
165 }
166 return allGroupsSB.toString();
167 }
168
169 /***
170 * A convenience method to write out the hidden form fields
171 * that notify intake of the group.
172 */
173 public String declareGroup(Group group)
174 {
175 groupSB.setLength(0);
176 declareGroup(group, groupSB);
177 return groupSB.toString();
178 }
179
180 /***
181 * xhtml valid hidden input field(s) that notifies intake of the
182 * group's presence.
183 */
184 public void declareGroup(Group group, StringBuffer sb)
185 {
186 if (!declaredGroups.containsKey(group.getIntakeGroupName()))
187 {
188 declaredGroups.put(group.getIntakeGroupName(), null);
189 sb.append("<input type=\"hidden\" name=\"")
190 .append(INTAKE_GRP)
191 .append("\" value=\"")
192 .append(group.getGID())
193 .append("\"/>\n");
194 }
195 group.appendHtmlFormInput(sb);
196 }
197
198 public void newForm()
199 {
200 declaredGroups.clear();
201 for (Iterator i = groups.values().iterator(); i.hasNext();)
202 {
203 ((Group) i.next()).resetDeclared();
204 }
205 }
206
207 /***
208 * Implementation of ApplicationTool interface is not needed for this
209 * tool as it is request scoped
210 */
211 public void refresh()
212 {
213
214 }
215
216 /***
217 * Inner class to present a nice interface to the template designer
218 */
219 public class PullHelper
220 {
221 /*** Name of the group used by the pull helper */
222 String groupName;
223
224 /***
225 * Private constructor to force use of factory method.
226 *
227 * @param groupName
228 */
229 private PullHelper(String groupName)
230 {
231 this.groupName = groupName;
232 }
233
234 /***
235 * Populates the object with the default values from the XML File
236 *
237 * @return a Group object with the default values
238 * @throws IntakeException
239 */
240 public Group getDefault()
241 throws IntakeException
242 {
243 return setKey(DEFAULT_KEY);
244 }
245
246 /***
247 * Calls setKey(key,true)
248 *
249 * @param key
250 * @return an Intake Group
251 * @throws IntakeException
252 */
253 public Group setKey(String key)
254 throws IntakeException
255 {
256 return setKey(key, true);
257 }
258
259 /***
260 *
261 * @param key
262 * @param create
263 * @return an Intake Group
264 * @throws IntakeException
265 */
266 public Group setKey(String key, boolean create)
267 throws IntakeException
268 {
269 Group g = null;
270
271 String inputKey = TurbineIntake.getGroupKey(groupName) + key;
272 if (groups.containsKey(inputKey))
273 {
274 g = (Group) groups.get(inputKey);
275 }
276 else if (create)
277 {
278 g = TurbineIntake.getGroup(groupName);
279 groups.put(inputKey, g);
280 g.init(key, pp);
281 }
282
283 return g;
284 }
285
286 /***
287 * maps an Intake Group to the values from a Retrievable object.
288 *
289 * @param obj A retrievable object
290 * @return an Intake Group
291 */
292 public Group mapTo(Retrievable obj)
293 throws IntakeException
294 {
295 Group g = null;
296
297 try
298 {
299 String inputKey = TurbineIntake.getGroupKey(groupName)
300 + obj.getQueryKey();
301 if (groups.containsKey(inputKey))
302 {
303 g = (Group) groups.get(inputKey);
304 }
305 else
306 {
307 g = TurbineIntake.getGroup(groupName);
308 groups.put(inputKey, g);
309 }
310 return g.init(obj);
311 }
312 catch (Exception e)
313 {
314 log.error(e);
315 }
316
317 return null;
318 }
319 }
320
321 /***
322 * get a specific group
323 */
324 public PullHelper get(String groupName)
325 throws IntakeException
326 {
327 return (PullHelper) pullMap.get(groupName);
328 }
329
330 /***
331 * Get a specific group
332 *
333 * @param throwExceptions if false, exceptions will be supressed.
334 * @throws IntakeException could not retrieve group
335 */
336 public PullHelper get(String groupName, boolean throwExceptions)
337 throws IntakeException
338 {
339 return (PullHelper) pullMap.get(groupName);
340 }
341
342 /***
343 * Loops through all of the Groups and checks to see if
344 * the data within the Group is valid.
345 */
346 public boolean isAllValid()
347 {
348 boolean allValid = true;
349 for (Iterator iter = groups.values().iterator(); iter.hasNext();)
350 {
351 Group group = (Group) iter.next();
352 allValid &= group.isAllValid();
353 }
354 return allValid;
355 }
356
357 /***
358 * Get a specific group by name and key.
359 */
360 public Group get(String groupName, String key)
361 throws IntakeException
362 {
363 if (groupName == null)
364 {
365 throw new IntakeException("Intake.get: groupName == null");
366 }
367 if (key == null)
368 {
369 throw new IntakeException("Intake.get: key == null");
370 }
371
372 PullHelper ph = get(groupName);
373 return (ph == null) ? null : ph.setKey(key);
374 }
375
376 /***
377 * Get a specific group by name and key. Also specify
378 * whether or not you want to create a new group.
379 */
380 public Group get(String groupName, String key, boolean create)
381 throws IntakeException
382 {
383 if (groupName == null)
384 {
385 throw new IntakeException("Intake.get: groupName == null");
386 }
387 if (key == null)
388 {
389 throw new IntakeException("Intake.get: key == null");
390 }
391
392 PullHelper ph = get(groupName);
393 return (ph == null) ? null : ph.setKey(key, create);
394 }
395
396 /***
397 * Removes group. Primary use is to remove a group that has
398 * been processed by an action and is no longer appropriate
399 * in the view (screen).
400 */
401 public void remove(Group group)
402 {
403 if (group != null)
404 {
405 groups.remove(group.getObjectKey());
406 group.removeFromRequest();
407
408 String[] groupKeys = pp.getStrings(INTAKE_GRP);
409
410 pp.remove(INTAKE_GRP);
411
412 if (groupKeys != null)
413 {
414 for (int i = 0; i < groupKeys.length; i++)
415 {
416 if (!groupKeys[i].equals(group.getGID()))
417 {
418 pp.add(INTAKE_GRP, groupKeys[i]);
419 }
420 }
421 }
422
423 try
424 {
425 TurbineIntake.releaseGroup(group);
426 }
427 catch (TurbineException se)
428 {
429 log.error("Tried to release unknown group "
430 + group.getIntakeGroupName());
431 }
432 }
433 }
434
435 /***
436 * Removes all groups. Primary use is to remove groups that have
437 * been processed by an action and are no longer appropriate
438 * in the view (screen).
439 */
440 public void removeAll()
441 {
442 Object[] allGroups = groups.values().toArray();
443 for (int i = allGroups.length - 1; i >= 0; i--)
444 {
445 Group group = (Group) allGroups[i];
446 remove(group);
447 }
448 }
449
450 /***
451 * Get a Map containing all the groups.
452 *
453 * @return the Group Map
454 */
455 public Map getGroups()
456 {
457 return groups;
458 }
459
460
461
462 private boolean disposed;
463
464 /***
465 * Recycles the object for a new client. Recycle methods with
466 * parameters must be added to implementing object and they will be
467 * automatically called by pool implementations when the object is
468 * taken from the pool for a new client. The parameters must
469 * correspond to the parameters of the constructors of the object.
470 * For new objects, constructors can call their corresponding recycle
471 * methods whenever applicable.
472 * The recycle methods must call their super.
473 */
474 public void recycle()
475 {
476 disposed = false;
477 }
478
479 /***
480 * Disposes the object after use. The method is called
481 * when the object is returned to its pool.
482 * The dispose method must call its super.
483 */
484 public void dispose()
485 {
486 for (Iterator iter = groups.values().iterator(); iter.hasNext();)
487 {
488 Group g = (Group) iter.next();
489
490 try
491 {
492 TurbineIntake.releaseGroup(g);
493 }
494 catch (TurbineException se)
495 {
496 log.error("Tried to release unknown group "
497 + g.getIntakeGroupName());
498 }
499 }
500
501 groups.clear();
502 declaredGroups.clear();
503 pp = null;
504
505 disposed = true;
506 }
507
508 /***
509 * Checks whether the recyclable has been disposed.
510 *
511 * @return true, if the recyclable is disposed.
512 */
513 public boolean isDisposed()
514 {
515 return disposed;
516 }
517 }