Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.el;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Stack;
import java.util.StringTokenizer;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import com.sun.jsftemplating.layout.descriptors.LayoutComponent;
import com.sun.jsftemplating.layout.descriptors.LayoutComposition;
import com.sun.jsftemplating.layout.descriptors.LayoutElement;
import com.sun.jsftemplating.util.LogUtil;
import com.sun.jsftemplating.util.MessageUtil;
import com.sun.jsftemplating.util.Util;
/**
*
VariableResolver is used to parse expressions of the format.
*
*
$<type>{<key>}
*
*
<type> refers to a registerd {@link VariableResolver.DataSource},
* custom {@link VariableResolver.DataSource}s can be registered via:
* {@link #setDataSource(FacesContext ctx, String key,
* VariableResolver.DataSource dataSource)}. However, there are many
* built-in {@link VariableResolver.DataSource} types that are
* pre-registered.
*
* @author Ken Paulsen ([email protected])
*/
public class VariableResolver {
/**
*
This method will substitute variables into the given String, or
* return the variable if the substitution is the whole String. This
* method looks for the LAST occurance of startToken in the given
* String. It then searches from that location (if found) to the
* first occurance of typeDelim. The value inbetween is used as the
* type of substitution to perform (i.e. request attribute, session,
* etc.). It next looks for the next occurance of endToken. The
* value inbetween is used as the key passed to the
* {@link VariableResolver.DataSource} specified by the type. The
* String value from the {@link VariableResolver.DataSource} replaces
* the portion of the String from the startToken to the endToken. If
* this is the entire String, the Object is returned instead of the
* String value. This process is repeated until no more
* substitutions are * needed.
*
*
This algorithm will accomodate nested variables (e.g. "${A{$x}}").
* It also allows the replacement value itself to contain variables.
* Care should be taken to ensure that the replacement String included
* does not directly or indirectly refer to itself -- this will cause
* an infinite loop.
*
*
There is one special case where the string to be evaluated begins
* with the startToken and ends with the endToken. In this case,
* string substitution is NOT performed. Instead the value of the
* request attribute is returned.
*
*
This method has a "hack" attached at the end of its processing
* which looks at the resulting value and does magic. If the value is
* a String that starts with "#{" then it will attempt to locate a
* composition parameter matching the next token value and replace or
* merge its content with the value. It will replace the value if the
* value is in the format #{key}. If there is additonal information
* after "key", it will attempt to merge value from the template
* parameter with the content after "key". A default value may be
* provided for the template parameter by providing a ",default" (e.g.
* #{key,default}.
*
* @param ctx The FacesContext
* @param desc The closest LayoutElement to this string
* @param component The assoicated UIComponent
* @param string The string to be evaluated.
* @param startToken Marks the beginning "$"
* @param typeDelim Marks separation of type/variable "{"
* @param endToken Marks the end of the variable "}"
*
* @return The new string with substitutions, or the specified request
* attribute value.
*/
public static Object resolveVariables(FacesContext ctx, LayoutElement desc, UIComponent component, String string, String startToken, String typeDelim, String endToken) {
int stringLen = string.length();
int delimIndex;
int endIndex;
int parenSemi;
int startTokenLen = startToken.length();
int delimLen = typeDelim.length();
int endTokenLen = endToken.length();
boolean expressionIsWholeString = false;
char firstEndChar = SUB_END.charAt(0);
char firstDelimChar = SUB_TYPE_DELIM.charAt(0);
char currChar;
String type;
Object variable;
for (int startIndex = string.lastIndexOf(startToken); startIndex != -1;
startIndex = string.lastIndexOf(startToken, startIndex - 1)) {
// Make sure the startToken isn't escaped
if ((startIndex > 0) && (string.charAt(startIndex-1) == ESCAPE_CHAR)) {
string = string.substring(0, startIndex-1) // Before '\\'
+ string.substring(startIndex); // After
stringLen--;
startIndex--;
continue;
}
// Find first typeDelim
delimIndex = string.indexOf(typeDelim, startIndex + startTokenLen);
if (delimIndex == -1) {
continue;
}
// Next find the end token
parenSemi = 0;
endIndex = -1;
// Iterate through the string looking for the matching end
for (int curr = delimIndex + delimLen; curr < stringLen; ) {
// Get the next char...
currChar = string.charAt(curr);
if ((currChar == firstDelimChar) && typeDelim.equals(
string.substring(curr, curr + delimLen))) {
// Found the start of another... inc the semi
parenSemi++;
curr += delimLen;
continue;
}
if ((currChar == firstEndChar) && endToken.equals(
string.substring(curr, curr + endTokenLen))) {
parenSemi--;
if (parenSemi < 0) {
// Found the right one!
endIndex = curr;
break;
}
// Found one, but this isn't the right one
curr += endTokenLen;
continue;
}
curr++;
}
if (endIndex == -1) {
// We didn't find a matching end...
continue;
}
/*
// Next find end token
endIndex = string.indexOf(endToken, delimIndex+delimLen);
matchingIndex = string.lastIndexOf(typeDelim, endIndex);
while ((endIndex != -1) && (matchingIndex != delimIndex)) {
// We found a endToken, but not the matching one...keep looking
endIndex = string.indexOf(endToken, endIndex+endTokenLen);
matchingIndex = string.lastIndexOf(typeDelim,
matchingIndex-delimLen);
}
if ((endIndex == -1) || (matchingIndex == -1)) {
continue;
}
*/
// Handle special case where string starts with startToken and ends
// with endToken (and no replacements inbetween). This is special
// because we don't want to convert the attribute to a string, we
// want to return it (this allows Object types).
if ((startIndex == 0) && (endIndex == string.lastIndexOf(endToken))
&& (string.endsWith(endToken))) {
// This is the special case...
expressionIsWholeString = true;
}
// Pull off the type...
type = string.substring(startIndex + startTokenLen, delimIndex);
DataSource ds = getDataSource(ctx, type);
if (ds == null) {
if ((type.indexOf('<') > -1) || (type.indexOf('&') > -1) ||
(type.indexOf('[') > -1) || (type.indexOf('#') > -1) ||
(type.indexOf('$') > -1) || (type.indexOf('%') > -1) ||
(type.indexOf('(') > -1) || (type.indexOf(')')) > -1) {
// Do not consider this a valid EL expression, continue...
continue;
}
throw new IllegalArgumentException("Invalid type '" + type
+ "' in attribute value: '" + string + "'.");
}
// Pull off the variable...
variable = string.substring(delimIndex + delimLen, endIndex);
// Get the value...
variable = ds.getValue(ctx, desc, component, (String) variable);
if (expressionIsWholeString) {
if (variable instanceof String) {
// See if we need to do EL magic manipulation...
variable = replaceCompParams(ctx, desc, component, (String) variable);
}
return variable;
}
// Make new string
string = string.substring(0, startIndex) + // Before replacement
((variable == null) ? "" : variable.toString())
+ string.substring(endIndex + endTokenLen); // After
stringLen = string.length();
}
// Return the string
return replaceCompParams(ctx, desc, component, string);
}
/**
*
This method implements a "hack" which manipulates the given String
* when it starts with "#{". In this case, it will attempt to locate a
* composition parameter matching the next token and replace or merge
* its content with this String. It will replace the String if the
* value is in the format #{key}. If there is additonal content after
* "key" (besides a (,) comma), it will attempt to merge the value of
* the composition parameter matching key with the content after
* "key". A default value may be provided for the template parameter
* by providing a ",default" at the end of the expression (e.g.
* #{key,default}.
*
*
This method does not support replacing template paramters in other
* locations within EL.
*
* @param ctx The FacesContext.
* @param string The String to evaluate and manipulate if necessary.
*
* @return The same String passed in, or a new one based on method
* description.
*/
private static Object replaceCompParams(FacesContext ctx, LayoutElement desc, UIComponent comp, String string) {
// Sanity check
if (string == null) {
return null;
}
// First see if we have any params
Map globalParams =
LayoutComposition.getGlobalParamMap(ctx);
if (globalParams.size() == 0) {
// No mappings, nothing to do
return string;
}
String token = null;
Object value = null;
int len, startEL, endEL = 0;
int loopStart = 0;
char chars[] = string.toCharArray();
boolean foundAtLeastOne = false, isWholeString = false;
StringBuilder buff = null;
Stack stack = null;
while (true) {
startEL = findOpenEL(chars, loopStart);
// Detect
while (startEL != -1) {
// Get the next token
// FIXME: This is not nearly adequate!!
// Need to find all real tokens in #{!(some == expression) || foo}
endEL = findChar(chars, startEL + 2, '}', '[', '.', '=', '>', '<', '!', '&', '|', '*', '+', '-', '?', '/', '%', '(');
if (endEL == -1) {
// Not a match, non-fatal
startEL = -1;
break;
}
token = string.substring(startEL + 2, endEL);
token = token.trim();
// Check to see if this is template param
value = globalParams.get(token);
if (value != null) {
// We're not done yet! This value is only a flag, we have to
// look at the composition stack to be accurate!
if (stack == null) {
stack = LayoutComposition.getCompositionStack(ctx);
}
value = LayoutComposition.findTemplateParam(stack, token);
break;
}
startEL = string.indexOf("#{", endEL + 1);
}
if (startEL == -1) {
if (!foundAtLeastOne) {
// We didn't find anything to substitute
return string;
}
// Append the rest of the String
buff.append(chars, loopStart, chars.length - loopStart);
// We're done
break;
}
// Only get here when we find one...
foundAtLeastOne = true;
if (buff == null) {
// Initialize the buffer
buff = new StringBuilder(100);
}
// Check to see if this expression starts at the beginning
isWholeString = (startEL == 0);
// Add everything before the "#{"
buff.append(chars, loopStart, startEL - loopStart);
// We got "...#{replaceMe?*", look at the next char to see what to do
if (chars[endEL] == '}') {
// Swap everything, no merge
endEL++; // Move past '}'
if (isWholeString && (endEL >= chars.length)) {
// Special case, #{} is entire string, return it
return resolveVariables(ctx, desc, comp, value);
}
isWholeString = false;
// Ok, we just take the String value of "value" and add it
if (value != null) {
buff.append(value);
}
} else {
// Merge... we're just going to strip off "#{}" from value and
// insert it for now, later we might support more.
int start = 0;
String strVal = value.toString();
if (strVal.startsWith("#{")) {
start = 2;
}
int end = strVal.length();
if (strVal.charAt(end - 1) == '}') {
end--;
}
// Add merged content...
buff.append("#{").append(strVal, start, end);
// Find the end of the rest of the #{}...
end = findChar(chars, endEL + 1, '}');
if (end == -1) {
throw new IllegalArgumentException(
"EL has unterminated #{} expression: (" + string + ")");
}
buff.append(chars, endEL, ++end - endEL);
endEL = end;
}
loopStart = endEL;
}
// Replace ${}, return the result...
return resolveVariables(ctx, desc, comp, buff.toString());
}
/**
*
This looks for the first occurance of "#{" in
* chars. It returns the index of the starting
* character, or -1 if not found.
*/
private static int findOpenEL(char chars[], int idx) {
// Allow for a minimum of 3 characters after the # (i.e. {x})
int len = chars.length-3;
for (; idx This method searches the given chars from the
* startingIndex for any of the characters in
* matchChars.
*/
private static int findChar(char chars[], int idx, char ... matchChars) {
int len = chars.length;
for (; idxLayoutElement descriptor
* @param component The UIComponent
* @param value The value to resolve
*
* @return The result
*/
public static Object resolveVariables(LayoutElement desc,
UIComponent component, Object value) {
if (value == null) {
return null;
}
return VariableResolver.resolveVariables(
FacesContext.getCurrentInstance(), desc, component, value);
}
/**
* This method replaces the ${..} variables with their attribute values.
* It will only do this for Strings and List's that contain Strings.
*
* @param ctx The FacesContext
* @param desc The LayoutElement descriptor
* @param component The UIComponent
* @param value The value to resolve
*
* @return The result
*/
public static Object resolveVariables(FacesContext ctx, LayoutElement desc, UIComponent component, Object value) {
if (value == null) {
return null;
}
if (value instanceof String) {
value = VariableResolver.resolveVariables(
ctx,
desc,
component,
(String) value,
VariableResolver.SUB_START,
VariableResolver.SUB_TYPE_DELIM,
VariableResolver.SUB_END);
} else if (value instanceof List) {
// Create a new List b/c invalid to change shared List
List