/*
* Copyright (c) 2015 Cisco Systems, 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
*/
package org.opendaylight.yangtools.yang.model.util.type;
import com.google.common.base.Preconditions;
import java.util.List;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
/**
* Compatibility utilities for dealing with differences between the old parser's ExtendedType-driven type
* representation versus the representation this package models.
*
* @deprecated This class is provided strictly for compatibility only. No new users should be introduced, as this class
* is scheduled for removal when its two OpenDaylight users, Java Binding v1 and YANG JMX Bindings are
* removed.
*/
@Deprecated
public final class CompatUtils {
private CompatUtils() {
throw new UnsupportedOperationException();
}
/**
* This package's type hierarchy model generates a type which encapsulates the default value and units for leaves.
* Java Binding specification is implemented in a way, where it needs to revert this process if the internal
* declaration has not restricted the type further -- which is not something available via
* {@link TypeDefinition#getBaseType()}.
*
* Here are the possible scenarios:
*
* <pre>
* leaf foo {
* type uint8 {
* range 1..2;
* }
* }
* </pre>
* The leaf type's schema path does not match the schema path of the leaf. We do NOT want to strip it, as
* we need to generate an inner class to hold the restrictions.
*
* <pre>
* leaf foo {
* type uint8 {
* range 1..2;
* }
* default 1;
* }
* </pre>
* The leaf type's schema path will match the schema path of the leaf. We do NOT want to strip it, as we need
* to generate an inner class to hold the restrictions.
*
* <pre>
* leaf foo {
* type uint8;
* default 1;
* }
* </pre>
* The leaf type's schema path will match the schema path of the leaf. We DO want to strip it, as we will deal
* with the default value ourselves.
*
* <pre>
* leaf foo {
* type uint8;
* }
* </pre>
* The leaf type's schema path will not match the schema path of the leaf. We do NOT want to strip it.
*
* The situation is different for types which do not have a default instantiation in YANG: leafref, enumeration,
* identityref, decimal64, bits and union. If these types are defined within this leaf's statement, a base type
* will be instantiated. If the leaf defines a default statement, this base type will be visible via getBaseType().
*
* <pre>
* leaf foo {
* type decimal64 {
* fraction-digits 2;
* }
* }
* </pre>
* The leaf type's schema path will not match the schema path of the leaf, and we do not want to strip it, as it
* needs to be generated.
*
* <pre>
* leaf foo {
* type decimal64 {
* fraction-digits 2;
* }
* default 1;
* }
* </pre>
* The leaf type's schema path will match the schema path of the leaf, and we DO want to strip it.
*
* @param leaf Leaf for which we are acquiring the type
* @return Potentially base type of the leaf type.
*/
@Nonnull public static TypeDefinition<?> compatLeafType(@Nonnull final LeafSchemaNode leaf) {
final TypeDefinition<?> leafType = leaf.getType();
Preconditions.checkNotNull(leafType);
if (!leaf.getPath().equals(leafType.getPath())) {
// Old parser semantics, or no new default/units defined for this leaf
return leafType;
}
// We are dealing with a type generated for the leaf itself
final TypeDefinition<?> baseType = leafType.getBaseType();
Preconditions.checkArgument(baseType != null, "Leaf %s has type for leaf, but no base type", leaf);
if (leaf.getPath().equals(baseType.getPath().getParent())) {
// Internal instantiation of a base YANG type (decimal64 and similar)
return baseType;
}
// At this point we have dealt with the easy cases. Now we need to perform per-type checking if there are no
// new constraints introduced by this type. If there were not, we will return the base type.
if (leafType instanceof BinaryTypeDefinition) {
return baseTypeIfNotConstrained((BinaryTypeDefinition) leafType);
} else if (leafType instanceof DecimalTypeDefinition) {
return baseTypeIfNotConstrained((DecimalTypeDefinition) leafType);
} else if (leafType instanceof InstanceIdentifierTypeDefinition) {
return baseTypeIfNotConstrained((InstanceIdentifierTypeDefinition) leafType);
} else if (leafType instanceof IntegerTypeDefinition) {
return baseTypeIfNotConstrained((IntegerTypeDefinition) leafType);
} else if (leafType instanceof StringTypeDefinition) {
return baseTypeIfNotConstrained((StringTypeDefinition) leafType);
} else if (leafType instanceof UnsignedIntegerTypeDefinition) {
return baseTypeIfNotConstrained((UnsignedIntegerTypeDefinition) leafType);
} else {
// Other types cannot be constrained, return the base type
return baseType;
}
}
private static TypeDefinition<?> baseTypeIfNotConstrained(final BinaryTypeDefinition type) {
final BinaryTypeDefinition base = type.getBaseType();
return baseTypeIfNotConstrained(type, type.getLengthConstraints(), base, base.getLengthConstraints());
}
private static TypeDefinition<?> baseTypeIfNotConstrained(final DecimalTypeDefinition type) {
final DecimalTypeDefinition base = type.getBaseType();
return baseTypeIfNotConstrained(type, type.getRangeConstraints(), base, base.getRangeConstraints());
}
private static TypeDefinition<?> baseTypeIfNotConstrained(final InstanceIdentifierTypeDefinition type) {
final InstanceIdentifierTypeDefinition base = type.getBaseType();
return type.requireInstance() == base.requireInstance() ? base : type;
}
private static TypeDefinition<?> baseTypeIfNotConstrained(final IntegerTypeDefinition type) {
final IntegerTypeDefinition base = type.getBaseType();
return baseTypeIfNotConstrained(type, type.getRangeConstraints(), base, base.getRangeConstraints());
}
private static TypeDefinition<?> baseTypeIfNotConstrained(final StringTypeDefinition type) {
final StringTypeDefinition base = type.getBaseType();
final List<PatternConstraint> patterns = type.getPatternConstraints();
final List<LengthConstraint> lengths = type.getLengthConstraints();
if ((patterns.isEmpty() || patterns.equals(base.getPatternConstraints())) &&
(lengths.isEmpty() || lengths.equals(base.getLengthConstraints()))) {
return base;
}
return type;
}
private static TypeDefinition<?> baseTypeIfNotConstrained(final UnsignedIntegerTypeDefinition type) {
final UnsignedIntegerTypeDefinition base = type.getBaseType();
return baseTypeIfNotConstrained(type, type.getRangeConstraints(), base, base.getRangeConstraints());
}
private static TypeDefinition<?> baseTypeIfNotConstrained(final TypeDefinition<?> type,
final List<?> typeConstraints, final TypeDefinition<?> base, final List<?> baseConstraints) {
if (typeConstraints.isEmpty() || typeConstraints.equals(baseConstraints)) {
return base;
}
return type;
}
}