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