import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
private final CodecRegistry codecRegistry;
+ private final Map<Class<?>,Set<List<QName>>> augmentationAdapted = new WeakHashMap<>();
+
private final Map<Class<?>, Map<List<QName>, Class<?>>> classToPreviousAugment = Collections
.synchronizedMap(new WeakHashMap<Class<?>, Map<List<QName>, Class<?>>>());
}
Map<List<QName>, Class<?>> injectAugment = classToPreviousAugment.get(baType);
if (injectAugment != null) {
+ @SuppressWarnings("unchecked")
Class<? extends DataObject> augment = (Class<? extends DataObject>) injectAugment.get(scannedPath);
if (augment != null) {
baArgs.add(new Item(augment));
}
baArgs.add(baArg);
}
- InstanceIdentifier ret = InstanceIdentifier.create(baArgs);
+ InstanceIdentifier<?> ret = InstanceIdentifier.create(baArgs);
LOG.debug("DOM Instance Identifier {} deserialized to {}", input, ret);
return ret;
}
@Override
public InstanceIdentifier<? extends Object> deserialize(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input,
- InstanceIdentifier<?> bindingIdentifier) {
+ final InstanceIdentifier<?> bindingIdentifier) {
return deserialize(input);
}
- private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument _deserializePathArgument(
+ private InstanceIdentifier.PathArgument deserializeNodeIdentifier(
final NodeIdentifier argument, final List<QName> processedPath) {
+ @SuppressWarnings("rawtypes")
final Class cls = codecRegistry.getClassForPath(processedPath);
+ @SuppressWarnings("unchecked")
Item<DataObject> item = new Item<>(cls);
return item;
}
- private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument _deserializePathArgument(
+ private InstanceIdentifier.PathArgument deserializeNodeIdentifierWithPrecicates(
final NodeIdentifierWithPredicates argument, final List<QName> processedPath) {
+ @SuppressWarnings("rawtypes")
final Class type = codecRegistry.getClassForPath(processedPath);
+ @SuppressWarnings({ "unchecked", "rawtypes" })
final IdentifierCodec codec = codecRegistry
.<Identifiable<? extends Object>> getIdentifierCodecForIdentifiable(type);
CompositeNode _compositeNode = this.toCompositeNode(argument);
+ @SuppressWarnings("unchecked")
ValueWithQName<CompositeNode> deserialize = codec.deserialize(_compositeNode);
Object value = null;
if (deserialize != null) {
@Override
public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier serialize(final InstanceIdentifier<?> input) {
Class<?> previousAugmentation = null;
- List<InstanceIdentifier.PathArgument> pathArgs = input.getPath();
+ Iterable<InstanceIdentifier.PathArgument> pathArgs = input.getPathArguments();
QName previousQName = null;
- List<PathArgument> components = new ArrayList<>(pathArgs.size());
- List<QName> qnamePath = new ArrayList<>(pathArgs.size());
+ List<PathArgument> components = new ArrayList<>();
+ List<QName> qnamePath = new ArrayList<>();
for (InstanceIdentifier.PathArgument baArg : pathArgs) {
-
if (!Augmentation.class.isAssignableFrom(baArg.getType())) {
- org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument biArg = serializePathArgument(
- baArg, previousQName);
- previousQName = biArg.getNodeType();
+ PathArgument biArg = serializePathArgumentAndUpdateMapping(qnamePath, baArg, previousQName,previousAugmentation);
components.add(biArg);
qnamePath.add(biArg.getNodeType());
- ImmutableList<QName> immutableList = ImmutableList.copyOf(qnamePath);
- codecRegistry.putPathToClass(immutableList, baArg.getType());
- if (previousAugmentation != null) {
- updateAugmentationInjection(baArg.getType(), immutableList, previousAugmentation);
- }
+ previousQName = biArg.getNodeType();
previousAugmentation = null;
} else {
previousQName = codecRegistry.getQNameForAugmentation(baArg.getType());
previousAugmentation = baArg.getType();
+ ensureAugmentation(qnamePath,previousQName,baArg.getType());
}
}
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ret = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
return ret;
}
+ private synchronized void ensureAugmentation(final List<QName> augPath, final QName augQName, final Class<? extends DataObject> type) {
+ Set<List<QName>> augPotential = augmentationAdapted.get(type);
+ if(augPotential == null) {
+ augPotential = new HashSet<>();
+ augmentationAdapted.put(type, augPotential);
+ }
+ ImmutableList<QName> augTargetPath = ImmutableList.copyOf(augPath);
+ if(augPotential.contains(augPath)) {
+ return;
+ }
+
+ for(Class<? extends DataObject> child : BindingReflections.getChildrenClasses(type)) {
+ Item<? extends DataObject> baArg = new Item<>(child);
+ PathArgument biArg = serializePathArgumentAndUpdateMapping(augPath, baArg, augQName,type);
+ }
+ augPotential.add(augTargetPath);
+ }
+
+
public Class<? extends Object> updateAugmentationInjection(final Class<? extends DataObject> class1,
- final ImmutableList<QName> list, final Class<?> augmentation) {
+ final List<QName> list, final Class<?> augmentation) {
if (classToPreviousAugment.get(class1) == null) {
classToPreviousAugment.put(class1, new ConcurrentHashMap<List<QName>, Class<?>>());
}
return classToPreviousAugment.get(class1).put(list, augmentation);
}
- private PathArgument _serializePathArgument(final Item<?> argument, final QName previousQname) {
+ private PathArgument serializeItem(final Item<?> argument, final QName previousQname) {
Class<?> type = argument.getType();
QName qname = BindingReflections.findQName(type);
if (previousQname == null || (BindingReflections.isAugmentationChild(argument.getType()))) {
return new NodeIdentifier(QName.create(previousQname, qname.getLocalName()));
}
- private PathArgument _serializePathArgument(final IdentifiableItem argument, final QName previousQname) {
+ private PathArgument serializeIdentifiableItem(final IdentifiableItem<?,?> argument, final QName previousQname) {
Map<QName, Object> predicates = new HashMap<>();
+ @SuppressWarnings("rawtypes")
Class type = argument.getType();
+ @SuppressWarnings("unchecked")
IdentifierCodec<? extends Object> keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type);
QName qname = BindingReflections.findQName(type);
if (previousQname != null && !(BindingReflections.isAugmentationChild(argument.getType()))) {
qname = QName.create(previousQname, qname.getLocalName());
}
+ @SuppressWarnings({ "rawtypes", "unchecked" })
ValueWithQName combinedInput = new ValueWithQName(previousQname, argument.getKey());
+ @SuppressWarnings("unchecked")
CompositeNode compositeOutput = keyCodec.serialize(combinedInput);
for (Node<?> outputValue : compositeOutput.getValue()) {
predicates.put(outputValue.getNodeType(), outputValue.getValue());
private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(
final PathArgument argument, final List<QName> processedPath) {
if (argument instanceof NodeIdentifier) {
- return _deserializePathArgument((NodeIdentifier) argument, processedPath);
+ return deserializeNodeIdentifier((NodeIdentifier) argument, processedPath);
} else if (argument instanceof NodeIdentifierWithPredicates) {
- return _deserializePathArgument((NodeIdentifierWithPredicates) argument, processedPath);
+ return deserializeNodeIdentifierWithPrecicates((NodeIdentifierWithPredicates) argument, processedPath);
} else {
throw new IllegalArgumentException("Unhandled parameter types: "
+ Arrays.<Object> asList(argument, processedPath).toString());
}
}
+ private PathArgument serializePathArgumentAndUpdateMapping(final List<QName> parentPath, final InstanceIdentifier.PathArgument baArg, final QName previousQName, final Class<?> previousAugmentation) {
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument biArg = serializePathArgument(baArg, previousQName);
+ List<QName> qnamePath = new ArrayList<>(parentPath);
+ qnamePath.add(biArg.getNodeType());
+ ImmutableList<QName> currentPath = ImmutableList.copyOf(qnamePath);
+ codecRegistry.putPathToClass(currentPath, baArg.getType());
+ if (previousAugmentation != null) {
+ updateAugmentationInjection(baArg.getType(), currentPath, previousAugmentation);
+ }
+ return biArg;
+ }
+
private PathArgument serializePathArgument(
- final org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument argument,
+ final InstanceIdentifier.PathArgument argument,
final QName previousQname) {
if (argument instanceof IdentifiableItem) {
- return _serializePathArgument((IdentifiableItem) argument, previousQname);
+ return serializeIdentifiableItem((IdentifiableItem<?,?>) argument, previousQname);
} else if (argument instanceof Item) {
- return _serializePathArgument((Item<?>) argument, previousQname);
+ return serializeItem((Item<?>) argument, previousQname);
} else {
throw new IllegalArgumentException("Unhandled parameter types: "
+ Arrays.<Object> asList(argument, previousQname).toString());
}
}
+
+
}
@SuppressWarnings("rawtypes")
private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
- private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+ private static final Map<SchemaPath, Type> pathToType = new ConcurrentHashMap<>();
private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
private static final BiMap<Type, AugmentationSchema> typeToAugment = HashBiMap
@SuppressWarnings("unchecked")
@Override
- public <T extends Augmentation<?>> AugmentationCodecWrapper<T> getCodecForAugmentation(final Class<T> object) {
+ public <T extends Augmentation<?>> AugmentationCodecWrapper<T> getCodecForAugmentation(final Class<T> augClass) {
AugmentationCodecWrapper<T> codec = null;
@SuppressWarnings("rawtypes")
- AugmentationCodecWrapper potentialCodec = augmentationCodecs.get(object);
+ AugmentationCodecWrapper potentialCodec = augmentationCodecs.get(augClass);
if (potentialCodec != null) {
codec = potentialCodec;
} else {
- lock.waitForSchema(object);
+ lock.waitForSchema(augClass);
Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
- .augmentationTransformerFor(object);
+ .augmentationTransformerFor(augClass);
BindingCodec<Map<QName, Object>, Object> rawCodec = newInstanceOf(augmentRawCodec);
- codec = new AugmentationCodecWrapper<T>(rawCodec, null, object);
- augmentationCodecs.put(object, codec);
+ codec = new AugmentationCodecWrapper<T>(rawCodec, augClass);
+ augmentationCodecs.put(augClass, codec);
}
final Class<? extends Augmentable<?>> objectSupertype;
try {
- objectSupertype = BindingReflections.findAugmentationTarget(object);
+ objectSupertype = BindingReflections.findAugmentationTarget(augClass);
} catch (Exception e) {
- LOG.warn("Failed to find target for augmentation {}, ignoring it", object, e);
+ LOG.warn("Failed to find target for augmentation {}, ignoring it", augClass, e);
return codec;
}
if (objectSupertype == null) {
- LOG.warn("Augmentation target for {} not found, ignoring it", object);
+ LOG.warn("Augmentation target for {} not found, ignoring it", augClass);
return codec;
}
@SuppressWarnings("rawtypes")
final WeakReference<Class> weakRef = typeToClass.get(type);
- Preconditions.checkState(weakRef != null, "Could not find loaded class for path: %s and type: %s", path, type.getFullyQualifiedName());
+ Preconditions.checkState(weakRef != null, "Could not find loaded class for path: %s and type: %s", path,
+ type.getFullyQualifiedName());
return weakRef.get();
}
private DataSchemaNode getSchemaNode(final List<QName> path) {
QName firstNode = path.get(0);
- DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(), firstNode.getRevision());
+ DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(),
+ firstNode.getRevision());
Preconditions.checkArgument(previous != null, "Failed to find module %s for path %s", firstNode, path);
Iterator<QName> iterator = path.iterator();
LOG.error("Failed to instantiate codec {}", cls.getSimpleName(), e);
throw new IllegalStateException(String.format("Failed to instantiate codec %s", cls), e);
} catch (IllegalAccessException e) {
- LOG.debug("Run-time consistency issue: constructor for {} is not available. This indicates either a code generation bug or a misconfiguration of JVM.",
+ LOG.debug(
+ "Run-time consistency issue: constructor for {} is not available. This indicates either a code generation bug or a misconfiguration of JVM.",
cls.getSimpleName(), e);
throw new IllegalStateException(String.format("Cannot access contructor of %s", cls), e);
}
identity.getKey());
}
- synchronized(augmentableToAugmentations) {
+ synchronized (augmentableToAugmentations) {
augmentableToAugmentations.putAll(context.getAugmentableToAugmentations());
}
- synchronized(choiceToCases) {
+ synchronized (choiceToCases) {
choiceToCases.putAll(context.getChoiceToCases());
}
captureCases(context.getCases(), schemaContext);
}
SchemaPath path = caseNode.getPath();
- GeneratedTypeBuilder type;
+ Type type;
if (path != null && (type = pathToType.get(path)) != null) {
ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
@SuppressWarnings("rawtypes")
}
}
- public AugmentableDispatchCodec getAugmentableCodec(final Class<?> dataClass) {
+ public synchronized AugmentableDispatchCodec getAugmentableCodec(final Class<?> dataClass) {
AugmentableDispatchCodec ret = augmentableCodecs.get(dataClass);
if (ret != null) {
return ret;
return implementation;
}
- protected final void adaptForPath(final InstanceIdentifier<?> path) {
+ protected final synchronized void adaptForPath(final InstanceIdentifier<?> path) {
if (adaptedForPaths.contains(path)) {
return;
}
/**
- * We search in schema context if the use of this location aware codec (augmentable codec, case codec)
- * makes sense on provided location (path)
+ * We search in schema context if the use of this location aware
+ * codec (augmentable codec, case codec) makes sense on provided
+ * location (path)
*
*/
- Optional<DataNodeContainer> contextNode = BindingSchemaContextUtils.findDataNodeContainer(currentSchema, path);
+ Optional<DataNodeContainer> contextNode = BindingSchemaContextUtils.findDataNodeContainer(currentSchema,
+ path);
/**
- * If context node is present, this codec makes sense on provided location.
+ * If context node is present, this codec makes sense on provided
+ * location.
*
*/
if (contextNode.isPresent()) {
synchronized (this) {
/**
*
- * We adapt (turn on / off) possible implementations of child codecs (augmentations, cases)
- * based on this location.
+ * We adapt (turn on / off) possible implementations of
+ * child codecs (augmentations, cases) based on this
+ * location.
*
*
*/
+
adaptForPathImpl(path, contextNode.get());
- try {
+ try {
/**
- * We trigger serialization of instance identifier, to make sure instance identifier
- * codec is aware of combination of this path / augmentation / case
+ * We trigger serialization of instance identifier, to
+ * make sure instance identifier codec is aware of
+ * combination of this path / augmentation / case
*/
instanceIdentifierCodec.serialize(path);
} catch (Exception e) {
- LOG.warn("Exception during preparation of instance identifier codec for path {}.",path,e);
+ LOG.warn("Exception during preparation of instance identifier codec for path {}.", path, e);
}
adaptedForPaths.add(path);
}
} else {
- LOG.debug("Context node (parent node) not found for {}",path);
+ LOG.debug("Context node (parent node) not found for {}", path);
}
}
}
}
- private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
+ private static class PublicChoiceCodecImpl<T> implements ChoiceCodec<T>,
+ Delegator<BindingCodec<Map<QName, Object>, Object>> {
private final BindingCodec<Map<QName, Object>, Object> delegate;
private class DispatchChoiceCodecImpl extends LocationAwareDispatchCodec<ChoiceCaseCodecImpl<?>> {
@Override
- public Object deserialize(final Object input, @SuppressWarnings("rawtypes") final InstanceIdentifier bindingIdentifier) {
+ public Object deserialize(final Object input,
+ @SuppressWarnings("rawtypes") final InstanceIdentifier bindingIdentifier) {
// TODO Auto-generated method stub
return null;
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- private class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
+ class AugmentableDispatchCodec extends LocationAwareDispatchCodec<AugmentationCodecWrapper> {
private final Class augmentableType;
protected void tryToLoadImplementations() {
Type type = referencedType(augmentableType);
Collection<Type> potentialAugmentations;
- synchronized(augmentableToAugmentations) {
+ synchronized (augmentableToAugmentations) {
potentialAugmentations = new ArrayList(augmentableToAugmentations.get(type));
}
for (Type potential : potentialAugmentations) {
}
@Override
- protected void adaptForPathImpl(final InstanceIdentifier<?> path, final DataNodeContainer ctxNode) {
+ protected void adaptForPathImpl(final InstanceIdentifier<?> augTarget, final DataNodeContainer ctxNode) {
if (ctxNode instanceof AugmentationTarget) {
Set<AugmentationSchema> availableAugmentations = ((AugmentationTarget) ctxNode)
.getAvailableAugmentations();
if (!availableAugmentations.isEmpty()) {
- updateAugmentationMapping(path,availableAugmentations);
+ updateAugmentationMapping(augTarget, availableAugmentations);
}
}
}
- private void updateAugmentationMapping(final InstanceIdentifier<?> path, final Set<AugmentationSchema> availableAugmentations) {
+ /**
+ *
+ * Adapts augmentation codec for specific provider location (target)
+ *
+ * Since augmentation are not forward-referencing and may be discovered
+ * during runtime, we need to adapt {@link AugmentableDispatchCodec},
+ * {@link AugmentationCodecWrapper} and {@link InstanceIdentifierCodec}
+ * for this newly discovered location where augmentation may be used.
+ *
+ * Adaptation consists of:
+ * <ol>
+ * <li> scan of available (valid) augmentations for
+ * current location
+ * <li>lookup for Java classes derived from this augmentations
+ * <li>generation of missing codecs
+ * <li>updating Augmentation codecs to work with new location
+ * <li>updating Instance Identifier to work with new location
+ *
+ */
+ private void updateAugmentationMapping(final InstanceIdentifier<?> augTarget,
+ final Set<AugmentationSchema> availableAugmentations) {
for (AugmentationSchema aug : availableAugmentations) {
Type potentialType = getTypeForAugmentation(aug);
if (potentialType != null) {
Optional<AugmentationCodecWrapper> potentialImpl = tryToLoadImplementation(potentialType);
if (potentialImpl.isPresent()) {
- potentialImpl.get().addApplicableFor(path,aug);
+ potentialImpl.get().addApplicableFor(augTarget, aug);
+ Class augType = potentialImpl.get().getDataType();
+ InstanceIdentifier augPath = augTarget.augmentation(augType);
+ try {
+
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = getInstanceIdentifierCodec().serialize(augPath);
+ if(domPath == null) {
+ LOG.error("Unable to serialize instance identifier for {}",augPath);
+ }
+ } catch (Exception e) {
+ LOG.error("Unable to serialize instance identifiers for {}",augPath,e);
+ }
+
}
} else {
- LOG.warn("Could not find generated type for augmentation {} with children {}", aug, aug.getChildNodes());
+ // Omits warning for empty augmentations since they are not represented in data
+ if(!aug.getChildNodes().isEmpty()) {
+ LOG.warn("Could not find generated type for augmentation {} with children {}", aug,
+ aug.getChildNodes());
+ }
}
}
- availableAugmentations.toString();
}
+
+
private Type getTypeForAugmentation(final AugmentationSchema aug) {
Optional<AugmentationSchema> currentAug = Optional.of(aug);
- while(currentAug.isPresent()) {
+ while (currentAug.isPresent()) {
Type potentialType = typeToAugment.inverse().get(currentAug.get());
- if(potentialType != null) {
+ if (potentialType != null) {
return potentialType;
}
currentAug = currentAug.get().getOriginalDefinition();
private final BindingCodec delegate;
private final QName augmentationQName;
- private final Multimap<InstanceIdentifier<?>,QName> validAugmentationTargets;
+ private final Multimap<InstanceIdentifier<?>, QName> validAugmentationTargets;
private final Class<?> augmentationType;
- public AugmentationCodecWrapper(final BindingCodec<Map<QName, Object>, Object> rawCodec,
- final InstanceIdentifier<?> targetId, final Class<?> dataType) {
+ public AugmentationCodecWrapper(final BindingCodec<Map<QName, Object>, Object> rawCodec, final Class<?> dataType) {
this.delegate = rawCodec;
this.augmentationType = dataType;
this.augmentationQName = BindingReflections.findQName(rawCodec.getClass());
- this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap.<InstanceIdentifier<?>,QName>create());
+ this.validAugmentationTargets = Multimaps.synchronizedSetMultimap(HashMultimap
+ .<InstanceIdentifier<?>, QName> create());
}
public void addApplicableFor(final InstanceIdentifier<?> path, final AugmentationSchema aug) {
- for(DataSchemaNode child : aug.getChildNodes()) {
- validAugmentationTargets.put(path,child.getQName());
+ for (DataSchemaNode child : aug.getChildNodes()) {
+ validAugmentationTargets.put(path, child.getQName());
}
}
}
@Override
- public Object deserialize(final Object input,final InstanceIdentifier bindingIdentifier) {
+ public Object deserialize(final Object input, final InstanceIdentifier bindingIdentifier) {
Type type = qnamesToIdentityMap.get(input);
if (type == null) {
return null;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import java.util.LinkedList;
+import java.util.List;
import java.util.ServiceLoader;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
* Returns a QName associated to supplied type
*
* @param dataType
- * @return QName associated to supplied dataType. If dataType is Augmentation
- * method does not return canonical QName, but QName with correct namespace
- * revision, but virtual local name, since augmentations do not have name.
+ * @return QName associated to supplied dataType. If dataType is
+ * Augmentation method does not return canonical QName, but QName
+ * with correct namespace revision, but virtual local name, since
+ * augmentations do not have name.
*/
public static final QName findQName(final Class<?> dataType) {
return classToQName.getUnchecked(dataType).orNull();
return Optional.of((QName) obj);
}
} catch (NoSuchFieldException e) {
- if(Augmentation.class.isAssignableFrom(key)) {
+ if (Augmentation.class.isAssignableFrom(key)) {
YangModuleInfo moduleInfo = getModuleInfo(key);
- return Optional.of(QName.create(moduleInfo.getNamespace(), moduleInfo.getRevision(), moduleInfo.getName()));
+ return Optional.of(QName.create(moduleInfo.getNamespace(), moduleInfo.getRevision(),
+ moduleInfo.getName()));
}
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
// NOOP
checkArgument(name.startsWith(BindingMapping.PACKAGE_PREFIX), "Package name not starting with %s, is: %s",
BindingMapping.PACKAGE_PREFIX, name);
Matcher match = ROOT_PACKAGE_PATTERN.matcher(name);
- checkArgument(match.find(),"Package name '%s' does not match required pattern '%s'",name,ROOT_PACKAGE_PATTERN_STRING);
+ checkArgument(match.find(), "Package name '%s' does not match required pattern '%s'", name,
+ ROOT_PACKAGE_PATTERN_STRING);
return match.group(0);
}
final String potentialClassName = getModuleInfoClassName(packageName);
return ClassLoaderUtils.withClassLoader(cls.getClassLoader(), new Callable<YangModuleInfo>() {
@Override
- public YangModuleInfo call() throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
+ public YangModuleInfo call() throws ClassNotFoundException, IllegalAccessException,
+ IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Class<?> moduleInfoClass = Thread.currentThread().getContextClassLoader().loadClass(potentialClassName);
return (YangModuleInfo) moduleInfoClass.getMethod("getInstance").invoke(null);
}
}
public static ImmutableSet<YangModuleInfo> loadModuleInfos(final ClassLoader loader) {
- Builder<YangModuleInfo> moduleInfoSet = ImmutableSet.<YangModuleInfo>builder();
- ServiceLoader<YangModelBindingProvider> serviceLoader = ServiceLoader.load(YangModelBindingProvider.class, loader);
- for(YangModelBindingProvider bindingProvider : serviceLoader) {
+ Builder<YangModuleInfo> moduleInfoSet = ImmutableSet.<YangModuleInfo> builder();
+ ServiceLoader<YangModelBindingProvider> serviceLoader = ServiceLoader.load(YangModelBindingProvider.class,
+ loader);
+ for (YangModelBindingProvider bindingProvider : serviceLoader) {
YangModuleInfo moduleInfo = bindingProvider.getModuleInfo();
- checkState(moduleInfo != null, "Module Info for %s is not available.",bindingProvider.getClass());
- collectYangModuleInfo(bindingProvider.getModuleInfo(),moduleInfoSet);
+ checkState(moduleInfo != null, "Module Info for %s is not available.", bindingProvider.getClass());
+ collectYangModuleInfo(bindingProvider.getModuleInfo(), moduleInfoSet);
}
- return moduleInfoSet.build();
+ return moduleInfoSet.build();
}
- private static void collectYangModuleInfo(final YangModuleInfo moduleInfo, final Builder<YangModuleInfo> moduleInfoSet) {
+ private static void collectYangModuleInfo(final YangModuleInfo moduleInfo,
+ final Builder<YangModuleInfo> moduleInfoSet) {
moduleInfoSet.add(moduleInfo);
- for(YangModuleInfo dependency : moduleInfo.getImportedModules()) {
+ for (YangModuleInfo dependency : moduleInfo.getImportedModules()) {
collectYangModuleInfo(dependency, moduleInfoSet);
}
}
public static boolean isRpcType(final Class<? extends DataObject> targetType) {
- return DataContainer.class.isAssignableFrom(targetType) //
+ return DataContainer.class.isAssignableFrom(targetType) //
&& !ChildOf.class.isAssignableFrom(targetType) //
&& !Notification.class.isAssignableFrom(targetType) //
&& (targetType.getName().endsWith("Input") || targetType.getName().endsWith("Output"));
}
+ /**
+ *
+ * Scans supplied class and returns an iterable of all data children classes.
+ *
+ * @param type YANG Modeled Entity derived from DataContainer
+ * @return Iterable of all data children, which have YANG modeled entity
+ */
+ @SuppressWarnings("unchecked")
+ public static Iterable<Class<? extends DataObject>> getChildrenClasses(final Class<? extends DataContainer> type) {
+ checkArgument(type != null, "Target type must not be null");
+ checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer");
+ List<Class<? extends DataObject>> ret = new LinkedList<>();
+ for (Method method : type.getMethods()) {
+ Optional<Class<? extends DataContainer>> entity = getYangModeledReturnType(method);
+ if (entity.isPresent()) {
+ ret.add((Class<? extends DataObject>) entity.get());
+ }
+ }
+ return ret;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method) {
+ if (method.getName().equals("getClass") || !method.getName().startsWith("get")
+ || method.getParameterTypes().length > 0) {
+ return Optional.absent();
+ }
+
+ @SuppressWarnings("rawtypes")
+ Class returnType = method.getReturnType();
+ if (DataContainer.class.isAssignableFrom(returnType)) {
+ return Optional.<Class<? extends DataContainer>> of(returnType);
+ } else if (List.class.isAssignableFrom(returnType)) {
+ try {
+ return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
+ new Callable<Optional<Class<? extends DataContainer>>>() {
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Optional<Class<? extends DataContainer>> call() {
+ Type listResult = ClassLoaderUtils.getFirstGenericParameter(method
+ .getGenericReturnType());
+ if (listResult instanceof Class
+ && DataContainer.class.isAssignableFrom((Class) listResult)) {
+ return Optional.<Class<? extends DataContainer>> of((Class) listResult);
+ }
+ return Optional.absent();
+ }
+
+ });
+ } catch (Exception e) {
+ LOG.debug("Unable to find YANG modeled return type for {}", method, e);
+ }
+ }
+ return Optional.absent();
+ }
+
}