Save This Page
Home » cocoon-2.1.11-src » org.apache » cocoon » components » [javadoc | source]
    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   package org.apache.cocoon.components;
   18   
   19   import org.apache.avalon.excalibur.component.ExcaliburComponentSelector;
   20   import org.apache.avalon.excalibur.component.RoleManager;
   21   import org.apache.avalon.framework.component.Component;
   22   import org.apache.avalon.framework.component.ComponentException;
   23   import org.apache.avalon.framework.configuration.Configuration;
   24   import org.apache.avalon.framework.configuration.ConfigurationException;
   25   import org.apache.avalon.framework.configuration.DefaultConfiguration;
   26   
   27   /**
   28    * An extension of <code>ExcaliburComponentSelector</code> that can have a parent
   29    * and accepts a wider variety of configurations.
   30    *
   31    * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
   32    * @version CVS $Id: ExtendedComponentSelector.java 433543 2006-08-22 06:22:54Z crossley $
   33    */
   34   public class ExtendedComponentSelector extends ExcaliburComponentSelector
   35                                          implements ParentAware {
   36   
   37       /** The role manager */
   38       protected RoleManager roles;
   39   
   40       /** The parent selector, if any */
   41       protected ExtendedComponentSelector parentSelector;
   42   
   43       /** The parent locator, if any */
   44       protected ComponentLocator parentLocator;
   45   
   46       /** The class loader to use */
   47       protected ClassLoader classLoader;
   48   
   49       /** The role of this selector. Set in <code>configure()</code>. */
   50       protected String roleName;
   51   
   52       /** The default hint */
   53       protected String defaultHint;
   54   
   55       /** This selector's location (used for debugging purposes) */
   56       private String location;
   57   
   58   
   59       /** Create the ComponentSelector with the Thread context ClassLoader */
   60       public ExtendedComponentSelector() {
   61           this.classLoader = Thread.currentThread().getContextClassLoader();
   62       }
   63   
   64       /** Create the ComponentSelector with a ClassLoader */
   65       public ExtendedComponentSelector(ClassLoader loader) {
   66           super(loader);
   67   
   68           if (loader == null) {
   69               this.classLoader = Thread.currentThread().getContextClassLoader();
   70           } else {
   71               this.classLoader = loader;
   72           }
   73       }
   74   
   75       /**
   76        * Get the name for component-instance elements (i.e. components not defined
   77        * by their role shortcut. If <code>null</code>, any element having a 'class'
   78        * attribute will be considered as a component instance.
   79        * <p>
   80        * The default here is to return <code>null</code>, and subclasses can redefine
   81        * this method to return particular values.
   82        *
   83        * @return <code>null</code>, but can be changed by subclasses
   84        */
   85       protected String getComponentInstanceName() {
   86           return null;
   87       }
   88   
   89       /**
   90        * Get the name of the attribute giving the class name of a component.
   91        * The default here is "class", but this can be overriden in subclasses.
   92        *
   93        * @return "<code>class</code>", but can be changed by subclasses
   94        */
   95       protected String getClassAttributeName() {
   96           return "class";
   97       }
   98   
   99       /**
  100        * Get the name of the attribute giving the default hint to use if
  101        * none is given. The default here is "default", but this can be
  102        * overriden in subclasses. If this method returns <code>null</code>,
  103        * no default hint can be specified.
  104        *
  105        * @return "<code>default</code>", but can be changed by subclasses
  106        */
  107       protected String getDefaultHintAttributeName() {
  108           return "default";
  109       }
  110   
  111       /**
  112        * Configure the RoleManager. Redeclared only because parent member is private.
  113        */
  114       public void setRoleManager(RoleManager roles) {
  115           super.setRoleManager(roles);
  116           this.roles = roles;
  117       }
  118   
  119       /**
  120        * Set the parent of this selector. This can be done after the selector is
  121        * initialized, but <em>only once</em>. This allows this selector to be
  122        * created by a component manager while still being able to have a parent.
  123        *
  124        * @param parent the parent selector
  125        * @throws IllegalStateException if parent is already set
  126        */
  127   /*    public void setParentSelector(ComponentSelector parent) {
  128           if (this.parentSelector != null) {
  129               throw new IllegalStateException("Parent selector is already set");
  130           }
  131           this.parentSelector = parent;
  132           this.parentComponents = new HashSet();
  133       }
  134   */
  135   
  136       /**
  137        * Get the role name for this selector. This is called by <code>configure()</code>
  138        * to set the value of <code>this.roleName</code>.
  139        *
  140        * @return the role name, or <code>null<code> if it couldn't be determined.
  141        */
  142       protected String getRoleName(Configuration config) {
  143           // Get the role for this selector
  144           String roleName = config.getAttribute("role", null);
  145           if (roleName == null && this.roles != null) {
  146               roleName = this.roles.getRoleForName(config.getName());
  147           }
  148   
  149           return roleName;
  150       }
  151   
  152       /**
  153        * Configure this selector. This is the main difference with the parent class :
  154        * <ul>
  155        * <li>if {@link #getComponentInstanceName()} returns <code>null</code>,
  156        *     any child configurations having a attribute named as the result of
  157        *     {@link #getClassAttributeName()}, is considered as a component instance.
  158        * </li>
  159        * <li>if {@link #getComponentInstanceName()} returns a non-null value,
  160        *     only child configurations having this name are considered as a
  161        *     component instance.
  162        * </li>
  163        * <li>if other cases, it's name is considered to be a hint in the role manager.
  164        *     The behaviour is then the same as <code>ExcaliburComponentSelector</code>.
  165        * </li>
  166        *
  167        * @param config the configuration
  168        * @throws ConfigurationException if some hints aren't defined
  169        */
  170       public void configure(Configuration config) throws ConfigurationException {
  171   
  172           // Store location
  173           this.location = config.getLocation();
  174   
  175           this.roleName = getRoleName(config);
  176   
  177           // Pass a copy of the top-level object to superclass so that
  178           // our name is properly initialized
  179           // FIXME : could be avoided if parent m_role was protected or had protected accessors
  180           DefaultConfiguration temp = new DefaultConfiguration(config.getName(), this.location);
  181           if (config.getAttribute("role", null) != null) {
  182               temp.setAttribute("role", this.roleName);
  183           }
  184           super.configure(temp);
  185   
  186           // Get default hint
  187           this.defaultHint = config.getAttribute(this.getDefaultHintAttributeName(), null);
  188   
  189           // Add components
  190           String compInstanceName = getComponentInstanceName();
  191   
  192           Configuration[] instances = config.getChildren();
  193   
  194           for (int i = 0; i < instances.length; i++) {
  195               Configuration instance = instances[i];
  196   
  197               Object hint = instance.getAttribute("name").trim();
  198   
  199               String classAttr = instance.getAttribute(getClassAttributeName(), null);
  200               String className;
  201   
  202               if (compInstanceName == null) {
  203                   // component-instance implicitly defined by the presence of the 'class' attribute
  204                   if (classAttr == null) {
  205                       className = this.roles.getDefaultClassNameForHint(roleName, instance.getName());
  206                   } else {
  207                       className = classAttr.trim();
  208                   }
  209   
  210               } else {
  211                   // component-instances names explicitly defined
  212                   if (compInstanceName.equals(instance.getName())) {
  213                       className = (classAttr == null) ? null : classAttr.trim();
  214                   } else {
  215                       className = this.roles.getDefaultClassNameForHint(roleName, instance.getName());
  216                   }
  217               }
  218   
  219               if (className == null) {
  220                   String message = "Unable to determine class name for component named '" + hint +
  221                       "' at " + instance.getLocation();
  222   
  223                   getLogger().error(message);
  224                   throw new ConfigurationException(message);
  225               }
  226   
  227               try {
  228                   Class clazz = this.classLoader.loadClass(className);
  229                   addComponent(hint, clazz, instance);
  230   
  231               } catch (Exception e) {
  232                   String message = "Could not load class " + className + " for component named '" +
  233                                    hint + "' at " + instance.getLocation();
  234   
  235                   getLogger().error(message, e);
  236                   throw new ConfigurationException(message, e);
  237               }
  238           }
  239       }
  240   
  241       /**
  242        * Get the default hint, if any for this selector.
  243        */
  244       public String getDefaultHint() {
  245           // Inherit parent default hint if have no own
  246           if (this.defaultHint == null && this.parentSelector != null) {
  247               return this.parentSelector.getDefaultHint();
  248           }
  249   
  250           return this.defaultHint;
  251       }
  252   
  253       /* (non-Javadoc)
  254        * @see org.apache.avalon.framework.component.ComponentSelector#select(java.lang.Object)
  255        */
  256       public Component select(Object hint) throws ComponentException {
  257           if (hint == null) {
  258               hint = this.defaultHint;
  259           }
  260   
  261           if (parentSelector == null) {
  262               // No parent: default behaviour
  263               return super.select(hint);
  264           }
  265   
  266           try {
  267               // Try in this selector first
  268               final Component component = super.select(hint);
  269               return component;
  270   
  271           } catch (ComponentException original) {
  272               try {
  273                   // Doesn't exist here: try in parent selector
  274                   final Component component = this.parentSelector.select(hint);
  275                   return component;
  276   
  277               } catch (ComponentException nested) {
  278                   // Doesn't exist in parent too: throw exception.
  279   
  280                   if (nested.getCause() != null) {
  281                       // Nested exception has a cause; let's throw it instead of original.
  282                       throw nested;
  283                   }
  284   
  285                   // Throw original exception
  286                   throw original;
  287               }
  288           }
  289       }
  290   
  291       /* (non-Javadoc)
  292        * @see org.apache.avalon.framework.component.ComponentSelector#release(org.apache.avalon.framework.component.Component)
  293        */
  294       public void release(Component component) {
  295           // Was it selected on the parent ?
  296           if (this.parentSelector != null && this.parentSelector.canRelease(component)) {
  297               // Yes
  298               this.parentSelector.release(component);
  299           } else {
  300               // No
  301               super.release(component);
  302           }
  303       }
  304   
  305       /**
  306        * Does this selector or its parent have the given hint ?
  307        */
  308       public boolean hasComponent(Object hint) {
  309           boolean exists = super.hasComponent(hint);
  310           if (!exists && this.parentSelector != null) {
  311               exists = this.parentSelector.hasComponent(hint);
  312           }
  313           return exists;
  314       }
  315   
  316       /**
  317        * Does this selector declare a given hint? Check is performed on the components declared for this
  318        * selector only, and <strong>not</strong> those potentially inherited from the parent selector.
  319        *
  320        * @param hint the hint to check for
  321        * @return <code>true</code> if this selector has the specified hint
  322        */
  323       protected boolean hasDeclaredComponent(Object hint) {
  324           return super.hasComponent(hint);
  325       }
  326   
  327       /* (non-Javadoc)
  328        * @see org.apache.cocoon.components.ParentAware#setParentInformation(org.apache.avalon.framework.component.ComponentManager, java.lang.String)
  329        */
  330       public void setParentLocator(ComponentLocator locator)
  331       throws ComponentException {
  332           if (this.parentSelector != null) {
  333               throw new ComponentException(null, "Parent selector is already set");
  334           }
  335           this.parentLocator = locator;
  336           this.parentSelector = (ExtendedComponentSelector) locator.lookup();
  337       }
  338   
  339       /* (non-Javadoc)
  340        * @see org.apache.avalon.framework.activity.Disposable#dispose()
  341        */
  342       public void dispose() {
  343           super.dispose();
  344           if (this.parentLocator != null) {
  345               this.parentLocator.release(this.parentSelector);
  346               this.parentLocator = null;
  347               this.parentSelector = null;
  348           }
  349       }
  350   
  351       /* (non-Javadoc)
  352        * @see org.apache.avalon.excalibur.component.ExcaliburComponentSelector#canRelease(org.apache.avalon.framework.component.Component)
  353        */
  354       protected boolean canRelease(Component component) {
  355           if (this.parentSelector != null && this.parentSelector.canRelease(component)) {
  356               return true;
  357           }
  358   
  359           return super.canRelease(component);
  360       }
  361   }

Save This Page
Home » cocoon-2.1.11-src » org.apache » cocoon » components » [javadoc | source]