All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.faces.component.CompositeComponentStackManager Maven / Gradle / Ivy

Go to download

Jakarta Faces defines an MVC framework for building user interfaces for web applications, including UI components, state management, event handing, input validation, page navigation, and support for internationalization and accessibility.

There is a newer version: 4.1.0
Show newest version
/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.faces.component;

import java.util.Stack;

import jakarta.faces.application.Resource;
import jakarta.faces.component.UIComponent;
import jakarta.faces.context.FacesContext;
import jakarta.faces.view.Location;

/**
 * 

* CompositeComponentStackManager is responsible for managing the two different composite component stacks * currently used by Mojarra. *

* *

* The stacks are identified by the {@link StackType} enum which has two elements, * TreeCreation and Evaluation. *

* *

* The TreeCreation stack represents the composite components that have been pushed by the TagHandlers * responsible for building the tree. *

* *

* The Evaluation stack is used by the EL in order to properly resolve nested composite component * expressions. *

*/ public class CompositeComponentStackManager { private static final String MANAGER_KEY = CompositeComponentStackManager.class.getName(); public enum StackType { TreeCreation, Evaluation } private StackHandler treeCreation = new TreeCreationStackHandler(); private StackHandler runtime = new RuntimeStackHandler(); // ------------------------------------------------------------ Constructors private CompositeComponentStackManager() { } // ---------------------------------------------------------- Public Methods /** * @param ctx the FacesContext for the current request * @return the CompositeComponentStackManager for the current request */ public static CompositeComponentStackManager getManager(FacesContext ctx) { CompositeComponentStackManager manager = (CompositeComponentStackManager) ctx.getAttributes().get(MANAGER_KEY); if (manager == null) { manager = new CompositeComponentStackManager(); ctx.getAttributes().put(MANAGER_KEY, manager); } return manager; } /** *

* Pushes the specified composite component to the Evaluation stack. *

* * @param compositeComponent the component to push * @return true if the component was pushed, otherwise returns false */ public boolean push(UIComponent compositeComponent) { return getStackHandler(StackType.Evaluation).push(compositeComponent); } /** *

* Pushes the specified composite component to the desired StackType stack. *

* * @param compositeComponent the component to push * @param stackType the stack to push to the component to * @return true if the component was pushed, otherwise returns false */ public boolean push(UIComponent compositeComponent, StackType stackType) { return getStackHandler(stackType).push(compositeComponent); } /** *

* Pushes a component derived by the push logic to the Evaluation stack. *

* * @return true if the component was pushed, otherwise returns false */ public boolean push() { return getStackHandler(StackType.Evaluation).push(); } /** *

* Pushes a component derived by the push logic to the specified stack. *

* * @param stackType the stack to push to the component to * * @return true if the component was pushed, otherwise returns false */ public boolean push(StackType stackType) { return getStackHandler(stackType).push(); } /** *

* Pops the top-level component from the stack. *

* * @param stackType the stack to pop the top level component from */ public void pop(StackType stackType) { getStackHandler(stackType).pop(); } /** *

* Pops the top-level component from the Evaluation stack. *

*/ public void pop() { getStackHandler(StackType.Evaluation).pop(); } /** * @return the top-level component from the Evaluation stack without removing the element */ public UIComponent peek() { return getStackHandler(StackType.Evaluation).peek(); } /** * @param stackType the stack to push to the component to * * @return the top-level component from the specified stack without removing the element */ public UIComponent peek(StackType stackType) { return getStackHandler(stackType).peek(); } public UIComponent getParentCompositeComponent(StackType stackType, FacesContext ctx, UIComponent forComponent) { return getStackHandler(stackType).getParentCompositeComponent(ctx, forComponent); } public UIComponent findCompositeComponentUsingLocation(FacesContext ctx, Location location) { StackHandler sh = getStackHandler(StackType.TreeCreation); Stack s = sh.getStack(false); if (s != null) { String path = location.getPath(); for (int i = s.size(); i > 0; i--) { UIComponent cc = s.get(i - 1); Resource r = (Resource) cc.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY); if (path.endsWith('/' + r.getResourceName()) && path.contains(r.getLibraryName())) { return cc; } } } else { // runtime eval String path = location.getPath(); UIComponent cc = UIComponent.getCurrentCompositeComponent(ctx); while (cc != null) { Resource r = (Resource) cc.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY); if (path.endsWith('/' + r.getResourceName()) && path.contains(r.getLibraryName())) { return cc; } cc = UIComponent.getCompositeComponentParent(cc); } } // we could not find the composite component because the location was not found, // this will happen if the #{cc} refers to a composite component one level up, // so we are going after the current composite component. // return UIComponent.getCurrentCompositeComponent(ctx); } // --------------------------------------------------------- Private Methods private StackHandler getStackHandler(StackType type) { StackHandler handler = null; switch (type) { case TreeCreation: handler = treeCreation; break; case Evaluation: handler = runtime; break; } return handler; } // ------------------------------------------------------ Private Interfaces private interface StackHandler { boolean push(UIComponent compositeComponent); boolean push(); void pop(); UIComponent peek(); UIComponent getParentCompositeComponent(FacesContext ctx, UIComponent forComponent); void delete(); Stack getStack(boolean create); } // ---------------------------------------------------------- Nested Classes private abstract class BaseStackHandler implements StackHandler { protected Stack stack; // ------------------------------------------- Methods from StackHandler @Override public void delete() { stack = null; } @Override public Stack getStack(boolean create) { if (stack == null && create) { stack = new Stack<>(); } return stack; } @Override public UIComponent peek() { if (stack != null && !stack.isEmpty()) { return stack.peek(); } return null; } } // END BaseStackHandler private final class RuntimeStackHandler extends BaseStackHandler { // ------------------------------------------- Methods from StackHandler @Override public void delete() { Stack s = getStack(false); if (s != null) { s.clear(); } } @Override public void pop() { Stack s = getStack(false); if (s != null && !s.isEmpty()) { s.pop(); } } @Override public boolean push() { return push(null); } @Override public boolean push(UIComponent compositeComponent) { Stack tstack = treeCreation.getStack(false); Stack stack = getStack(false); UIComponent ccp; if (tstack != null) { // We have access to the stack of composite components // the tree creation process has made available. // Since we can' reliably access the parent composite component // of the current composite component, use the index of the // current composite component within the stack to locate the // parent. ccp = compositeComponent; } else { // no tree creation stack available, so use the runtime stack. // If the current stack isn't empty, then use the component // on the stack as the current composite component. stack = getStack(false); if (compositeComponent == null) { if (stack != null && !stack.isEmpty()) { ccp = getCompositeParent(stack.peek()); } else { ccp = getCompositeParent(UIComponent.getCurrentCompositeComponent(FacesContext.getCurrentInstance())); } } else { ccp = compositeComponent; } } if (ccp != null) { if (stack == null) { stack = getStack(true); } stack.push(ccp); return true; } return false; } @Override public UIComponent getParentCompositeComponent(FacesContext ctx, UIComponent forComponent) { return getCompositeParent(forComponent); } // ----------------------------------------------------- Private Methods private UIComponent getCompositeParent(UIComponent comp) { return UIComponent.getCompositeComponentParent(comp); } } // END RuntimeStackHandler private final class TreeCreationStackHandler extends BaseStackHandler { // ------------------------------------------- Methods from StackHandler @Override public void pop() { Stack s = getStack(false); if (s != null && !stack.isEmpty()) { stack.pop(); if (stack.isEmpty()) { delete(); } } } @Override public boolean push() { return false; } @Override public boolean push(UIComponent compositeComponent) { if (compositeComponent != null) { assert UIComponent.isCompositeComponent(compositeComponent); Stack s = getStack(true); s.push(compositeComponent); return true; } return false; } @Override public UIComponent getParentCompositeComponent(FacesContext ctx, UIComponent forComponent) { Stack s = getStack(false); if (s == null) { return null; } else { int idx = s.indexOf(forComponent); if (idx == 0) { // no parent return null; } return s.get(idx - 1); } } } // END TreeCreationStackHandler }