1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.myfaces.view.facelets;
20
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import javax.faces.FactoryFinder;
25
26 import javax.faces.component.UIComponent;
27 import javax.faces.component.UIViewRoot;
28 import javax.faces.component.UniqueIdVendor;
29 import javax.faces.component.visit.VisitContextFactory;
30 import javax.faces.context.FacesContext;
31 import javax.faces.view.AttachedObjectHandler;
32 import javax.faces.view.EditableValueHolderAttachedObjectHandler;
33 import javax.faces.view.facelets.FaceletContext;
34
35 /**
36 * @since 2.0.1
37 * @author Leonardo Uribe (latest modification by $Author$)
38 * @version $Revision$ $Date$
39 */
40 abstract public class FaceletCompositionContext
41 {
42 static protected final String FACELET_COMPOSITION_CONTEXT_KEY = "oam.facelets.FACELET_COMPOSITION_CONTEXT";
43
44 protected FaceletCompositionContext()
45 {
46 }
47
48 static public FaceletCompositionContext getCurrentInstance()
49 {
50 return (FaceletCompositionContext)
51 FacesContext.getCurrentInstance().getAttributes().get(FACELET_COMPOSITION_CONTEXT_KEY);
52 }
53
54 static public FaceletCompositionContext getCurrentInstance(FaceletContext ctx)
55 {
56 if (ctx instanceof AbstractFaceletContext)
57 {
58 return ((AbstractFaceletContext)ctx).getFaceletCompositionContext();
59 }
60 else
61 {
62 // Here we have two choices: retrieve it throught ThreadLocal var
63 // or use the attribute value on FacesContext, but it seems better
64 // use the FacesContext attribute map.
65 return (FaceletCompositionContext)
66 ctx.getFacesContext().getAttributes().get(FACELET_COMPOSITION_CONTEXT_KEY);
67 }
68 }
69
70 static public FaceletCompositionContext getCurrentInstance(FacesContext ctx)
71 {
72 return (FaceletCompositionContext) ctx.getAttributes().get(FACELET_COMPOSITION_CONTEXT_KEY);
73 }
74
75 public void init(FacesContext facesContext)
76 {
77 facesContext.getAttributes().put(
78 FaceletCompositionContext.FACELET_COMPOSITION_CONTEXT_KEY, this);
79 }
80
81 /**
82 * Releases the MyFaceletContext object. This method must only
83 * be called by the code that created the MyFaceletContext.
84 */
85 public void release(FacesContext facesContext)
86 {
87 facesContext.getAttributes().remove(FACELET_COMPOSITION_CONTEXT_KEY);
88 }
89
90 public abstract FaceletFactory getFaceletFactory();
91
92 /**
93 * Return the composite component being applied on the current facelet.
94 *
95 * Note this is different to UIComponent.getCurrentCompositeComponent, because a composite
96 * component is added to the stack each time a composite:implementation tag handler is applied.
97 *
98 * This could be used by InsertChildrenHandler and InsertFacetHandler to retrieve the current
99 * composite component to be applied.
100 *
101 * @since 2.0.1
102 * @return
103 */
104 public abstract UIComponent getCompositeComponentFromStack();
105
106 /**
107 * @since 2.0.1
108 * @param parent
109 */
110 public abstract void pushCompositeComponentToStack(UIComponent parent);
111
112 /**
113 * @since 2.0.1
114 */
115 public abstract void popCompositeComponentToStack();
116
117 /**
118 * Return the latest UniqueIdVendor created from stack. The reason why we need to keep
119 * a UniqueIdVendor stack is because we need to look the closest one in ComponentTagHandlerDelegate.
120 * Note that facelets tree is built from leafs to root, that means use UIComponent.getParent() does not
121 * always return parent components.
122 *
123 * @since 2.0.1
124 * @return
125 */
126 public abstract UniqueIdVendor getUniqueIdVendorFromStack();
127
128 /**
129 * @since 2.0.1
130 * @param parent
131 */
132 public abstract void pushUniqueIdVendorToStack(UniqueIdVendor parent);
133
134 /**
135 * @since 2.0.1
136 */
137 public abstract void popUniqueIdVendorToStack();
138
139 /**
140 * Gets the top of the validationGroups stack.
141 * @return
142 * @since 2.0.1
143 */
144 @Deprecated
145 public abstract String getFirstValidationGroupFromStack();
146
147 /**
148 * Removes top of stack.
149 * @since 2.0.1
150 */
151 @Deprecated
152 public abstract void popValidationGroupsToStack();
153
154 /**
155 * Pushes validationGroups to the stack.
156 * @param validationGroups
157 * @since 2.0.1
158 */
159 @Deprecated
160 public abstract void pushValidationGroupsToStack(String validationGroups);
161
162 /**
163 * Gets all validationIds on the stack.
164 * @return
165 * @since 2.0.1
166 */
167 @Deprecated
168 public abstract Iterator<String> getExcludedValidatorIds();
169
170 /**
171 * Removes top of stack.
172 * @since 2.0.1
173 */
174 @Deprecated
175 public abstract void popExcludedValidatorIdToStack();
176
177 /**
178 * Pushes validatorId to the stack of excluded validatorIds.
179 * @param validatorId
180 * @since 2.0.1
181 */
182 @Deprecated
183 public abstract void pushExcludedValidatorIdToStack(String validatorId);
184
185 /**
186 * Gets all validationIds on the stack.
187 * @return
188 * @since 2.0.1
189 */
190 @Deprecated
191 public abstract Iterator<String> getEnclosingValidatorIds();
192
193 /**
194 * Removes top of stack.
195 * @since 2.0.1
196 */
197 public abstract void popEnclosingValidatorIdToStack();
198
199 /**
200 * Pushes validatorId to the stack of all enclosing validatorIds.
201 * @param validatorId
202 * @since 2.0.1
203 */
204 @Deprecated
205 public abstract void pushEnclosingValidatorIdToStack(String validatorId);
206
207 /**
208 * Pushes validatorId to the stack of all enclosing validatorIds.
209 *
210 * @param validatorId
211 * @param attachedObjectHandler
212 * @since 2.0.10
213 */
214 public abstract void pushEnclosingValidatorIdToStack(String validatorId,
215 EditableValueHolderAttachedObjectHandler attachedObjectHandler);
216
217 /**
218 * Gets all validationIds with its associated EditableValueHolderAttachedObjectHandler from the stack.
219 *
220 * @return
221 * @since 2.0.10
222 */
223 public abstract Iterator<Map.Entry<String, EditableValueHolderAttachedObjectHandler>>
224 getEnclosingValidatorIdsAndHandlers();
225
226 /**
227 *
228 * @param id
229 * @return
230 * @since 2.0.10
231 */
232 public abstract boolean containsEnclosingValidatorId(String id);
233
234 /**
235 * Check if this build is being refreshed, adding transient components
236 * and adding/removing components under c:if or c:forEach or not.
237 *
238 * @return
239 * @since 2.0.1
240 */
241 public abstract boolean isRefreshingTransientBuild();
242
243 /**
244 * Check if this build should be marked as initial state. In other words,
245 * all components must call UIComponent.markInitialState.
246 *
247 * @return
248 * @since 2.0.1
249 */
250 public abstract boolean isMarkInitialState();
251
252 public void setMarkInitialState(boolean value)
253 {
254 }
255
256 /**
257 * Check if the current view will be refreshed with partial state saving.
258 *
259 * This param is used in two posible events:
260 *
261 * 1. To notify UIInstruction instances to look for instances moved by
262 * cc:insertChildren or cc:insertFacet.
263 * 2. To do proper actions when a tag that could change tree structure is applied
264 * (c:if, c:forEach...)
265 *
266 * @return
267 * @since 2.0.1
268 */
269 public abstract boolean isRefreshTransientBuildOnPSS();
270
271 /**
272 *
273 * @since 2.0.12, 2.1.6
274 * @return
275 */
276 public boolean isRefreshTransientBuildOnPSSPreserveState()
277 {
278 return false;
279 }
280
281 /**
282 * Check if we are using partial state saving on this view
283 *
284 * @return
285 * @since 2.0.1
286 */
287 public abstract boolean isUsingPSSOnThisView();
288
289 /**
290 * @since 2.0.1
291 * @return
292 */
293 public abstract boolean isMarkInitialStateAndIsRefreshTransientBuildOnPSS();
294
295 /**
296 * Add to the composite component parent this handler, so it will be processed later when
297 * ViewDeclarationLanguage.retargetAttachedObjects is called.
298 *
299 * Tag Handlers exposing attached objects should call this method to expose them when the
300 * parent to be applied is a composite components.
301 *
302 * @since 2.0.2
303 * @param compositeComponentParent
304 * @param handler
305 */
306 public abstract void addAttachedObjectHandler(UIComponent compositeComponentParent, AttachedObjectHandler handler);
307
308 /**
309 * Remove from the composite component parent the list of attached handlers.
310 *
311 * @since 2.0.2
312 * @param compositeComponentParent
313 */
314 public abstract void removeAttachedObjectHandlers(UIComponent compositeComponentParent);
315
316 /**
317 * Retrieve the list of object handlers attached to a composite component parent.
318 *
319 * @since 2.0.2
320 * @param compositeComponentParent
321 */
322 public abstract List<AttachedObjectHandler> getAttachedObjectHandlers(UIComponent compositeComponentParent);
323
324 /**
325 * Marks all direct children and Facets with an attribute for deletion.
326 *
327 * @since 2.0.2
328 * @see #finalizeForDeletion(UIComponent)
329 * @param component
330 * UIComponent to mark
331 */
332 public abstract void markForDeletion(UIComponent component);
333
334 /**
335 * Used in conjunction with markForDeletion where any UIComponent marked will be removed.
336 *
337 * @since 2.0.2
338 * @param component
339 * UIComponent to finalize
340 */
341 public abstract void finalizeForDeletion(UIComponent component);
342
343 public void removeComponentForDeletion(UIComponent component)
344 {
345 }
346
347 /**
348 * Marks the given resource for deletion. Is to be used for relocatable
349 * components instead of {@link #markForDeletion(UIComponent)}.
350 *
351 * @since 2.0.17 2.1.11
352 * @param component
353 * UIComponent to finalize
354 */
355 public void markRelocatableResourceForDeletion(UIComponent component)
356 {
357 }
358
359 /**
360 * Used to clean up all unused relocatable components on the root component.
361 *
362 * @since 2.0.17 2.1.11
363 * @param component
364 * UIComponent to finalize (root component)
365 */
366 public void finalizeRelocatableResourcesForDeletion(UIViewRoot root)
367 {
368 }
369
370 /**
371 * Add a method expression as targeted for the provided composite component
372 *
373 * @since 2.0.3
374 * @param targetedComponent
375 * @param attributeName
376 * @param backingValue A value that could be useful to revert its effects.
377 */
378 public abstract void addMethodExpressionTargeted(UIComponent targetedComponent, String attributeName,
379 Object backingValue);
380
381 /**
382 * Check if the MethodExpression attribute has been applied using vdl.retargetMethodExpression
383 *
384 * @since 2.0.3
385 * @param compositeComponentParent
386 * @param attributeName
387 * @return
388 */
389 public abstract boolean isMethodExpressionAttributeApplied(UIComponent compositeComponentParent,
390 String attributeName);
391
392 /**
393 * Mark the MethodExpression attribute as applied using vdl.retargetMethodExpression
394 *
395 * @since 2.0.3
396 * @param compositeComponentParent
397 * @param attributeName
398 */
399 public abstract void markMethodExpressionAttribute(UIComponent compositeComponentParent, String attributeName);
400
401 /**
402 * Clear the MethodExpression attribute to call vdl.retargetMethodExpression again
403 *
404 * @since 2.0.3
405 * @param compositeComponentParent
406 * @param attributeName
407 */
408 public abstract void clearMethodExpressionAttribute(UIComponent compositeComponentParent, String attributeName);
409
410 /**
411 * Remove a method expression as targeted for the provided composite component
412 *
413 * @since 2.0.3
414 * @param targetedComponent
415 * @param attributeName
416 * @return A value that could be useful to revert its effects.
417 */
418 public abstract Object removeMethodExpressionTargeted(UIComponent targetedComponent, String attributeName);
419
420 /**
421 * Indicates if a EL Expression can be or not cached by facelets vdl.
422 *
423 * @since 2.0.8
424 * @return
425 */
426 public ELExpressionCacheMode getELExpressionCacheMode()
427 {
428 return ELExpressionCacheMode.noCache;
429 }
430
431 /**
432 *
433 * @since 2.0.9
434 * @return
435 */
436 public boolean isWrapTagExceptionsAsContextAware()
437 {
438 return true;
439 }
440
441 /**
442 * Start a new unique id section, which means a new counter is used to
443 * generate unique ids to components
444 *
445 * @since 2.0.10, 2.1.4
446 * @return
447 */
448 public String startComponentUniqueIdSection()
449 {
450 return null;
451 }
452
453 /**
454 * Start a new unique id section, which means a new counter is used to
455 * generate unique ids to components, but appending a base to the
456 * new counter.
457 *
458 * @since 2.2.0
459 * @return
460 */
461 public String startComponentUniqueIdSection(String base)
462 {
463 return null;
464 }
465
466 /**
467 * @since 2.2.0
468 * @param base
469 */
470 public void endComponentUniqueIdSection(String base)
471 {
472 }
473
474 /**
475 * Generate a unique id that will be used later to derive a unique id per tag
476 * by FaceletContext.generateUniqueId(). This generator ensures uniqueness per
477 * view but FaceletContext.generateUniqueId() ensures uniqueness per view and
478 * per facelet hierarchy, so different included facelets will generate different
479 * ids.
480 *
481 * @return
482 */
483 public String generateUniqueId()
484 {
485 return null;
486 }
487
488 public void generateUniqueId(StringBuilder builderToAdd)
489 {
490 }
491
492 /**
493 * Generate a unique id for component instances.
494 *
495 * @return
496 */
497 public String generateUniqueComponentId()
498 {
499 return null;
500 }
501
502 /**
503 * Ends the current unique id section, so the previous counter will be used
504 * to generate unique ids to components.
505 */
506 public void endComponentUniqueIdSection()
507 {
508 }
509
510 /**
511 * Set the iterator used to retrieve unique ids.
512 *
513 * since 2.1.7, 2.0.13
514 * @param uniqueIdsIterator
515 */
516 public void setUniqueIdsIterator(Iterator<String> uniqueIdsIterator)
517 {
518 }
519
520 /**
521 * Activater record unique id mode, so an structure will be
522 * used to hold those values.
523 *
524 * since 2.1.7, 2.0.13
525 */
526 public void initUniqueIdRecording()
527 {
528 }
529
530 /**
531 * Add an unique id to the list if recording is enabled,
532 * if recording is not enabled it has no effect.
533 *
534 * since 2.1.7, 2.0.13
535 * @param uniqueId
536 */
537 public void addUniqueId(String uniqueId)
538 {
539 }
540
541 /**
542 * Return the unique id from the iterator if applies
543 *
544 * since 2.1.7, 2.0.13
545 * @return
546 */
547 public String getUniqueIdFromIterator()
548 {
549 return null;
550 }
551
552 /**
553 * Return the list of unique ids
554 *
555 * since 2.1.7, 2.0.13
556 * @return
557 */
558 public List<String> getUniqueIdList()
559 {
560 return null;
561 }
562
563 /**
564 * Increment the unique id without construct it.
565 *
566 * since 2.1.7, 2.0.13
567 * @return
568 */
569 public void incrementUniqueId()
570 {
571 }
572
573 /**
574 * Check if the facelet is building view metadata
575 *
576 * since 2.1.7, 2.0.13
577 * @return
578 */
579 public boolean isBuildingViewMetadata()
580 {
581 return FaceletViewDeclarationLanguage.isBuildingViewMetadata(
582 FacesContext.getCurrentInstance());
583 }
584
585 /**
586 * Call this method to indicate a f:metadata section is about to be processed
587 *
588 * since 2.1.7, 2.0.13
589 * @return
590 */
591 public void startMetadataSection()
592 {
593 }
594
595 /**
596 * Call this method to indicate f:metadata section has been already processed
597 *
598 * since 2.1.7, 2.0.13
599 * @return
600 */
601 public void endMetadataSection()
602 {
603 }
604
605 /**
606 * Check if the component is created inside f:metadata section
607 *
608 * since 2.1.7, 2.0.13
609 * @return
610 */
611 public boolean isInMetadataSection()
612 {
613 return false;
614 }
615
616 /**
617 * Check if the section to be processed is being refreshed.
618 *
619 * since 2.1.7, 2.0.13
620 * @return
621 */
622 public boolean isRefreshingSection()
623 {
624 return isRefreshingTransientBuild() || (!isBuildingViewMetadata() && isInMetadataSection());
625 }
626
627 /**
628 *
629 * @since 2.1.8, 2.0.14
630 */
631 public void incrementUniqueComponentId()
632 {
633 }
634
635 public StringBuilder getSharedStringBuilder()
636 {
637 return new StringBuilder();
638 }
639
640 /**
641 * Returns the current nesting level of composite components found. If
642 * no composite component has been used returns 0.
643 *
644 * @since 2.1.9, 2.0.15
645 */
646 public int getCompositeComponentLevel()
647 {
648 return 0;
649 }
650
651 public boolean isDynamicCompositeComponentHandler()
652 {
653 return false;
654 }
655
656 public void setDynamicCompositeComponentHandler(boolean value)
657 {
658 }
659
660 public void pushDynamicComponentSection(String baseKey)
661 {
662 }
663
664 public void popDynamicComponentSection()
665 {
666 }
667
668 /**
669 * Check if the algorithm is applying a dynamic component and the current component
670 * is the top level one. This is necessary to avoid remove/add the component under
671 * a refresh and in that way change the position of the component in the tree. Remember
672 * facelets algorithm removes/add components to sort the components under a refresh, but
673 * in this case, it is up to the user to put the component in the tree, so the idea is
674 * do not make interference with the user's code. Note if the dynamic content is wrapped
675 * by a generated panel, the top level component is the wrapper itself, which has no
676 * attached tag handler.
677 *
678 * @since 2.2
679 * @return
680 */
681 public boolean isDynamicComponentTopLevel()
682 {
683 return false;
684 }
685
686 public void setDynamicComponentTopLevel(boolean value)
687 {
688 }
689
690 /**
691 * Indicate if the current facelet section is a dynamic component section,
692 * which means it was added to the component tree using vdl.createComponent(...);
693 *
694 * @since 2.2
695 * @return
696 */
697 public boolean isDynamicComponentSection()
698 {
699 return false;
700 }
701
702 public UIViewRoot getViewRoot(FacesContext facesContext)
703 {
704 return facesContext.getViewRoot();
705 }
706
707 public void setViewRoot(UIViewRoot root)
708 {
709 }
710
711 public VisitContextFactory getVisitContextFactory()
712 {
713 return (VisitContextFactory)FactoryFinder.getFactory(FactoryFinder.VISIT_CONTEXT_FACTORY);
714 }
715 }