View Javadoc

1   package org.apache.turbine.services.intake;
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.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         // empty
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     // ****************** Recyclable implementation ************************
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 }