##### Coverage Report - org.apache.turbine.services.intake.IntakeTool

Classes in this File | Line Coverage | Branch Coverage | Complexity
IntakeTool |
31% | 35/110
22% | 11/48
| 2.4166666666666665;2,417
IntakeTool$PullHelper |
45% | 11/24
33% | 2/6
| 2.4166666666666665;2,417

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