mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-09-20 23:19:33 +02:00
d4a6d8e653
to StanzaFilter and ExtensionElement.
412 lines
13 KiB
Java
412 lines
13 KiB
Java
/**
|
|
*
|
|
* Copyright 2014 Anno van Vliet
|
|
*
|
|
* Licensed 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.jivesoftware.smackx.xdatavalidation.packet;
|
|
|
|
import org.jivesoftware.smack.packet.NamedElement;
|
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
|
import org.jivesoftware.smack.util.NumberUtil;
|
|
import org.jivesoftware.smack.util.StringUtils;
|
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
|
import org.jivesoftware.smackx.xdata.FormField;
|
|
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
|
import org.jivesoftware.smackx.xdatavalidation.ValidationConsistencyException;
|
|
|
|
/**
|
|
* DataValidation Extension according to XEP-0122: Data Forms Validation. This specification defines a
|
|
* backwards-compatible extension to the XMPP Data Forms protocol that enables applications to specify additional
|
|
* validation guidelines related to a {@link FormField} in a {@link DataForm}, such as validation of standard XML
|
|
* datatypes, application-specific datatypes, value ranges, and regular expressions.
|
|
*
|
|
* @author Anno van Vliet
|
|
*/
|
|
public abstract class ValidateElement implements ExtensionElement {
|
|
|
|
public static final String DATATYPE_XS_STRING = "xs:string";
|
|
public static final String ELEMENT = "validate";
|
|
public static final String NAMESPACE = "http://jabber.org/protocol/xdata-validate";
|
|
|
|
private final String datatype;
|
|
|
|
private ListRange listRange;
|
|
|
|
/**
|
|
* The 'datatype' attribute specifies the datatype. This attribute is OPTIONAL, and when not specified, defaults to
|
|
* "xs:string".
|
|
*
|
|
* @param datatype the data type of any value contained within the {@link FormField} element.
|
|
*/
|
|
private ValidateElement(String datatype) {
|
|
this.datatype = StringUtils.isNotEmpty(datatype) ? datatype : null;
|
|
}
|
|
|
|
/**
|
|
* Specifies the data type of any value contained within the {@link FormField} element. It MUST meet one of the
|
|
* following conditions:
|
|
* <ul>
|
|
* <li>Start with "xs:", and be one of the "built-in" datatypes defined in XML Schema Part 2 <a
|
|
* href="http://www.xmpp.org/extensions/xep-0122.html#nt-idp1476016">[2]</a></li>
|
|
* <li>Start with a prefix registered with the XMPP Registrar <a
|
|
* href="http://www.xmpp.org/extensions/xep-0122.html#nt-idp1478544">[3]</a></li>
|
|
* <li>Start with "x:", and specify a user-defined datatype <a
|
|
* href="http://www.xmpp.org/extensions/xep-0122.html#nt-idp1477360">[4]</a></li>
|
|
* </ul>
|
|
*
|
|
* @return the datatype
|
|
*/
|
|
public String getDatatype() {
|
|
return datatype != null ? datatype : DATATYPE_XS_STRING;
|
|
}
|
|
|
|
@Override
|
|
public String getElementName() {
|
|
return ELEMENT;
|
|
}
|
|
|
|
@Override
|
|
public String getNamespace() {
|
|
return NAMESPACE;
|
|
}
|
|
|
|
@Override
|
|
public XmlStringBuilder toXML() {
|
|
XmlStringBuilder buf = new XmlStringBuilder(this);
|
|
buf.optAttribute("datatype", datatype);
|
|
buf.rightAngleBracket();
|
|
appendXML(buf);
|
|
buf.optAppend(getListRange());
|
|
buf.closeElement(this);
|
|
return buf;
|
|
}
|
|
|
|
/**
|
|
* @param buf
|
|
*/
|
|
protected abstract void appendXML(XmlStringBuilder buf);
|
|
|
|
/**
|
|
* @param listRange the listRange to set
|
|
*/
|
|
public void setListRange(ListRange listRange) {
|
|
this.listRange = listRange;
|
|
}
|
|
|
|
/**
|
|
* @return the listRange
|
|
*/
|
|
public ListRange getListRange() {
|
|
return listRange;
|
|
}
|
|
|
|
/**
|
|
* Check if this element is consistent according to the business rules in XEP=0122
|
|
*
|
|
* @param formField
|
|
*/
|
|
public abstract void checkConsistency(FormField formField);
|
|
|
|
/**
|
|
* Validation only against the datatype itself. Indicates that the value(s) should simply match the field type and
|
|
* datatype constraints.
|
|
*
|
|
* @see ValidateElement
|
|
*/
|
|
public static class BasicValidateElement extends ValidateElement {
|
|
|
|
public static final String METHOD = "basic";
|
|
|
|
/**
|
|
* @param dataType
|
|
* @see #getDatatype()
|
|
*/
|
|
public BasicValidateElement(String dataType) {
|
|
super(dataType);
|
|
}
|
|
|
|
@Override
|
|
protected void appendXML(XmlStringBuilder buf) {
|
|
buf.emptyElement(METHOD);
|
|
}
|
|
|
|
public void checkConsistency(FormField formField) {
|
|
checkListRangeConsistency(formField);
|
|
if (formField.getType() != null) {
|
|
switch (formField.getType()) {
|
|
case hidden:
|
|
case jid_multi:
|
|
case jid_single:
|
|
throw new ValidationConsistencyException(String.format(
|
|
"Field type '%1$s' is not consistent with validation method '%2$s'.",
|
|
formField.getType(), BasicValidateElement.METHOD));
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* For "list-single" or "list-multi", indicates that the user may enter a custom value (matching the datatype
|
|
* constraints) or choose from the predefined values.
|
|
*
|
|
* @see ValidateElement
|
|
*/
|
|
public static class OpenValidateElement extends ValidateElement {
|
|
|
|
public static final String METHOD = "open";
|
|
|
|
/**
|
|
* @param dataType
|
|
* @see #getDatatype()
|
|
*/
|
|
public OpenValidateElement(String dataType) {
|
|
super(dataType);
|
|
}
|
|
|
|
@Override
|
|
protected void appendXML(XmlStringBuilder buf) {
|
|
buf.emptyElement(METHOD);
|
|
}
|
|
|
|
public void checkConsistency(FormField formField) {
|
|
checkListRangeConsistency(formField);
|
|
if (formField.getType() != null) {
|
|
switch (formField.getType()) {
|
|
case hidden:
|
|
throw new ValidationConsistencyException(String.format(
|
|
"Field type '%1$s' is not consistent with validation method '%2$s'.",
|
|
formField.getType(), OpenValidateElement.METHOD));
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Indicate that the value should fall within a certain range.
|
|
*
|
|
* @see ValidateElement
|
|
*/
|
|
public static class RangeValidateElement extends ValidateElement {
|
|
|
|
public static final String METHOD = "range";
|
|
private final String min;
|
|
private final String max;
|
|
|
|
/**
|
|
* @param dataType
|
|
* @param min the minimum allowable value. This attribute is OPTIONAL. The value depends on the datatype in use.
|
|
* @param max the maximum allowable value. This attribute is OPTIONAL. The value depends on the datatype in use.
|
|
* @see #getDatatype()
|
|
*
|
|
*/
|
|
public RangeValidateElement(String dataType, String min, String max) {
|
|
super(dataType);
|
|
this.min = min;
|
|
this.max = max;
|
|
}
|
|
|
|
@Override
|
|
protected void appendXML(XmlStringBuilder buf) {
|
|
buf.halfOpenElement(METHOD);
|
|
buf.optAttribute("min", getMin());
|
|
buf.optAttribute("max", getMax());
|
|
buf.closeEmptyElement();
|
|
}
|
|
|
|
/**
|
|
* The 'min' attribute specifies the minimum allowable value.
|
|
*
|
|
* @return the minimum allowable value. This attribute is OPTIONAL. The value depends on the datatype in use.
|
|
*/
|
|
public String getMin() {
|
|
return min;
|
|
}
|
|
|
|
/**
|
|
* The 'max' attribute specifies the maximum allowable value.
|
|
*
|
|
* @return the maximum allowable value. This attribute is OPTIONAL. The value depends on the datatype in use.
|
|
*/
|
|
public String getMax() {
|
|
return max;
|
|
}
|
|
|
|
public void checkConsistency(FormField formField) {
|
|
checkNonMultiConsistency(formField, METHOD);
|
|
if (getDatatype().equals(ValidateElement.DATATYPE_XS_STRING)) {
|
|
throw new ValidationConsistencyException(String.format(
|
|
"Field data type '%1$s' is not consistent with validation method '%2$s'.",
|
|
getDatatype(), RangeValidateElement.METHOD));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Indicates that the value should be restricted to a regular expression. The regular expression must be that
|
|
* defined for <a href="http://www.xmpp.org/extensions/xep-0122.html#nt-idp1501344"> POSIX extended regular
|
|
* expressions </a> including support for <a
|
|
* href="http://www.xmpp.org/extensions/xep-0122.html#nt-idp1502496">Unicode</a>.
|
|
*
|
|
* @see ValidateElement
|
|
*/
|
|
public static class RegexValidateElement extends ValidateElement {
|
|
|
|
public static final String METHOD = "regex";
|
|
private final String regex;
|
|
|
|
/**
|
|
* @param dataType
|
|
* @param regex
|
|
* @see #getDatatype()
|
|
*/
|
|
public RegexValidateElement(String dataType, String regex) {
|
|
super(dataType);
|
|
this.regex = regex;
|
|
}
|
|
|
|
/**
|
|
* the expression is that defined for POSIX extended regular expressions, including support for Unicode.
|
|
*
|
|
* @return the regex
|
|
*/
|
|
public String getRegex() {
|
|
return regex;
|
|
}
|
|
|
|
@Override
|
|
protected void appendXML(XmlStringBuilder buf) {
|
|
buf.element("regex", getRegex());
|
|
}
|
|
|
|
public void checkConsistency(FormField formField) {
|
|
checkNonMultiConsistency(formField, METHOD);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* This element indicates for "list-multi", that a minimum and maximum number of options should be selected and/or
|
|
* entered.
|
|
*/
|
|
public static class ListRange implements NamedElement {
|
|
|
|
public static final String ELEMENT = "list-range";
|
|
private final Long min;
|
|
private final Long max;
|
|
|
|
/**
|
|
* The 'max' attribute specifies the maximum allowable number of selected/entered values. The 'min' attribute
|
|
* specifies the minimum allowable number of selected/entered values. Both attributes are optional, but at
|
|
* least one must bet set, and the value must be within the range of a unsigned 32-bit integer.
|
|
*
|
|
* @param min
|
|
* @param max
|
|
*/
|
|
public ListRange(Long min, Long max) {
|
|
if (min != null) {
|
|
NumberUtil.checkIfInUInt32Range(min);
|
|
}
|
|
if (max != null) {
|
|
NumberUtil.checkIfInUInt32Range(max);
|
|
}
|
|
if (max == null && min == null) {
|
|
throw new IllegalArgumentException("Either min or max must be given");
|
|
}
|
|
this.min = min;
|
|
this.max = max;
|
|
}
|
|
|
|
public XmlStringBuilder toXML() {
|
|
XmlStringBuilder buf = new XmlStringBuilder(this);
|
|
buf.optLongAttribute("min", getMin());
|
|
buf.optLongAttribute("max", getMax());
|
|
buf.closeEmptyElement();
|
|
return buf;
|
|
}
|
|
|
|
@Override
|
|
public String getElementName() {
|
|
return ELEMENT;
|
|
}
|
|
|
|
/**
|
|
* The minimum allowable number of selected/entered values.
|
|
*
|
|
* @return a positive integer, can be null
|
|
*/
|
|
public Long getMin() {
|
|
return min;
|
|
}
|
|
|
|
/**
|
|
* The maximum allowable number of selected/entered values.
|
|
*
|
|
* @return a positive integer, can be null
|
|
*/
|
|
public Long getMax() {
|
|
return max;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* The <list-range/> element SHOULD be included only when the <field/> is of type "list-multi" and SHOULD be ignored
|
|
* otherwise.
|
|
*
|
|
* @param formField
|
|
*/
|
|
protected void checkListRangeConsistency(FormField formField) {
|
|
ListRange listRange = getListRange();
|
|
if (listRange == null) {
|
|
return;
|
|
}
|
|
|
|
Long max = listRange.getMax();
|
|
Long min = listRange.getMin();
|
|
if ((max != null || min != null) && formField.getType() != FormField.Type.list_multi) {
|
|
throw new ValidationConsistencyException(
|
|
"Field type is not of type 'list-multi' while a 'list-range' is defined.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param formField
|
|
* @param method
|
|
*/
|
|
protected void checkNonMultiConsistency(FormField formField, String method) {
|
|
checkListRangeConsistency(formField);
|
|
if (formField.getType() != null) {
|
|
switch (formField.getType()) {
|
|
case hidden:
|
|
case jid_multi:
|
|
case list_multi:
|
|
case text_multi:
|
|
throw new ValidationConsistencyException(String.format(
|
|
"Field type '%1$s' is not consistent with validation method '%2$s'.",
|
|
formField.getType(), method));
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|