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 root
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 */
568 public void incrementUniqueId()
569 {
570 }
571
572 /**
573 * Check if the facelet is building view metadata
574 *
575 * since 2.1.7, 2.0.13
576 * @return
577 */
578 public boolean isBuildingViewMetadata()
579 {
580 return FaceletViewDeclarationLanguage.isBuildingViewMetadata(
581 FacesContext.getCurrentInstance());
582 }
583
584 /**
585 * Call this method to indicate a f:metadata section is about to be processed
586 *
587 * since 2.1.7, 2.0.13
588 */
589 public void startMetadataSection()
590 {
591 }
592
593 /**
594 * Call this method to indicate f:metadata section has been already processed
595 *
596 * since 2.1.7, 2.0.13
597 */
598 public void endMetadataSection()
599 {
600 }
601
602 /**
603 * Check if the component is created inside f:metadata section
604 *
605 * since 2.1.7, 2.0.13
606 * @return
607 */
608 public boolean isInMetadataSection()
609 {
610 return false;
611 }
612
613 /**
614 * Check if the section to be processed is being refreshed.
615 *
616 * since 2.1.7, 2.0.13
617 * @return
618 */
619 public boolean isRefreshingSection()
620 {
621 return isRefreshingTransientBuild() || (!isBuildingViewMetadata() && isInMetadataSection());
622 }
623
624 /**
625 *
626 * @since 2.1.8, 2.0.14
627 */
628 public void incrementUniqueComponentId()
629 {
630 }
631
632 public StringBuilder getSharedStringBuilder()
633 {
634 return new StringBuilder();
635 }
636
637 /**
638 * Returns the current nesting level of composite components found. If
639 * no composite component has been used returns 0.
640 *
641 * @since 2.1.9, 2.0.15
642 */
643 public int getCompositeComponentLevel()
644 {
645 return 0;
646 }
647
648 public boolean isDynamicCompositeComponentHandler()
649 {
650 return false;
651 }
652
653 public void setDynamicCompositeComponentHandler(boolean value)
654 {
655 }
656
657 public void pushDynamicComponentSection(String baseKey)
658 {
659 }
660
661 public void popDynamicComponentSection()
662 {
663 }
664
665 /**
666 * Check if the algorithm is applying a dynamic component and the current component
667 * is the top level one. This is necessary to avoid remove/add the component under
668 * a refresh and in that way change the position of the component in the tree. Remember
669 * facelets algorithm removes/add components to sort the components under a refresh, but
670 * in this case, it is up to the user to put the component in the tree, so the idea is
671 * do not make interference with the user's code. Note if the dynamic content is wrapped
672 * by a generated panel, the top level component is the wrapper itself, which has no
673 * attached tag handler.
674 *
675 * @since 2.2
676 * @return
677 */
678 public boolean isDynamicComponentTopLevel()
679 {
680 return false;
681 }
682
683 public void setDynamicComponentTopLevel(boolean value)
684 {
685 }
686
687 /**
688 * Indicate if the current facelet section is a dynamic component section,
689 * which means it was added to the component tree using vdl.createComponent(...);
690 *
691 * @since 2.2
692 * @return
693 */
694 public boolean isDynamicComponentSection()
695 {
696 return false;
697 }
698
699 public UIViewRoot getViewRoot(FacesContext facesContext)
700 {
701 return facesContext.getViewRoot();
702 }
703
704 public void setViewRoot(UIViewRoot root)
705 {
706 }
707
708 public VisitContextFactory getVisitContextFactory()
709 {
710 return (VisitContextFactory)FactoryFinder.getFactory(FactoryFinder.VISIT_CONTEXT_FACTORY);
711 }
712 }