2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

Coverage Report - org.apache.shale.usecases.rolodex.Rolodex
 
Classes in this File Line Coverage Branch Coverage Complexity
Rolodex
100%
130/130
N/A
2
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to you under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.shale.usecases.rolodex;
 19  
 
 20  
 import java.io.UnsupportedEncodingException;
 21  
 import java.net.URLDecoder;
 22  
 import java.util.List;
 23  
 
 24  
 import javax.faces.context.FacesContext;
 25  
 import javax.faces.model.SelectItem;
 26  
 
 27  
 import org.apache.commons.logging.Log;
 28  
 import org.apache.commons.logging.LogFactory;
 29  
 import org.apache.shale.clay.config.beans.AttributeBean;
 30  
 import org.apache.shale.clay.config.beans.ComponentBean;
 31  
 import org.apache.shale.clay.config.beans.ElementBean;
 32  
 import org.apache.shale.view.AbstractViewController;
 33  
 
 34  
 /**
 35  
  * <p>
 36  
  * The ViewController for the rolodex use case. This is a contacts list that is
 37  
  * to demonstrate the reuse ability for the Clay component.
 38  
  * </p>
 39  
  * 
 40  
  */
 41  5
 public class Rolodex extends AbstractViewController {
 42  
 
 43  
     /**
 44  
      * <p>
 45  
      * Commons logging utility object static instance.
 46  
      * </p>
 47  
      */
 48  
     private static Log log;
 49  
     static {
 50  2
         log = LogFactory.getLog(Rolodex.class);
 51  1
     }
 52  
 
 53  
     /**
 54  
      * <p>
 55  
      * The the selected tab index.
 56  
      * </p>
 57  
      */
 58  5
     private int selectedTab = 0;
 59  
 
 60  
     /**
 61  
      * <p>
 62  
      * Returns the current tab index.
 63  
      * </p>
 64  
      */
 65  
     public int getSelectedTab() {
 66  22
         return selectedTab;
 67  
     }
 68  
 
 69  
     /**
 70  
      * <p>
 71  
      * The contact that is selected for edit.
 72  
      * </p>
 73  
      */
 74  5
     private Contact selectedContact = null;
 75  
 
 76  
     /**
 77  
      * <p>
 78  
      * Returns the selected contact for edit.
 79  
      * </p>
 80  
      */
 81  
     public Contact getSelectedContact() {
 82  41
         return selectedContact;
 83  
     }
 84  
 
 85  
     /**
 86  
      * <p>
 87  
      * Sets the selected contact for edit.
 88  
      * </p>
 89  
      */
 90  
     public void setSelectedContact(Contact contact) {
 91  46
         selectedContact = contact;
 92  46
     }
 93  
 
 94  
     /**
 95  
      * <p>
 96  
      * Records a change in tab index.
 97  
      * </p>
 98  
      */
 99  
     public void setSelectedTab(int index) {
 100  21
         if (log.isInfoEnabled())
 101  21
             log.info("Switching from tab " + selectedTab + " to tab " + index);
 102  
 
 103  21
         selectedTab = index;
 104  21
         contacts = null;
 105  21
     }
 106  
 
 107  
     /**
 108  
      * <p>
 109  
      * Creates an object graph uses to build the rolodex folder tabs dynamically.
 110  
      * </p>
 111  
      * 
 112  
      * @param item -
 113  
      *            SelectItem holding the information to create the tab link
 114  
      * @param context -
 115  
      *            FacesContext
 116  
      * @return returns a top level clay meta component bean
 117  
      */
 118  
     protected ElementBean createCommandLinkMetadata(SelectItem item,
 119  
             FacesContext context) {
 120  
 
 121  
         // create a command link attribute
 122  9
         ElementBean link = new ElementBean();
 123  9
         link.setRenderId(generateId());
 124  9
         link.setJsfid("commandLink");
 125  9
         link.setComponentType("javax.faces.HtmlCommandLink");
 126  
 
 127  
         // add a value attribute
 128  9
         AttributeBean attr = new AttributeBean();
 129  9
         attr.setName("value");
 130  9
         attr.setValue(item.getLabel());
 131  9
         link.addAttribute(attr);
 132  
 
 133  
         // turn on the the immediate attribute so the validation
 134  
         // logic is not invoked when switching tabs
 135  9
         attr = new AttributeBean();
 136  9
         attr.setName("immediate");
 137  9
         attr.setValue("true");
 138  9
         link.addAttribute(attr);
 139  
 
 140  
         // add a action method binding event when the link is clicked
 141  9
         attr = new AttributeBean();
 142  9
         attr.setName("action");
 143  9
         attr.setValue("#{@managed-bean-name.changeTab}");
 144  9
         link.addAttribute(attr);
 145  
 
 146  
         // create a parameter
 147  9
         ElementBean param = new ElementBean();
 148  9
         param.setJsfid("param");
 149  9
         param.setComponentType("javax.faces.Parameter");
 150  
         // RenderId is the key to the Map. Increment for each new parameter
 151  9
         param.setRenderId(generateId());
 152  
 
 153  
         
 154  
         // add a query param for the selected tab index
 155  9
         attr = new AttributeBean();
 156  9
         attr.setName("name");
 157  9
         attr.setValue("tabIndex");
 158  9
         param.addAttribute(attr);
 159  
 
 160  
         // add a query parameter for the tab index
 161  9
         attr = new AttributeBean();
 162  9
         attr.setName("value");
 163  9
         attr.setValue(((Integer) item.getValue()).toString());
 164  9
         param.addAttribute(attr);
 165  
 
 166  
         // add a parameter to the commandLink
 167  9
         link.addChild(param);
 168  
 
 169  9
         return link;
 170  
     }
 171  
 
 172  
     /**
 173  
      * <p>
 174  
      * A sequential counter to generate a unique renderId.
 175  
      * </p>
 176  
      */
 177  5
     int renderId = 0;
 178  
 
 179  
     /**
 180  
      * <p>
 181  
      * Returns the next sequential renderId. Because the logic builds the list
 182  
      * in a linear fashion, a sequential unintelligent counter works.
 183  
      * </p>
 184  
      */
 185  
     private int generateId() {
 186  65
         return renderId++;
 187  
     }
 188  
 
 189  
     /**
 190  
      * <p>
 191  
      * This method builds a verbatim meta tag. It is passed a "rendered"
 192  
      * expression that will be evaluated to determine if the component is
 193  
      * visible.
 194  
      * </p>
 195  
      * 
 196  
      * @param html
 197  
      *            The HTML tag to write to the document
 198  
      * @param renderExp
 199  
      *            A value binding EL for the "rendered" attribute.
 200  
      * @param context
 201  
      *            faces context
 202  
      * @return A clay element bean used to construct a faces outputText
 203  
      *         component.
 204  
      */
 205  
     protected ElementBean createVerbatimMetadata(String html, String renderExp,
 206  
             FacesContext context) {
 207  18
         ElementBean text = createVerbatimMetadata(html, context);
 208  
 
 209  
         // add a rendered attribute
 210  18
         AttributeBean attr = new AttributeBean();
 211  18
         attr.setName("rendered");
 212  18
         attr.setValue(renderExp);
 213  18
         attr.setBindingType(AttributeBean.BINDING_TYPE_VALUE);
 214  18
         text.addAttribute(attr);
 215  
 
 216  18
         return text;
 217  
 
 218  
     }
 219  
 
 220  
     /**
 221  
      * <p>
 222  
      * This mehtod builds a simple verbatim meta tag. The value will not be
 223  
      * escaped.
 224  
      * <p>
 225  
      * 
 226  
      * @param html
 227  
      *            HTML tag to write to the document
 228  
      * @param context -
 229  
      *            faces context
 230  
      * @return A clay element bean used to construct a faces outputText
 231  
      *         component.
 232  
      */
 233  
     protected ElementBean createVerbatimMetadata(String html,
 234  
             FacesContext context) {
 235  
 
 236  
         // create an output Text
 237  47
         ElementBean text = new ElementBean();
 238  47
         text.setRenderId(generateId());
 239  47
         text.setJsfid("f:verbatim");
 240  47
         text.setComponentType("javax.faces.HtmlOutputText");
 241  
              
 242  
         // add a value attribute
 243  47
         AttributeBean attr = new AttributeBean();
 244  47
         attr.setName("value");
 245  47
         attr.setValue(html);
 246  47
         text.addAttribute(attr);
 247  
 
 248  
         // add a escape attribute
 249  47
         attr = new AttributeBean();
 250  47
         attr.setName("escape");
 251  47
         attr.setValue(Boolean.FALSE.toString());
 252  47
         text.addAttribute(attr);
 253  
         
 254  
         // add a isTransient attribute
 255  47
         attr = new AttributeBean();
 256  47
         attr.setName("isTransient");
 257  47
         attr.setValue(Boolean.TRUE.toString());
 258  47
         text.addAttribute(attr);
 259  
 
 260  47
         return text;
 261  
     }
 262  
 
 263  
     /**
 264  
      * <p>
 265  
      * This action event is fired when clicking on a tab link. The
 266  
      * <code>selectedTab</code> is set with the value of the
 267  
      * <code>tabIndex</code> request parameter.
 268  
      * </p>
 269  
      */
 270  
     public String changeTab() {
 271  9
         if (log.isInfoEnabled())
 272  9
             log.info("changeTab()");
 273  
         
 274  9
         QueryParam paramObj = (QueryParam) getBean("queryParam");
 275  9
         String tabIndex = paramObj.getTabIndex();
 276  
         
 277  9
         if (tabIndex != null) {
 278  9
             setSelectedTab(Integer.parseInt(tabIndex));
 279  
 
 280  
             // clear out the selected contact
 281  9
             setSelectedContact(null);
 282  
         }
 283  
 
 284  9
         return "rolodex$test";
 285  
     }
 286  
 
 287  
     /**
 288  
      * <p>
 289  
      * This is a method binding event fired from the <strong>Clay</strong>
 290  
      * component before building the component tree. The method signature is a
 291  
      * "Validator" event signature and the binding attribute is
 292  
      * <code>shapeValidator</code>.
 293  
      * </p>
 294  
      * 
 295  
      * @param context
 296  
      *            facesContext
 297  
      * @param component
 298  
      * @param displayElementRoot
 299  
      */
 300  
     public void createTabs(javax.faces.context.FacesContext context,
 301  
             javax.faces.component.UIComponent component,
 302  
             java.lang.Object displayElementRoot) {
 303  
 
 304  1
         if (log.isInfoEnabled())
 305  1
             log.info("createTabs()");
 306  
 
 307  
         // find the dao cached in application scope
 308  1
         RolodexDao dao = (RolodexDao) getBean("rolodexDao");
 309  
 
 310  
         // return a list of tabs
 311  1
         List tabs = dao.getTabs();
 312  
 
 313  1
         ComponentBean root = (ComponentBean) displayElementRoot;
 314  1
         root.setComponentType("javax.faces.HtmlPanelGroup");
 315  1
         root.addChild(createVerbatimMetadata("<ul id=\"menu\">", context));
 316  
 
 317  10
         for (int i = 0; i < tabs.size(); i++) {
 318  9
             SelectItem item = (SelectItem) tabs.get(i);
 319  
 
 320  9
             root.addChild(createVerbatimMetadata("<li id=\"", context));
 321  
 
 322  9
             root.addChild(createVerbatimMetadata("nav-sel",
 323  
                     "#{@managed-bean-name.selectedTab == " + i + "}", context));
 324  9
             root.addChild(createVerbatimMetadata("nav",
 325  
                     "#{@managed-bean-name.selectedTab != " + i + "}", context));
 326  
 
 327  9
             root.addChild(createVerbatimMetadata("\">", context));
 328  9
             root.addChild(createCommandLinkMetadata(item, context));
 329  9
             root.addChild(createVerbatimMetadata("</li>", context));
 330  
         }
 331  
 
 332  1
         root.addChild(createVerbatimMetadata("</ul>", context));
 333  
 
 334  1
     }
 335  
 
 336  
     /**
 337  
      * <p>Caches the current contacts.</p>
 338  
      */
 339  5
     private List contacts = null;
 340  
     
 341  
     /**
 342  
      * <p>
 343  
      * This is called by the data table component to return a list of
 344  
      * {@link Contact}s that belong within the selected index.
 345  
      * </p>
 346  
      */
 347  
     public List getContactsForTab() {
 348  12
         if (log.isInfoEnabled())
 349  12
             log.info("getContactsForTab()");
 350  
 
 351  12
         if (contacts == null) {
 352  
             // find the dao cached in application scope
 353  12
             RolodexDao dao = (RolodexDao) getBean("rolodexDao");
 354  
             
 355  
             // gets a list of contacts matching the selected tab index
 356  12
             contacts = dao.findContactsForTab(getSelectedTab());
 357  
         }
 358  
         
 359  12
         return contacts;
 360  
     }
 361  
 
 362  
         
 363  
     /**
 364  
      * <p>
 365  
      * This is an action event fired from clicking on a contact in the data
 366  
      * grid. The latest contact is located using the data access object and is
 367  
      * set as the "select" contact.
 368  
      * </p>
 369  
      */
 370  
     public String selectContact() {
 371  13
         if (log.isInfoEnabled())
 372  13
             log.info("selectContact()");
 373  
 
 374  
         // look for the commandLink query parameter
 375  13
         QueryParam paramObj = (QueryParam) getBean("queryParam");
 376  13
         String name = paramObj.getSelectedName();
 377  
         
 378  13
         if (name != null) {
 379  
             // find the dao cached in application scope
 380  13
             RolodexDao dao = (RolodexDao) getBean("rolodexDao");
 381  
 
 382  
             //decode value 
 383  
             try {
 384  13
                 name = URLDecoder.decode(name, "UTF-8");
 385  13
             } catch (UnsupportedEncodingException e) {}
 386  
             
 387  
             // finds the selected contact by name
 388  13
             setSelectedContact(dao.findContact(name));
 389  
         }
 390  
 
 391  13
         return "rolodex$test";
 392  
     }
 393  
 
 394  
     /**
 395  
      * <p>
 396  
      * Saves a {@link Contact} to the mock data store.
 397  
      * </p>
 398  
      */
 399  
     public String saveContact() {
 400  1
         if (log.isInfoEnabled())
 401  1
             log.info("saveContact()");
 402  
 
 403  1
         if (getSelectedContact() != null) {
 404  1
             RolodexDao dao = (RolodexDao) getBean("rolodexDao");
 405  
             // the saveContact method will return the page the 
 406  
             // new contact will appear
 407  1
             setSelectedTab(dao.saveContact(getSelectedContact()));
 408  
         }
 409  
 
 410  1
         return "rolodex$test";
 411  
     }
 412  
 
 413  
     /**
 414  
      * <p>
 415  
      * Removes a {@link Contact} from the mock data store.
 416  
      * </p>
 417  
      */
 418  
     public String deleteContact() {
 419  1
         if (log.isInfoEnabled())
 420  1
             log.info("deleteContact()");
 421  
 
 422  1
         if (getSelectedContact() != null) {
 423  1
             RolodexDao dao = (RolodexDao) getBean("rolodexDao");
 424  1
             dao.deleteContact(getSelectedContact());
 425  1
             setSelectedContact(null);
 426  1
             contacts = null;
 427  
         }
 428  
 
 429  1
         return "rolodex$test";
 430  
     }
 431  
 
 432  
     /**
 433  
      * <p>
 434  
      * Creates a new {@link Contact} instance to be entered and saved.
 435  
      * </p>
 436  
      */
 437  
     public String newContact() {
 438  1
        if (log.isInfoEnabled())
 439  1
            log.info("newContact()");
 440  
                
 441  1
         setSelectedContact(new Contact());
 442  
         
 443  1
         return "rolodex$test";
 444  
     }
 445  
 
 446  
 }