extends AbstractPathArgument {
private static final long serialVersionUID = -3637456085341738431L;
private final @NonNull T value;
public NodeWithValue(final QName node, final T value) {
super(node);
this.value = requireNonNull(value);
}
public @NonNull T getValue() {
return value;
}
@Override
protected int hashCodeImpl() {
return 31 * super.hashCodeImpl() + YangInstanceIdentifier.hashCode(value);
}
@Override
@SuppressWarnings("checkstyle:equalsHashCode")
public boolean equals(final Object obj) {
if (!super.equals(obj)) {
return false;
}
final NodeWithValue> other = (NodeWithValue>) obj;
return Objects.deepEquals(value, other.value);
}
@Override
public String toString() {
return super.toString() + '[' + value + ']';
}
@Override
public String toRelativeString(final PathArgument previous) {
return super.toRelativeString(previous) + '[' + value + ']';
}
@Override
Object writeReplace() {
return new NIVv1(this);
}
}
/**
* Composite path argument identifying a {@link org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode}
* node in particular subtree.
*
*
* Augmentation is uniquely identified by set of all possible child nodes.
* This is possible
* to identify instance of augmentation,
* since RFC6020 states that augment
that augment
* statement must not add multiple nodes from same namespace
* / module to the target node.
*
* @see RFC6020
*/
public static final class AugmentationIdentifier implements PathArgument {
private static final long serialVersionUID = -8122335594681936939L;
private static final LoadingCache, AugmentationIdentifier> CACHE = CacheBuilder.newBuilder()
.weakValues().build(new CacheLoader, AugmentationIdentifier>() {
@Override
public AugmentationIdentifier load(final ImmutableSet key) {
return new AugmentationIdentifier(key);
}
});
private final @NonNull ImmutableSet childNames;
@Override
public QName getNodeType() {
// This should rather throw exception than return always null
throw new UnsupportedOperationException("Augmentation node has no QName");
}
/**
* Construct new augmentation identifier using supplied set of possible
* child nodes.
*
* @param childNames
* Set of possible child nodes.
*/
public AugmentationIdentifier(final ImmutableSet childNames) {
this.childNames = requireNonNull(childNames);
}
/**
* Construct new augmentation identifier using supplied set of possible
* child nodes.
*
* @param childNames
* Set of possible child nodes.
*/
public AugmentationIdentifier(final Set childNames) {
this.childNames = ImmutableSet.copyOf(childNames);
}
/**
* Return an AugmentationIdentifier for a particular set of QNames. Unlike the constructor, this factory method
* uses a global instance cache, resulting in object reuse for equal inputs.
*
* @param childNames Set of possible child nodes
* @return An {@link AugmentationIdentifier}
*/
public static @NonNull AugmentationIdentifier create(final ImmutableSet childNames) {
return CACHE.getUnchecked(childNames);
}
/**
* Return an AugmentationIdentifier for a particular set of QNames. Unlike the constructor, this factory method
* uses a global instance cache, resulting in object reuse for equal inputs.
*
* @param childNames Set of possible child nodes
* @return An {@link AugmentationIdentifier}
*/
public static @NonNull AugmentationIdentifier create(final Set childNames) {
final AugmentationIdentifier existing = CACHE.getIfPresent(childNames);
return existing != null ? existing : create(ImmutableSet.copyOf(childNames));
}
/**
* Returns set of all possible child nodes.
*
* @return set of all possible child nodes.
*/
public @NonNull Set getPossibleChildNames() {
return childNames;
}
@Override
public String toString() {
return "AugmentationIdentifier{" + "childNames=" + childNames + '}';
}
@Override
public String toRelativeString(final PathArgument previous) {
return toString();
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof AugmentationIdentifier)) {
return false;
}
AugmentationIdentifier that = (AugmentationIdentifier) obj;
return childNames.equals(that.childNames);
}
@Override
public int hashCode() {
return childNames.hashCode();
}
@Override
@SuppressWarnings("checkstyle:parameterName")
public int compareTo(final PathArgument o) {
if (!(o instanceof AugmentationIdentifier)) {
return -1;
}
AugmentationIdentifier other = (AugmentationIdentifier) o;
Set otherChildNames = other.getPossibleChildNames();
int thisSize = childNames.size();
int otherSize = otherChildNames.size();
if (thisSize == otherSize) {
// Quick Set-based comparison
if (childNames.equals(otherChildNames)) {
return 0;
}
// We already know the sets are not equal, but have equal size, hence the sets differ in their elements,
// but potentially share a common set of elements. The most consistent way of comparing them is using
// total ordering defined by QName's compareTo. Hence convert both sets to lists ordered
// by QName.compareTo() and decide on the first differing element.
final List diff = new ArrayList<>(Sets.symmetricDifference(childNames, otherChildNames));
verify(!diff.isEmpty(), "Augmentation identifiers %s and %s report no difference", this, o);
diff.sort(QName::compareTo);
return childNames.contains(diff.get(0)) ? -1 : 1;
} else if (thisSize < otherSize) {
return 1;
} else {
return -1;
}
}
private Object writeReplace() {
return new AIv1(this);
}
}
/**
* Fluent Builder of Instance Identifier instances.
*/
public interface InstanceIdentifierBuilder extends Mutable {
/**
* Adds a {@link PathArgument} to path arguments of resulting instance identifier.
*
* @param arg A {@link PathArgument} to be added
* @return this builder
*/
@NonNull InstanceIdentifierBuilder node(PathArgument arg);
/**
* Adds {@link NodeIdentifier} with supplied QName to path arguments of resulting instance identifier.
*
* @param nodeType QName of {@link NodeIdentifier} which will be added
* @return this builder
*/
@NonNull InstanceIdentifierBuilder node(QName nodeType);
/**
* Adds {@link NodeIdentifierWithPredicates} with supplied QName and key values to path arguments of resulting
* instance identifier.
*
* @param nodeType QName of {@link NodeIdentifierWithPredicates} which will be added
* @param keyValues Map of key components and their respective values for {@link NodeIdentifierWithPredicates}
* @return this builder
*/
@NonNull InstanceIdentifierBuilder nodeWithKey(QName nodeType, Map keyValues);
/**
* Adds {@link NodeIdentifierWithPredicates} with supplied QName and key, value.
*
* @param nodeType QName of {@link NodeIdentifierWithPredicates} which will be added
* @param key QName of key which will be added
* @param value value of key which will be added
* @return this builder
*/
@NonNull InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value);
/**
* Adds a collection of {@link PathArgument}s to path arguments of resulting instance identifier.
*
* @param args {@link PathArgument}s to be added
* @return this builder
* @throws NullPointerException if any of the arguments is null
*/
@NonNull InstanceIdentifierBuilder append(Collection extends PathArgument> args);
/**
* Adds a collection of {@link PathArgument}s to path arguments of resulting instance identifier.
*
* @param args {@link PathArgument}s to be added
* @return this builder
* @throws NullPointerException if any of the arguments is null
*/
default @NonNull InstanceIdentifierBuilder append(final PathArgument... args) {
return append(Arrays.asList(args));
}
/**
* Builds an {@link YangInstanceIdentifier} with path arguments from this builder.
*
* @return {@link YangInstanceIdentifier}
*/
@NonNull YangInstanceIdentifier build();
}
}