/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.myfaces.extensions.validator.core.el; | |
import org.apache.myfaces.extensions.validator.internal.UsageCategory; | |
import org.apache.myfaces.extensions.validator.internal.UsageInformation; | |
import org.apache.myfaces.extensions.validator.internal.ToDo; | |
import org.apache.myfaces.extensions.validator.internal.Priority; | |
import org.apache.myfaces.extensions.validator.util.ExtValUtils; | |
/** | |
* An instance of this class stores the different parts of an expression string and | |
* allows an easier usage of value-bindings. | |
* | |
* @since 1.x.1 | |
*/ | |
@ToDo(value = Priority.MEDIUM, description = "difference between [ and [' - test with more constellations") | |
@UsageInformation({UsageCategory.API}) | |
public class ValueBindingExpression | |
{ | |
private ValueBindingExpression base; | |
private String value; | |
private String prefix; | |
private String token; | |
private static final ELHelper EL_HELPER = ExtValUtils.getELHelper(); | |
/** | |
* The given property is used as new property of the expression. | |
* Examples for 'newProperty':<br/> | |
* #{bean} -> #{bean.newProperty} | |
* <p/> | |
* #{bean.property} -> #{bean.newProperty} | |
* | |
* @param valueBindingExpression The target instance of {@link ValueBindingExpression} | |
* @param newProperty The property to use. | |
* @return The resulting {@link ValueBindingExpression} (with the new property) | |
*/ | |
public static ValueBindingExpression replaceOrAddProperty(ValueBindingExpression valueBindingExpression, | |
String newProperty) | |
{ | |
if(valueBindingExpression.getBaseExpression() != null) | |
{ | |
return replaceProperty(valueBindingExpression, newProperty); | |
} | |
else | |
{ | |
return addProperty(valueBindingExpression, newProperty); | |
} | |
} | |
/** | |
* Replace the property in the expression string with the given property. | |
* | |
* @param valueBindingExpression The valueBindingExpression where we want to replace the property | |
* @param newProperty The new property which should replace the existing one. | |
* @return The resulting {@link ValueBindingExpression} (with the new property) | |
*/ | |
public static ValueBindingExpression replaceProperty(ValueBindingExpression valueBindingExpression, | |
String newProperty) | |
{ | |
//TODO adjustments for isDynamicBaseAndProperty | |
if(valueBindingExpression.getProperty().endsWith("']")) | |
{ | |
valueBindingExpression = valueBindingExpression.getBaseExpression(); | |
} | |
if(valueBindingExpression.getBaseExpression() != null) | |
{ | |
return addProperty(valueBindingExpression.getBaseExpression(), newProperty); | |
} | |
else | |
{ | |
return addProperty(valueBindingExpression, newProperty); | |
} | |
} | |
/** | |
* Adds the property to the given {@link ValueBindingExpression}. | |
* | |
* @param valueBindingExpression The valueBindingExpression where we want to add the property | |
* @param newProperty The property to add. | |
* @return The resulting {@link ValueBindingExpression} (with the new property) | |
*/ | |
public static ValueBindingExpression addProperty(ValueBindingExpression valueBindingExpression, String newProperty) | |
{ | |
String sourceExpression = valueBindingExpression.getExpressionString(); | |
String result = sourceExpression.substring(0, sourceExpression.length() - 1); | |
//TODO adjustments for isDynamicBaseAndProperty | |
if(newProperty.startsWith("['")) | |
{ | |
return new ValueBindingExpression(result + newProperty + "}"); | |
} | |
else | |
{ | |
return new ValueBindingExpression(result + "." + newProperty + "}"); | |
} | |
} | |
/** | |
* Creates an instance of a ValueBindingExpression based on a well formed EL expression. | |
* | |
* @param expression The EL expression | |
*/ | |
public ValueBindingExpression(String expression) | |
{ | |
if(!EL_HELPER.isELTermWellFormed(expression)) | |
{ | |
throw new IllegalStateException(expression + " is no valid el-expression"); | |
} | |
boolean isDynamicBaseAndProperty = expression.lastIndexOf("']") == -1; | |
int index1 = isDynamicBaseAndProperty ? expression.lastIndexOf("]") : expression.lastIndexOf("']"); | |
int index2 = expression.lastIndexOf("."); | |
if(index1 > index2) | |
{ | |
expression = expression.substring(0, index1); | |
int index3 = findIndexOfStartingBracket(expression); | |
if(isDynamicBaseAndProperty) | |
{ | |
this.value = expression.substring(index3 + 1, index1); | |
} | |
else | |
{ | |
this.value = expression.substring(index3 + 2, index1); | |
} | |
this.base = new ValueBindingExpression(expression.substring(0, index3) + "}"); | |
this.token = isDynamicBaseAndProperty ? "[" : "['"; | |
} | |
else if( index2 > index1) | |
{ | |
this.value = expression.substring(index2 + 1, expression.length() - 1 ); | |
this.base = new ValueBindingExpression(expression.substring(0, index2) + "}"); | |
this.token = "."; | |
} | |
else | |
{ | |
this.value = expression.substring(2, expression.length() - 1); | |
this.prefix = expression.substring(0, 1); | |
} | |
} | |
/** | |
* The (last) property of the expression. | |
* @return The (last) property of the expression. | |
*/ | |
public String getProperty() | |
{ | |
this.value = this.value.trim(); | |
if("[".equals(this.token)) | |
{ | |
if(this.value.startsWith("'")) | |
{ | |
return this.value.substring(1, this.value.length() - 1); | |
} | |
//return this.base.value + this.token + this.value.substring(0, this.value.length()) + "']"; | |
} | |
return value; | |
} | |
public ValueBindingExpression getBaseExpression() | |
{ | |
return base; | |
} | |
/** | |
* Recreates the expression string from which this valueBindingExpression was build. There is no guarantee that the | |
* same format is kep, for example {#bean['property']} could become {#bean.property} | |
* | |
* @return The expression string equivalent of the valueBindingExpression. | |
*/ | |
public String getExpressionString() | |
{ | |
if(this.base != null) | |
{ | |
String baseExpression = this.base.getExpressionString(); | |
if("['".equals(this.token)) | |
{ | |
return baseExpression.substring(0, baseExpression.length() - 1) + this.token + this.value + "']}"; | |
} | |
else if("[".equals(this.token)) | |
{ | |
return baseExpression.substring(0, baseExpression.length() - 1) + this.token + this.value + "]}"; | |
} | |
return baseExpression.substring(0, baseExpression.length() - 1) + this.token + this.value + "}"; | |
} | |
else | |
{ | |
return this.prefix + "{" + this.value + "}"; | |
} | |
} | |
public String getPrefix() | |
{ | |
if(this.base != null) | |
{ | |
return this.base.getPrefix(); | |
} | |
else | |
{ | |
return prefix; | |
} | |
} | |
public void setPrefix(String prefix) | |
{ | |
if(this.base != null) | |
{ | |
this.base.setPrefix(prefix); | |
} | |
else | |
{ | |
this.prefix = prefix; | |
} | |
} | |
@Override | |
public String toString() | |
{ | |
return getExpressionString(); | |
} | |
@Override | |
public int hashCode() | |
{ | |
return getExpressionString().hashCode(); | |
} | |
@Override | |
public boolean equals(Object target) | |
{ | |
return target instanceof ValueBindingExpression && getExpressionString() | |
.equals(((ValueBindingExpression) target).getExpressionString()); | |
} | |
private int findIndexOfStartingBracket(String expression) | |
{ | |
int closeCount = 0; | |
for(int i = expression.length() - 1; i > 0; i--) | |
{ | |
if(expression.charAt(i) == '[') | |
{ | |
closeCount--; | |
if(closeCount < 0) | |
{ | |
return i; | |
} | |
} | |
else if(expression.charAt(i) == ']') | |
{ | |
closeCount++; | |
} | |
} | |
return 0; | |
} | |
} |