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

For more information, please explore the Attic.

Coverage Report - org.apache.shale.clay.parser.builder.ElementBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
ElementBuilder
100%
113/113
N/A
3.286
 
 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  
 /*
 19  
  * $Id: ElementBuilder.java 471910 2006-11-06 22:44:56Z gvanmatre $
 20  
  */
 21  
 package org.apache.shale.clay.parser.builder;
 22  
 
 23  
 import java.util.ArrayList;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 
 27  
 import org.apache.commons.logging.Log;
 28  
 import org.apache.commons.logging.LogFactory;
 29  
 import org.apache.shale.clay.config.beans.ActionListenerBean;
 30  
 import org.apache.shale.clay.config.beans.AttributeBean;
 31  
 import org.apache.shale.clay.config.beans.ComponentBean;
 32  
 import org.apache.shale.clay.config.beans.ConfigBean;
 33  
 import org.apache.shale.clay.config.beans.ConfigBeanFactory;
 34  
 import org.apache.shale.clay.config.beans.ConverterBean;
 35  
 import org.apache.shale.clay.config.beans.ElementBean;
 36  
 import org.apache.shale.clay.config.beans.SymbolBean;
 37  
 import org.apache.shale.clay.config.beans.ValidatorBean;
 38  
 import org.apache.shale.clay.config.beans.ValueChangeListenerBean;
 39  
 import org.apache.shale.clay.parser.Node;
 40  
 
 41  
 /**
 42  
  * <p>This class handles building the {@link org.apache.shale.clay.config.beans.ElementBean}'s
 43  
  * from the html markup resembling the &lt;attributes&gt; node in the clay
 44  
  * DTD, http://shale.apache.org/dtds/clay-config_1_0.dtd.</p>
 45  
  */
 46  212
 public class ElementBuilder extends Builder {
 47  
 
 48  
     /**
 49  
      * <p>Common Logger utility class.</p>
 50  
      */
 51  
     private static Log log;
 52  
     static {
 53  2
         log = LogFactory.getLog(ElementBuilder.class);
 54  1
     }
 55  
 
 56  
 
 57  
     /**
 58  
      * <p>Returns the <code>jsfid</code> from the target HTML
 59  
      * {@link org.apache.shale.clay.parser.Node}.</p>
 60  
      *
 61  
      * @param node markup
 62  
      * @return jsfid
 63  
      */
 64  
     protected String getJsfid(Node node) {
 65  38
         String jsfid = (String) node.getAttributes().get("jsfid");
 66  38
         return jsfid;
 67  
     }
 68  
 
 69  
     /**
 70  
      * <p>Returns the <code>componentType</code> from the target HTML
 71  
      * {@link org.apache.shale.clay.parser.Node}.</p>
 72  
      *
 73  
      * @param node markup
 74  
      * @return component type
 75  
      */
 76  
     protected String getComponentType(Node node) {
 77  34
         String componentType = (String) node.getAttributes().get("componentType");
 78  34
         return componentType;
 79  
     }
 80  
 
 81  
     /**
 82  
      * <p>Adds a {@link org.apache.shale.clay.config.beans.ConverterBean}
 83  
      * to the <code>target</code> {@link org.apache.shale.clay.config.beans.ElementBean}
 84  
      * using the {@link org.apache.shale.clay.parser.Node} as the input source.</p>
 85  
      *
 86  
      * @param node markup
 87  
      * @param target child config bean
 88  
      */
 89  
     protected void addConverter(Node node, ElementBean target) {
 90  1
        ConverterBean targetConverter = new ConverterBean();
 91  
 
 92  1
        String jsfid = getJsfid(node);
 93  1
        targetConverter.setJsfid(jsfid);
 94  
 
 95  
        // resolve inheritance and attribute overrides
 96  1
        realizeComponent(node, targetConverter);
 97  
        //attach to the target element
 98  1
        target.addConverter(targetConverter);
 99  
 
 100  1
     }
 101  
 
 102  
 
 103  
     /**
 104  
      * <p>Adds a {@link org.apache.shale.clay.config.beans.ValidatorBean}
 105  
      * to the <code>target</code> {@link org.apache.shale.clay.config.beans.ElementBean}
 106  
      * using the {@link org.apache.shale.clay.parser.Node} as the input source.</p>
 107  
      *
 108  
      * @param node markup
 109  
      * @param target child config bean
 110  
      */
 111  
     protected void addValidator(Node node, ElementBean target) {
 112  1
        ValidatorBean targetValidator = new ValidatorBean();
 113  
 
 114  1
        String jsfid = getJsfid(node);
 115  1
        targetValidator.setJsfid(jsfid);
 116  
 
 117  
        // resolve inheritance and attribute overrides
 118  1
        realizeComponent(node, targetValidator);
 119  
        //attach to the target element
 120  1
        target.addValidator(targetValidator);
 121  
 
 122  1
     }
 123  
 
 124  
     /**
 125  
      * <p>Adds an {@link org.apache.shale.clay.config.beans.ActionListenerBean}
 126  
      * to the <code>target</code> {@link org.apache.shale.clay.config.beans.ElementBean}
 127  
      * using the {@link org.apache.shale.clay.parser.Node} as the input source.</p>
 128  
      *
 129  
      * @param node markup
 130  
      * @param target child config bean
 131  
      */
 132  
     protected void addActionListener(Node node, ElementBean target) {
 133  1
        ActionListenerBean targetActionListener = new ActionListenerBean();
 134  
 
 135  1
        String jsfid = getJsfid(node);
 136  1
        targetActionListener.setJsfid(jsfid);
 137  
 
 138  
        // resolve inheritance and attribute overrides
 139  1
        realizeComponent(node, targetActionListener);
 140  
        //attach to the target element
 141  1
        target.addActionListener(targetActionListener);
 142  
 
 143  1
     }
 144  
 
 145  
     /**
 146  
      * <p>Adds a {@link org.apache.shale.clay.config.beans.ActionListenerBean}
 147  
      * to the <code>target</code> {@link org.apache.shale.clay.config.beans.ElementBean}
 148  
      * using the {@link org.apache.shale.clay.parser.Node} as the input source.</p>
 149  
      *
 150  
      * @param node markup
 151  
      * @param target child config bean
 152  
      */
 153  
     protected void addValueChangeListener(Node node, ElementBean target) {
 154  1
        ValueChangeListenerBean targetValueChangeListener = new ValueChangeListenerBean();
 155  
 
 156  1
        String jsfid = getJsfid(node);
 157  1
        targetValueChangeListener.setJsfid(jsfid);
 158  
 
 159  
        // resolve inheritance and attribute overrides
 160  1
        realizeComponent(node, targetValueChangeListener);
 161  
        //attach to the target element
 162  1
        target.addValueChangeListener(targetValueChangeListener);
 163  1
     }
 164  
 
 165  
 
 166  
     /**
 167  
      * <p>Realizes the inheritance of the <code>target</code>
 168  
      * {@link org.apache.shale.clay.config.beans.ComponentBean} and
 169  
      * and then applies attributes that are optionally nested
 170  
      * under the <code>node</code>.</p>
 171  
      *
 172  
      * @param node markup
 173  
      * @param target child config bean
 174  
      */
 175  
     protected void realizeComponent(Node node, ComponentBean target) {
 176  
         // lookup the ConfigBean that handles the id
 177  16
         ConfigBean config = ConfigBeanFactory.findConfig(target.getJsfid());
 178  
 
 179  
         try {
 180  
            //assign the parent
 181  16
            config.assignParent(target);
 182  
            // resolve inheritance
 183  16
            config.realizingInheritance(target);
 184  
         } catch (RuntimeException e) {
 185  
             log.error(e);
 186  
             throw new RuntimeException(
 187  
                     messages.getMessage("parser.unresolved",
 188  
                     new Object[] {node.getToken(), node.getToken().getRawText()}));
 189  16
         }
 190  
 
 191  16
         assignAttributes(node, target);
 192  
 
 193  
         //look for attributes
 194  16
         Iterator ci = node.getChildren().iterator();
 195  19
         while (ci.hasNext()) {
 196  3
            Node child = (Node) ci.next();
 197  3
            if (child.isWellFormed() && child.getName() != null
 198  
                && child.getName().equals("attributes")) {
 199  
 
 200  1
                    addAttributes(child, target);
 201  
            }
 202  3
         }
 203  
 
 204  16
     }
 205  
 
 206  
 
 207  
     /**
 208  
      * <p>Looks for &lt;set/&gt; nodes within a &lt;attributes&gt; node and
 209  
      * converting them to {@link org.apache.shale.clay.config.beans.AttributeBean}'s
 210  
      * on the <code>target</code> {@link org.apache.shale.clay.config.beans.ComponentBean}.
 211  
      * </p>
 212  
      *
 213  
      * @param attributesNode markup
 214  
      * @param target child config bean
 215  
      */
 216  
     protected void addAttributes(Node attributesNode, ComponentBean target) {
 217  23
         Iterator ci = attributesNode.getChildren().iterator();
 218  134
         while (ci.hasNext()) {
 219  111
             Node child = (Node) ci.next();
 220  111
             if (child.isWellFormed() && child.getName() != null
 221  
                 && child.getName().equals("set")) {
 222  
 
 223  44
                 String name = (String) child.getAttributes().get("name");
 224  44
                 String value = (String) child.getAttributes().get("value");
 225  44
                 String bindingType = (String) child.getAttributes().get("bindingType");
 226  
 
 227  44
                 AttributeBean attr = target.getAttribute(name);
 228  44
                 if (attr != null) {
 229  44
                     createAttribute(attr, value, target);
 230  44
                 } else {
 231  
                     attr = new AttributeBean();
 232  
                     attr.setName(name);
 233  
                     attr.setValue(value);
 234  
                     attr.setBindingType(bindingType);
 235  
                     target.addAttribute(attr);
 236  
                 }
 237  
             }
 238  111
         }
 239  23
     }
 240  
 
 241  
 
 242  
     /**
 243  
      * <p>Adds markup <code>symbols</code> to the <code>target</code>
 244  
      * {@link org.apache.shale.clay.config.beans.ElementBean}.
 245  
      * </p>
 246  
      *
 247  
      * @param symbolsNode markup
 248  
      * @param target child config bean
 249  
      */
 250  
     protected void addSymbols(Node symbolsNode, ElementBean target) {
 251  
         Iterator si = symbolsNode.getChildren().iterator();
 252  
         while (si.hasNext()) {
 253  
             Node child = (Node) si.next();
 254  
             if (child.isWellFormed() && child.getName() != null
 255  
                 && child.getName().equals("set")) {
 256  
 
 257  
                 String name = (String) child.getAttributes().get("name");
 258  
                 String value = (String) child.getAttributes().get("value");
 259  
 
 260  
                 if (name != null && name.length() > 0) {
 261  
                     SymbolBean symbol = new SymbolBean();
 262  
                     StringBuffer tmp = new StringBuffer(name);
 263  
                     if (tmp.charAt(0) != '@') {
 264  
                        tmp.insert(0, '@');
 265  
                     }
 266  
 
 267  
                     symbol.setName(tmp.toString());
 268  
                     symbol.setValue(value);
 269  
                     target.addSymbol(symbol);
 270  
                 }
 271  
             }
 272  
         }
 273  
     }
 274  
 
 275  
 
 276  
 
 277  
     /**
 278  
      * <p>Handles converting markup resembling the &lt;element&gt; node
 279  
      * in the clay DTD, http://shale.apache.org/dtds/clay-config_1_0.dtd,
 280  
      * to the target {@link org.apache.shale.clay.config.beans.ElementBean}.</p>
 281  
      *
 282  
      * @param node markup
 283  
      * @param target child config bean
 284  
      * @param root parent config bean
 285  
      */
 286  
     protected void encodeBegin(Node node, ElementBean target, ComponentBean root) {
 287  34
         super.encodeBegin(node, target, root);
 288  
 
 289  34
         List deleteList = new ArrayList();
 290  34
         Iterator ci = node.getChildren().iterator();
 291  112
         while (ci.hasNext()) {
 292  78
             Node child = (Node) ci.next();
 293  78
             if (child.isWellFormed() && child.getName() != null) {
 294  28
                 if (child.getName().equals("attributes")) {
 295  22
                     addAttributes(child, target);
 296  22
                     deleteList.add(child);
 297  22
                 } else if (child.getName().equals("symbols")) {
 298  
                     addSymbols(child, target);
 299  
                     deleteList.add(child);
 300  
                 } else if (child.getName().equals("converter")) {
 301  1
                     addConverter(child, target);
 302  1
                     deleteList.add(child);
 303  1
                 } else if (child.getName().equals("validator")) {
 304  1
                     addValidator(child, target);
 305  1
                     deleteList.add(child);
 306  1
                 } else if (child.getName().equals("actionListener")) {
 307  1
                     addActionListener(child, target);
 308  1
                     deleteList.add(child);
 309  1
                 } else if (child.getName().equals("valueChangeListener")) {
 310  1
                     addValueChangeListener(child, target);
 311  1
                     deleteList.add(child);
 312  1
                 }
 313  
             } else {
 314  50
                 if (child.isComment() || isNodeWhitespace(child)) {
 315  
                     // remove white space
 316  50
                     deleteList.add(child);
 317  
                 }
 318  
             }
 319  78
         }
 320  
 
 321  34
         ci = deleteList.iterator();
 322  110
         while (ci.hasNext()) {
 323  76
             node.getChildren().remove(ci.next());
 324  76
         }
 325  
 
 326  34
     }
 327  
 
 328  
 
 329  
     /**
 330  
      * <p>This method is overridden to look for a <code>renderId</code>
 331  
      * attribute in the {@link org.apache.shale.clay.parser.Node}.
 332  
      * If one exists, it is applied to the target
 333  
      * {@link org.apache.shale.clay.config.beans.ElementBean}. The
 334  
      * super class {@link Builder} generates a unique id by default.
 335  
      * The clay namespace HTML nodes can override the renderId to
 336  
      * allow overridding of nested elements.</p>
 337  
      *
 338  
      * @param node markup
 339  
      * @return config bean
 340  
      */
 341  
     public ElementBean createElement(Node node) {
 342  34
         ElementBean target = super.createElement(node);
 343  34
         String renderId = (String) node.getAttributes().get("renderId");
 344  34
         if (renderId != null) {
 345  2
            Integer id = null;
 346  
            try {
 347  2
             id = Integer.valueOf(renderId);
 348  
            } catch (NumberFormatException e) {
 349  
                log.error(e);
 350  
                throw new RuntimeException(
 351  
                        messages.getMessage("parser.unresolved",
 352  
                        new Object[] {node.getToken(), node.getToken().getRawText()}));
 353  2
            }
 354  2
            if (id != null) {
 355  2
               target.setRenderId(id.intValue());
 356  
            }
 357  
         }
 358  
 
 359  34
         return target;
 360  
     }
 361  
 
 362  
     /**
 363  
      * <p>
 364  
      * This override returns <code>true</code> indicating that the from JSF
 365  
      * component can have children.
 366  
      * </p>
 367  
      *
 368  
      * @return <code>true</code>
 369  
      */
 370  
     public boolean isChildrenAllowed() {
 371  81
         return true;
 372  
     }
 373  
 
 374  
 
 375  
     /**
 376  
      * <p>
 377  
      * This method resolves the <code>jsfid</code> attribute for an HTML
 378  
      * element to a component definition in the XML configuration files.
 379  
      * </p>
 380  
      *
 381  
      * @param node markup
 382  
      * @param target child config bean
 383  
      */
 384  
     protected void assignNode(Node node, ElementBean target) {
 385  
         //the name attribute can not be used here because of the conflict with
 386  
         //the param tag.
 387  81
         String id = (String) node.getAttributes().get("id");
 388  81
         target.setId(id);
 389  
 
 390  
         // look to see if this node should be bound to a component
 391  81
         if (target.getJsfid() != null) {
 392  
             // lookup the ConfigBean that handles the id
 393  81
             ConfigBean config = ConfigBeanFactory.findConfig(target.getJsfid());
 394  
             // disconnect component type
 395  81
             target.setComponentType(null);
 396  
 
 397  
 
 398  
             try {
 399  
                //assign the parent
 400  81
                config.assignParent(target);
 401  
                // resolve inheritance
 402  81
                config.realizingInheritance(target);
 403  
             } catch (RuntimeException e) {
 404  
                 log.error(e);
 405  
                 throw new RuntimeException(
 406  
                         messages.getMessage("parser.unresolved",
 407  
                         new Object[] {node.getToken(), node.getToken().getRawText()}));
 408  81
             }
 409  
 
 410  
             // if the inheritance is broken, toggle back to the default
 411  81
             if (target.getComponentType() == null) {
 412  
                 target.setComponentType(this.getComponentType(node));
 413  
             }
 414  
 
 415  
         }
 416  
 
 417  
         // HTML attributes will override the declarative component
 418  81
         assignAttributes(node, target);
 419  
 
 420  81
     }
 421  
 
 422  
 
 423  
     /**
 424  
      * <p>Test the value of the node and returns <code>true</code> if
 425  
      * the value is only whitespace.</p>
 426  
      *
 427  
      * @param node markup node
 428  
      * @return <code>true</code> if value of the node is only whitespace
 429  
      */
 430  
     protected boolean isNodeWhitespace(Node node) {
 431  80
         StringBuffer document = node.getToken().getDocument();
 432  80
         for (int i = node.getToken().getBeginOffset();
 433  1832
              i < node.getToken().getEndOffset(); i++) {
 434  876
            char c = document.charAt(i);
 435  876
            if (!Character.isWhitespace(c)) {
 436  
                return false;
 437  
            }
 438  
         }
 439  80
         return true;
 440  
     }
 441  
 
 442  
 }