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

com.sun.jsftemplating.layout.descriptors.handler.Handler 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.handler;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import com.sun.jsftemplating.component.ComponentUtil;
import com.sun.jsftemplating.el.PermissionChecker;
import com.sun.jsftemplating.layout.descriptors.LayoutElement;
import com.sun.jsftemplating.layout.event.UIComponentHolder;
import com.sun.jsftemplating.util.LogUtil;
import com.sun.jsftemplating.util.TypeConverter;


/**
 *  

This class contains the information necessary to invoke a Handler. The * {@link HandlerDefinition} class provides a definition of how to invoke * a Handler, this class uses that information with in conjuction with * information provided in this class to execute the handler * method. This class typically will hold input values and * specify where output should be stored.

* *

The handler method to be invoked must have the * following method signature:

* *

* * public void doSomething(HandlerContext handlerCtx) * *

* *

void be replaced with any type. Depending on the type of * event, return values may be handled differently.

* *

It is advisable to use Java annotations when defining a handler * method. See examples of annotations in the * com.sun.jsftemplating.handlers package. Here is an * example:

* *

* * @Handler(id="abc:doSomething",
* input={
* @HandlerInput(name="foo", type=Integer.class),
* @HandlerInput(name="bar", type=My.class, required=true)
* },
* output={
* @HandlerOutput(name="result", type=String.class)
* })
* public void doSomething(HandlerContext handlerCtx) *
*

* * @author Ken Paulsen (ken.paulsen@sun.com) */ public class Handler implements java.io.Serializable { private static final long serialVersionUID = 1L; /** *

Constructor.

*/ public Handler(HandlerDefinition handlerDef) { setHandlerDefinition(handlerDef); } /** *

Accessor for the {@link HandlerDefinition}.

*/ public HandlerDefinition getHandlerDefinition() { return _handlerDef; } /** *

This method sets the HandlerDefinition used by this Handler.

*/ protected void setHandlerDefinition(HandlerDefinition handler) { _handlerDef = handler; } /** *

This method is invoked by a parser to help populate this * Handler. This information is generally static but * may contain expressions to make the value dynamic.

*/ public void setInputValue(String name, Object value) { IODescriptor inDesc = getHandlerDefinition().getInputDef(name); if (inDesc == null) { throw new RuntimeException("Attempted to set input value '" + name + "' with value '" + value + "', however, '" + name + "' is not a declared input parameter in HandlerDefinition '" + getHandlerDefinition().getId() + "'!"); } _inputs.put(name, value); } /** *

This method returns a Map of NVPs representing the input to this * handler.

*/ protected Map getInputMap() { return _inputs; } /** *

This method simply returns the named input value, null if not * found. It will not attempt to resolve $...{...} expressions or * do modifications of any kind. If you are looking for a method to * do these types of operations, try * {@link #getInputValue(HandlerContext, String)}.

* * @param name The name used to identify the input value. */ public Object getInputValue(String name) { return _inputs.get(name); } /** *

This method returns the value for the named input. Input values * are not stored in this HandlerContext itself, but in the Handler. * If you are trying to set input values for a handler, you must * create a new Handler object and set its input values.

* *

This method attempts to resolve $...{...} expressions. It also * will return the default value if the value is null. If you don't * want these things to happen, look at * Handler.getInputValue(String).

* * @param name The input name * * @return The value of the input (null if not found) */ public Object getInputValue(HandlerContext ctx, String name) { // Make sure the requested name is valid IODescriptor inDesc = getHandlerDefinition().getInputDef(name); FacesContext facesCtx = ctx.getFacesContext(); if (inDesc == null) { throw new RuntimeException("Attempted to get input value '" + name + "', however, this is not a declared input " + "parameter in handler definition '" + getHandlerDefinition().getId() + "'! Check your handler " + " and/or the XML (near LayoutElement '" + ctx.getLayoutElement().getId(facesCtx, null) + "')"); } // Get the value, and parse it Object value = getInputValue(name); if (value == null) { if (inDesc.isRequired()) { throw new RuntimeException("'" + name + "' is required for handler '" + getHandlerDefinition().getId() + "'!"); } value = inDesc.getDefault(); } // Resolve any expressions EventObject event = ctx.getEventObject(); UIComponent component = null; if (event instanceof UIComponentHolder) { component = ((UIComponentHolder) event).getUIComponent(); } else if (event != null) { Object src = event.getSource(); if (src instanceof UIComponent) { component = (UIComponent) src; } } value = ComponentUtil.getInstance(facesCtx).resolveValue( facesCtx, ctx.getLayoutElement(), component, value); // Make sure the value is the correct type... value = TypeConverter.asType(inDesc.getType(), value); return value; } /** *

This method retrieves an output value. Output values are stored * in the location specified by the {@link OutputType} in the * Handler.

* * @param context The HandlerContext * @param name The output name * * @return The value of the output (null if not set) */ public Object getOutputValue(HandlerContext context, String name) { // Make sure the requested name is valid HandlerDefinition handlerDef = getHandlerDefinition(); IODescriptor outIODesc = handlerDef.getOutputDef(name); if (outIODesc == null) { throw new RuntimeException("Attempted to get output value '" + name + "' from handler '" + handlerDef.getId() + "', however, this is not a declared output parameter! " + "Check your handler and/or the XML."); } // Get the OutputMapping that describes how to store this output OutputMapping outputDesc = getOutputValue(name); // NOTE: Interesting that this method does not evaluate the EL in // NOTE: getOutputKey... probably a bug. Although it is very uncommon // NOTE: (to get a output types output key which is dynamic from a // NOTE: handler which just set the output value). It is uncommon to // NOTE: use this method at all, let alone for dynamicly key'd // NOTE: OutputTypes, so this code path probably hasn't ever been // NOTE: executed. // Return the value return outputDesc.getOutputType(). getValue(context, outIODesc, outputDesc.getOutputKey()); } /** *

This method stores an output value. Output values are stored * as specified by the {@link OutputType} in the Handler. This * method is not used to create the "mapping" of an output value, * for that see {@link #setOutputMapping(String, String, String)}.

* * @param context The HandlerContext * @param name The name the Handler uses for the output * @param value The value to set */ public void setOutputValue(HandlerContext context, String name, Object value) { // Make sure the requested name is valid HandlerDefinition handlerDef = getHandlerDefinition(); IODescriptor outIODesc = handlerDef.getOutputDef(name); if (outIODesc == null) { throw new RuntimeException("Attempted to set output value '" + name + "' from handler '" + handlerDef.getId() + "', however, this is not a declared output parameter! " + "Check your handler and/or the XML."); } // Get the OutputMapping that describes how to store this output OutputMapping outputMapping = getOutputValue(name); if (outputMapping == null) { // They did not Map the output, do nothing... return; } // Make sure the value is the correct type... value = TypeConverter.asType(outIODesc.getType(), value); // Set the value EventObject event = context.getEventObject(); UIComponent component = null; if (event instanceof UIComponentHolder) { component = ((UIComponentHolder) event).getUIComponent(); } // Most output types appreciate resolving EL for the "key", however // in some cases (such as the EL output type), resolving the key // is counterproductive. Check output type to see if the output // key should be resolved. OutputType outType = outputMapping.getOutputType(); String outputKey = outputMapping.getOutputKey(); // FIXME: For now I'm going to do instanceof instead of modifying the // FIXME: OutputType interface. I can't think of another OutputType that would // FIXME: want this... if anyone ever has a use case, I'll happily modify the // FIXME: OutputType interface, or add a new interface to flag this code-path. if (!(outType instanceof ELOutputType)) { FacesContext ctx = context.getFacesContext(); outputKey = "" + ComponentUtil.getInstance(ctx).resolveValue( ctx, context.getLayoutElement(), component, outputKey); } outType.setValue(context, outIODesc, outputKey, value); } /** *

This method adds a new OutputMapping to this handler. An * OutputMapping allows the handler to return a value and have it * "mapped" to the location of your choice. The "outputType" * corresponds to a registered {@link OutputType} * (see {@link OutputTypeManager}).

* * @param outputName The Handler's name for the output value * @param targetKey The 'key' the OutputType uses to store the output * @param targetType The OutputType implementation map the output */ public void setOutputMapping(String outputName, String targetKey, String targetType) { // Ensure we have a valid outputName (check HandlerDefinition) if (getHandlerDefinition().getOutputDef(outputName) == null) { throw new IllegalArgumentException("Handler named '" + getHandlerDefinition().getId() + "' does not declare output " + "mapping named '" + outputName + "'."); } // Ensure the data is trim if (targetKey != null) { targetKey = targetKey.trim(); if (targetKey.length() == 0) { targetKey = null; } } targetType = targetType.trim(); try { _outputs.put(outputName, new OutputMapping( outputName, targetKey, targetType)); } catch (IllegalArgumentException ex) { throw new RuntimeException( "Unable to create OutputMapping with given information: " + "outputName='" + outputName + "', targetKey='" + targetKey + "', targetType=" + targetType + "'", ex); } } /** *

This method returns the {@link OutputMapping} for the given * name. If not found, it will return * null.

*/ public OutputMapping getOutputValue(String name) { return _outputs.get(name); } /** *

This method returns the condition that must be true in order for * this Handler (or its child Handlers) to * be invoked. If this condition is empty ("") or null, * it is considered to be true.

*/ public String getCondition() { return _condition; } /** *

This method sets the condition that must evaluate to true in order * for this Handler to be invoked.

*/ public void setCondition(String cond) { if (cond != null) { cond = cond.trim(); } _condition = cond; } /** *

This method determines if the handler is static.

*/ public boolean isStatic() { return getHandlerDefinition().isStatic(); } /** *

This method adds a Handler to the list of child * Handlers. Child Handlers are executed * AFTER this Handler is executed.

* * @param desc The Handler to add. */ public void addChildHandler(Handler desc) { if (_childHandlers == _emptyList) { _childHandlers = new ArrayList(); } _childHandlers.add(desc); } /** *

This method sets the List of child * Handlers.

* * @param childHandlers The List of child * Handlers. */ public void setChildHandlers(List childHandlers) { if ((childHandlers == null) || (childHandlers.size() == 0)) { childHandlers = _emptyList; } _childHandlers = childHandlers; } /** *

This method retrieves the List of child * {@link Handler}s. This List should not be changed * directly. Call {@link #addChildHandler(Handler)}, or make a copy * and call {@link #setChildHandlers(List)}.

* * @return The List of child {@link Handler}s. */ public List getChildHandlers() { return _childHandlers; } /** *

This method is responsible for invoking this Handler * as well as all child Handlers. Neither will be * invoked if this methods condition is non-null and unstatisfied * (see {@link #getCondition()}). The method associated with this * Handler will be invoked first, then any child * Handlers.

* * @param handlerContext The {@link HandlerContext}. */ public Object invoke(HandlerContext handlerContext) throws InstantiationException, IllegalAccessException, InvocationTargetException { Object result = null; HandlerDefinition handlerDef = getHandlerDefinition(); // Invoke if (hasPermission(handlerContext)) { // Only attempt to do this if there is a handler method, there // might only be child handlers Method method = handlerDef.getHandlerMethod(); if (method != null) { Object instance = null; if (!isStatic()) { // Get the class that contains the method instance = method.getDeclaringClass().newInstance(); } // Invoke the Method result = method.invoke(instance, new Object[] {handlerContext}); } // Execute all the child handlers if ((result == null) || (!result.toString().equals("false"))) { // NOTE: 'handler' in handlerContext will change. // before we execute this Handler. // FIRST: Execute handlerDef child handlers List handlers = handlerDef.getChildHandlers(); Object retVal = null; LayoutElement elt = handlerContext.getLayoutElement(); if (handlers.size() > 0) { retVal = elt.dispatchHandlers(handlerContext, handlers); if (retVal != null) { result = retVal; } } // NEXT: Execute instance child handlers // Useful for applying a condition to a group handlers = getChildHandlers(); if (handlers.size() > 0) { retVal = elt.dispatchHandlers(handlerContext, handlers); if (retVal != null) { result = retVal; } } } } else { if (LogUtil.finerEnabled()) { LogUtil.finer("Handler '" + handlerDef.getId() + "' skipped because condition not met: '" + getCondition() + "'."); } } // Return the result (null if no result) return result; } /** *

This method determines if the condition * (see {@link #getCondition()}) is satisfied.

* * @return true if the condition is met. */ public boolean hasPermission(HandlerContext handlerContext) { String cond = getCondition(); if ((cond == null) || cond.equals("")) { return true; } // Try to get the UIComponent UIComponent comp = null; Object obj = handlerContext.getEventObject().getSource(); if (obj instanceof UIComponent) { comp = (UIComponent) obj; } // Create a PermissionChecker PermissionChecker checker = new PermissionChecker( handlerContext.getLayoutElement(), comp, cond); // Return the result return checker.hasPermission(); } private HandlerDefinition _handlerDef = null; private String _condition = null; private List _childHandlers = _emptyList; private Map _inputs = new HashMap(); private Map _outputs = new HashMap(); private static final List _emptyList = new ArrayList(0); }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy