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

com.sun.jsftemplating.layout.descriptors.LayoutDefinition 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.Iterator;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Method;

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

import com.sun.jsftemplating.component.TemplateComponent;
import com.sun.jsftemplating.layout.descriptors.handler.Handler;
import com.sun.jsftemplating.layout.event.DecodeEvent;
import com.sun.jsftemplating.layout.event.InitPageEvent;
import com.sun.jsftemplating.util.Util;

/**
 *  

This represents the top-level {@link LayoutElement}, it is the * container for every other {@link LayoutElement}. By itself, it has no * functionality. Its purpose in life is to group all top-level child * {@link LayoutElement}s. LayoutDefintion objects can be registered * with the * {@link com.sun.jsftemplating.layout.LayoutDefinitionManager}.

* *

This class provide a helper method * {@link #getChildLayoutElementById(FacesContext, String, LayoutElement, UIComponent)} * which will search recursively for the given child LayoutElement by id.

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

Constructor.

*/ public LayoutDefinition(String id) { // LayoutDefinition objects do not have a parent super(null, id); // Set the default StaticText ComponentType addComponentType(new ComponentType( STATIC_TEXT_TYPE, STATIC_TEXT_FACTORY_CLASS_NAME)); } /** *

This method returns the Map containing the * {@link ComponentType}s. It ensures that the Map is * not null.

*/ protected Map getComponentTypes() { if (_types == null) { _types = new HashMap(); } return _types; } /** *

Retrieve a {@link ComponentType} by typeID.

* * @param typeID The key used to retrieve the ComponentType * * @return The requested ComponentType or null * * @deprecated Reader's should use global {@link ComponentType}s (see * {@link com.sun.jsftemplating.layout.LayoutDefinitionManager#getGlobalComponentType(FacesContext, String)}) * or should cache {@link ComponentType}s locally, this information is * not needed in the LayoutDefinition. */ public ComponentType getComponentType(String typeID) { return getComponentTypes().get(typeID); } /** *

This will add the given ComponentType to the map of * registered ComponentType's. It will use the * ComponentType ID as the key to the Map. * This means that if a ComponentType with the same ID had * previously been registered, it will be replaced with the * ComponentType passed in.

* * @param type The ComponentType. * * @deprecated Reader's should use global {@link ComponentType}s (see * {@link com.sun.jsftemplating.layout.LayoutDefinitionManager#addGlobalComponentType(FacesContext, ComponentType)}) * or should cache {@link ComponentType}s locally, this information is * not needed in the LayoutDefinition. */ public void addComponentType(ComponentType type) { getComponentTypes().put(type.getId(), type); } /** *

This method adds a {@link Resource}. These resources should be * added to the request scope when this component is used. This is * mainly used for ResourceBundles (at this time).

* * @param res The {@link Resource} to associate with the * LayoutDefinition. */ public void addResource(Resource res) { _resources.add(res); } /** *

This method returns a List of {@link Resource} objects.

* * @return This method returns a List of {@link Resource} objects. */ public List getResources() { return _resources; } /** *

This method allows the List of {@link Resource}s to * be set.

* * @param resources List to {@link Resource}s. */ public void setResources(List resources) { _resources = resources; } /** *

This method searches for the requested {@link LayoutComponent} by * id.

* * @param context FacesContext * @param id id to look for * @param parent Search starts from this {@link LayoutElement} * @param parentComponent Parent UIComponent * * @return The matching {@link LayoutElement} if found, null otherwise. */ public static LayoutElement getChildLayoutElementById(FacesContext context, String id, LayoutElement parent, UIComponent parentComponent) { // NOTE: I may want to optimize this by putting all values in a Map so // NOTE: that I don't have to do this search. // Make sure this isn't what we're looking for if (parent.getId(context, parentComponent).equals(id)) { return parent; } // Not 'this' so lets check the children Iterator it = parent.getChildLayoutElements().iterator(); LayoutElement elt = null; while (it.hasNext()) { elt = getChildLayoutElementById( context, id, it.next(), parentComponent); if (elt != null) { // Found it! return elt; } } // Not found... return null; } /** *

Retrieve an attribute by key.

* * @param key The key used to retrieve the attribute * * @return The requested attribute or null. */ public Object getAttribute(String key) { return _attributes.get(key); } /** *

Associate the given key with the given Object as an attribute.

* * @param key The key associated with the given object (if this key * is already in use, it will replace the previously set attribute * object). * * @param value The Object to store. */ public void setAttribute(String key, Object value) { _attributes.put(key, value); } /** *

This function overrides the superclass in order to call * encodeBegin / encodeEnd on the UIViewRoot (and only for UIViewRoot * instances). This is especially important for Ajax requests.

*/ @Override public void encode(FacesContext context, UIComponent component) throws IOException { if (component instanceof UIViewRoot) { component.encodeBegin(context); // FIXME: For now I am treating "@all" Ajax requests as normal requests... // FIXME: Otherwise the partialviewcontext tries to render the whole view, and // FIXME: fails b/c JSFT may use Facets for top-level components. Need to find // FIXME: a better way to handle this. if (context.getPartialViewContext().isPartialRequest() && !context.getPartialViewContext().isRenderAll()) { // JSF is now overriding this, so this is required... component.encodeChildren(context); } else { // This is not an ajax request... behave normal super.encode(context, component); } component.encodeEnd(context); } else { super.encode(context, component); } } /** *

The LayoutDefinition does not encode anything for * itself, this method simply returns true.

* * @param context The FacesContext. * @param component The UIComponent. * * @return true. */ protected boolean encodeThis(FacesContext context, UIComponent component) throws IOException { return true; } /** *

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 (NOTE: We do // not pull off handlers if the parent is a TemplateComponent b/c it // is the responsibility of the parent class to invoke handlers via // its LayoutComponent. If we do it here, it will happen 2x.) if ((comp != null) && (!(comp.getParent() instanceof TemplateComponent))) { 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 decode method invokes any registered {@link #DECODE} * handlers.

* * @param context The FacesContext. * @param component The UIComponent. */ public void decode(FacesContext context, UIComponent component) { // Invoke "decode" handlers dispatchHandlers(context, DECODE, new DecodeEvent(component)); } /** *

This method is responsible for dispatching the "initPage" handlers * associated with this LayoutDefinition (if any).

* *

The source passed in should be the * UIViewRoot. However, it is expected that in most * cases this will not be available. It is reasonable for this to be * null.

* *

If the FacesContext provided is null, this method * will simply return.

*/ public void dispatchInitPageHandlers(FacesContext ctx, Object source) { // Sanity check (this may happen if invoked outside JSF)... if (ctx == null) { // Do nothing... return; } // Check to see if we've already done this... if (isInitPageExecuted(ctx)) { // We've already init'd this request, do nothing return; } // Dispatch Handlers dispatchHandlers(ctx, INIT_PAGE, new InitPageEvent(source)); // Flag request as having processed the initPage handlers setInitPageExecuted(ctx, Boolean.TRUE); } /** *

This method checks to see if the initPage event has fired yet * for this request.

*/ public boolean isInitPageExecuted(FacesContext ctx) { Map reqAtts = ctx.getExternalContext().getRequestMap(); String key = INIT_PAGE_PREFIX + getId(ctx, (UIComponent) null); return Boolean.TRUE.equals(reqAtts.get(key)); } /** *

This method marks the initPage event as fired for this request.

*/ public void setInitPageExecuted(FacesContext ctx, boolean value) { String key = INIT_PAGE_PREFIX + getId(ctx, (UIComponent) null); ctx.getExternalContext().getRequestMap().put(key, value); } /** * */ private static final String INIT_PAGE_PREFIX = "__ip"; /** *

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

*/ public static final String DECODE = "decode"; /** *

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

*/ public static final String INIT_PAGE = "initPage"; /** *

This is a hard-coded LayoutComponent type. By default it * corresponds to * {@link com.sun.jsftemplating.component.factory.basic.StaticTextFactory}.

*/ public static final String STATIC_TEXT_TYPE = "staticText"; /** *

This is the full classname of the default StaticTextFactory.

*/ public static final String STATIC_TEXT_FACTORY_CLASS_NAME = "com.sun.jsftemplating.component.factory.basic.StaticTextFactory"; /** *

This is a list of Resource objects. These resources are to be * added to the Request scope when this LayoutDefinition * is used.

*/ private List _resources = new ArrayList(); /** *

Map of types. This information is needed to instantiate * UIComponents.

*/ private Map _types = null; /** *

Map of attributes. Attributes can be used to store extra * information about the LayoutDefinition.

*/ private Map _attributes = new HashMap(); }