View Javadoc

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