View Javadoc

    1   /*
    2    * $Id: ComponentDefinition.java 471754 2006-11-06 14:55:09Z husted $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
    10   * with the License.  You may obtain a copy of the License at
    11   *
    12   *  http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing,
    15   * software distributed under the License is distributed on an
    16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    17   * KIND, either express or implied.  See the License for the
    18   * specific language governing permissions and limitations
    19   * under the License.
    20   */
    21
    22  package org.apache.struts.tiles;
    23
    24  import java.io.Serializable;
    25  import java.util.HashMap;
    26  import java.util.Map;
    27
    28  import org.apache.commons.logging.Log;
    29  import org.apache.commons.logging.LogFactory;
    30  import org.apache.struts.tiles.xmlDefinition.XmlDefinition;
    31  import org.apache.struts.util.RequestUtils;
    32
    33  /**
    34   * Definition of a template / component attributes.
    35   * Attributes of a component can be defined with the help of this class.
    36   * An instance of this class can be used as a bean, and passed to 'insert' tag.
    37   */
    38  public class ComponentDefinition implements Serializable {
    39
    40      /**
    41       * Commons Logging instance.
    42       */
    43      protected static Log log = LogFactory.getLog(ComponentDefinition.class);
    44
    45      /**
    46       * Definition name
    47       */
    48      protected String name = null;
    49
    50      /**
    51       * Component / template path (URL).
    52       */
    53      protected String path = null;
    54
    55      /**
    56       * Attributes defined for the component.
    57       */
    58      protected Map attributes = null;
    59
    60      /**
    61       * Role associated to definition.
    62       */
    63      protected String role = null;
    64
    65      /** Associated Controller URL or classname, if defined */
    66      protected String controller = null;
    67
    68      /**
    69       * Associated Controller typename, if controllerName defined.
    70       * Can be CONTROLLER, ACTION or URL, or null.
    71       */
    72      protected String controllerType = null;
    73
    74      /**
    75       * Controller name type.
    76       */
    77      public static final String URL = "url";
    78
    79      /**
    80       * Controller name type.
    81       */
    82      public static final String CONTROLLER = "controller";
    83
    84      /**
    85       * Controller name type.
    86       */
    87      public static final String ACTION = "action";
    88
    89      /**
    90       * Controller associated to Definition.
    91       * Lazy creation : only on first request
    92       */
    93      private Controller controllerInstance = null;
    94
    95      /**
    96       * Constructor.
    97       */
    98      public ComponentDefinition() {
    99          attributes = new HashMap();
    100     }
    101
    102     /**
    103      * Copy Constructor.
    104      * Create a new definition initialized with parent definition.
    105      * Do a shallow copy : attributes are shared between copies, but not the Map
    106      * containing attributes.
    107      */
    108     public ComponentDefinition(ComponentDefinition definition) {
    109         attributes = new HashMap(definition.getAttributes());
    110         this.name = definition.getName();
    111         this.path = definition.getPath();
    112         this.role = definition.getRole();
    113         this.controllerInstance = definition.getControllerInstance();
    114         this.controller = definition.getController();
    115         this.controllerType = definition.getControllerType();
    116     }
    117
    118     /**
    119      * Constructor.
    120      * Create a new definition initialized from a RawDefinition.
    121      * Raw definitions are used to read definition from a data source (xml file, db, ...).
    122      * A RawDefinition mainly contains properties of type String, while Definition
    123      * contains more complex type (ex : Controller).
    124      * Do a shallow copy : attributes are shared between objects, but not the Map
    125      * containing attributes.
    126      * OO Design issues : Actually RawDefinition (XmlDefinition) extends ComponentDefinition.
    127      * This must not be the case. I have do it because I am lazy.
    128      * @throws InstantiationException if an error occur while instanciating Controller :
    129      * (classname can't be instanciated, Illegal access with instanciated class,
    130      * Error while instanciating class, classname can't be instanciated.
    131      */
    132     public ComponentDefinition(XmlDefinition definition) {
    133
    134         this((ComponentDefinition) definition);
    135     }
    136
    137     /**
    138      * Constructor.
    139      */
    140     public ComponentDefinition(String name, String path, Map attributes) {
    141         this.name = name;
    142         this.path = path;
    143         this.attributes = attributes;
    144     }
    145
    146     /**
    147      * Access method for the name property.
    148      *
    149      * @return   the current value of the name property
    150      */
    151     public String getName() {
    152         return name;
    153     }
    154
    155     /**
    156      * Sets the value of the name property.
    157      *
    158      * @param aName the new value of the name property
    159      */
    160     public void setName(String aName) {
    161         name = aName;
    162     }
    163
    164     /**
    165      * Access method for the path property.
    166      *
    167      * @return The current value of the path property.
    168      */
    169     public String getPage() {
    170         return path;
    171     }
    172
    173     /**
    174      * Sets the value of the path property.
    175      *
    176      * @param page the new value of the path property
    177      */
    178     public void setPage(String page) {
    179         path = page;
    180     }
    181
    182     /**
    183      * Access method for the path property.
    184      *
    185      * @return   the current value of the path property
    186      */
    187     public String getPath() {
    188         return path;
    189     }
    190
    191     /**
    192      * Sets the value of the path property.
    193      *
    194      * @param aPath the new value of the path property
    195      */
    196     public void setPath(String aPath) {
    197         path = aPath;
    198     }
    199
    200     /**
    201      * Access method for the template property.
    202      * Same as getPath()
    203      * @return   the current value of the template property
    204      */
    205     public String getTemplate() {
    206         return path;
    207     }
    208
    209     /**
    210      * Sets the value of the template property.
    211      * Same as setPath()
    212      *
    213      * @param template the new value of the path property
    214      */
    215     public void setTemplate(String template) {
    216         path = template;
    217     }
    218
    219     /**
    220      * Access method for the role property.
    221      * @return   the current value of the role property
    222      */
    223     public String getRole() {
    224         return role;
    225     }
    226
    227     /**
    228      * Sets the value of the role property.
    229      *
    230      * @param role the new value of the path property
    231      */
    232     public void setRole(String role) {
    233         this.role = role;
    234     }
    235
    236     /**
    237      * Access method for the attributes property.
    238      * If there is no attributes, return an empty map.
    239      * @return   the current value of the attributes property
    240      */
    241     public Map getAttributes() {
    242         return attributes;
    243     }
    244
    245     /**
    246      * Returns the value of the named attribute as an Object, or null if no
    247      * attribute of the given name exists.
    248      *
    249      * @return   requested attribute or null if not found
    250      */
    251     public Object getAttribute(String key) {
    252         return attributes.get(key);
    253     }
    254
    255     /**
    256      * Put a new attribute in this component
    257      *
    258      * @param key String key for attribute
    259      * @param value Attibute value.
    260      */
    261     public void putAttribute(String key, Object value) {
    262         attributes.put(key, value);
    263     }
    264
    265     /**
    266      * Put an attribute in component / template definition.
    267      * Attribute can be used as content for tag get.
    268      * @param name Attribute name
    269      * @param content Attribute value
    270      */
    271     public void put(String name, Object content) {
    272         put(name, content, false, null);
    273     }
    274
    275     /**
    276      * Put an attribute in template definition.
    277      * Attribute can be used as content for tag get.
    278      * @param name Attribute name
    279      * @param content Attribute value �
    280      * @param direct Determines how content is handled by get tag: true means content is printed directly; false, the default, means content is included
    281      */
    282     public void put(String name, Object content, boolean direct) {
    283         put(name, content, direct, null);
    284     }
    285
    286     /**
    287      * Put an attribute in template definition.
    288      * Attribute can be used as content for tag get.
    289      * @param name Attribute name
    290      * @param content Attribute value
    291      * @param direct Determines how content is handled by get tag: true means content is printed directly; false, the default, means content is included
    292      * @param role Determine if content is used by get tag. If user is in role, content is used.
    293      */
    294     public void put(String name, Object content, boolean direct, String role) {
    295         if (direct == true) { // direct String
    296             put(name, content, "string", role);
    297         } else {
    298             put(name, content, "template", role);
    299         }
    300
    301     }
    302
    303     /**
    304      * Put an attribute in template definition.
    305      * Attribute can be used as content for tag get.
    306      * @param name Attribute name
    307      * @param content Attribute value
    308      * @param type attribute type: template, string, definition
    309      * @param role Determine if content is used by get tag. If user is in role, content is used.
    310      */
    311     public void put(String name, Object content, String type, String role) {
    312         // Is there a type set ?
    313         // First check direct attribute, and translate it to a valueType.
    314         // Then, evaluate valueType, and create requested typed attribute.
    315         AttributeDefinition attribute = null;
    316
    317         if (content != null
    318             && type != null
    319             && !(content instanceof AttributeDefinition)) {
    320
    321             String strValue = content.toString();
    322             if (type.equalsIgnoreCase("string")) {
    323                 attribute = new DirectStringAttribute(strValue);
    324
    325             } else if (type.equalsIgnoreCase("page")) {
    326                 attribute = new PathAttribute(strValue);
    327
    328             } else if (type.equalsIgnoreCase("template")) {
    329                 attribute = new PathAttribute(strValue);
    330
    331             } else if (type.equalsIgnoreCase("instance")) {
    332                 attribute = new DefinitionNameAttribute(strValue);
    333
    334             } else if (type.equalsIgnoreCase("definition")) {
    335                 attribute = new DefinitionNameAttribute(strValue);
    336             }
    337         }
    338
    339         putAttribute(name, attribute);
    340     }
    341
    342     /**
    343      * Returns a description of the attributes.
    344      */
    345     public String toString() {
    346         return "{name="
    347             + name
    348             + ", path="
    349             + path
    350             + ", role="
    351             + role
    352             + ", controller="
    353             + controller
    354             + ", controllerType="
    355             + controllerType
    356             + ", controllerInstance="
    357             + controllerInstance
    358             + ", attributes="
    359             + attributes
    360             + "}\n";
    361     }
    362
    363     /**
    364      * Get associated controller type.
    365      * Type denote a fully qualified classname.
    366      */
    367     public String getControllerType() {
    368         return controllerType;
    369     }
    370
    371     /**
    372      * Set associated controller type.
    373      * Type denote a fully qualified classname.
    374      * @param controllerType Typeof associated controller
    375      */
    376     public void setControllerType(String controllerType) {
    377         this.controllerType = controllerType;
    378     }
    379
    380     /**
    381      * Set associated controller name as an url, and controller
    382      * type as "url".
    383      * Name must be an url (not checked).
    384      * Convenience method.
    385      * @param controller Controller url
    386      */
    387     public void setControllerUrl(String controller) {
    388         setController(controller);
    389         setControllerType("url");
    390     }
    391
    392     /**
    393      * Set associated controller name as a classtype, and controller
    394      * type as "classname".
    395      * Name denote a fully qualified classname
    396      * Convenience method.
    397      * @param controller Controller classname.
    398      */
    399     public void setControllerClass(String controller) {
    400         setController(controller);
    401         setControllerType("classname");
    402     }
    403
    404     /**
    405      * Get associated controller local URL.
    406      * URL should be local to webcontainer in order to allow request context followup.
    407      * URL comes as a string.
    408      */
    409     public String getController() {
    410         return controller;
    411     }
    412
    413     /**
    414      * Set associated controller URL.
    415      * URL should be local to webcontainer in order to allow request context followup.
    416      * URL is specified as a string.
    417      * @param url Url called locally
    418      */
    419     public void setController(String url) {
    420         this.controller = url;
    421     }
    422
    423     /**
    424      * Get controller instance.
    425      * @return controller instance.
    426      */
    427     public Controller getControllerInstance() {
    428         return controllerInstance;
    429     }
    430
    431     /**
    432      * Get or create controller.
    433      * Get controller, create it if necessary.
    434      * @return controller if controller or controllerType is set, null otherwise.
    435      * @throws InstantiationException if an error occur while instanciating Controller :
    436      * (classname can't be instanciated, Illegal access with instanciated class,
    437      * Error while instanciating class, classname can't be instanciated.
    438      */
    439     public Controller getOrCreateController() throws InstantiationException {
    440
    441         if (controllerInstance != null) {
    442             return controllerInstance;
    443         }
    444
    445         // Do we define a controller ?
    446         if (controller == null && controllerType == null) {
    447             return null;
    448         }
    449
    450         // check parameters
    451         if (controllerType != null && controller == null) {
    452             throw new InstantiationException("Controller name should be defined if controllerType is set");
    453         }
    454
    455         controllerInstance = createController(controller, controllerType);
    456
    457         return controllerInstance;
    458     }
    459
    460     /**
    461      * Set controller.
    462      */
    463     public void setControllerInstance(Controller controller) {
    464         this.controllerInstance = controller;
    465     }
    466
    467     /**
    468      * Create a new instance of controller named in parameter.
    469      * If controllerType is specified, create controller accordingly.
    470      * Otherwise, if name denote a classname, create an instance of it. If class is
    471      *  subclass of org.apache.struts.action.Action, wrap controller
    472      * appropriately.
    473      * Otherwise, consider name as an url.
    474      * @param name Controller name (classname, url, ...)
    475      * @param controllerType Expected Controller type
    476      * @return org.apache.struts.tiles.Controller
    477      * @throws InstantiationException if an error occur while instanciating Controller :
    478      * (classname can't be instanciated, Illegal access with instanciated class,
    479      * Error while instanciating class, classname can't be instanciated.
    480      */
    481     public static Controller createController(String name, String controllerType)
    482         throws InstantiationException {
    483
    484         if (log.isDebugEnabled()) {
    485             log.debug("Create controller name=" + name + ", type=" + controllerType);
    486         }
    487
    488         Controller controller = null;
    489
    490         if (controllerType == null) { // first try as a classname
    491             try {
    492                 return createControllerFromClassname(name);
    493
    494             } catch (InstantiationException ex) { // ok, try something else
    495                 controller = new UrlController(name);
    496             }
    497
    498         } else if ("url".equalsIgnoreCase(controllerType)) {
    499             controller = new UrlController(name);
    500
    501         } else if ("classname".equalsIgnoreCase(controllerType)) {
    502             controller = createControllerFromClassname(name);
    503         }
    504
    505         return controller;
    506     }
    507
    508     /**
    509      * Create a controller from specified classname
    510      * @param classname Controller classname.
    511      * @return org.apache.struts.tiles.Controller
    512      * @throws InstantiationException if an error occur while instanciating Controller :
    513      * (classname can't be instanciated, Illegal access with instanciated class,
    514      * Error while instanciating class, classname can't be instanciated.
    515      */
    516     public static Controller createControllerFromClassname(String classname)
    517         throws InstantiationException {
    518
    519         try {
    520             Class requestedClass = RequestUtils.applicationClass(classname);
    521             Object instance = requestedClass.newInstance();
    522
    523             if (log.isDebugEnabled()) {
    524                 log.debug("Controller created : " + instance);
    525             }
    526             return (Controller) instance;
    527
    528         } catch (java.lang.ClassNotFoundException ex) {
    529             throw new InstantiationException(
    530                 "Error - Class not found :" + ex.getMessage());
    531
    532         } catch (java.lang.IllegalAccessException ex) {
    533             throw new InstantiationException(
    534                 "Error - Illegal class access :" + ex.getMessage());
    535
    536         } catch (java.lang.InstantiationException ex) {
    537             throw ex;
    538
    539         } catch (java.lang.ClassCastException ex) {
    540             throw new InstantiationException(
    541                 "Controller of class '"
    542                     + classname
    543                     + "' should implements 'Controller' or extends 'Action'");
    544         }
    545     }
    546
    547 }