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 }