X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-binding-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fbinding%2Fimpl%2FBindingToNormalizedNodeCodec.java;h=776691c0475aef6d969d3262176aaa86ce3bbd6d;hb=refs%2Fchanges%2F07%2F19607%2F5;hp=3795ad3bac8c4787bda7ff27cd22668b398eeb33;hpb=96246098ccbe56af4f688d93dfffc9fdf62713ab;p=controller.git diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java index 3795ad3bac..776691c047 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java @@ -15,12 +15,16 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableBiMap; import java.lang.reflect.Method; +import java.net.URI; import java.util.AbstractMap.SimpleEntry; +import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; @@ -30,6 +34,7 @@ import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeNode; import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.binding.data.codec.impl.MissingSchemaException; import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; import org.opendaylight.yangtools.yang.binding.BindingMapping; @@ -51,28 +56,51 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFactory, BindingNormalizedNodeSerializer, SchemaContextListener, AutoCloseable { + private static final long WAIT_DURATION_SEC = 5; + private static final Logger LOG = LoggerFactory.getLogger(BindingToNormalizedNodeCodec.class); + private final BindingNormalizedNodeCodecRegistry codecRegistry; - private DataNormalizer legacyToNormalized; + private final GeneratedClassLoadingStrategy classLoadingStrategy; - private BindingRuntimeContext runtimeContext; + private final FutureSchema futureSchema; private final LoadingCache, YangInstanceIdentifier> iiCache = CacheBuilder.newBuilder() .softValues().build(new CacheLoader, YangInstanceIdentifier>() { @Override public YangInstanceIdentifier load(final InstanceIdentifier key) throws Exception { - return toYangInstanceIdentifier(key); + return toYangInstanceIdentifierBlocking(key); } }); + private BindingRuntimeContext runtimeContext; + private DataNormalizer legacyToNormalized; + public BindingToNormalizedNodeCodec(final GeneratedClassLoadingStrategy classLoadingStrategy, final BindingNormalizedNodeCodecRegistry codecRegistry) { + this(classLoadingStrategy,codecRegistry,false); + + } + + public BindingToNormalizedNodeCodec(final GeneratedClassLoadingStrategy classLoadingStrategy, + final BindingNormalizedNodeCodecRegistry codecRegistry,final boolean waitForSchema) { this.classLoadingStrategy = Preconditions.checkNotNull(classLoadingStrategy,"classLoadingStrategy"); this.codecRegistry = Preconditions.checkNotNull(codecRegistry,"codecRegistry"); + this.futureSchema = waitForSchema ? new FutureSchema(WAIT_DURATION_SEC, TimeUnit.SECONDS) : null; + } + final YangInstanceIdentifier toYangInstanceIdentifierBlocking(final InstanceIdentifier binding) { + try { + return codecRegistry.toYangInstanceIdentifier(binding); + } catch (final MissingSchemaException e) { + waitForSchema(decompose(binding),e); + return codecRegistry.toYangInstanceIdentifier(binding); + } } /** @@ -203,6 +231,9 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto legacyToNormalized = new DataNormalizer (arg0); runtimeContext = BindingRuntimeContext.create(classLoadingStrategy, arg0); codecRegistry.onBindingRuntimeContextUpdated(runtimeContext); + if(futureSchema != null) { + futureSchema.onRuntimeContextUpdated(runtimeContext); + } } public Function>, Optional> deserializeFunction(final InstanceIdentifier path) { @@ -244,8 +275,7 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto // FIXME: This should be probably part of Binding Runtime context public ImmutableBiMap getRpcMethodToSchemaPath(final Class key) { - final QNameModule moduleName = BindingReflections.getQNameModule(key); - final Module module = runtimeContext.getSchemaContext().findModuleByNamespaceAndRevision(moduleName.getNamespace(), moduleName.getRevision()); + final Module module = getModuleBlocking(key); final ImmutableBiMap.Builder ret = ImmutableBiMap.builder(); try { for (final RpcDefinition rpcDef : module.getRpcs()) { @@ -259,8 +289,7 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto } protected ImmutableBiMap getRpcMethodToSchema(final Class key) { - final QNameModule moduleName = BindingReflections.getQNameModule(key); - final Module module = runtimeContext.getSchemaContext().findModuleByNamespaceAndRevision(moduleName.getNamespace(), moduleName.getRevision()); + final Module module = getModuleBlocking(key); final ImmutableBiMap.Builder ret = ImmutableBiMap.builder(); try { for (final RpcDefinition rpcDef : module.getRpcs()) { @@ -273,6 +302,28 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto return ret.build(); } + private Module getModuleBlocking(final Class modeledClass) { + final QNameModule moduleName = BindingReflections.getQNameModule(modeledClass); + final URI namespace = moduleName.getNamespace(); + final Date revision = moduleName.getRevision(); + Module module = runtimeContext.getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision); + if(module == null && futureSchema != null && futureSchema.waitForSchema(namespace,revision)) { + module = runtimeContext.getSchemaContext().findModuleByNamespaceAndRevision(namespace, revision); + } + Preconditions.checkState(module != null, "Schema for %s is not available.", modeledClass); + return module; + } + + private void waitForSchema(final Collection> binding, final MissingSchemaException e) { + if(futureSchema != null) { + LOG.warn("Blocking thread to wait for schema convergence updates for {} {}",futureSchema.getDuration(), futureSchema.getUnit()); + if(!futureSchema.waitForSchema(binding)) { + return; + } + } + throw e; + } + private Method findRpcMethod(final Class key, final RpcDefinition rpcDef) throws NoSuchMethodException { final String methodName = BindingMapping.getMethodName(rpcDef.getQName()); if(rpcDef.getInput() != null) { @@ -307,6 +358,7 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto return new SimpleEntry, BindingCodecTreeNode>(bindingPath, codecContext); } + @SuppressWarnings("unchecked") public Set> getNotificationClasses(final Set interested) { final Set> result = new HashSet<>(); final Set knownNotifications = runtimeContext.getSchemaContext().getNotifications(); @@ -316,10 +368,19 @@ public final class BindingToNormalizedNodeCodec implements BindingCodecTreeFacto result.add((Class) runtimeContext.getClassForSchema(notification)); } catch (final IllegalStateException e) { // Ignore + LOG.warn("Class for {} is currently not known.",notification.getPath(),e); } } } return result; } + private static Collection> decompose(final InstanceIdentifier path) { + final Set> clazzes = new HashSet<>(); + for(final InstanceIdentifier.PathArgument arg : path.getPathArguments()) { + clazzes.add(arg.getType()); + } + return clazzes; + } + }