Save This Page
Home » tiles-2.2.1-src » org.apache » tiles » impl » [javadoc | source]
    1   /*
    2    * $Id: BasicTilesContainer.java 797765 2009-07-25 13:20:26Z apetrelli $
    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   package org.apache.tiles.impl;
   22   
   23   import java.io.IOException;
   24   import java.io.Writer;
   25   import java.util.ArrayList;
   26   import java.util.List;
   27   import java.util.Map;
   28   import java.util.StringTokenizer;
   29   
   30   import org.apache.tiles.ArrayStack;
   31   import org.apache.tiles.Attribute;
   32   import org.apache.tiles.AttributeContext;
   33   import org.apache.tiles.BasicAttributeContext;
   34   import org.apache.tiles.Definition;
   35   import org.apache.tiles.TilesApplicationContext;
   36   import org.apache.tiles.TilesContainer;
   37   import org.apache.tiles.context.TilesRequestContext;
   38   import org.apache.tiles.context.TilesRequestContextFactory;
   39   import org.apache.tiles.definition.DefinitionsFactory;
   40   import org.apache.tiles.definition.DefinitionsFactoryException;
   41   import org.apache.tiles.definition.NoSuchDefinitionException;
   42   import org.apache.tiles.evaluator.AttributeEvaluator;
   43   import org.apache.tiles.evaluator.AttributeEvaluatorFactory;
   44   import org.apache.tiles.evaluator.AttributeEvaluatorFactoryAware;
   45   import org.apache.tiles.preparer.NoSuchPreparerException;
   46   import org.apache.tiles.preparer.PreparerFactory;
   47   import org.apache.tiles.preparer.ViewPreparer;
   48   import org.apache.tiles.renderer.AttributeRenderer;
   49   import org.apache.tiles.renderer.RendererFactory;
   50   import org.slf4j.Logger;
   51   import org.slf4j.LoggerFactory;
   52   
   53   /**
   54    * Basic implementation of the tiles container interface.
   55    * In most cases, this container will be customized by
   56    * injecting customized services, not necessarily by
   57    * override the container
   58    *
   59    * @since 2.0
   60    * @version $Rev: 797765 $ $Date: 2009-07-25 15:20:26 +0200 (sab, 25 lug 2009) $
   61    */
   62   public class BasicTilesContainer implements TilesContainer,
   63           AttributeEvaluatorFactoryAware {
   64   
   65       /**
   66        * Constant representing the configuration parameter used to define the
   67        * tiles definition resources.
   68        *
   69        * @deprecated Use
   70        * {@link org.apache.tiles.definition.DefinitionsFactory#DEFINITIONS_CONFIG}.
   71        */
   72       public static final String DEFINITIONS_CONFIG = "org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG";
   73   
   74       /**
   75        * Compatibility constant.
   76        *
   77        * @deprecated use {@link #DEFINITIONS_CONFIG} to avoid namespace collisions.
   78        */
   79       private static final String LEGACY_DEFINITIONS_CONFIG = "definitions-config";
   80   
   81       /**
   82        * Name used to store attribute context stack.
   83        */
   84       private static final String ATTRIBUTE_CONTEXT_STACK =
   85           "org.apache.tiles.AttributeContext.STACK";
   86   
   87       /**
   88        * Log instance for all BasicTilesContainer
   89        * instances.
   90        */
   91       private final Logger log = LoggerFactory
   92               .getLogger(BasicTilesContainer.class);
   93   
   94       /**
   95        * The Tiles application context object.
   96        */
   97       private TilesApplicationContext context;
   98   
   99       /**
  100        * The definitions factory.
  101        */
  102       private DefinitionsFactory definitionsFactory;
  103   
  104       /**
  105        * The preparer factory.
  106        */
  107       private PreparerFactory preparerFactory;
  108   
  109       /**
  110        * The renderer factory.
  111        */
  112       private RendererFactory rendererFactory;
  113   
  114       /**
  115        * The attribute evaluator.
  116        */
  117       private AttributeEvaluatorFactory attributeEvaluatorFactory;
  118   
  119       /**
  120        * The Tiles request context factory.
  121        */
  122       private TilesRequestContextFactory contextFactory;
  123   
  124       /**
  125        * Initialization flag. If set, this container cannot be changed.
  126        */
  127       private boolean initialized = false;
  128   
  129       /**
  130        * Initialize the Container with the given configuration.
  131        *
  132        * @param initParameters application context for this container
  133        * @throws IllegalStateException If the container has been already
  134        * initialized.
  135        * @throws DefinitionsFactoryException If something goes wrong during
  136        * initialization.
  137        */
  138       public void init(Map<String, String> initParameters) {
  139           checkInit();
  140           initialized = true;
  141   
  142           if (rendererFactory == null) {
  143               throw new IllegalStateException("RendererFactory not specified");
  144           }
  145           if (preparerFactory == null) {
  146               throw new IllegalStateException("PreparerFactory not specified");
  147           }
  148           if (definitionsFactory == null) {
  149               throw new IllegalStateException("DefinitionsFactory not specified");
  150           }
  151           if (attributeEvaluatorFactory == null) {
  152               throw new IllegalStateException("AttributeEvaluatorFactory not specified");
  153           }
  154           if (contextFactory == null) {
  155               throw new IllegalStateException("TilesContextFactory not specified");
  156           }
  157           if (context == null) {
  158               throw new IllegalStateException("TilesApplicationContext not specified");
  159           }
  160       }
  161   
  162       /** {@inheritDoc} */
  163       public AttributeContext startContext(Object... requestItems) {
  164           TilesRequestContext tilesContext = getRequestContext(requestItems);
  165           return startContext(tilesContext);
  166       }
  167   
  168       /** {@inheritDoc} */
  169       public void endContext(Object... requestItems) {
  170           TilesRequestContext tilesContext = getRequestContext(requestItems);
  171           endContext(tilesContext);
  172       }
  173   
  174       /** {@inheritDoc} */
  175       public void renderContext(Object... requestItems) {
  176           TilesRequestContext request = getRequestContext(requestItems);
  177           AttributeContext attributeContext = getAttributeContext(request);
  178   
  179           render(request, attributeContext);
  180       }
  181   
  182       /**
  183        * Returns the Tiles application context used by this container.
  184        *
  185        * @return the application context for this container.
  186        */
  187       public TilesApplicationContext getApplicationContext() {
  188           return context;
  189       }
  190   
  191       /**
  192        * Sets the Tiles application context to use.
  193        *
  194        * @param context The Tiles application context.
  195        */
  196       public void setApplicationContext(TilesApplicationContext context) {
  197           this.context = context;
  198       }
  199   
  200       /** {@inheritDoc} */
  201       public AttributeContext getAttributeContext(Object... requestItems) {
  202           TilesRequestContext tilesContext = getRequestContext(requestItems);
  203           return getAttributeContext(tilesContext);
  204   
  205       }
  206   
  207       /**
  208        * Returns the context factory.
  209        *
  210        * @return Always <code>null</code>.
  211        * @deprecated Do not use it, it returns <code>null</code>. Use
  212        * {@link #getRequestContextFactory()}.
  213        */
  214       @Deprecated
  215       public org.apache.tiles.context.TilesContextFactory getContextFactory() {
  216           return null;
  217       }
  218   
  219       /**
  220        * Returns the request context factory.
  221        *
  222        * @return The request context factory.
  223        * @since 2.1.1
  224        */
  225       protected TilesRequestContextFactory getRequestContextFactory() {
  226           return contextFactory;
  227       }
  228   
  229       /**
  230        * Sets the context factory.
  231        *
  232        * @param contextFactory The context factory.
  233        * @deprecated Use
  234        * {@link #setRequestContextFactory(TilesRequestContextFactory)}.
  235        */
  236       public void setContextFactory(org.apache.tiles.context.TilesContextFactory contextFactory) {
  237           // Does nothing
  238       }
  239   
  240       /**
  241        * Sets the request context factory.
  242        *
  243        * @param contextFactory The context factory.
  244        * @since 2.1.1
  245        */
  246       public void setRequestContextFactory(TilesRequestContextFactory contextFactory) {
  247           checkInit();
  248           this.contextFactory = contextFactory;
  249       }
  250   
  251       /**
  252        * Returns the definitions factory.
  253        *
  254        * @return The definitions factory used by this container.
  255        */
  256       public DefinitionsFactory getDefinitionsFactory() {
  257           return definitionsFactory;
  258       }
  259   
  260       /**
  261        * Set the definitions factory. This method first ensures
  262        * that the container has not yet been initialized.
  263        *
  264        * @param definitionsFactory the definitions factory for this instance.
  265        */
  266       public void setDefinitionsFactory(DefinitionsFactory definitionsFactory) {
  267           checkInit();
  268           this.definitionsFactory = definitionsFactory;
  269       }
  270   
  271       /**
  272        * Returns the preparer factory used by this container.
  273        *
  274        * @return return the preparerInstance factory used by this container.
  275        */
  276       public PreparerFactory getPreparerFactory() {
  277           return preparerFactory;
  278       }
  279   
  280       /**
  281        * Set the preparerInstance factory.  This method first ensures
  282        * that the container has not yet been initialized.
  283        *
  284        * @param preparerFactory the preparerInstance factory for this conainer.
  285        */
  286       public void setPreparerFactory(PreparerFactory preparerFactory) {
  287           this.preparerFactory = preparerFactory;
  288       }
  289   
  290       /**
  291        * Sets the renderer instance factory.
  292        *
  293        * @param rendererFactory the renderer instance factory for this container.
  294        * @since 2.1.0
  295        */
  296       public void setRendererFactory(RendererFactory rendererFactory) {
  297           this.rendererFactory = rendererFactory;
  298       }
  299   
  300       /** {@inheritDoc} */
  301       public void setAttributeEvaluatorFactory(
  302               AttributeEvaluatorFactory attributeEvaluatorFactory) {
  303           this.attributeEvaluatorFactory = attributeEvaluatorFactory;
  304       }
  305   
  306       /** {@inheritDoc} */
  307       public void prepare(String preparer, Object... requestItems) {
  308           TilesRequestContext requestContext = getRequestContextFactory().createRequestContext(
  309               getApplicationContext(),
  310               requestItems
  311           );
  312           prepare(requestContext, preparer, false);
  313       }
  314   
  315       /** {@inheritDoc} */
  316       public void render(String definitionName, Object... requestItems) {
  317           TilesRequestContext requestContext = getRequestContextFactory().createRequestContext(
  318               getApplicationContext(),
  319               requestItems
  320           );
  321           render(requestContext, definitionName);
  322       }
  323   
  324       /** {@inheritDoc} */
  325       @Deprecated
  326       public void render(Attribute attr, Writer writer, Object... requestItems)
  327           throws IOException {
  328           render(attr, requestItems);
  329       }
  330   
  331       /** {@inheritDoc} */
  332       public void render(Attribute attr, Object... requestItems)
  333           throws IOException {
  334           TilesRequestContext requestContext = getRequestContextFactory()
  335                   .createRequestContext(getApplicationContext(), requestItems);
  336           render(attr, requestContext);
  337       }
  338   
  339       /** {@inheritDoc} */
  340       public Object evaluate(Attribute attribute, Object... requestItems) {
  341           TilesRequestContext request = getRequestContextFactory()
  342                   .createRequestContext(context, requestItems);
  343           AttributeEvaluator evaluator = attributeEvaluatorFactory
  344                   .getAttributeEvaluator(attribute);
  345           return evaluator.evaluate(attribute, request);
  346       }
  347   
  348       /** {@inheritDoc} */
  349       public boolean isValidDefinition(String definitionName, Object... requestItems) {
  350           return isValidDefinition(getRequestContext(requestItems), definitionName);
  351       }
  352   
  353       /**
  354        * Returns a definition specifying its name.
  355        *
  356        * @param definitionName The name of the definition to find.
  357        * @param request The request context.
  358        * @return The definition, if found.
  359        * @throws DefinitionsFactoryException If the definitions factory throws an
  360        * exception.
  361        */
  362       protected Definition getDefinition(String definitionName,
  363               TilesRequestContext request) {
  364           Definition definition =
  365               definitionsFactory.getDefinition(definitionName, request);
  366           return definition;
  367       }
  368   
  369       /**
  370        * Derive the resource string from the initialization parameters.
  371        * If no parameter {@link #DEFINITIONS_CONFIG} is available, attempts
  372        * to retrieve {@link #LEGACY_DEFINITIONS_CONFIG}.  If niether are
  373        * available, returns "/WEB-INF/tiles.xml".
  374        *
  375        * @return resource string to be parsed.
  376        */
  377       protected String getResourceString() {
  378           return getResourceString(context.getInitParams());
  379       }
  380   
  381       /**
  382        * Derive the resource string from the initialization parameters.
  383        * If no parameter {@link #DEFINITIONS_CONFIG} is available, attempts
  384        * to retrieve {@link #LEGACY_DEFINITIONS_CONFIG}.  If niether are
  385        * available, returns "/WEB-INF/tiles.xml".
  386        *
  387        * @param parms The initialization parameters.
  388        * @return resource string to be parsed.
  389        */
  390       protected String getResourceString(Map<String, String> parms) {
  391           String resourceStr = parms.get(DEFINITIONS_CONFIG);
  392           if (resourceStr == null) {
  393               resourceStr = parms.get(LEGACY_DEFINITIONS_CONFIG);
  394           }
  395           if (resourceStr == null) {
  396               resourceStr = "/WEB-INF/tiles.xml";
  397           }
  398           return resourceStr;
  399       }
  400   
  401       /**
  402        * Parse the resourceString into a list of resource paths
  403        * which can be loaded by the application context.
  404        *
  405        * @param resourceString comma seperated resources
  406        * @return parsed resources
  407        */
  408       protected List<String> getResourceNames(String resourceString) {
  409           StringTokenizer tokenizer = new StringTokenizer(resourceString, ",");
  410           List<String> filenames = new ArrayList<String>(tokenizer.countTokens());
  411           while (tokenizer.hasMoreTokens()) {
  412               filenames.add(tokenizer.nextToken().trim());
  413           }
  414           return filenames;
  415       }
  416   
  417       /**
  418        * Determine whether or not the container has been
  419        * initialized. Utility method used for methods which
  420        * can not be invoked after the container has been
  421        * started.
  422        *
  423        * @throws IllegalStateException if the container has already been initialized.
  424        */
  425       protected void checkInit() {
  426           if (initialized) {
  427               throw new IllegalStateException("Container allready initialized");
  428           }
  429       }
  430   
  431       /**
  432        * Initializes a definitions factory.
  433        *
  434        * @param definitionsFactory The factory to initialize.
  435        * @param resourceString The string containing a comma-separated-list of
  436        * resources.
  437        * @param initParameters A map containing the initialization parameters.
  438        * @throws DefinitionsFactoryException If something goes wrong.
  439        * @deprecated Do not use, the Definitions Factory should be initialized by
  440        * the Tiles Container Factory.
  441        */
  442       @Deprecated
  443       protected void initializeDefinitionsFactory(
  444               DefinitionsFactory definitionsFactory, String resourceString,
  445               Map<String, String> initParameters) {
  446           if (rendererFactory == null) {
  447               throw new IllegalStateException("No RendererFactory found");
  448           }
  449   
  450           definitionsFactory.init(initParameters);
  451   
  452           if (log.isInfoEnabled()) {
  453               log.info("Tiles2 container initialization complete.");
  454           }
  455       }
  456   
  457       /**
  458        * Returns the context stack.
  459        *
  460        * @param tilesContext The Tiles context object to use.
  461        * @return The needed stack of contexts.
  462        * @since 2.0.6
  463        */
  464       @SuppressWarnings("unchecked")
  465       protected ArrayStack<AttributeContext> getContextStack(TilesRequestContext tilesContext) {
  466           ArrayStack<AttributeContext> contextStack =
  467               (ArrayStack<AttributeContext>) tilesContext
  468                   .getRequestScope().get(ATTRIBUTE_CONTEXT_STACK);
  469           if (contextStack == null) {
  470               contextStack = new ArrayStack<AttributeContext>();
  471               tilesContext.getRequestScope().put(ATTRIBUTE_CONTEXT_STACK,
  472                       contextStack);
  473           }
  474   
  475           return contextStack;
  476       }
  477   
  478       /**
  479        * Pushes a context object in the stack.
  480        *
  481        * @param context The context to push.
  482        * @param tilesContext The Tiles context object to use.
  483        * @since 2.0.6
  484        */
  485       protected void pushContext(AttributeContext context,
  486               TilesRequestContext tilesContext) {
  487           ArrayStack<AttributeContext> contextStack = getContextStack(tilesContext);
  488           contextStack.push(context);
  489       }
  490   
  491       /**
  492        * Pops a context object out of the stack.
  493        *
  494        * @param tilesContext The Tiles context object to use.
  495        * @return The popped context object.
  496        * @since 2.0.6
  497        */
  498       protected AttributeContext popContext(TilesRequestContext tilesContext) {
  499           ArrayStack<AttributeContext> contextStack = getContextStack(tilesContext);
  500           return contextStack.pop();
  501       }
  502   
  503       /**
  504        * Get attribute context from request.
  505        *
  506        * @param tilesContext current Tiles application context.
  507        * @return BasicAttributeContext or null if context is not found.
  508        * @since 2.0.6
  509        */
  510       protected AttributeContext getContext(TilesRequestContext tilesContext) {
  511           ArrayStack<AttributeContext> contextStack = getContextStack(tilesContext);
  512           if (!contextStack.isEmpty()) {
  513               return contextStack.peek();
  514           } else {
  515               return null;
  516           }
  517       }
  518   
  519       /**
  520        * Returns the current attribute context.
  521        *
  522        * @param tilesContext The request context to use.
  523        * @return The current attribute context.
  524        */
  525       private AttributeContext getAttributeContext(TilesRequestContext tilesContext) {
  526           AttributeContext context = getContext(tilesContext);
  527           if (context == null) {
  528               context = new BasicAttributeContext();
  529               pushContext(context, tilesContext);
  530           }
  531           return context;
  532       }
  533   
  534       /**
  535        * Creates a Tiles request context from request items.
  536        *
  537        * @param requestItems The request items.
  538        * @return The created Tiles request context.
  539        */
  540       private TilesRequestContext getRequestContext(Object... requestItems) {
  541           return getRequestContextFactory().createRequestContext(
  542                   getApplicationContext(), requestItems);
  543       }
  544   
  545       /**
  546        * Starts an attribute context inside the container.
  547        *
  548        * @param tilesContext The request context to use.
  549        * @return The newly created attribute context.
  550        */
  551       private AttributeContext startContext(TilesRequestContext tilesContext) {
  552           AttributeContext context = new BasicAttributeContext();
  553           ArrayStack<AttributeContext>  stack = getContextStack(tilesContext);
  554           if (!stack.isEmpty()) {
  555               AttributeContext parent = stack.peek();
  556               context.inheritCascadedAttributes(parent);
  557           }
  558           stack.push(context);
  559           return context;
  560       }
  561   
  562       /**
  563        * Releases and removes a previously created attribute context.
  564        *
  565        * @param tilesContext The request context to use.
  566        */
  567       private void endContext(TilesRequestContext tilesContext) {
  568           popContext(tilesContext);
  569       }
  570   
  571       /**
  572        * Execute a preparer.
  573        *
  574        * @param context The request context.
  575        * @param preparerName The name of the preparer.
  576        * @param ignoreMissing If <code>true</code> if the preparer is not found,
  577        * it ignores the problem.
  578        * @throws NoSuchPreparerException If the preparer is not found (and
  579        * <code>ignoreMissing</code> is not set) or if the preparer itself threw an
  580        * exception.
  581        */
  582       private void prepare(TilesRequestContext context, String preparerName, boolean ignoreMissing) {
  583   
  584           if (log.isDebugEnabled()) {
  585               log.debug("Prepare request received for '" + preparerName);
  586           }
  587   
  588           ViewPreparer preparer = preparerFactory.getPreparer(preparerName, context);
  589           if (preparer == null && ignoreMissing) {
  590               return;
  591           }
  592   
  593           if (preparer == null) {
  594               throw new NoSuchPreparerException("Preparer '" + preparerName + " not found");
  595           }
  596   
  597           AttributeContext attributeContext = getContext(context);
  598   
  599           preparer.execute(context, attributeContext);
  600       }
  601   
  602       /**
  603        * Renders the definition with specified name.
  604        *
  605        * @param request The request context.
  606        * @param definitionName The name of the definition to render.
  607        * @throws NoSuchDefinitionException If the definition has not been found.
  608        * @throws DefinitionsFactoryException If something goes wrong when
  609        * obtaining the definition.
  610        * @since 2.1.3
  611        */
  612       protected void render(TilesRequestContext request, String definitionName) {
  613   
  614           if (log.isDebugEnabled()) {
  615               log.debug("Render request recieved for definition '" + definitionName + "'");
  616           }
  617   
  618           Definition definition = getDefinition(definitionName, request);
  619   
  620           if (definition == null) {
  621               if (log.isWarnEnabled()) {
  622                   String message = "Unable to find the definition '" + definitionName + "'";
  623                   log.warn(message);
  624               }
  625               throw new NoSuchDefinitionException(definitionName);
  626           }
  627           render(request, definition);
  628       }
  629   
  630       /**
  631        * Renders the specified definition.
  632        * @param request The request context.
  633        * @param definition The definition to render.
  634        * @since 2.1.3
  635        */
  636       protected void render(TilesRequestContext request, Definition definition) {
  637           AttributeContext originalContext = getAttributeContext(request);
  638           BasicAttributeContext subContext = new BasicAttributeContext(originalContext);
  639           subContext.inherit(definition);
  640   
  641           pushContext(subContext, request);
  642   
  643           try {
  644               render(request, subContext);
  645           } finally {
  646               popContext(request);
  647           }
  648       }
  649   
  650       /**
  651        * Renders an attribute.
  652        *
  653        * @param attr The attribute to render.
  654        * @param requestContext The Tiles request context.
  655        * @throws IOException If something goes wrong during rendering.
  656        */
  657       private void render(Attribute attr, TilesRequestContext requestContext)
  658               throws IOException {
  659           if (attr == null) {
  660               throw new CannotRenderException("Cannot render a null attribute");
  661           }
  662   
  663           AttributeRenderer renderer = rendererFactory.getRenderer(attr
  664                   .getRenderer());
  665           if (renderer == null) {
  666               throw new CannotRenderException(
  667                       "Cannot render an attribute with renderer name "
  668                               + attr.getRenderer());
  669           }
  670           renderer.render(attr, requestContext);
  671       }
  672   
  673       /**
  674        * Renders the specified attribute context.
  675        *
  676        * @param request The request context.
  677        * @param attributeContext The context to render.
  678        * @throws InvalidTemplateException If the template is not valid.
  679        * @throws CannotRenderException If something goes wrong during rendering.
  680        * @since 2.1.3
  681        */
  682       protected void render(TilesRequestContext request,
  683               AttributeContext attributeContext) {
  684   
  685           try {
  686               if (attributeContext.getPreparer() != null) {
  687                   prepare(request, attributeContext.getPreparer(), true);
  688               }
  689   
  690               render(attributeContext.getTemplateAttribute(), request);
  691           } catch (IOException e) {
  692               throw new CannotRenderException(e.getMessage(), e);
  693           }
  694       }
  695   
  696       /**
  697        * Checks if a string is a valid definition name.
  698        *
  699        * @param context The request context.
  700        * @param definitionName The name of the definition to find.
  701        * @return <code>true</code> if <code>definitionName</code> is a valid
  702        * definition name.
  703        */
  704       private boolean isValidDefinition(TilesRequestContext context, String definitionName) {
  705           try {
  706               Definition definition = getDefinition(definitionName, context);
  707               return definition != null;
  708           } catch (NoSuchDefinitionException nsde) {
  709               return false;
  710           } catch (DefinitionsFactoryException e) {
  711               // TODO, is this the right thing to do?
  712               return false;
  713           }
  714       }
  715   }

Save This Page
Home » tiles-2.2.1-src » org.apache » tiles » impl » [javadoc | source]