Search in sources :

Example 1 with RefreshDynamicComponentListener

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);
    }
}
Also used : FacesContext(jakarta.faces.context.FacesContext) FaceletCompositionContext(org.apache.myfaces.view.facelets.FaceletCompositionContext) AbstractFacelet(org.apache.myfaces.view.facelets.AbstractFacelet) Facelet(jakarta.faces.view.facelets.Facelet) FaceletFactory(org.apache.myfaces.view.facelets.FaceletFactory) AbstractFacelet(org.apache.myfaces.view.facelets.AbstractFacelet) UIComponent(jakarta.faces.component.UIComponent) FaceletViewDeclarationLanguage(org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage) IOException(java.io.IOException) RefreshDynamicComponentListener(org.apache.myfaces.view.facelets.compiler.RefreshDynamicComponentListener) LocationAwareFacesException(org.apache.myfaces.view.facelets.LocationAwareFacesException)

Example 2 with RefreshDynamicComponentListener

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;
}
Also used : PostAddToViewEvent(jakarta.faces.event.PostAddToViewEvent) Facelet(jakarta.faces.view.facelets.Facelet) UIComponent(jakarta.faces.component.UIComponent) UIPanel(jakarta.faces.component.UIPanel) PostRestoreStateEvent(jakarta.faces.event.PostRestoreStateEvent) IOException(java.io.IOException) RefreshDynamicComponentListener(org.apache.myfaces.view.facelets.compiler.RefreshDynamicComponentListener) FacesException(jakarta.faces.FacesException) CreateDynamicCompositeComponentListener(org.apache.myfaces.view.facelets.tag.composite.CreateDynamicCompositeComponentListener)

Aggregations

UIComponent (jakarta.faces.component.UIComponent)2 Facelet (jakarta.faces.view.facelets.Facelet)2 IOException (java.io.IOException)2 RefreshDynamicComponentListener (org.apache.myfaces.view.facelets.compiler.RefreshDynamicComponentListener)2 FacesException (jakarta.faces.FacesException)1 UIPanel (jakarta.faces.component.UIPanel)1 FacesContext (jakarta.faces.context.FacesContext)1 PostAddToViewEvent (jakarta.faces.event.PostAddToViewEvent)1 PostRestoreStateEvent (jakarta.faces.event.PostRestoreStateEvent)1 AbstractFacelet (org.apache.myfaces.view.facelets.AbstractFacelet)1 FaceletCompositionContext (org.apache.myfaces.view.facelets.FaceletCompositionContext)1 FaceletFactory (org.apache.myfaces.view.facelets.FaceletFactory)1 FaceletViewDeclarationLanguage (org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage)1 LocationAwareFacesException (org.apache.myfaces.view.facelets.LocationAwareFacesException)1 CreateDynamicCompositeComponentListener (org.apache.myfaces.view.facelets.tag.composite.CreateDynamicCompositeComponentListener)1