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