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

com.sun.jsftemplating.layout.descriptors.LayoutComponent Maven / Gradle / Ivy

/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://jsftemplating.dev.java.net/cddl1.html or
 * jsftemplating/cddl1.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at jsftemplating/cddl1.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */
package com.sun.jsftemplating.layout.descriptors;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;

import com.sun.jsftemplating.component.ChildManager;
import com.sun.jsftemplating.component.ComponentUtil;
import com.sun.jsftemplating.component.TemplateComponent;
import com.sun.jsftemplating.el.VariableResolver;
import com.sun.jsftemplating.layout.LayoutViewHandler;
import com.sun.jsftemplating.layout.ViewRootUtil;
import com.sun.jsftemplating.layout.descriptors.handler.Handler;
import com.sun.jsftemplating.layout.event.AfterCreateEvent;
import com.sun.jsftemplating.layout.event.AfterEncodeEvent;
import com.sun.jsftemplating.layout.event.BeforeCreateEvent;
import com.sun.jsftemplating.layout.event.BeforeEncodeEvent;
import com.sun.jsftemplating.util.LayoutElementUtil;


/**
 *  

This class defines a LayoutComponent. A * LayoutComponent describes a UIComponent to be * instantiated. The method {@link #getType()} provides a * {@link ComponentType} descriptor that is capable of providing a * {@link com.sun.jsftemplating.component.factory.ComponentFactory} * to perform the actual instantiation. This class also stores properties * and facets (children) to be set on a newly instantiated instance.

* * @author Ken Paulsen ([email protected]) */ public class LayoutComponent extends LayoutElementBase implements LayoutElement { private static final long serialVersionUID = 1L; /** *

Constructor.

*/ public LayoutComponent(LayoutElement parent, String id, ComponentType type) { super(parent, id); _type = type; } /** *

Accessor for type.

*/ public ComponentType getType() { return _type; } /** *

Determines if this component should be created even if there is * already an existing UIComponent. It will "overwrite" * the existing component if this property is true.

*/ public void setOverwrite(boolean value) { _overwrite = value; } /** *

Determines if this component should be created even if there is * already an existing UIComponent. It will "overwrite" * the existing component if this property is true.

*/ public boolean isOverwrite() { return _overwrite; } /** *

This method adds an option to the LayoutComponent. Options may be * useful in constructing the LayoutComponent.

* * @param name The name of the option * @param value The value of the option (may be List or String) */ public void addOption(String name, Object value) { _options.put(name, value); } /** *

This method adds all the options in the given Map to the * {@link LayoutComponent}. Options may be useful in constructing the * {@link LayoutComponent}.

* * @param map The map of options to add. */ public void addOptions(Map map) { _options.putAll(map); } /** *

Accessor method for an option. This method does not evaluate * expressions.

* * @param name The option name to retrieve. * * @return The option value (List or String), or null if not found. * * @see #getEvaluatedOption(FacesContext, String, UIComponent) */ public Object getOption(String name) { return _options.get(name); } /** *

Accessor method for an option. This method evaluates our own * expressions (not JSF expressions).

* * @param ctx The FacesContext. * @param name The option name to retrieve. * @param component The UIComponent (may be null). * * @return The option value (List or String), or null if not found. * * @see #getOption(String) */ public Object getEvaluatedOption(FacesContext ctx, String name, UIComponent component) { // Get the option value Object value = getOption(name); // Invoke our own EL. This is needed b/c JSF's EL is designed for // Bean getters only. It does not get CONSTANTS or pull data from // other sources (such as session, request attributes, etc., etc.) // Resolve our variables now because we cannot depend on the // individual components to do this. We may want to find a way to // make this work as a regular ValueExpression... but for // now, we'll just resolve it here. return VariableResolver.resolveVariables(ctx, this, component, value); } /** *

This method returns true/false based on whether the given option * name has been set.

* * @param name The option name to look for. * * @return true/false depending on whether the options exists. */ public boolean containsOption(String name) { return _options.containsKey(name); } /** *

This method sets the Map of options.

* * @param options Map of options. */ public void setOptions(Map options) { _options = options; } /** *

This method returns the options as a Map. This method does not * evaluate expressions.

* * @return Map of options. */ public Map getOptions() { return _options; } /** *

This method is overriden so that the correct UIComponent can be * passed into the events. This is important so that correct * component is searched for "instance" handlers.

* * @param context The FacesContext. * @param parent The UIComponent. */ public void encode(FacesContext context, UIComponent parent) throws IOException { if (!this.getClass().getName().equals(CLASS_NAME)) { // The sub-classes of this component shouldn't use this method, // this is a hack to allow them to use LayoutElementBase.encode super.encode(context, parent); return; } // If overwrite... if (isOverwrite()) { // FIXME: shouldn't this do a replace, not a remove? Otherwise the order may change String id = getId(context, parent); if (parent.getFacets().remove(id) == null) { UIComponent child = ComponentUtil.getInstance(context).findChild(parent, id, null); if (child != null) { // Not a facet, try child... parent.getChildren().remove(child); } } } // Display this UIComponent // First find the UIComponent UIComponent childComponent = null; if (parent instanceof ChildManager) { // If we have a ChildManager, take advantage of it... childComponent = ((ChildManager) parent).getChild(context, this); } else { // Use local util method for finding / creating child component... childComponent = getChild(context, parent); } dispatchHandlers(context, BEFORE_ENCODE, new BeforeEncodeEvent(childComponent)); // Add child components... (needs to be done here, LE's can't do it) // Use check for instance of TC. If present we must instantiate its // children as they were skipped when the tree was initially created. if (parent instanceof TemplateComponent) { // Only do this for TemplateRenderer use-cases (LayoutViewHandler // does this for pages) LayoutViewHandler.buildUIComponentTree( context, childComponent, this); } // Render the child UIComponent encodeChild(context, childComponent); // Invoke "after" handlers dispatchHandlers(context, AFTER_ENCODE, new AfterEncodeEvent(childComponent)); } /** *

Although this method is part of the interface, it is not used b/c * I overrode the encode() method which calls this method. This * method does nothing except satisfy the compiler.

*/ public boolean encodeThis(FacesContext context, UIComponent parent) throws IOException { return false; } /** *

This method will find or create a UIComponent as * described by this LayoutComponent descriptor. If the * component already exists as a child or facet, it will be returned. * If it creates a new UIComponent, it will typically be * added to the given parent UIComponent as a facet (this * actually depends on the factory that instantiates the * UIComponent).

* * @param context The FacesContext * @param parent The UIComponent to serve as the parent to * search and to store the new UIComponent. * * @return The UIComponent requested (found or newly created) */ public UIComponent getChild(FacesContext context, UIComponent parent) { UIComponent childComponent = null; // First pull off the id from the descriptor String id = this.getId(context, parent); // We have an id, use it to search for an already-created child ComponentUtil compUtil = ComponentUtil.getInstance(context); childComponent = compUtil.findChild(parent, id, id); if (childComponent != null) { return childComponent; } // Invoke "beforeCreate" handlers this.beforeCreate(context, parent); // Create UIComponent childComponent = compUtil.createChildComponent(context, this, parent); // Invoke "afterCreate" handlers this.afterCreate(context, childComponent); // Return the newly created UIComponent return childComponent; } /** *

This method retrieves the Handlers for the requested type. But * also includes any handlers that are associated with the instance * (i.e. the UIComponent).

* * @param type The type of Handlers to retrieve. * @param comp The associated UIComponent (or null). * * @return A List of Handlers. */ public List getHandlers(String type, UIComponent comp) { // 1st get list of handlers for definition of this LayoutElement List handlers = null; // Now check to see if there are any on the UIComponent if (comp != null) { List instHandlers = (List) comp.getAttributes().get(type); if ((instHandlers != null) && (instHandlers.size() > 0)) { // NOTE: Copy b/c this is instance + static // Add the UIComponent instance handlers handlers = new ArrayList(instHandlers); List defHandlers = getHandlers(type); if (defHandlers != null) { // Add the LayoutElement "definition" handlers, if any handlers.addAll(getHandlers(type)); } } } if (handlers == null) { handlers = getHandlers(type); } return handlers; } /** *

This method is invoked before the Component described by this * LayoutComponent is created. This allows handlers registered for * "beforeCreate" functionality to be invoked.

* * @param context The FacesContext * * @return The result of invoking the handlers (null by default) */ public Object beforeCreate(FacesContext context, UIComponent parent) { // Invoke "beforeCreate" handlers return dispatchHandlers( context, BEFORE_CREATE, new BeforeCreateEvent(parent)); } /** *

This method is invoked after the Component described by this * LayoutComponent is created. This allows handlers registered for * "afterCreate" functionality to be invoked.

* * @param context The FacesContext * * @return The result of invoking the handlers (null by default) */ public Object afterCreate(FacesContext context, UIComponent component) { // Invoke "afterCreate" handlers return dispatchHandlers( context, AFTER_CREATE, new AfterCreateEvent(component)); } /** *

This method returns true if the child should be added to the parent * component as a facet. Otherwise, it returns false indicating that * it should exist as a real child.

* *

This value is calculated every time this call is made to allow for * the context in which the LayoutComponent exists to determine its * value. If a {@link LayoutFacet} exists as a parent * {@link LayoutElement}, or a UIViewRoot or * {@link TemplateComponent} exists as the immediate parent, it will * return the facet name that should be used. Otherwise, it will * return null.

* * @param parent This is the parent UIComponent. * * @return The facet name if the UIComponent should be added as a facet. */ public String getFacetName(UIComponent parent) { String name = null; // First check to see if this LC specifies a different facet name... name = (String) getOption(FACET_NAME); if ((name != null) && name.equals(getUnevaluatedId())) { // No special facet name supplied, don't assume this is a facet yet name = null; } // Next check to see if we are inside a LayoutFacet if (name == null) { LayoutElement parentElt = getParent(); while (parentElt != null) { if (parentElt instanceof LayoutFacet) { // Inside a LayoutFacet, use its name... only if this facet // is a child of a LayoutComponent (otherwise, it is a // layout facet used for layout, not for defining a facet // of a UIComponent) if (LayoutElementUtil.isLayoutComponentChild(parentElt)) { name = parentElt.getUnevaluatedId(); } else { name = getUnevaluatedId(); } if (name == null) { name = "_noname"; } break; } if (parentElt instanceof LayoutComponent) { // No need to process further, this is not a facet child return null; } parentElt = parentElt.getParent(); } } // If not found yet, check to see if we're at the top... if (name == null) { if (parent instanceof TemplateComponent) { // We don't know if we are adding a child of a // TemplateComponent from a page, or if the TemplateComponent // itself has a child... if the TemplateComponent is driving // the rendering process, then we want this to be a facet. If // the page is adding a child to a TemplateComponent, we do // not want this to be a facet. // Look to see if the parent LayoutDefinition == the current // LayoutDefinition. If so, we're "inside" a // TemplateComponent, not a page. FacesContext ctx = FacesContext.getCurrentInstance(); if (((TemplateComponent) parent).getLayoutDefinition(ctx) == getLayoutDefinition()) { name = getUnevaluatedId(); } } else if ((parent instanceof UIViewRoot) && (ViewRootUtil. getLayoutDefinition((UIViewRoot) parent) != null)) { // NOTE: Only set the name if its a JSFT ViewRoot name = getUnevaluatedId(); } } // Return the result return name; } /** *

This method returns a flag that indicates if this * LayoutComponent is nested (directly or indirectly) * inside another LayoutComponent. This flag is used * for such purposes as deciding if "instance" handlers are * appropriate.

* * @return true if component is nested. */ public boolean isNested() { return _nested; } /** *

This method sets the nested flag for this * LayoutComponent. This method is commonly only called * from code that constructs the tree of {@link LayoutElement} * components.

* * @param value The boolean value. */ public void setNested(boolean value) { _nested = value; } /** *

Component type

*/ private ComponentType _type = null; /** *

Determines if this component should be created even if there is * already an existing UIComponent. It will "overwrite" * the existing component if this property is true. Usually only * applies when this is used within the context of a * Renderer.

*/ private boolean _overwrite = false; /** *

Map of options.

*/ private Map _options = new HashMap(); /** *

This is the "type" for handlers to be invoked to handle * "afterCreate" functionality for this element.

*/ public static final String AFTER_CREATE = "afterCreate"; /** *

This is the "type" for handlers to be invoked to handle * "beforeCreate" functionality for this element.

*/ public static final String BEFORE_CREATE = "beforeCreate"; /** *

This is the "type" for handlers to be invoked to handle * "command" functionality for this element.

*/ public static final String COMMAND = "command"; /** *

This defines the property key for specifying the facet name in * which the component should be stored under in its parent * UIComponent.

*/ public static final String FACET_NAME = "_facetName"; public static final String CLASS_NAME = LayoutComponent.class.getName(); /** *

The value of the nested property.

*/ private boolean _nested = false; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy