| /* |
| * Copyright 2016-present Open Networking Laboratory |
| * |
| * 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.onosproject.yangutils.datamodel; |
| |
| import org.onosproject.yangutils.datamodel.exceptions.DataModelException; |
| import com.google.common.base.Strings; |
| |
| import static org.onosproject.yangutils.datamodel.ResolvableStatus.INTRA_FILE_RESOLVED; |
| import static org.onosproject.yangutils.datamodel.ResolvableStatus.RESOLVED; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.BITS; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.BOOLEAN; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.DERIVED; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.EMPTY; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.ENUMERATION; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.IDENTITYREF; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.LEAFREF; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.STRING; |
| import static org.onosproject.yangutils.datamodel.YangDataTypes.UNION; |
| import static org.onosproject.yangutils.utils.RestrictionResolver.isOfRangeRestrictedType; |
| import static org.onosproject.yangutils.utils.RestrictionResolver.processLengthRestriction; |
| import static org.onosproject.yangutils.utils.RestrictionResolver.processRangeRestriction; |
| |
| /** |
| * Represents the derived information. |
| * |
| * @param <T> extended information. |
| */ |
| public class YangDerivedInfo<T> implements LocationInfo { |
| |
| /** |
| * YANG typedef reference. |
| */ |
| private YangTypeDef referredTypeDef; |
| |
| /** |
| * Resolved additional information about data type after linking, example |
| * restriction info, named values, etc. The extra information is based |
| * on the data type. Based on the data type, the extended info can vary. |
| */ |
| private T resolvedExtendedInfo; |
| |
| /** |
| * Line number of pattern restriction in YANG file. |
| */ |
| private int lineNumber; |
| |
| /** |
| * Position of pattern restriction in line. |
| */ |
| private int charPositionInLine; |
| |
| /** |
| * Effective built-in type, requried in case type of typedef is again a |
| * derived type. This information is to be added during linking. |
| */ |
| private YangDataTypes effectiveBuiltInType; |
| |
| /** |
| * Length restriction string to temporary store the length restriction when the type |
| * is derived. |
| */ |
| private String lengthRestrictionString; |
| |
| /** |
| * Range restriction string to temporary store the range restriction when the type |
| * is derived. |
| */ |
| private String rangeRestrictionString; |
| |
| /** |
| * Pattern restriction string to temporary store the pattern restriction when the type |
| * is derived. |
| */ |
| private YangPatternRestriction patternRestriction; |
| |
| /** |
| * Returns the referred typedef reference. |
| * |
| * @return referred typedef reference |
| */ |
| public YangTypeDef getReferredTypeDef() { |
| return referredTypeDef; |
| } |
| |
| /** |
| * Sets the referred typedef reference. |
| * |
| * @param referredTypeDef referred typedef reference |
| */ |
| public void setReferredTypeDef(YangTypeDef referredTypeDef) { |
| this.referredTypeDef = referredTypeDef; |
| } |
| |
| /** |
| * Returns resolved extended information after successful linking. |
| * |
| * @return resolved extended information |
| */ |
| public T getResolvedExtendedInfo() { |
| return resolvedExtendedInfo; |
| } |
| |
| /** |
| * Sets resolved extended information after successful linking. |
| * |
| * @param resolvedExtendedInfo resolved extended information |
| */ |
| public void setResolvedExtendedInfo(T resolvedExtendedInfo) { |
| this.resolvedExtendedInfo = resolvedExtendedInfo; |
| } |
| |
| @Override |
| public int getLineNumber() { |
| return lineNumber; |
| } |
| |
| @Override |
| public int getCharPosition() { |
| return charPositionInLine; |
| } |
| |
| @Override |
| public void setLineNumber(int lineNumber) { |
| this.lineNumber = lineNumber; |
| } |
| |
| @Override |
| public void setCharPosition(int charPositionInLine) { |
| this.charPositionInLine = charPositionInLine; |
| } |
| |
| /** |
| * Returns the length restriction string. |
| * |
| * @return the length restriction string |
| */ |
| public String getLengthRestrictionString() { |
| return lengthRestrictionString; |
| } |
| |
| /** |
| * Sets the length restriction string. |
| * |
| * @param lengthRestrictionString the length restriction string |
| */ |
| public void setLengthRestrictionString(String lengthRestrictionString) { |
| this.lengthRestrictionString = lengthRestrictionString; |
| } |
| |
| /** |
| * Returns the range restriction string. |
| * |
| * @return the range restriction string |
| */ |
| public String getRangeRestrictionString() { |
| return rangeRestrictionString; |
| } |
| |
| /** |
| * Sets the range restriction string. |
| * |
| * @param rangeRestrictionString the range restriction string |
| */ |
| public void setRangeRestrictionString(String rangeRestrictionString) { |
| this.rangeRestrictionString = rangeRestrictionString; |
| } |
| |
| /** |
| * Returns the pattern restriction. |
| * |
| * @return the pattern restriction |
| */ |
| public YangPatternRestriction getPatternRestriction() { |
| return patternRestriction; |
| } |
| |
| /** |
| * Sets the pattern restriction. |
| * |
| * @param patternRestriction the pattern restriction |
| */ |
| public void setPatternRestriction(YangPatternRestriction patternRestriction) { |
| this.patternRestriction = patternRestriction; |
| } |
| |
| /** |
| * Returns effective built-in type. |
| * |
| * @return effective built-in type |
| */ |
| public YangDataTypes getEffectiveBuiltInType() { |
| return effectiveBuiltInType; |
| } |
| |
| /** |
| * Sets effective built-in type. |
| * |
| * @param effectiveBuiltInType effective built-in type |
| */ |
| public void setEffectiveBuiltInType(YangDataTypes effectiveBuiltInType) { |
| this.effectiveBuiltInType = effectiveBuiltInType; |
| } |
| |
| /** |
| * Resolves the type derived info, by obtaining the effective built-in type |
| * and resolving the restrictions. |
| * |
| * @return resolution status |
| * @throws DataModelException a violation in data mode rule |
| */ |
| public ResolvableStatus resolve() throws DataModelException { |
| |
| YangType<?> baseType = getReferredTypeDef().getTypeDefBaseType(); |
| |
| /* |
| * Checks the data type of the referred typedef, if it's derived, |
| * obtain effective built-in type and restrictions from it's derived |
| * info, otherwise take from the base type of type itself. |
| */ |
| if (baseType.getDataType() == DERIVED) { |
| /* |
| * Check whether the referred typedef is resolved. |
| */ |
| if (baseType.getResolvableStatus() != INTRA_FILE_RESOLVED && baseType.getResolvableStatus() != RESOLVED) { |
| throw new DataModelException("Linker Error: Referred typedef is not resolved."); |
| } |
| |
| /* |
| * Check if the referred typedef is intra file resolved, if yes sets |
| * current status also to intra file resolved . |
| */ |
| if (getReferredTypeDef().getTypeDefBaseType().getResolvableStatus() == INTRA_FILE_RESOLVED) { |
| return INTRA_FILE_RESOLVED; |
| } |
| setEffectiveBuiltInType(((YangDerivedInfo<?>) baseType.getDataTypeExtendedInfo()) |
| .getEffectiveBuiltInType()); |
| YangDerivedInfo refDerivedInfo = ((YangDerivedInfo<?>) baseType.getDataTypeExtendedInfo()); |
| /* |
| * Check whether the effective built-in type can have range |
| * restrictions, if yes call resolution of range. |
| */ |
| if (isOfRangeRestrictedType(getEffectiveBuiltInType())) { |
| if (refDerivedInfo.getResolvedExtendedInfo() == null) { |
| resolveRangeRestriction(null); |
| /* |
| * Return the resolution status as resolved, if it's not |
| * resolve range/string restriction will throw exception |
| * in previous function. |
| */ |
| return RESOLVED; |
| } else { |
| if (!(refDerivedInfo.getResolvedExtendedInfo() instanceof YangRangeRestriction)) { |
| throw new DataModelException("Linker error: Referred typedef restriction info is of invalid " + |
| "type."); |
| } |
| resolveRangeRestriction((YangRangeRestriction) refDerivedInfo.getResolvedExtendedInfo()); |
| /* |
| * Return the resolution status as resolved, if it's not |
| * resolve range/string restriction will throw exception |
| * in previous function. |
| */ |
| return RESOLVED; |
| } |
| /* |
| * If the effective built-in type is of type string calls |
| * for string resolution. |
| */ |
| } else if (getEffectiveBuiltInType() == STRING) { |
| if (refDerivedInfo.getResolvedExtendedInfo() == null) { |
| resolveStringRestriction(null); |
| /* |
| * Return the resolution status as resolved, if it's not |
| * resolve range/string restriction will throw exception |
| * in previous function. |
| */ |
| return RESOLVED; |
| } else { |
| if (!(refDerivedInfo.getResolvedExtendedInfo() instanceof YangStringRestriction)) { |
| throw new DataModelException("Linker error: Referred typedef restriction info is of invalid " + |
| "type."); |
| } |
| resolveStringRestriction((YangStringRestriction) refDerivedInfo.getResolvedExtendedInfo()); |
| /* |
| * Return the resolution status as resolved, if it's not |
| * resolve range/string restriction will throw exception |
| * in previous function. |
| */ |
| return RESOLVED; |
| } |
| } |
| } else { |
| setEffectiveBuiltInType((baseType.getDataType())); |
| /* |
| * Check whether the effective built-in type can have range |
| * restrictions, if yes call resolution of range. |
| */ |
| if (isOfRangeRestrictedType(getEffectiveBuiltInType())) { |
| if (baseType.getDataTypeExtendedInfo() == null) { |
| resolveRangeRestriction(null); |
| /* |
| * Return the resolution status as resolved, if it's not |
| * resolve range/string restriction will throw exception |
| * in previous function. |
| */ |
| return RESOLVED; |
| } else { |
| if (!(baseType.getDataTypeExtendedInfo() instanceof YangRangeRestriction)) { |
| throw new DataModelException("Linker error: Referred typedef restriction info is of invalid " + |
| "type."); |
| } |
| resolveRangeRestriction((YangRangeRestriction) baseType.getDataTypeExtendedInfo()); |
| /* |
| * Return the resolution status as resolved, if it's not |
| * resolve range/string restriction will throw exception |
| * in previous function. |
| */ |
| return RESOLVED; |
| } |
| /* |
| * If the effective built-in type is of type string calls |
| * for string resolution. |
| */ |
| } else if (getEffectiveBuiltInType() == STRING) { |
| if (baseType.getDataTypeExtendedInfo() == null) { |
| resolveStringRestriction(null); |
| /* |
| * Return the resolution status as resolved, if it's not |
| * resolve range/string restriction will throw exception |
| * in previous function. |
| */ |
| return RESOLVED; |
| } else { |
| if (!(baseType.getDataTypeExtendedInfo() instanceof YangStringRestriction)) { |
| throw new DataModelException("Linker error: Referred typedef restriction info is of invalid " + |
| "type."); |
| } |
| resolveStringRestriction((YangStringRestriction) baseType.getDataTypeExtendedInfo()); |
| /* |
| * Return the resolution status as resolved, if it's not |
| * resolve range/string restriction will throw exception |
| * in previous function. |
| */ |
| return RESOLVED; |
| } |
| } |
| } |
| |
| /* |
| * Check if the data type is the one which can't be restricted, in |
| * this case check whether no self restrictions should be present. |
| */ |
| if (isOfValidNonRestrictedType(getEffectiveBuiltInType())) { |
| if (Strings.isNullOrEmpty(getLengthRestrictionString()) |
| && Strings.isNullOrEmpty(getRangeRestrictionString()) |
| && getPatternRestriction() == null) { |
| return RESOLVED; |
| } else { |
| throw new DataModelException("YANG file error: Restrictions can't be applied to a given type"); |
| } |
| } |
| |
| // Throw exception for unsupported types |
| throw new DataModelException("Linker error: Unable to process the derived type."); |
| } |
| |
| /** |
| * Resolves the string restrictions. |
| * |
| * @param refStringRestriction referred string restriction of typedef |
| * @throws DataModelException a violation in data model rule |
| */ |
| private void resolveStringRestriction(YangStringRestriction refStringRestriction) throws DataModelException { |
| YangStringRestriction curStringRestriction = null; |
| YangRangeRestriction refRangeRestriction = null; |
| YangPatternRestriction refPatternRestriction = null; |
| |
| /* |
| * Check that range restriction should be null when built-in type is |
| * string. |
| */ |
| if (!(Strings.isNullOrEmpty(getRangeRestrictionString()))) { |
| DataModelException dataModelException = new DataModelException("YANG file error: Range restriction " + |
| "should't be present for string data type."); |
| dataModelException.setLine(lineNumber); |
| dataModelException.setCharPosition(charPositionInLine); |
| throw dataModelException; |
| } |
| |
| /* |
| * If referred restriction and self restriction both are null, no |
| * resolution is required. |
| */ |
| if (refStringRestriction == null && Strings.isNullOrEmpty(getLengthRestrictionString()) |
| && getPatternRestriction() == null) { |
| return; |
| } |
| |
| /* |
| * If referred string restriction is not null, take value of length |
| * and pattern restriction and assign. |
| */ |
| if (refStringRestriction != null) { |
| refRangeRestriction = refStringRestriction.getLengthRestriction(); |
| refPatternRestriction = refStringRestriction.getPatternRestriction(); |
| } |
| |
| YangRangeRestriction lengthRestriction = resolveLengthRestriction(refRangeRestriction); |
| YangPatternRestriction patternRestriction = resolvePatternRestriction(refPatternRestriction); |
| |
| /* |
| * Check if either of length or pattern restriction is present, if yes |
| * create string restriction and assign value. |
| */ |
| if (lengthRestriction != null || patternRestriction != null) { |
| curStringRestriction = new YangStringRestriction(); |
| curStringRestriction.setLengthRestriction(lengthRestriction); |
| curStringRestriction.setPatternRestriction(patternRestriction); |
| } |
| setResolvedExtendedInfo((T) curStringRestriction); |
| } |
| |
| /** |
| * Resolves pattern restriction. |
| * |
| * @param refPatternRestriction referred pattern restriction of typedef |
| * @return resolved pattern restriction |
| */ |
| private YangPatternRestriction resolvePatternRestriction(YangPatternRestriction refPatternRestriction) { |
| /* |
| * If referred restriction and self restriction both are null, no |
| * resolution is required. |
| */ |
| if (refPatternRestriction == null && getPatternRestriction() == null) { |
| return null; |
| } |
| |
| /* |
| * If self restriction is null, and referred restriction is present |
| * shallow copy the referred to self. |
| */ |
| if (getPatternRestriction() == null) { |
| return refPatternRestriction; |
| } |
| |
| /* |
| * If referred restriction is null, and self restriction is present |
| * carry out self resolution. |
| */ |
| if (refPatternRestriction == null) { |
| return getPatternRestriction(); |
| } |
| |
| /* |
| * Get patterns of referred type and add it to current pattern |
| * restrictions. |
| */ |
| for (String pattern : refPatternRestriction.getPatternList()) { |
| getPatternRestriction().addPattern(pattern); |
| } |
| return getPatternRestriction(); |
| } |
| |
| /** |
| * Resolves the length restrictions. |
| * |
| * @param refLengthRestriction referred length restriction of typedef |
| * @return resolved length restriction |
| * @throws DataModelException a violation in data model rule |
| */ |
| private YangRangeRestriction resolveLengthRestriction(YangRangeRestriction refLengthRestriction) throws |
| DataModelException { |
| |
| /* |
| * If referred restriction and self restriction both are null, no |
| * resolution is required. |
| */ |
| if (refLengthRestriction == null && Strings.isNullOrEmpty(getLengthRestrictionString())) { |
| return null; |
| } |
| |
| /* |
| * If self restriction is null, and referred restriction is present |
| * shallow copy the referred to self. |
| */ |
| if (Strings.isNullOrEmpty(getLengthRestrictionString())) { |
| return refLengthRestriction; |
| } |
| |
| /* |
| * If referred restriction is null, and self restriction is present |
| * carry out self resolution. |
| */ |
| if (refLengthRestriction == null) { |
| YangRangeRestriction curLengthRestriction = processLengthRestriction(null, lineNumber, |
| charPositionInLine, false, getLengthRestrictionString()); |
| return curLengthRestriction; |
| } |
| |
| /* |
| * Carry out self resolution based with obtained effective built-in |
| * type and MIN/MAX values as per the referred typedef's values. |
| */ |
| YangRangeRestriction curLengthRestriction = processLengthRestriction(refLengthRestriction, lineNumber, |
| charPositionInLine, true, getLengthRestrictionString()); |
| |
| // Resolve the range with referred typedef's restriction. |
| resolveLengthAndRangeRestriction(refLengthRestriction, curLengthRestriction); |
| return curLengthRestriction; |
| } |
| |
| /** |
| * Resolves the length/range self and referred restriction, to check whether |
| * the all the range interval in self restriction is stricter than the |
| * referred typedef's restriction. |
| * |
| * @param refRestriction referred restriction |
| * @param curRestriction self restriction |
| */ |
| private void resolveLengthAndRangeRestriction(YangRangeRestriction refRestriction, |
| YangRangeRestriction curRestriction) throws DataModelException { |
| for (Object curInterval : curRestriction.getAscendingRangeIntervals()) { |
| if (!(curInterval instanceof YangRangeInterval)) { |
| throw new DataModelException("Linker error: Current range intervals not processed correctly."); |
| } |
| try { |
| refRestriction.isValidInterval((YangRangeInterval) curInterval); |
| } catch (DataModelException e) { |
| DataModelException dataModelException = new DataModelException(e); |
| dataModelException.setLine(lineNumber); |
| dataModelException.setCharPosition(charPositionInLine); |
| throw dataModelException; |
| } |
| } |
| } |
| |
| /** |
| * Resolves the range restrictions. |
| * |
| * @param refRangeRestriction referred range restriction of typedef |
| * @throws DataModelException a violation in data model rule |
| */ |
| private void resolveRangeRestriction(YangRangeRestriction refRangeRestriction) throws DataModelException { |
| |
| /* |
| * Check that string restriction should be null when built-in type is |
| * of range type. |
| */ |
| if (!(Strings.isNullOrEmpty(getLengthRestrictionString())) || getPatternRestriction() != null) { |
| DataModelException dataModelException = new DataModelException("YANG file error: Length/Pattern " + |
| "restriction should't be present for int/uint/decimal data type."); |
| dataModelException.setLine(lineNumber); |
| dataModelException.setCharPosition(charPositionInLine); |
| throw dataModelException; |
| } |
| |
| /* |
| * If referred restriction and self restriction both are null, no |
| * resolution is required. |
| */ |
| if (refRangeRestriction == null && Strings.isNullOrEmpty(getRangeRestrictionString())) { |
| return; |
| } |
| |
| /* |
| * If self restriction is null, and referred restriction is present |
| * shallow copy the referred to self. |
| */ |
| if (Strings.isNullOrEmpty(getRangeRestrictionString())) { |
| setResolvedExtendedInfo((T) refRangeRestriction); |
| return; |
| } |
| |
| /* |
| * If referred restriction is null, and self restriction is present |
| * carry out self resolution. |
| */ |
| if (refRangeRestriction == null) { |
| YangRangeRestriction curRangeRestriction = processRangeRestriction(null, lineNumber, |
| charPositionInLine, false, getRangeRestrictionString(), getEffectiveBuiltInType()); |
| setResolvedExtendedInfo((T) curRangeRestriction); |
| return; |
| } |
| |
| /* |
| * Carry out self resolution based with obtained effective built-in |
| * type and MIN/MAX values as per the referred typedef's values. |
| */ |
| YangRangeRestriction curRangeRestriction = processRangeRestriction(refRangeRestriction, lineNumber, |
| charPositionInLine, true, getRangeRestrictionString(), getEffectiveBuiltInType()); |
| |
| // Resolve the range with referred typedef's restriction. |
| resolveLengthAndRangeRestriction(refRangeRestriction, curRangeRestriction); |
| setResolvedExtendedInfo((T) curRangeRestriction); |
| } |
| |
| /** |
| * Returns whether the data type is of non restricted type. |
| * |
| * @param dataType data type to be checked |
| * @return true, if data type can't be restricted, false otherwise |
| */ |
| private boolean isOfValidNonRestrictedType(YangDataTypes dataType) { |
| return (dataType == BOOLEAN |
| || dataType == ENUMERATION |
| || dataType == BITS |
| || dataType == EMPTY |
| || dataType == UNION |
| || dataType == IDENTITYREF |
| || dataType == LEAFREF); |
| } |
| } |