*/
package org.opendaylight.mdsal.binding.javav2.runtime.context;
+import static java.util.Objects.requireNonNull;
+
import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
+import java.lang.reflect.Method;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import org.opendaylight.mdsal.binding.javav2.generator.api.ClassLoadingStrategy;
+import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
import org.opendaylight.mdsal.binding.javav2.generator.impl.BindingGeneratorImpl;
-import org.opendaylight.mdsal.binding.javav2.generator.impl.ModuleContext;
import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
import org.opendaylight.mdsal.binding.javav2.generator.util.ReferencedTypeImpl;
import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
import org.opendaylight.mdsal.binding.javav2.runtime.context.util.BindingSchemaContextUtils;
import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Action;
+import org.opendaylight.mdsal.binding.javav2.spec.base.Rpc;
import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentation;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
private static final char DOT = '.';
private final ClassLoadingStrategy strategy;
private final SchemaContext schemaContext;
+ private final Multimap<Type, AugmentationSchemaNode> augmentationToSchemas = HashMultimap.create();
+ private final BiMap<SchemaPath,Type> targetToAugmentation = HashBiMap.create();
- private final Map<Type, AugmentationSchema> augmentationToSchema = new HashMap<>();
- private final BiMap<Type, Object> typeToDefiningSchema = HashBiMap.create();
+ private final BiMap<Type, WithStatus> typeToDefiningSchema = HashBiMap.create();
private final Multimap<Type, Type> choiceToCases = HashMultimap.create();
private final Map<QName, Type> identities = new HashMap<>();
final Map<Module, ModuleContext> modules = generator.getModuleContexts(this.schemaContext);
for (final ModuleContext ctx : modules.values()) {
- this.augmentationToSchema.putAll(ctx.getTypeToAugmentation());
+ this.augmentationToSchemas.putAll(ctx.getTypeToAugmentations());
+ this.targetToAugmentation.putAll(ctx.getTargetToAugmentation());
this.typeToDefiningSchema.putAll(ctx.getTypeToSchema());
ctx.getTypedefs();
* augmentations, which may be present in runtime for them, thus returned
* schema is unsuitable for use for validation of data.
* <p>
- * For retrieving {@link AugmentationSchema}, which will contains full model
+ * For retrieving {@link AugmentationSchemaNode}, which will contains full model
* for child nodes, you should use method
* {@link #getResolvedAugmentationSchema(DataNodeContainer, Class)} which
* will return augmentation schema derived from supplied augmentation target
* @throws IllegalArgumentException
* - if supplied class is not an augmentation
*/
- public @Nullable AugmentationSchema getAugmentationDefinition(final Class<?> augClass) throws IllegalArgumentException {
- Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass), "Class %s does not represent augmentation", augClass);
- return this.augmentationToSchema.get(referencedType(augClass));
+ public @Nullable Entry<Type, Collection<AugmentationSchemaNode>>
+ getAugmentationDefinition(final Class<?> augClass) {
+ Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass),
+ "Class %s does not represent augmentation", augClass);
+
+ final Type refType = referencedType(augClass);
+ for (Entry<Type, Collection<AugmentationSchemaNode>> entry : this.augmentationToSchemas.asMap().entrySet()) {
+ if (refType.equals(entry.getKey())) {
+ return entry;
+ }
+ }
+
+ throw new IllegalArgumentException("Supplied class is not an augmentation.");
}
/**
return (DataSchemaNode) this.typeToDefiningSchema.get(referencedType(cls));
}
+ public RpcDefinition getRpcDefinition(final Class<? extends Rpc<?, ?>> cls) {
+ return (RpcDefinition) typeToDefiningSchema.get(referencedType(cls));
+ }
+
+ public ActionDefinition getActionDefinition(final Class<? extends Action<?, ?, ?, ?>> cls) {
+ return (ActionDefinition) typeToDefiningSchema.get(referencedType(cls));
+ }
+
/**
- * Returns defining {@link AugmentationSchema} of target for supplied class.
+ * Returns defining {@link AugmentationSchemaNode} of target for supplied class.
*
* @param target
* - {@link DataNodeContainer}
* @param aug
* - supplied class
- * @return entry of {@link AugmentationSchema} according to its identifier
+ * @return entry of {@link AugmentationSchemaNode} according to its identifier
* {@link AugmentationIdentifier}
*/
- public Entry<AugmentationIdentifier, AugmentationSchema> getResolvedAugmentationSchema(final DataNodeContainer target,
- final Class<? extends Augmentation<?>> aug) {
- final AugmentationSchema origSchema = getAugmentationDefinition(aug);
- Preconditions.checkArgument(origSchema != null, "Augmentation %s is not known in current schema context",aug);
+ public Entry<AugmentationIdentifier, AugmentationSchemaNode> getResolvedAugmentationSchema(
+ final DataNodeContainer target, final Class<? extends Augmentation<?>> aug) {
+ final Collection<AugmentationSchemaNode> origSchemas = getAugmentationDefinition(aug).getValue();
+ Preconditions.checkArgument(origSchemas != null, "Augmentation %s is not known in current schema context",aug);
/*
* FIXME: Validate augmentation schema lookup
*
*/
final Set<QName> childNames = new HashSet<>();
final Set<DataSchemaNode> realChilds = new HashSet<>();
- for (final DataSchemaNode child : origSchema.getChildNodes()) {
- final DataSchemaNode dataChildQNname = target.getDataChildByName(child.getQName());
- final String childLocalName = child.getQName().getLocalName();
- if (dataChildQNname == null) {
- for (final DataSchemaNode dataSchemaNode : target.getChildNodes()) {
- if (childLocalName.equals(dataSchemaNode.getQName().getLocalName())) {
- realChilds.add(dataSchemaNode);
- childNames.add(dataSchemaNode.getQName());
+ for (final AugmentationSchemaNode origSchema : origSchemas) {
+ for (final DataSchemaNode child : origSchema.getChildNodes()) {
+ final DataSchemaNode dataChildQNname = target.getDataChildByName(child.getQName());
+ final String childLocalName = child.getQName().getLocalName();
+ if (dataChildQNname == null) {
+ for (final DataSchemaNode dataSchemaNode : target.getChildNodes()) {
+ if (childLocalName.equals(dataSchemaNode.getQName().getLocalName())) {
+ realChilds.add(dataSchemaNode);
+ childNames.add(dataSchemaNode.getQName());
+ }
}
+ } else {
+ realChilds.add(dataChildQNname);
+ childNames.add(child.getQName());
}
- } else {
- realChilds.add(dataChildQNname);
- childNames.add(child.getQName());
}
}
final AugmentationIdentifier identifier = new AugmentationIdentifier(childNames);
- final AugmentationSchema proxy = new EffectiveAugmentationSchema(origSchema, realChilds);
+ final AugmentationSchemaNode proxy = new EffectiveAugmentationSchema(origSchemas.stream().findFirst().get(),
+ realChilds);
return new SimpleEntry<>(identifier, proxy);
}
* - resolved parent choice schema
* @param childClass
* - class representing case.
- * @return Optionally a resolved case schema, absent if the choice is not
+ * @return Optionally a resolved case schema,.empty if the choice is not
* legal in the given context.
* @throws IllegalArgumentException
* - if supplied class does not represent case
*/
- public Optional<ChoiceCaseNode> getCaseSchemaDefinition(final ChoiceSchemaNode schema, final Class<?> childClass) throws IllegalArgumentException {
+ public Optional<CaseSchemaNode> getCaseSchemaDefinition(final ChoiceSchemaNode schema, final Class<?> childClass) throws IllegalArgumentException {
final DataSchemaNode origSchema = getSchemaDefinition(childClass);
- Preconditions.checkArgument(origSchema instanceof ChoiceCaseNode, "Supplied schema %s is not case.", origSchema);
+ Preconditions.checkArgument(origSchema instanceof CaseSchemaNode, "Supplied schema %s is not case.", origSchema);
/*
* FIXME: Make sure that if there are multiple augmentations of same
* unaware that he is using incorrect case which was generated for
* choice inside grouping.
*/
- final Optional<ChoiceCaseNode> found = BindingSchemaContextUtils.findInstantiatedCase(schema,
- (ChoiceCaseNode) origSchema);
+ final Optional<CaseSchemaNode> found = BindingSchemaContextUtils.findInstantiatedCase(schema,
+ (CaseSchemaNode) origSchema);
return found;
}
private static Type referencedType(final Class<?> type) {
- return new ReferencedTypeImpl(type.getPackage().getName(), type.getSimpleName());
+ return new ReferencedTypeImpl(type.getPackage().getName(), type.getSimpleName(), true, null);
}
static Type referencedType(final String type) {
final int packageClassSeparator = type.lastIndexOf(DOT);
- return new ReferencedTypeImpl(type.substring(0, packageClassSeparator), type.substring(packageClassSeparator + 1));
+ return new ReferencedTypeImpl(type.substring(0, packageClassSeparator),
+ type.substring(packageClassSeparator + 1), true, null);
}
/**
- * Returns schema ({@link DataSchemaNode}, {@link AugmentationSchema} or {@link TypeDefinition})
+ * Returns schema ({@link DataSchemaNode}, {@link AugmentationSchemaNode} or {@link TypeDefinition})
* from which supplied class was generated. Returned schema may be augmented with
* additional information, which was not available at compile type
* (e.g. third party augmentations).
*
* @param type Binding Class for which schema should be retrieved.
* @return Instance of generated type (definition of Java API), along with
- * {@link DataSchemaNode}, {@link AugmentationSchema} or {@link TypeDefinition}
+ * {@link DataSchemaNode}, {@link AugmentationSchemaNode} or {@link TypeDefinition}
* which was used to generate supplied class.
*/
public Entry<GeneratedType, Object> getTypeWithSchema(final Class<?> type) {
private Entry<GeneratedType, Object> getTypeWithSchema(final Type referencedType) {
final Object schema = this.typeToDefiningSchema.get(referencedType);
- Preconditions.checkNotNull(schema, "Failed to find schema for type %s", referencedType);
+ requireNonNull(schema, () -> "Failed to find schema for type " + referencedType);
final Type definedType = this.typeToDefiningSchema.inverse().get(schema);
- Preconditions.checkNotNull(definedType, "Failed to find defined type for %s schema %s", referencedType, schema);
+ requireNonNull(definedType, () -> "Failed to find defined type for " + referencedType + " schema " + schema);
if (definedType instanceof GeneratedTypeBuilder) {
return new SimpleEntry<>(((GeneratedTypeBuilder) definedType).toInstance(), schema);
}
}
+ private static boolean isLocalAugment(final AugmentationTarget container, final AugmentationSchemaNode augment) {
+ Preconditions.checkState(container instanceof SchemaNode);
+ final QName root = ((SchemaNode) container).getPath().getPathFromRoot().iterator().next();
+ // findFirst makes no sense but just pick up one child to judge whether the target node is
+ // in the same module.
+ final Optional<DataSchemaNode> child = augment.getChildNodes().stream().findFirst();
+ if (child.isPresent()) {
+ return root.getModule().equals(child.get().getQName().getModule());
+ }
+ return false;
+ }
+
public ImmutableMap<AugmentationIdentifier,Type> getAvailableAugmentationTypes(final DataNodeContainer container) {
final Map<AugmentationIdentifier,Type> identifierToType = new HashMap<>();
if (container instanceof AugmentationTarget) {
- final Set<AugmentationSchema> augments = ((AugmentationTarget) container).getAvailableAugmentations();
- for (final AugmentationSchema augment : augments) {
- // Augmentation must have child nodes if is to be used with Binding classes
- AugmentationSchema augOrig = augment;
- while (augOrig.getOriginalDefinition().isPresent()) {
- augOrig = augOrig.getOriginalDefinition().get();
- }
+ for (final AugmentationSchemaNode augment : ((AugmentationTarget) container).getAvailableAugmentations()) {
+ if (!isLocalAugment((AugmentationTarget) container, augment)) {
+ // Augmentation must have child nodes if is to be used with Binding classes
+ AugmentationSchemaNode augOrig = augment;
+ while (augOrig.getOriginalDefinition().isPresent()) {
+ augOrig = augOrig.getOriginalDefinition().get();
+ }
- if (!augment.getChildNodes().isEmpty()) {
- final Type augType = this.typeToDefiningSchema.inverse().get(augOrig);
- if (augType != null) {
- identifierToType.put(getAugmentationIdentifier(augment),augType);
+ if (!augment.getChildNodes().isEmpty()) {
+ final Type augType = this.targetToAugmentation.get(augOrig.getTargetPath());
+ if (augType != null) {
+ identifierToType.put(getAugmentationIdentifier(augment), augType);
+ }
}
}
}
return ImmutableMap.copyOf(identifierToType);
}
- private static AugmentationIdentifier getAugmentationIdentifier(final AugmentationSchema augment) {
+ private static AugmentationIdentifier getAugmentationIdentifier(final AugmentationSchemaNode augment) {
final Set<QName> childNames = new HashSet<>();
for (final DataSchemaNode child : augment.getChildNodes()) {
childNames.add(child.getQName());
if (type instanceof ReferencedTypeImpl) {
return type;
}
- return new ReferencedTypeImpl(type.getPackageName(), type.getName());
+ return new ReferencedTypeImpl(type.getPackageName(), type.getName(), true, null);
}
private static Set<Type> collectAllContainerTypes(final GeneratedType type, final Set<Type> collection) {
public Class<?> getIdentityClass(final QName input) {
return this.identityClasses.getUnchecked(input);
}
+
+ public Method findOperationMethod(final Class<?> key, final OperationDefinition operationDef)
+ throws NoSuchMethodException {
+ final String methodName =
+ JavaIdentifierNormalizer.normalizeSpecificIdentifier(operationDef.getQName().getLocalName(),
+ JavaIdentifier.METHOD);
+ if (operationDef.getInput() != null && isExplicitStatement(operationDef.getInput())) {
+ final Class<?> inputClz = this.getClassForSchema(operationDef.getInput());
+ return key.getMethod(methodName, inputClz);
+ }
+ return key.getMethod(methodName);
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static boolean isExplicitStatement(final ContainerSchemaNode node) {
+ return node instanceof EffectiveStatement
+ && ((EffectiveStatement) node).getDeclared().getStatementSource() == StatementSource.DECLARATION;
+ }
}