blob: 49733033461cc605e38e7ca2bcaeeda5b5909843 [file] [log] [blame]
/*
* 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 java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
import org.onosproject.yangutils.datamodel.utils.Parsable;
import org.onosproject.yangutils.datamodel.utils.ResolvableStatus;
import org.onosproject.yangutils.datamodel.utils.YangConstructType;
import org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes;
import static org.onosproject.yangutils.datamodel.utils.ResolvableStatus.INTRA_FILE_RESOLVED;
import static org.onosproject.yangutils.datamodel.utils.ResolvableStatus.RESOLVED;
import static org.onosproject.yangutils.datamodel.utils.YangErrMsgConstants.DATA_MISSING_ERROR_TAG;
import static org.onosproject.yangutils.datamodel.utils.YangErrMsgConstants.ERROR_PATH_LEAFREF_LEAF;
import static org.onosproject.yangutils.datamodel.utils.YangErrMsgConstants.INSTANCE_REQUIRED_ERROR_APP_TAG;
/*
* Reference:RFC 6020.
* The leafref type is used to reference a particular leaf instance in
* the data tree. The "path" substatement (Section 9.9.2) selects a set
* of leaf instances, and the leafref value space is the set of values
* of these leaf instances.
*/
/**
* Represents the leafref information.
*
* @param <T> YANG leafref info
*/
public class YangLeafRef<T> implements Parsable, Resolvable, Serializable, YangIfFeatureHolder,
YangXPathResolver, YangAppErrorHolder {
private static final long serialVersionUID = 286201644L;
/**
* YANG data type.
*/
private YangType effectiveDataType;
/**
* Referred leaf/leaf-list for the path specified in the leafref type.
*/
private T referredLeafOrLeafList;
/**
* Path of the leafref.
*/
private String path;
/**
* Leafref path type. Either absolute or relative path.
*/
private YangPathArgType pathType;
/**
* List of atomic paths in absolute Path.
*/
private List<YangAtomicPath> atomicPath;
/**
* YANG relative path.
*/
private YangRelativePath relativePath;
/**
* Status of resolution. If completely resolved enum value is "RESOLVED",
* if not enum value is "UNRESOLVED", in case reference of grouping/typedef/leafref
* is added to uses/type/leafref but it's not resolved value of enum should be
* "INTRA_FILE_RESOLVED".
*/
private ResolvableStatus resolvableStatus;
/**
* Require instance status in leafref type.
*/
private boolean requireInstance;
/**
* List of if-feature.
*/
private List<YangIfFeature> ifFeatureList;
/**
* YANG application error information.
*/
private YangAppErrorInfo yangAppErrorInfo;
/**
* Creates a YANG leaf ref.
*/
public YangLeafRef() {
yangAppErrorInfo = new YangAppErrorInfo();
yangAppErrorInfo.setErrorTag(DATA_MISSING_ERROR_TAG);
yangAppErrorInfo.setErrorAppTag(INSTANCE_REQUIRED_ERROR_APP_TAG);
yangAppErrorInfo.setErrorAppPath(ERROR_PATH_LEAFREF_LEAF);
}
/**
* Returns the status of the require instance in leafref.
*
* @return status of the require instance
*/
public boolean getRequireInstance() {
return requireInstance;
}
/**
* Sets the status of the require instance in leafref.
*
* @param requireInstance status of the require instance
*/
public void setRequireInstance(boolean requireInstance) {
this.requireInstance = requireInstance;
}
/**
* Returns the type of data.
*
* @return the data type
*/
public YangType getEffectiveDataType() {
return effectiveDataType;
}
/**
* Sets the type of data.
*
* @param effectiveDataType data type
*/
public void setEffectiveDataType(YangType effectiveDataType) {
this.effectiveDataType = effectiveDataType;
}
/**
* Returns the path of the leafref.
*
* @return path of the leafref
*/
public String getPath() {
return path;
}
/**
* Sets the path of the leafref.
*
* @param path leafref path
*/
public void setPath(String path) {
this.path = path;
}
/**
* Returns the type of path in the leafref.
*
* @return type of path
*/
public YangPathArgType getPathType() {
return pathType;
}
/**
* Sets the type of path in the leafref. It can be either absolute or relative type.
*
* @param pathType type of path
*/
public void setPathType(YangPathArgType pathType) {
this.pathType = pathType;
}
/**
* Returns the list of atomic path.
*
* @return list of atomic path
*/
public List<YangAtomicPath> getAtomicPath() {
return atomicPath;
}
/**
* Sets the list of atomic path.
*
* @param atomicPath list of atomic path.
*/
public void setAtomicPath(List<YangAtomicPath> atomicPath) {
this.atomicPath = atomicPath;
}
/**
* Returns the object of relative path.
*
* @return object of relative path
*/
public YangRelativePath getRelativePath() {
return relativePath;
}
/**
* Sets the object of relative path.
*
* @param relativePath object of relative path.
*/
public void setRelativePath(YangRelativePath relativePath) {
this.relativePath = relativePath;
}
/**
* Returns the object of referred leaf/leaf-list.
*
* @return object of referred leaf/leaf-list
*/
public T getReferredLeafOrLeafList() {
return referredLeafOrLeafList;
}
/**
* Sets the object of referred leaf/leaf-list.
*
* @param targetExtendedInfo object of referred leaf/leaf-list
*/
public void setReferredLeafOrLeafList(T targetExtendedInfo) {
this.referredLeafOrLeafList = targetExtendedInfo;
}
@Override
public List<YangIfFeature> getIfFeatureList() {
return ifFeatureList;
}
@Override
public void addIfFeatureList(YangIfFeature ifFeature) {
if (getIfFeatureList() == null) {
setIfFeatureList(new LinkedList<>());
}
getIfFeatureList().add(ifFeature);
}
@Override
public void setIfFeatureList(List<YangIfFeature> ifFeatureList) {
this.ifFeatureList = ifFeatureList;
}
@Override
public YangConstructType getYangConstructType() {
return YangConstructType.LEAFREF_DATA;
}
@Override
public void validateDataOnEntry() throws DataModelException {
// TODO auto-generated method stub, to be implemented by parser
}
@Override
public void validateDataOnExit() throws DataModelException {
// TODO auto-generated method stub, to be implemented by parser
}
@Override
public ResolvableStatus getResolvableStatus() {
return resolvableStatus;
}
@Override
public void setResolvableStatus(ResolvableStatus resolvableStatus) {
this.resolvableStatus = resolvableStatus;
}
@Override
public void setAppErrorInfo(YangAppErrorInfo yangAppErrorInfo) {
this.yangAppErrorInfo = yangAppErrorInfo;
}
@Override
public YangAppErrorInfo getAppErrorInfo() {
return yangAppErrorInfo;
}
@Override
public void resolve() throws DataModelException {
if (getReferredLeafOrLeafList() == null) {
throw new DataModelException("Linker Error: The leafref does not refer to any leaf/leaf-list.");
}
// Initiate the resolution
try {
setResolvableStatus(getResolution());
} catch (DataModelException e) {
throw new DataModelException(e.getMessage());
}
}
/**
* Returns the resolution status by getting the effective built-in type.
*
* @return status of resolution
* @throws DataModelException a violation of data model rules
*/
private ResolvableStatus getResolution() throws DataModelException {
if (getReferredLeafOrLeafList() instanceof YangLeaf) {
YangLeaf yangLeaf = ((YangLeaf) getReferredLeafOrLeafList());
YangType baseType = yangLeaf.getDataType();
if (baseType.getDataType() == YangDataTypes.LEAFREF) {
YangLeafRef referredLeafRefInfo = (YangLeafRef) (yangLeaf.getDataType().getDataTypeExtendedInfo());
/*
* Check whether the referred typedef is resolved.
*/
if (referredLeafRefInfo.getResolvableStatus() != INTRA_FILE_RESOLVED
&& referredLeafRefInfo.getResolvableStatus() != RESOLVED) {
throw new DataModelException("Linker Error: Referred typedef is not resolved for type.");
}
/*
* Check if the referred typedef is intra file resolved, if yes
* sets current status also to intra file resolved .
*/
if ((referredLeafRefInfo.getResolvableStatus() == INTRA_FILE_RESOLVED)) {
return INTRA_FILE_RESOLVED;
}
// Add the if-feature list from referred leafref to current leafref.
List<YangIfFeature> referredLeafIfFeatureListFromLeafref = referredLeafRefInfo.getIfFeatureList();
if (referredLeafIfFeatureListFromLeafref != null && !referredLeafIfFeatureListFromLeafref.isEmpty()) {
Iterator<YangIfFeature> referredLeafIfFeature = referredLeafIfFeatureListFromLeafref.iterator();
while (referredLeafIfFeature.hasNext()) {
YangIfFeature ifFeature = referredLeafIfFeature.next();
addIfFeatureList(ifFeature);
}
}
setEffectiveDataType(referredLeafRefInfo.getEffectiveDataType());
} else if (baseType.getDataType() == YangDataTypes.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 for type.");
}
/*
* Check if the referred typedef is intra file resolved, if yes
* sets current status also to intra file resolved .
*/
if ((baseType.getResolvableStatus() == INTRA_FILE_RESOLVED)) {
return INTRA_FILE_RESOLVED;
}
setEffectiveDataType(baseType);
} else {
setEffectiveDataType(baseType);
}
// Add the if-feature list from referred leaf to current leafref.
List<YangIfFeature> referredLeafIfFeatureList = yangLeaf.getIfFeatureList();
if (referredLeafIfFeatureList != null && !referredLeafIfFeatureList.isEmpty()) {
Iterator<YangIfFeature> referredLeafIfFeature = referredLeafIfFeatureList.iterator();
while (referredLeafIfFeature.hasNext()) {
YangIfFeature ifFeature = referredLeafIfFeature.next();
addIfFeatureList(ifFeature);
}
}
return RESOLVED;
} else if (getReferredLeafOrLeafList() instanceof YangLeafList) {
YangLeafList yangLeafList = ((YangLeafList) getReferredLeafOrLeafList());
YangType baseType = yangLeafList.getDataType();
if (baseType.getDataType() == YangDataTypes.LEAFREF) {
YangLeafRef referredLeafRefInfo = (YangLeafRef) yangLeafList.getDataType().getDataTypeExtendedInfo();
/*
* Check whether the referred typedef is resolved.
*/
if (referredLeafRefInfo.getResolvableStatus() != INTRA_FILE_RESOLVED
&& referredLeafRefInfo.getResolvableStatus() != RESOLVED) {
throw new DataModelException("Linker Error: Referred typedef is not resolved for type.");
}
/*
* Check if the referred typedef is intra file resolved, if yes
* sets current status also to intra file resolved .
*/
if ((referredLeafRefInfo.getResolvableStatus() == INTRA_FILE_RESOLVED)) {
return INTRA_FILE_RESOLVED;
}
// Add the if-feature list from referred leafref to current leafref.
List<YangIfFeature> referredLeafListIfFeatureListFromLeafref = referredLeafRefInfo.getIfFeatureList();
if (referredLeafListIfFeatureListFromLeafref != null
&& !referredLeafListIfFeatureListFromLeafref.isEmpty()) {
Iterator<YangIfFeature> referredLeafListIfFeature = referredLeafListIfFeatureListFromLeafref
.iterator();
while (referredLeafListIfFeature.hasNext()) {
YangIfFeature ifFeature = referredLeafListIfFeature.next();
addIfFeatureList(ifFeature);
}
}
setEffectiveDataType(referredLeafRefInfo.getEffectiveDataType());
} else if (baseType.getDataType() == YangDataTypes.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 for type.");
}
/*
* Check if the referred typedef is intra file resolved, if yes
* sets current status also to intra file resolved .
*/
if ((baseType.getResolvableStatus() == INTRA_FILE_RESOLVED)) {
return INTRA_FILE_RESOLVED;
}
setEffectiveDataType(baseType);
} else {
setEffectiveDataType(baseType);
}
// Add the if-feature list from referred leaf-list to current leafref.
List<YangIfFeature> referredLeafListIfFeatureList = yangLeafList.getIfFeatureList();
if (referredLeafListIfFeatureList != null && !referredLeafListIfFeatureList.isEmpty()) {
Iterator<YangIfFeature> referredLeafListIfFeature = referredLeafListIfFeatureList.iterator();
while (referredLeafListIfFeature.hasNext()) {
YangIfFeature ifFeature = referredLeafListIfFeature.next();
addIfFeatureList(ifFeature);
}
}
return RESOLVED;
} else {
throw new DataModelException("Linker Error: The leafref must refer only to leaf/leaf-list.");
}
}
}