use of org.apache.myfaces.view.facelets.compiler.RefreshDynamicComponentListener in project myfaces by apache.
the class CreateDynamicCompositeComponentListener method processEvent.
@Override
public void processEvent(ComponentSystemEvent event) {
FacesContext facesContext = FacesContext.getCurrentInstance();
FaceletViewDeclarationLanguage vdl = (FaceletViewDeclarationLanguage) facesContext.getApplication().getViewHandler().getViewDeclarationLanguage(facesContext, facesContext.getViewRoot().getViewId());
Facelet componentFacelet;
FaceletFactory faceletFactory = vdl.getFaceletFactory();
FaceletFactory.setInstance(faceletFactory);
try {
componentFacelet = faceletFactory.compileComponentFacelet(taglibURI, tagName, attributes);
} finally {
FaceletFactory.setInstance(null);
}
UIComponent component = event.getComponent();
// The execution of this listener activated another call to PostAddToViewEvent, because
// ComponentTagHandlerDelegate removes and add the component again. This is necessary because
// the inner components also require the propagation of PostAddToViewEvent to refresh themselves.
// but this check avoids the duplicate call to the facelet, even if the duplicate call does not
// have any side effect (counts as a refresh).
Integer step = (Integer) component.getAttributes().get(CompositeComponentResourceTagHandler.CREATE_CC_ON_POST_ADD_TO_VIEW);
if (step != null && step == 0) {
component.getAttributes().put(CompositeComponentResourceTagHandler.CREATE_CC_ON_POST_ADD_TO_VIEW, 1);
} else {
return;
}
try {
facesContext.getAttributes().put(FaceletViewDeclarationLanguage.REFRESHING_TRANSIENT_BUILD, Boolean.TRUE);
// Detect the relationship between parent and child, to ensure the component is properly created
// and refreshed. In facelets this is usually done by core.FacetHandler, but since it is a
// dynamic component, we need to do it here before apply the handler
UIComponent parent = component.getParent();
String facetName = null;
if (parent.getFacetCount() > 0 && !parent.getChildren().contains(component)) {
facetName = ComponentSupport.findFacetNameByComponentInstance(parent, component);
}
try {
if (facetName != null) {
parent.getAttributes().put(org.apache.myfaces.view.facelets.tag.faces.core.FacetHandler.KEY, facetName);
}
// The trick here is restore MARK_CREATED, just to allow ComponentTagHandlerDelegate to
// find the component. Then we reset it to exclude it from facelets refresh algorithm.
String markId = (String) component.getAttributes().get(FaceletViewDeclarationLanguage.GEN_MARK_ID);
if (markId == null) {
((AbstractFacelet) componentFacelet).applyDynamicComponentHandler(facesContext, component, baseKey);
} else {
try {
component.getAttributes().put(ComponentSupport.MARK_CREATED, markId);
((AbstractFacelet) componentFacelet).applyDynamicComponentHandler(facesContext, component.getParent(), baseKey);
} finally {
component.getAttributes().put(ComponentSupport.MARK_CREATED, null);
}
}
if (FaceletViewDeclarationLanguageBase.isDynamicComponentNeedsRefresh(facesContext)) {
FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(facesContext);
if (fcc == null) {
FaceletViewDeclarationLanguageBase.activateDynamicComponentRefreshTransientBuild(facesContext);
FaceletViewDeclarationLanguageBase.resetDynamicComponentNeedsRefreshFlag(facesContext);
component.subscribeToEvent(DynamicComponentRefreshTransientBuildEvent.class, new RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
component.getAttributes().put(DynamicComponentRefreshTransientBuildEvent.DYN_COMP_REFRESH_FLAG, Boolean.TRUE);
} else {
component.subscribeToEvent(FaceletDynamicComponentRefreshTransientBuildEvent.class, new RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
}
}
} finally {
if (facetName != null) {
parent.getAttributes().remove(org.apache.myfaces.view.facelets.tag.faces.core.FacetHandler.KEY);
}
}
} catch (IOException e) {
throw new LocationAwareFacesException(e, component);
} finally {
facesContext.getAttributes().remove(FaceletViewDeclarationLanguage.REFRESHING_TRANSIENT_BUILD);
}
}
use of org.apache.myfaces.view.facelets.compiler.RefreshDynamicComponentListener in project myfaces by apache.
the class FaceletViewDeclarationLanguage method createComponent.
@Override
public UIComponent createComponent(FacesContext context, String taglibURI, String tagName, Map<String, Object> attributes) {
Assert.notNull(context, "context");
UIComponent createdComponent = null;
try {
Facelet componentFacelet;
FaceletFactory.setInstance(faceletFactory);
try {
componentFacelet = faceletFactory.compileComponentFacelet(taglibURI, tagName, attributes);
} finally {
FaceletFactory.setInstance(null);
}
if (componentFacelet == null) {
return null;
}
// Create a temporal component base class where all components will be put, but we are only
// interested in the inner UIComponent and if multiple are created, return this one.
boolean requiresDynamicRefresh = false;
boolean requiresFaceletDynamicRefresh = false;
UIPanel tempParent = (UIPanel) context.getApplication().createComponent(context, UIPanel.COMPONENT_TYPE, null);
tempParent.setId(context.getViewRoot().createUniqueId(context, null));
String baseKey = tempParent.getId();
baseKey = baseKey.startsWith(UIViewRoot.UNIQUE_ID_PREFIX) ? baseKey.substring(4) : baseKey;
try {
tempParent.pushComponentToEL(context, tempParent);
((AbstractFacelet) componentFacelet).applyDynamicComponentHandler(context, tempParent, baseKey);
} finally {
tempParent.popComponentFromEL(context);
// There are two cases:
// 1. If we are under facelets algorithm control (binding case), the refreshing logic will be done
// outside this block. We can check that condition easily with FaceletCompositionContext
// 2. If we are not under facelets algorithm control, check if the dynamic component requires refresh,
// if that so, mark the view to be refreshed and reset the flag, otherwise continue. This check
// allows us to decide if we add a third listener to refresh on transient build.
// Check if the current component requires dynamic refresh and if that so,
FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(context);
if (fcc != null) {
requiresFaceletDynamicRefresh = true;
} else if (FaceletViewDeclarationLanguageBase.isDynamicComponentNeedsRefresh(context)) {
FaceletViewDeclarationLanguageBase.activateDynamicComponentRefreshTransientBuild(context);
FaceletViewDeclarationLanguageBase.resetDynamicComponentNeedsRefreshFlag(context);
requiresDynamicRefresh = true;
}
}
if (tempParent.getChildCount() > 1) {
// Multiple child. The tempParent will be returned. No need to
// save MARK_CREATED.
createdComponent = tempParent;
tempParent.getAttributes().put(DYN_WRAPPER, baseKey);
tempParent.subscribeToEvent(PostRestoreStateEvent.class, new RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
if (requiresFaceletDynamicRefresh) {
FaceletViewDeclarationLanguageBase.dynamicComponentNeedsRefresh(context);
}
} else if (tempParent.getChildCount() == 1) {
createdComponent = tempParent.getChildren().get(0);
boolean requiresRefresh = false;
// One child. In that case there are three choices:
if (UIComponent.isCompositeComponent(createdComponent)) {
// 1. Composite component. Needs special handling because
// facets will be added programatically. The algorithm that
// process the composite component content should occur
// after the component is added to the view (PostAddToViewEvent).
// Requires refresh. To do that, we need to save the MARK_CREATED
// value and set it only when the full component is refreshed after
// restore it.
createdComponent.getAttributes().put(GEN_MARK_ID, createdComponent.getAttributes().get(ComponentSupport.MARK_CREATED));
createdComponent.getAttributes().put(ComponentSupport.MARK_CREATED, null);
createdComponent.subscribeToEvent(PostAddToViewEvent.class, new CreateDynamicCompositeComponentListener(taglibURI, tagName, attributes, baseKey));
requiresRefresh = true;
if (requiresFaceletDynamicRefresh) {
FaceletViewDeclarationLanguageBase.dynamicComponentNeedsRefresh(context);
}
} else if (createdComponent.getChildCount() > 0) {
// 2. Single component with children inside.
// Requires refresh. To do that, we need to save the MARK_CREATED
// value and set it only when the full component is refreshed after
// restore it.
createdComponent.getAttributes().put(GEN_MARK_ID, createdComponent.getAttributes().get(ComponentSupport.MARK_CREATED));
createdComponent.getAttributes().put(ComponentSupport.MARK_CREATED, null);
requiresRefresh = true;
if (requiresFaceletDynamicRefresh) {
FaceletViewDeclarationLanguageBase.dynamicComponentNeedsRefresh(context);
}
} else if (createdComponent.isTransient()) {
// Just transient markup inside. It is necessary to wrap
// that content into a component. Requires refresh. No need to
// save MARK_CREATED. No requires dynamic refresh.
createdComponent = tempParent;
tempParent.getAttributes().put(DYN_WRAPPER, baseKey);
requiresRefresh = true;
} else {
// 4. Single component without children:
// Remove MARK_CREATED because it does not requires
// refresh on restore. When it is added to the component
// tree, it will be saved and restored as if was a programatically
// added component.
createdComponent.getAttributes().put(ComponentSupport.MARK_CREATED, null);
}
if (requiresRefresh) {
createdComponent.subscribeToEvent(PostRestoreStateEvent.class, new RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
}
if (requiresDynamicRefresh) {
createdComponent.subscribeToEvent(DynamicComponentRefreshTransientBuildEvent.class, new RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
createdComponent.getAttributes().put(DynamicComponentRefreshTransientBuildEvent.DYN_COMP_REFRESH_FLAG, Boolean.TRUE);
}
if (requiresFaceletDynamicRefresh) {
createdComponent.subscribeToEvent(FaceletDynamicComponentRefreshTransientBuildEvent.class, new RefreshDynamicComponentListener(taglibURI, tagName, attributes, baseKey));
}
}
} catch (IOException e) {
throw new FacesException(e);
}
return createdComponent;
}
Aggregations