WW-4198 Merges changes to develop

This commit is contained in:
Lukasz Lenart
2014-03-13 18:39:15 +01:00
6 changed files with 112 additions and 89 deletions
@@ -120,7 +120,7 @@ END SNIPPET: supported-validators
<#if validator.shortCircuit>continueValidation = false;</#if>
}
<#elseif validator.validatorType = "url">
if (continueValidation && fieldValue != null && fieldValue.length > 0 && fieldValue.match("${validator.regex?js_string}")==null) {
if (continueValidation && fieldValue != null && fieldValue.length > 0 && fieldValue.match("/${validator.urlRegex?js_string}/i")==null) {
addError(field, error);
errors = true;
<#if validator.shortCircuit>continueValidation = false;</#if>
@@ -33,6 +33,7 @@ public class URLUtil {
* @param url The url string to verify.
* @return a boolean indicating whether the URL seems to be incorrect.
*/
@Deprecated
public static boolean verifyUrl(String url) {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking if url [#0] is valid", url);
@@ -528,6 +528,12 @@ public class AnnotationValidationConfigurationBuilder {
} else if (v.fieldName() != null && v.fieldName().length() > 0) {
params.put("fieldName", v.fieldName());
}
if (StringUtils.isNotEmpty(v.urlRegex())) {
params.put("urlRegex", v.urlRegex());
}
if (StringUtils.isNotEmpty(v.urlRegexExpression())) {
params.put("urlRegexExpression", v.urlRegexExpression());
}
validatorFactory.lookupRegisteredValidatorType(validatorType);
return new ValidatorConfig.Builder(validatorType)
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.validator.annotations;
import java.lang.annotation.ElementType;
@@ -22,75 +21,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <!-- START SNIPPET: description -->
* This validator checks that a field is a valid URL.
* <!-- END SNIPPET: description -->
*
* <p/> <u>Annotation usage:</u>
*
* <!-- START SNIPPET: usage -->
* <p/>The annotation must be applied at method level.
* <!-- END SNIPPET: usage -->
*
* <p/> <u>Annotation parameters:</u>
*
* <!-- START SNIPPET: parameters -->
* <table class='confluenceTable'>
* <tr>
* <th class='confluenceTh'> Parameter </th>
* <th class='confluenceTh'> Required </th>
* <th class='confluenceTh'> Default </th>
* <th class='confluenceTh'> Notes </th>
* </tr>
* <tr>
* <td class='confluenceTd'>message</td>
* <td class='confluenceTd'>yes</td>
* <td class='confluenceTd'>&nbsp;</td>
* <td class='confluenceTd'>field error message</td>
* </tr>
* <tr>
* <td class='confluenceTd'>key</td>
* <td class='confluenceTd'>no</td>
* <td class='confluenceTd'>&nbsp;</td>
* <td class='confluenceTd'>i18n key from language specific properties file.</td>
* </tr>
* <tr>
* <td class='confluenceTd'>messageParams</td>
* <td class='confluenceTd'>no</td>
* <td class='confluenceTd'>&nbsp;</td>
* <td class='confluenceTd'>Additional params to be used to customize message - will be evaluated against the Value Stack</td>
* </tr>
* <tr>
* <td class='confluenceTd'>fieldName</td>
* <td class='confluenceTd'>no</td>
* <td class='confluenceTd'>&nbsp;</td>
* <td class='confluenceTd'>&nbsp;</td>
* </tr>
* <tr>
* <td class='confluenceTd'>shortCircuit</td>
* <td class='confluenceTd'>no</td>
* <td class='confluenceTd'>false</td>
* <td class='confluenceTd'>If this validator should be used as shortCircuit.</td>
* </tr>
* <tr>
* <td class='confluenceTd'>type</td>
* <td class='confluenceTd'>yes</td>
* <td class='confluenceTd'>ValidatorType.FIELD</td>
* <td class='confluenceTd'>Enum value from ValidatorType. Either FIELD or SIMPLE can be used here.</td>
* </tr>
* </table>
* <!-- END SNIPPET: parameters -->
*
* <p/> <u>Example code:</u>
*
* <pre>
* <!-- START SNIPPET: example -->
* &#64;UrlValidator(message = "Default message", key = "i18n.key", shortCircuit = true)
* <!-- END SNIPPET: example -->
* </pre>
*
* @author Rainer Hermanns
* @version $Id$
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@@ -121,7 +56,6 @@ public @interface UrlValidator {
* If this is activated, the validator will be used as short-circuit.
*
* Adds the short-circuit="true" attribute value if <tt>true</tt>.
*
*/
boolean shortCircuit() default false;
@@ -130,4 +64,14 @@ public @interface UrlValidator {
*/
ValidatorType type() default ValidatorType.FIELD;
/**
* Defines regex to use to validate url
*/
String urlRegex() default "";
/**
* Defines regex as an expression which will be evaluated to string and used to validate url
*/
String urlRegexExpression() default "";
}
@@ -17,28 +17,12 @@ package com.opensymphony.xwork2.validator.validators;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.util.URLUtil;
import org.apache.commons.lang3.StringUtils;
/**
* <!-- START SNIPPET: javadoc -->
*
* URLValidator checks that a given field is a String and a valid URL
*
* <!-- END SNIPPET: javadoc -->
*
* <p/>
*
* <!-- START SNIPPET: parameters -->
*
* <ul>
* <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li>
* </ul>
*
* <!-- END SNIPPET: parameters -->
*
* <p/>
*
* <pre>
* <!-- START SNIPPET: examples -->
* &lt;validators&gt;
* &lt;!-- Plain Validator Syntax --&gt;
* &lt;validator type="url"&gt;
@@ -53,15 +37,13 @@ import com.opensymphony.xwork2.util.URLUtil;
* &lt;/field-validator&gt;
* &lt;/field&gt;
* &lt;/validators&gt;
* <!-- END SNIPPET: examples -->
* </pre>
*
*
* @author $Author$
* @version $Date$ $Revision$
*/
public class URLValidator extends FieldValidatorSupport {
private String urlRegex;
private String urlRegexExpression;
public void validate(Object object) throws ValidationException {
String fieldName = getFieldName();
Object value = this.getFieldValue(fieldName, object);
@@ -72,8 +54,48 @@ public class URLValidator extends FieldValidatorSupport {
return;
}
// FIXME deprecated! the same regex below should be used instead
// replace logic with next major release
if (!(value.getClass().equals(String.class)) || !URLUtil.verifyUrl((String) value)) {
addFieldError(fieldName, object);
}
}
/**
* This is used to support client-side validation, it's based on
* http://stackoverflow.com/questions/161738/what-is-the-best-regular-expression-to-check-if-a-string-is-a-valid-url
*
* @return regex to validate URLs
*/
public String getUrlRegex() {
if (StringUtils.isNotEmpty(urlRegexExpression)) {
return (String) parse(urlRegexExpression, String.class);
} else if (StringUtils.isNotEmpty(urlRegex)) {
return urlRegex;
} else {
return "^(https?|ftp):\\/\\/" +
"(([a-z0-9$_\\.\\+!\\*\\'\\(\\),;\\?&=-]|%[0-9a-f]{2})+" +
"(:([a-z0-9$_\\.\\+!\\*\\'\\(\\),;\\?&=-]|%[0-9a-f]{2})+)?" +
"@)?(#?" +
")((([a-z0-9]\\.|[a-z0-9][a-z0-9-]*[a-z0-9]\\.)*" +
"[a-z][a-z0-9-]*[a-z0-9]" +
"|((\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])\\.){3}" +
"(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])" +
")(:\\d+)?" +
")(((\\/+([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)*" +
"(\\?([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)" +
"?)?)?" +
"(#([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)?" +
"$";
}
}
public void setUrlRegex(String urlRegex) {
this.urlRegex = urlRegex;
}
public void setUrlRegexExpression(String urlRegexExpression) {
this.urlRegexExpression = urlRegexExpression;
}
}
@@ -17,9 +17,12 @@ package com.opensymphony.xwork2.validator;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.XWorkTestCase;
import com.opensymphony.xwork2.util.URLUtil;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.validator.validators.URLValidator;
import java.util.regex.Pattern;
/**
* Test case for URLValidator
*
@@ -103,6 +106,46 @@ public class URLValidatorTest extends XWorkTestCase {
assertFalse(validator.getValidatorContext().hasFieldErrors());
}
public void testValidUrlWithRegex() throws Exception {
URLValidator validator = new URLValidator();
validator.setUrlRegex("^myapp:\\/\\/[a-z]*\\.com$");
Pattern pattern = Pattern.compile(validator.getUrlRegex());
assertTrue(pattern.matcher("myapp://test.com").matches());
assertFalse(pattern.matcher("myap://test.com").matches());
}
public void testValidUrlWithRegexExpression() throws Exception {
URLValidator validator = new URLValidator();
ActionContext.getContext().getValueStack().push(new MyAction());
validator.setValueStack(ActionContext.getContext().getValueStack());
validator.setUrlRegexExpression("${urlRegex}");
Pattern pattern = Pattern.compile(validator.getUrlRegex());
assertTrue(pattern.matcher("myapp://test.com").matches());
assertFalse(pattern.matcher("myap://test.com").matches());
}
public void testValidUrlWithDefaultRegex() throws Exception {
URLValidator validator = new URLValidator();
Pattern pattern = Pattern.compile(validator.getUrlRegex());
assertFalse(pattern.matcher("myapp://test.com").matches());
assertFalse(pattern.matcher("myap://test.com").matches());
assertFalse(pattern.matcher("").matches());
assertFalse(pattern.matcher(" ").matches());
assertFalse(pattern.matcher("no url").matches());
assertTrue(pattern.matcher("http://www.opensymphony.com").matches());
assertTrue(pattern.matcher("https://www.opensymphony.com").matches());
assertTrue(pattern.matcher("https://www.opensymphony.com:443/login").matches());
assertTrue(pattern.matcher("http://localhost:8080/myapp").matches());
}
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -140,4 +183,11 @@ public class URLValidatorTest extends XWorkTestCase {
return "http://yahoo.com/articles?id=123";
}
}
class MyAction {
public String getUrlRegex() {
return "myapp:\\/\\/[a-z]*\\.com";
}
}
}