View Javadoc

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