import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.BaseEncoding;
import java.io.Serializable;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.commons.text.StringEscapeUtils;
import org.opendaylight.mdsal.binding.generator.spi.TypeProvider;
import org.opendaylight.mdsal.binding.model.api.AccessModifier;
import org.opendaylight.mdsal.binding.model.api.ConcreteType;
* </ul>
*/
@Override
- public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode, final Restrictions r) {
+ public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
+ final Restrictions r) {
Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
Preconditions.checkArgument(typeDefinition.getQName() != null,
"Type Definition cannot have non specified QName (QName cannot be NULL!)");
// and generated an enclosing ExtendedType to hold any range constraints. The new parser instantiates
// a base type which holds these constraints.
if (typeDefinition instanceof DecimalTypeDefinition) {
- final Type ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition, parentNode, r);
+ final Type ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition,
+ parentNode, r);
if (ret != null) {
return ret;
}
final GeneratedTransferObject gto = (GeneratedTransferObject) returnType;
final Module module = findParentModule(schemaContext, parentNode);
final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
- final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typeDefinition.getPath());
+ final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName,
+ typeDefinition.getPath());
final String genTOName = BindingMapping.getClassName(typedefName);
final String name = packageName + "." + genTOName;
if (!returnType.getFullyQualifiedName().equals(name)) {
return returnType;
}
- private static GeneratedTransferObject shadedTOWithRestrictions(final GeneratedTransferObject gto, final Restrictions r) {
+ private static GeneratedTransferObject shadedTOWithRestrictions(final GeneratedTransferObject gto,
+ final Restrictions r) {
final GeneratedTOBuilder gtob = new GeneratedTOBuilderImpl(gto.getPackageName(), gto.getName());
final GeneratedTransferObject parent = gto.getSuperType();
if (parent != null) {
gtob.setExtendsType(parent);
}
gtob.setRestrictions(r);
- for (final GeneratedProperty gp : gto.getProperties()) {
+ for (GeneratedProperty gp : gto.getProperties()) {
final GeneratedPropertyBuilder gpb = gtob.addProperty(gp.getName());
gpb.setValue(gp.getValue());
gpb.setReadOnly(gp.isReadOnly());
final Module module = findParentModule(schemaContext, typeDefinition);
final Restrictions r = BindingGeneratorUtil.getRestrictions(typeDefinition);
if (module != null) {
- final Map<Optional<Revision>, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
+ final Map<Optional<Revision>, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(
+ module.getName());
final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
if (genTOs != null) {
returnType = genTOs.get(typedefName);
final QName baseIdQName = identities.iterator().next().getQName();
final Module module = schemaContext.findModule(baseIdQName.getModule()).orElse(null);
IdentitySchemaNode identity = null;
- for (final IdentitySchemaNode id : module.getIdentities()) {
+ for (IdentitySchemaNode id : module.getIdentities()) {
if (id.getQName().equals(baseIdQName)) {
identity = id;
}
Preconditions.checkArgument(identity != null, "Target identity '" + baseIdQName + "' do not exists");
final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
- final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity.getPath());
+ final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName,
+ identity.getPath());
final String genTypeName = BindingMapping.getClassName(identity.getQName());
final Type baseType = Types.typeForClass(Class.class);
final Module module = findParentModule(schemaContext, parentNode);
if (module != null) {
- final Map<Optional<Revision>, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
+ final Map<Optional<Revision>, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(
+ module.getName());
final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
if (genTOs != null) {
return genTOs.get(typeDefinition.getQName().getLocalName());
* <li>if name of <code>enumTypeDef</code> equal null</li>
* </ul>
*/
- private Enumeration provideTypeForEnum(final EnumTypeDefinition enumTypeDef, final String enumName, final SchemaNode parentNode) {
+ private Enumeration provideTypeForEnum(final EnumTypeDefinition enumTypeDef, final String enumName,
+ final SchemaNode parentNode) {
Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
Preconditions.checkArgument(enumTypeDef.getValues() != null,
"EnumTypeDefinition MUST contain at least ONE value definition!");
* </ul>
*
*/
- private static Enumeration addInnerEnumerationToTypeBuilder(final EnumTypeDefinition enumTypeDef, final String enumName, final GeneratedTypeBuilderBase<?> typeBuilder) {
+ private static Enumeration addInnerEnumerationToTypeBuilder(final EnumTypeDefinition enumTypeDef,
+ final String enumName, final GeneratedTypeBuilderBase<?> typeBuilder) {
Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
Preconditions.checkArgument(enumTypeDef.getValues() != null,
"EnumTypeDefinition MUST contain at least ONE value definition!");
Preconditions.checkArgument(modules != null, "Set of Modules cannot be NULL!");
final List<Module> modulesSortedByDependency = ModuleDependencySort.sort(modules);
- for (final Module module : modulesSortedByDependency) {
+ for (Module module : modulesSortedByDependency) {
Map<Optional<Revision>, Map<String, Type>> dateTypeMap = genTypeDefsContextMap.get(module.getName());
if (dateTypeMap == null) {
dateTypeMap = new HashMap<>();
genTypeDefsContextMap.put(module.getName(), dateTypeMap);
}
- for (final Module module : modulesSortedByDependency) {
+ for (Module module : modulesSortedByDependency) {
if (module != null) {
final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
if (basePackageName != null) {
final List<TypeDefinition<?>> typeDefinitions = TypedefResolver.getAllTypedefs(module);
- final List<TypeDefinition<?>> listTypeDefinitions = sortTypeDefinitionAccordingDepth(typeDefinitions);
- if (listTypeDefinitions != null) {
- for (final TypeDefinition<?> typedef : listTypeDefinitions) {
- typedefToGeneratedType(basePackageName, module, typedef);
- }
+ for (TypeDefinition<?> typedef : sortTypeDefinitionAccordingDepth(typeDefinitions)) {
+ typedefToGeneratedType(basePackageName, module, typedef);
}
}
}
Preconditions.checkState(!builders.isEmpty(), "No GeneratedTOBuilder objects generated from union %s", typedef);
final GeneratedTOBuilder resultTOBuilder = builders.remove(0);
- for (final GeneratedTOBuilder genTOBuilder : builders) {
- resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
- }
+ builders.forEach(resultTOBuilder::addEnclosingTransferObject);
resultTOBuilder.addProperty("value").setReturnType(Types.CHAR_ARRAY);
return resultTOBuilder;
generatedTOBuilders.add(unionGenTOBuilder);
unionGenTOBuilder.setIsUnion(true);
- final List<String> regularExpressions = new ArrayList<>();
- for (final TypeDefinition<?> unionType : unionTypes) {
+
+ // Pattern string is the key, XSD regex is the value. The reason for this choice is that the pattern carries
+ // also negation information and hence guarantees uniqueness.
+ final Map<String, String> expressions = new HashMap<>();
+ for (TypeDefinition<?> unionType : unionTypes) {
final String unionTypeName = unionType.getQName().getLocalName();
// If we have a base type we should follow the type definition backwards, except for identityrefs, as those
// do not follow type encapsulation -- we use the general case for that.
if (unionType.getBaseType() != null && !(unionType instanceof IdentityrefTypeDefinition)) {
- resolveExtendedSubtypeAsUnion(unionGenTOBuilder, unionType, regularExpressions, parentNode);
+ resolveExtendedSubtypeAsUnion(unionGenTOBuilder, unionType, expressions, parentNode);
} else if (unionType instanceof UnionTypeDefinition) {
generatedTOBuilders.addAll(resolveUnionSubtypeAsUnion(unionGenTOBuilder,
(UnionTypeDefinition) unionType, basePackageName, parentNode));
updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
}
}
- if (!regularExpressions.isEmpty()) {
- addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
- }
+ addStringRegExAsConstant(unionGenTOBuilder, expressions);
storeGenTO(typedef, unionGenTOBuilder, parentNode);
* @param unionSubtype
* type definition of the <code>ExtendedType</code> type which
* represents union subtype
- * @param regularExpressions
+ * @param expressions
* list of strings with the regular expressions
* @param parentNode
* parent Schema Node for Extended Subtype
*
*/
private void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
- final TypeDefinition<?> unionSubtype, final List<String> regularExpressions, final SchemaNode parentNode) {
+ final TypeDefinition<?> unionSubtype, final Map<String, String> expressions, final SchemaNode parentNode) {
final String unionTypeName = unionSubtype.getQName().getLocalName();
final Type genTO = findGenTO(unionTypeName, unionSubtype);
if (genTO != null) {
updateUnionTypeAsProperty(parentUnionGenTOBuilder, genTO, genTO.getName());
- } else {
- final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
- if (unionTypeName.equals(baseType.getQName().getLocalName())) {
- final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
- parentNode);
- if (javaType != null) {
- updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
- }
- } else if (baseType instanceof LeafrefTypeDefinition) {
- final Type javaType = javaTypeForSchemaDefinitionType(baseType, parentNode);
- boolean typeExist = false;
- for (final GeneratedPropertyBuilder generatedPropertyBuilder : parentUnionGenTOBuilder
- .getProperties()) {
- final Type origType = ((GeneratedPropertyBuilderImpl) generatedPropertyBuilder).getReturnType();
- if (origType != null && javaType != null && javaType == origType) {
- typeExist = true;
- break;
- }
- }
- if (!typeExist && javaType != null) {
- updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, new StringBuilder(javaType.getName())
- .append(parentUnionGenTOBuilder.getName()).append("Value").toString());
+ return;
+ }
+
+ final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
+ if (unionTypeName.equals(baseType.getQName().getLocalName())) {
+ final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
+ parentNode);
+ if (javaType != null) {
+ updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
+ }
+ } else if (baseType instanceof LeafrefTypeDefinition) {
+ final Type javaType = javaTypeForSchemaDefinitionType(baseType, parentNode);
+ boolean typeExist = false;
+ for (GeneratedPropertyBuilder generatedPropertyBuilder : parentUnionGenTOBuilder.getProperties()) {
+ final Type origType = ((GeneratedPropertyBuilderImpl) generatedPropertyBuilder).getReturnType();
+ if (origType != null && javaType != null && javaType == origType) {
+ typeExist = true;
+ break;
}
}
- if (baseType instanceof StringTypeDefinition) {
- regularExpressions.addAll(resolveRegExpressionsFromTypedef(unionSubtype));
+ if (!typeExist && javaType != null) {
+ updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType,
+ javaType.getName() + parentUnionGenTOBuilder.getName() + "Value");
}
}
+ if (baseType instanceof StringTypeDefinition) {
+ expressions.putAll(resolveRegExpressionsFromTypedef(unionSubtype));
+ }
}
/**
final List<Bit> bitList = bitsTypeDefinition.getBits();
GeneratedPropertyBuilder genPropertyBuilder;
- for (final Bit bit : bitList) {
+ for (Bit bit : bitList) {
final String name = bit.getName();
genPropertyBuilder = genTOBuilder.addProperty(BindingMapping.getPropertyName(name));
genPropertyBuilder.setReadOnly(true);
* if <code>typedef</code> equals null
*
*/
- private static List<String> resolveRegExpressionsFromTypedef(final TypeDefinition<?> typedef) {
- Preconditions.checkArgument(typedef != null, "typedef can't be null");
-
- final List<PatternConstraint> patternConstraints;
- if (typedef instanceof StringTypeDefinition) {
- // FIXME: run diff against base
- patternConstraints = ((StringTypeDefinition) typedef).getPatternConstraints();
- } else {
- patternConstraints = ImmutableList.of();
+ private static Map<String, String> resolveRegExpressionsFromTypedef(final TypeDefinition<?> typedef) {
+ if (!(typedef instanceof StringTypeDefinition)) {
+ return ImmutableMap.of();
}
- final List<String> regExps = new ArrayList<>(patternConstraints.size());
- for (final PatternConstraint patternConstraint : patternConstraints) {
+ // TODO: run diff against base ?
+ final List<PatternConstraint> patternConstraints = ((StringTypeDefinition) typedef).getPatternConstraints();
+ final Map<String, String> regExps = Maps.newHashMapWithExpectedSize(patternConstraints.size());
+ for (PatternConstraint patternConstraint : patternConstraints) {
String regEx = patternConstraint.getJavaPatternString();
// The pattern can be inverted
regEx = applyModifier(optModifier.get(), regEx);
}
- final String modifiedRegEx = StringEscapeUtils.escapeJava(regEx);
- regExps.add(modifiedRegEx);
+ regExps.put(regEx, patternConstraint.getRegularExpressionString());
}
return regExps;
* @param genTOBuilder
* generated TO builder to which are
* <code>regular expressions</code> added
- * @param regularExpressions
+ * @param expressions
* list of string which represent regular expressions
- * @throws IllegalArgumentException
- * <ul>
- * <li>if <code>genTOBuilder</code> equals null</li>
- * <li>if <code>regularExpressions</code> equals null</li>
- * </ul>
*/
- private static void addStringRegExAsConstant(final GeneratedTOBuilder genTOBuilder, final List<String> regularExpressions) {
- if (genTOBuilder == null) {
- throw new IllegalArgumentException("Generated transfer object builder can't be null");
- }
- if (regularExpressions == null) {
- throw new IllegalArgumentException("List of regular expressions can't be null");
- }
- if (!regularExpressions.isEmpty()) {
+ private static void addStringRegExAsConstant(final GeneratedTOBuilder genTOBuilder,
+ final Map<String, String> expressions) {
+ if (!expressions.isEmpty()) {
genTOBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), TypeConstants.PATTERN_CONSTANT_NAME,
- ImmutableList.copyOf(regularExpressions));
+ ImmutableMap.copyOf(expressions));
}
}
final List<TypeDefinition<?>> sortedTypeDefinition = new ArrayList<>();
final Map<Integer, List<TypeDefinition<?>>> typeDefinitionsDepths = new TreeMap<>();
- for (final TypeDefinition<?> unsortedTypeDefinition : unsortedTypeDefinitions) {
+ for (TypeDefinition<?> unsortedTypeDefinition : unsortedTypeDefinitions) {
final Integer depth = getTypeDefinitionDepth(unsortedTypeDefinition);
List<TypeDefinition<?>> typeDefinitionsConcreteDepth = typeDefinitionsDepths.get(depth);
if (typeDefinitionsConcreteDepth == null) {
}
// SortedMap guarantees order corresponding to keys in ascending order
- for (final List<TypeDefinition<?>> v : typeDefinitionsDepths.values()) {
+ for (List<TypeDefinition<?>> v : typeDefinitionsDepths.values()) {
sortedTypeDefinition.addAll(v);
}
final List<TypeDefinition<?>> childTypeDefinitions = ((UnionTypeDefinition) baseType).getTypes();
int maxChildDepth = 0;
int childDepth = 1;
- for (final TypeDefinition<?> childTypeDefinition : childTypeDefinitions) {
+ for (TypeDefinition<?> childTypeDefinition : childTypeDefinitions) {
childDepth = childDepth + getTypeDefinitionDepth(childTypeDefinition);
if (childDepth > maxChildDepth) {
maxChildDepth = childDepth;
Module module = null;
final Set<Module> modules = schemaContext.findModules(typeQName.getNamespace());
if (modules.size() > 1) {
- for (final Module m : modules) {
+ for (Module m : modules) {
if (m.getRevision().equals(typeQName.getRevision())) {
module = m;
break;
*/
package org.opendaylight.mdsal.binding.java.api.generator
-import com.google.common.base.Preconditions
+import static java.util.Objects.requireNonNull
+import static extension org.apache.commons.text.StringEscapeUtils.escapeJava;
+
import com.google.common.collect.ImmutableList
import com.google.common.collect.Lists
import com.google.common.io.BaseEncoding
import java.util.Arrays
import java.util.Collections
import java.util.List
+import java.util.Map
import java.util.Objects
import java.util.regex.Pattern
import org.opendaylight.mdsal.binding.model.api.ConcreteType
import org.opendaylight.mdsal.binding.model.api.Restrictions
import org.opendaylight.mdsal.binding.model.api.Type
import org.opendaylight.mdsal.binding.model.util.TypeConstants
+import org.opendaylight.yangtools.yang.binding.CodeHelpers
import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
/**
this.enclosedGeneratedTypes = genType.enclosedTypes
if (restrictions !== null && restrictions.rangeConstraint.present) {
- rangeGenerator = AbstractRangeGenerator.forType(findProperty(genType, "value").returnType)
- Preconditions.checkNotNull(rangeGenerator)
+ rangeGenerator = requireNonNull(AbstractRangeGenerator.forType(findProperty(genType, "value").returnType))
} else {
rangeGenerator = null
}
* consequence of how this code is structured.
*/
IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»
-
- «Preconditions.importedName».checkNotNull(_value, "Supplied value may not be null");
-
+ «Objects.importedName».requireNonNull(_value, "Supplied value may not be null");
«FOR c : consts»
- «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME && c.value instanceof List<?>»
- for (Pattern p : «Constants.MEMBER_PATTERN_LIST») {
- «Preconditions.importedName».checkArgument(p.matcher(_value).matches(), "Supplied value \"%s\" does not match required pattern \"%s\"", _value, p);
- }
+ «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
+ «CodeHelpers.importedName».checkPattern(_value, «Constants.MEMBER_PATTERN_LIST», «Constants.MEMBER_REGEX_LIST»);
«ENDIF»
«ENDFOR»
«ENDIF»
«IF restrictions.rangeConstraint.present»
«rangeGenerator.generateRangeCheckerCall(paramName, paramValue(returnType, paramName))»
«ENDIF»
- }
+ }
«ENDIF»
«ENDIF»
'''
«IF !consts.empty»
«FOR c : consts»
«IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
- «val cValue = c.value»
- «IF cValue instanceof List<?>»
- private static final «Pattern.importedName»[] «Constants.MEMBER_PATTERN_LIST»;
- public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(«
- FOR v : cValue SEPARATOR ", "»«
- IF v instanceof String»"«
- v»"«
- ENDIF»«
- ENDFOR»);
-
- «generateStaticInitializationBlock»
+ «val cValue = c.value as Map<String, String>»
+ public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(«
+ FOR v : cValue.keySet SEPARATOR ", "»"«v.escapeJava»"«ENDFOR»);
+ «IF cValue.size == 1»
+ private static final «Pattern.importedName» «Constants.MEMBER_PATTERN_LIST» = «Pattern.importedName».compile(«TypeConstants.PATTERN_CONSTANT_NAME».get(0));
+ private static final String «Constants.MEMBER_REGEX_LIST» = "«cValue.values.get(0).escapeJava»";
+ «ELSE»
+ private static final «Pattern.importedName»[] «Constants.MEMBER_PATTERN_LIST» = «CodeHelpers.importedName».compilePatterns(«TypeConstants.PATTERN_CONSTANT_NAME»);
+ private static final String[] «Constants.MEMBER_REGEX_LIST» = { «
+ FOR v : cValue.values SEPARATOR ", "»"«v.escapeJava»"«ENDFOR» };
«ENDIF»
«ELSE»
«emitConstant(c)»
«ENDIF»
'''
- /**
- * Template method which generates JAVA static initialization block.
- *
- * @return string with static initialization block in JAVA format
- */
- def protected generateStaticInitializationBlock() '''
- static {
- final «Pattern.importedName» a[] = new «Pattern.importedName»[«TypeConstants.PATTERN_CONSTANT_NAME».size()];
- int i = 0;
- for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») {
- a[i++] = Pattern.compile(regEx);
- }
-
- «Constants.MEMBER_PATTERN_LIST» = a;
- }
- '''
-
/**
* Template method which generates JAVA class attributes.
*
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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
+ */
+package org.opendaylight.yangtools.yang.binding;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.VerifyException;
+import java.util.List;
+import java.util.regex.Pattern;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Helper methods for generated binding code. This class concentrates useful primitives generated code may call
+ * to perform specific shared functions. This allows for generated classes to be leaner. Methods in this class follows
+ * general API stability requirements of the Binding Specification.
+ *
+ * @author Robert Varga
+ */
+public final class CodeHelpers {
+ private CodeHelpers() {
+ // Hidden
+ }
+
+ /**
+ * Require that an a value-related expression is true.
+ *
+ * @param expression Expression to evaluate
+ * @param value Value being validated
+ * @param options Valid value options checked
+ * @throws IllegalArgumentException if expression is false
+ */
+ public static void validValue(final boolean expression, final Object value, final String options) {
+ checkArgument(expression, "expected one of: %s \n%but was: %s", options, value);
+ }
+
+ /**
+ * Require an argument being received. This is similar to {@link java.util.Objects#requireNonNull(Object)}, but
+ * throws an IllegalArgumentException.
+ *
+ * <p>
+ * Implementation note: we expect argName to be a string literal or a constant, so that it's non-nullness can be
+ * quickly discovered for a call site (where we are going to be inlined).
+ *
+ * @param value Value itself
+ * @param name Symbolic name
+ * @return non-null value
+ * @throws IllegalArgumentException if value is null
+ * @throws NullPointerException if name is null
+ */
+ // FIXME: another advantage is that it is JDT-annotated, but we could live without that. At some point we should
+ // schedule a big ISE-to-NPE conversion and just use Objects.requireNonNull() instead.
+ public static <T> @NonNull T nonNullValue(@Nullable final T value, final @NonNull String name) {
+ requireNonNull(name);
+ checkArgument(value != null, "%s must not be null", name);
+ return value;
+ }
+
+ /**
+ * Compile a list of pattern regular expressions and return them as an array. The list must hold at least two
+ * expressions.
+ *
+ * @param patterns Patterns to compile
+ * @return Compiled patterns in an array
+ * @throws NullPointerException if the list or any of its elements is null
+ * @throws VerifyException if the list has fewer than two elements
+ */
+ public static @NonNull Pattern[] compilePatterns(final @NonNull List<String> patterns) {
+ final int size = patterns.size();
+ verify(size > 1, "Patterns has to have at least 2 elements");
+ final @NonNull Pattern[] result = new Pattern[size];
+ for (int i = 0; i < size; ++i) {
+ result[i] = Pattern.compile(patterns.get(i));
+ }
+ return result;
+ }
+
+ /**
+ * Check whether a specified string value matches a specified pattern. This method handles the distinction between
+ * modeled XSD expression and enforcement {@link Pattern} which may reflect negation.
+ *
+ * @param value Value to be checked.
+ * @param pattern Enforcement pattern
+ * @param regex Source regular expression, as defined in YANG model
+ * @throws IllegalArgumentException if the value does not match the pattern
+ * @throws NullPointerException if any of the arguments are null
+ */
+ public static void checkPattern(final String value, final Pattern pattern, final String regex) {
+ if (!pattern.matcher(value).matches()) {
+ final String match = BindingMapping.isNegatedPattern(pattern) ? "matches forbidden"
+ : "does not match required";
+ throw new IllegalArgumentException("Supplied value \"" + value + "\" " + match + " pattern \""
+ + regex + "\"");
+ }
+ }
+
+ /**
+ * Check whether a specified string value matches specified patterns. This method handles the distinction between
+ * modeled XSD expression and enforcement {@link Pattern} which may reflect negation.
+ *
+ * @param value Value to be checked.
+ * @param patterns Enforcement patterns
+ * @param regexes Source regular expression, as defined in YANG model. Size and order must match patterns.
+ * @throws IllegalArgumentException if the value does not match the pattern
+ * @throws NullPointerException if any of the arguments are null
+ * @throws VerifyException if the size of patterns and regexes does not match
+ */
+ public static void checkPattern(final String value, final Pattern[] patterns, final String[] regexes) {
+ verify(patterns.length == regexes.length, "Patterns and regular expression lengths have to match");
+ for (int i = 0; i < patterns.length; ++i) {
+ checkPattern(value, patterns[i], regexes[i]);
+ }
+ }
+}