001/**
002 * Copyright 2005-2015 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.LinkedHashSet;
019import java.util.Queue;
020import java.util.Set;
021
022import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
023import org.kuali.rice.krad.uif.UifConstants;
024import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle.LifecycleEvent;
025import org.kuali.rice.krad.uif.util.RecycleUtils;
026
027/**
028 * Lifecycle phase processing task for finalizing a component.
029 *
030 * <p>
031 * The finalize phase is the last phase before the view is rendered. Here final preparations can be
032 * made based on the updated view state.
033 * </p>
034 *
035 * <p>
036 * The finalize phase runs after the apply model phase and can be called multiple times for the
037 * view's lifecylce (however typically only once per request)
038 * </p>
039 *
040 * @author Kuali Rice Team (rice.collab@kuali.org)
041 */
042public class FinalizeComponentPhase extends ViewLifecyclePhaseBase {
043
044    /**
045     * Lifecycle phase to render this component after finalization, if in-lifecycle rendering is
046     * enabled.
047     *
048     * @see ViewLifecycle#isRenderInLifecycle()
049     */
050    private RenderComponentPhase renderPhase;
051
052    /**
053     * {@inheritDoc}
054     */
055    @Override
056    public void recycle() {
057        super.recycle();
058        renderPhase = null;
059    }
060
061    /**
062     * {@inheritDoc}
063     *
064     * @return UifConstants.ViewPhases.FINALIZE
065     */
066    @Override
067    public String getViewPhase() {
068        return UifConstants.ViewPhases.FINALIZE;
069    }
070
071    /**
072     * {@inheritDoc}
073     *
074     * @return UifConstants.ViewStatus.MODEL_APPLIED
075     */
076    @Override
077    public String getStartViewStatus() {
078        return UifConstants.ViewStatus.MODEL_APPLIED;
079    }
080
081    /**
082     * {@inheritDoc}
083     *
084     * @return UifConstants.ViewStatus.FINAL
085     */
086    @Override
087    public String getEndViewStatus() {
088        return UifConstants.ViewStatus.FINAL;
089    }
090
091    /**
092     * {@inheritDoc}
093     *
094     * @return LifecycleEvent.LIFECYCLE_COMPLETE
095     */
096    @Override
097    public LifecycleEvent getEventToNotify() {
098        return LifecycleEvent.LIFECYCLE_COMPLETE;
099    }
100
101    /**
102     * Verify that the render phase has no pending children.
103     */
104    @Override
105    protected void verifyCompleted() {
106        super.verifyCompleted();
107
108        if (renderPhase != null) {
109            renderPhase.verifyCompleted();
110        }
111    }
112
113    /**
114     * {@inheritDoc}
115     */
116    @Override
117    protected void initializeSuccessors(Queue<ViewLifecyclePhase> successors) {
118        super.initializeSuccessors(successors);
119
120        if (ViewLifecycle.isRenderInLifecycle()) {
121            RenderComponentPhase parentRenderPhase = null;
122
123            ViewLifecyclePhase predecessor = getPredecessor();
124            if (predecessor instanceof FinalizeComponentPhase) {
125                parentRenderPhase = ((FinalizeComponentPhase) predecessor).renderPhase;
126            }
127
128            @SuppressWarnings("unchecked") Set<String> pendingChildren = RecycleUtils.getInstance(LinkedHashSet.class);
129            for (ViewLifecyclePhase successor : successors) {
130                boolean skipSuccessor;
131                if (successor instanceof ViewLifecyclePhaseBase) {
132                    skipSuccessor = ((ViewLifecyclePhaseBase) successor).shouldSkipLifecycle();
133                } else {
134                    // TODO: consider moving shouldSkipLifecycle to public interface
135                    skipSuccessor = successor.getElement().skipLifecycle();
136                }
137
138                // Don't queue successors that will be skipped.
139                // Doing so would cause notification issues for the render phase.
140                if (skipSuccessor) {
141                    continue;
142                }
143
144                // Queue the successor, with strict validation that it hasn't already been queued
145                if (!pendingChildren.add(successor.getParentPath())) {
146                    ViewLifecycle.reportIllegalState(
147                            "Successor is already pending " + pendingChildren + "\n" + successor + "\n" + this);
148                }
149            }
150
151            renderPhase = (RenderComponentPhase) KRADServiceLocatorWeb.getViewLifecyclePhaseBuilder().buildPhase(
152                    UifConstants.ViewPhases.RENDER, getElement(), getParent(), getParentPath(), getRefreshPaths());
153            renderPhase.prepareRenderPhase(parentRenderPhase, pendingChildren);
154
155            trace("create-render " + getElement().getId() + " " + pendingChildren);
156        }
157
158        if (successors.isEmpty() && renderPhase != null) {
159            successors.add(renderPhase);
160        }
161    }
162
163}