| /******************************************************************************* |
| * Copyright (c) 2006 Sybase, Inc. and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Sybase, Inc. - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.pagedesigner.jsp.core.el; |
| |
| import java.io.StringReader; |
| |
| import org.apache.commons.el.Expression; |
| import org.apache.commons.el.ExpressionString; |
| import org.apache.commons.el.parser.ELParser; |
| import org.apache.commons.el.parser.ParseException; |
| |
| /** |
| * Utility class to implement support functionality to "morph" JSP EL into JSF |
| * EL |
| * |
| * @author mengbo |
| * @version 1.5 |
| */ |
| public final class JSFELParserHelper { |
| /** |
| * an EL left brace |
| */ |
| public static String JSF_EL_LEFT_BRACE = "#{"; //$NON-NLS-1$ |
| |
| /** |
| * an EL right brace |
| */ |
| public static String JSF_EL_RIGHT_BRACE = "}"; //$NON-NLS-1$ |
| |
| private JSFELParserHelper() { |
| // util class, do not instantiate |
| } |
| |
| /** |
| * Gets the parsed form of the given expression string. Returns either an |
| * Expression or ExpressionString. |
| * @param expressionString |
| * @return the result of parsing expressionString |
| */ |
| public static Object parseExpression(String expressionString) { |
| expressionString = toJspElExpression(expressionString); |
| |
| ELParser parser = new ELParser(new StringReader(expressionString)); |
| try { |
| Object expression = parser.ExpressionString(); |
| if (!(expression instanceof Expression) |
| && !(expression instanceof ExpressionString)) { |
| return null; |
| } |
| |
| return expression; |
| } catch (ParseException e) { |
| |
| // String msg = "Invalid expression: '" + expressionString + "'"; |
| // log.debug(msg, e); |
| // throw new ReferenceSyntaxException(msg, e); |
| } |
| return null; |
| } |
| |
| /** |
| * @param expressionString |
| * @return true if the expression is 'valid' |
| */ |
| public static boolean isValidEL(String expressionString) { |
| if (expressionString == null || expressionString.length() == 0) { |
| return false; |
| } |
| |
| return expressionString.startsWith(JSF_EL_LEFT_BRACE) |
| && expressionString.endsWith(JSF_EL_RIGHT_BRACE); |
| } |
| |
| /** |
| * @param expressionString |
| * @return expressionString with the left and right braces removed |
| * or the original string if isValidEL(expression) == false |
| */ |
| public static String trimELBrace(String expressionString) { |
| if (!isValidEL(expressionString)) { |
| return expressionString; |
| } |
| String trimedExpression = null; |
| |
| trimedExpression = expressionString.substring(JSF_EL_LEFT_BRACE |
| .length(), expressionString.length() |
| - JSF_EL_RIGHT_BRACE.length()); |
| |
| return trimedExpression; |
| } |
| |
| /** |
| * Convert ValueBinding syntax #{ } to JSP EL syntax ${ } |
| * |
| * @param expressionString |
| * <code>ValueBinding</code> reference expression |
| * |
| * @return JSP EL compatible expression |
| */ |
| public static String toJspElExpression(String expressionString) { |
| StringBuffer sb = new StringBuffer(expressionString.length()); |
| int remainsPos = 0; |
| |
| for (int posOpenBrace = expressionString.indexOf('{'); posOpenBrace >= 0; posOpenBrace = expressionString |
| .indexOf('{', remainsPos)) { |
| if (posOpenBrace > 0) { |
| if (posOpenBrace - 1 > remainsPos) |
| sb.append(expressionString.substring(remainsPos, |
| posOpenBrace - 1)); |
| |
| if (expressionString.charAt(posOpenBrace - 1) == '$') { |
| sb.append("${'${'}"); //$NON-NLS-1$ |
| remainsPos = posOpenBrace + 1; |
| continue; |
| } else if (expressionString.charAt(posOpenBrace - 1) == '#') { |
| // TODO: should use \\ as escape for \ always, not just when |
| // before #{ |
| // allow use of '\' as escape symbol for #{ (for |
| // compatibility with Sun's extended implementation) |
| /* |
| * if (isEscaped(expressionString, posOpenBrace - 1)) { |
| * escapes: { for (int i = sb.length() - 1; i >= 0; i--) { |
| * if (sb.charAt(i) != '\\') { sb.setLength( sb.length() - |
| * (sb.length() - i) / 2); break escapes; } } |
| * sb.setLength(sb.length() / 2); } sb.append("#{"); } else { |
| */ |
| sb.append("${"); //$NON-NLS-1$ |
| int posCloseBrace = indexOfMatchingClosingBrace( |
| expressionString, posOpenBrace); |
| sb.append(expressionString.substring(posOpenBrace + 1, |
| posCloseBrace + 1)); |
| remainsPos = posCloseBrace + 1; |
| continue; |
| // } |
| } else { |
| if (posOpenBrace > remainsPos) |
| sb.append(expressionString.charAt(posOpenBrace - 1)); |
| } |
| } |
| |
| // Standalone brace |
| sb.append('{'); |
| remainsPos = posOpenBrace + 1; |
| } |
| |
| sb.append(expressionString.substring(remainsPos)); |
| |
| // Create a new String to shrink mem size since we are caching |
| return new String(sb.toString()); |
| } |
| |
| private static int findQuote(String expressionString, int start) { |
| int indexofSingleQuote = expressionString.indexOf('\'', start); |
| int indexofDoubleQuote = expressionString.indexOf('"', start); |
| return minIndex(indexofSingleQuote, indexofDoubleQuote); |
| } |
| |
| /** |
| * Return the index of the matching closing brace, skipping over quoted text |
| * |
| * @param expressionString |
| * string to search |
| * @param indexofOpeningBrace |
| * the location of opening brace to match |
| * |
| * @return the index of the matching closing brace |
| * |
| * @throws ReferenceSyntaxException |
| * if matching brace cannot be found |
| */ |
| private static int indexOfMatchingClosingBrace(String expressionString, |
| int indexofOpeningBrace) { |
| int len = expressionString.length(); |
| int i = indexofOpeningBrace + 1; |
| |
| // Loop through quoted strings |
| for (;;) { |
| if (i >= len) { |
| throw new IllegalStateException( |
| "Missing closing brace. Expression: '" //$NON-NLS-1$ |
| + expressionString + "'"); //$NON-NLS-1$ |
| } |
| |
| int indexofClosingBrace = expressionString.indexOf('}', i); |
| i = minIndex(indexofClosingBrace, findQuote(expressionString, i)); |
| |
| if (i < 0) { |
| // No delimiter found |
| throw new IllegalStateException( |
| "Missing closing brace. Expression: '" //$NON-NLS-1$ |
| + expressionString + "'"); //$NON-NLS-1$ |
| } |
| |
| // 1. If quoted literal, find closing quote |
| if (i != indexofClosingBrace) { |
| i = indexOfMatchingClosingQuote(expressionString, i) + 1; |
| if (i == 0) { |
| // Note: if no match, i==0 because -1 + 1 = 0 |
| throw new IllegalStateException( |
| "Missing closing quote. Expression: '" //$NON-NLS-1$ |
| + expressionString + "'"); //$NON-NLS-1$ |
| } |
| } else { |
| // Closing brace |
| return i; |
| } |
| } |
| } |
| |
| /** |
| * Returns the index of the matching closing quote, skipping over escaped |
| * quotes |
| * |
| * @param expressionString |
| * string to scan |
| * @param indexOfOpeningQuote |
| * start from this position in the string |
| * @return -1 if no match, the index of closing quote otherwise |
| */ |
| private static int indexOfMatchingClosingQuote(String expressionString, |
| int indexOfOpeningQuote) { |
| char quote = expressionString.charAt(indexOfOpeningQuote); |
| for (int i = expressionString.indexOf(quote, indexOfOpeningQuote + 1); i >= 0; i = expressionString |
| .indexOf(quote, i + 1)) { |
| if (!isEscaped(expressionString, i)) { |
| return i; |
| } |
| } |
| |
| // No matching quote found |
| return -1; |
| } |
| |
| private static boolean isEscaped(String expressionString, int i) { |
| int escapeCharCount = 0; |
| while ((--i >= 0) && (expressionString.charAt(i) == '\\')) { |
| escapeCharCount++; |
| } |
| |
| return (escapeCharCount % 2) != 0; |
| } |
| |
| /** |
| * Returns the minimum index >= 0, if any |
| * |
| * <p> |
| * Use to find the first of two characters in a string:<br> |
| * <code>minIndex(s.indexOf('/'), indexOf('\'))</code> |
| * </p> |
| * @param a |
| * @param b |
| * @return the minimum index >= 0, if any |
| * |
| */ |
| public static int minIndex(int a, int b) { |
| return (a < 0) ? b : (b < 0) ? a : (a < b) ? a : b; |
| } |
| } |