001/**
002 * Copyright 2005-2018 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.uif.lifecycle;
017
018import java.util.Queue;
019import java.util.Set;
020
021import org.kuali.rice.krad.uif.UifConstants;
022import org.kuali.rice.krad.uif.component.Component;
023import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle.LifecycleEvent;
024import org.kuali.rice.krad.uif.util.LifecycleElement;
025import org.kuali.rice.krad.uif.util.RecycleUtils;
026
027/**
028 * Lifecycle phase processing task for rendering a component.
029 *
030 * @author Kuali Rice Team (rice.collab@kuali.org)
031 * @see ViewLifecycle#isRenderInLifecycle()
032 */
033public class RenderComponentPhase extends ViewLifecyclePhaseBase {
034
035    private RenderComponentPhase renderParent;
036    private Set<String> pendingChildren;
037
038    /**
039     * {@inheritDoc}
040     */
041    @Override
042    public void recycle() {
043        super.recycle();
044        renderParent = null;
045        pendingChildren = null;
046    }
047
048    /**
049     * Create a new lifecycle phase processing task for finalizing a component.
050     *
051     * @param renderParent rendering phase to queue as a successor when all children have processed
052     * @param pendingChildren set of paths to child rendering phases to expect to be queued for
053     * processing before this phase
054     */
055    void prepareRenderPhase(RenderComponentPhase renderParent, Set<String> pendingChildren) {
056        this.renderParent = renderParent;
057        this.pendingChildren = pendingChildren;
058    }
059
060    /**
061     * {@inheritDoc}
062     *
063     * @return UifConstants.ViewPhases.RENDER
064     */
065    @Override
066    public String getViewPhase() {
067        return UifConstants.ViewPhases.RENDER;
068    }
069
070    /**
071     * {@inheritDoc}
072     *
073     * @return UifConstants.ViewStatus.FINAL
074     */
075    @Override
076    public String getStartViewStatus() {
077        return UifConstants.ViewStatus.FINAL;
078    }
079
080    /**
081     * {@inheritDoc}
082     *
083     * @return UifConstants.ViewStatus.RENDERED
084     */
085    @Override
086    public String getEndViewStatus() {
087        return UifConstants.ViewStatus.RENDERED;
088    }
089
090    /**
091     * {@inheritDoc}
092     */
093    @Override
094    public LifecycleEvent getEventToNotify() {
095        return null;
096    }
097
098    /**
099     * Verify that the all pending children have completed.
100     */
101    @Override
102    protected void verifyCompleted() {
103        if (pendingChildren != null) {
104            ViewLifecycle.reportIllegalState("Render phase is not complete, children are still pending "
105                    + pendingChildren + "\n" + this);
106        }
107    }
108
109    /**
110     * {@inheritDoc}
111     */
112    @Override
113    protected void initializeSuccessors(Queue<ViewLifecyclePhase> successors) {
114        if (renderParent == null || renderParent.pendingChildren == null) {
115            trace(renderParent == null ? "no-parent" : "no-children");
116            return;
117        }
118
119        synchronized (renderParent) {
120            // InitializeSuccessors is invoked right after processing.
121            // Once the last sibling is processed, then queue the parent phase as a successor.
122            if (!renderParent.pendingChildren.remove(getParentPath())) {
123                ViewLifecycle.reportIllegalState("Render phase isn't a pending child\n"
124                        + this + "\nRender Parent: " + renderParent);
125            }
126
127            trace("remove-child " + renderParent.getElement().getId() + " " +
128                    renderParent.getViewPath() + " " + getParentPath() + " "
129                    + renderParent.pendingChildren);
130
131            if (renderParent.pendingChildren.isEmpty()) {
132                successors.add(renderParent);
133                renderParent.trace("pend-rend");
134                
135                Set<String> toRecycle = renderParent.pendingChildren;
136                renderParent.pendingChildren = null;
137                RecycleUtils.recycle(toRecycle);
138            }
139        }
140    }
141
142    /**
143     * {@inheritDoc}
144     */
145    @Override
146    protected ViewLifecyclePhase initializeSuccessor(LifecycleElement nestedElement, String nestedPath,
147            Component parent) {
148        return null;
149    }
150
151}