From 79b9c7a61fa718094a10f46c7a972291def78a11 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 2 Mar 2020 08:18:31 +0100 Subject: [PATCH] Refactor OSGi ModuleInfoSnapshot/BindingRuntimeContext All components acting on EffectiveModel should end up reacting to new generation by publishing components based on it before tearing down the previous instance. Refactor lifecycle by introducing this into both mdsal-dom-schema-osgi and mdsal-binding-runtime-osgi -- providing the infrastructure for mdsal-binding-dom-codec doing the same. This leads to mdsal-binding-dom-codec-osgi to provide atomic updates of BindingDOMCodecServices (and its constituent services), hence we no longer want binding-dom-adapter to publish BindingNormalizedNodeSerializer from its internal service. JIRA: MDSAL-525 Change-Id: Ia6757b3db8068d585638bd8e2d3d17aaadb08955 Signed-off-by: Robert Varga --- artifacts/pom.xml | 5 + .../blueprint/binding-adapter.xml | 6 - binding/mdsal-binding-dom-codec-osgi/pom.xml | 70 ++++++++ .../osgi/OSGiBindingDOMCodecServices.java | 17 ++ .../impl/GlobalBindingDOMCodecServices.java | 125 +++++++++++++ .../codec/osgi/impl/OSGiBindingDOMCodec.java | 160 +++++++++++++++++ .../impl/OSGiBindingDOMCodecServicesImpl.java | 83 +++++++++ .../dom/codec/spi/BindingDOMCodecFactory.java | 19 ++ .../ForwardingBindingDOMCodecServices.java | 154 ++++++++++++++++ .../impl/DefaultBindingDOMCodecFactory.java | 47 +++++ .../osgi/OSGiBindingRuntimeContext.java | 17 ++ .../osgi/impl/BindingRuntimeContextImpl.java | 64 ------- .../impl/GlobalBindingRuntimeContext.java | 55 ++++++ .../runtime/osgi/impl/OSGiBindingRuntime.java | 165 ++++++++++++++++++ .../impl/OSGiBindingRuntimeContextImpl.java | 82 +++++++++ .../spi/ForwardingBindingRuntimeContext.java | 105 +++++++++++ .../spi/ForwardingModuleInfoSnapshot.java | 38 ++++ binding/pom.xml | 1 + .../dom/schema/osgi/ModelGenerationAware.java | 47 +++++ .../schema/osgi/OSGiModuleInfoSnapshot.java | 5 +- .../osgi/impl/OSGiDOMSchemaService.java | 14 +- .../schema/osgi/impl/OSGiModelRuntime.java | 2 +- ...l.java => OSGiModuleInfoSnapshotImpl.java} | 38 ++-- .../impl/RegularYangModuleInfoRegistry.java | 2 +- features/odl-mdsal-binding-runtime/pom.xml | 4 + 25 files changed, 1215 insertions(+), 110 deletions(-) create mode 100644 binding/mdsal-binding-dom-codec-osgi/pom.xml create mode 100644 binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/OSGiBindingDOMCodecServices.java create mode 100644 binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/GlobalBindingDOMCodecServices.java create mode 100644 binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/OSGiBindingDOMCodec.java create mode 100644 binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/OSGiBindingDOMCodecServicesImpl.java create mode 100644 binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/BindingDOMCodecFactory.java create mode 100644 binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java create mode 100644 binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DefaultBindingDOMCodecFactory.java create mode 100644 binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/OSGiBindingRuntimeContext.java delete mode 100644 binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/BindingRuntimeContextImpl.java create mode 100644 binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/GlobalBindingRuntimeContext.java create mode 100644 binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/OSGiBindingRuntime.java create mode 100644 binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/OSGiBindingRuntimeContextImpl.java create mode 100644 binding/mdsal-binding-runtime-spi/src/main/java/org/opendaylight/binding/runtime/spi/ForwardingBindingRuntimeContext.java create mode 100644 binding/mdsal-binding-runtime-spi/src/main/java/org/opendaylight/binding/runtime/spi/ForwardingModuleInfoSnapshot.java create mode 100644 dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/ModelGenerationAware.java rename dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/{OSGiEffectiveModelImpl.java => OSGiModuleInfoSnapshotImpl.java} (63%) diff --git a/artifacts/pom.xml b/artifacts/pom.xml index 59ff6c91cb..cb5bd0f3a6 100644 --- a/artifacts/pom.xml +++ b/artifacts/pom.xml @@ -152,6 +152,11 @@ mdsal-binding-dom-codec 6.0.0-SNAPSHOT + + org.opendaylight.mdsal + mdsal-binding-dom-codec-osgi + 6.0.0-SNAPSHOT + org.opendaylight.mdsal mdsal-binding-runtime-api diff --git a/binding/mdsal-binding-dom-adapter/src/main/resources/org/opendaylight/blueprint/binding-adapter.xml b/binding/mdsal-binding-dom-adapter/src/main/resources/org/opendaylight/blueprint/binding-adapter.xml index b6a0d46fb6..5f2a73bef6 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/resources/org/opendaylight/blueprint/binding-adapter.xml +++ b/binding/mdsal-binding-dom-adapter/src/main/resources/org/opendaylight/blueprint/binding-adapter.xml @@ -12,12 +12,6 @@ - - - org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer - - - diff --git a/binding/mdsal-binding-dom-codec-osgi/pom.xml b/binding/mdsal-binding-dom-codec-osgi/pom.xml new file mode 100644 index 0000000000..bc0240180c --- /dev/null +++ b/binding/mdsal-binding-dom-codec-osgi/pom.xml @@ -0,0 +1,70 @@ + + + + + 4.0.0 + + org.opendaylight.mdsal + dom-parent + 6.0.0-SNAPSHOT + ../../dom/dom-parent + + + mdsal-binding-dom-codec-osgi + bundle + + + + org.opendaylight.mdsal + mdsal-binding-dom-codec + + + org.opendaylight.mdsal + mdsal-binding-runtime-osgi + + + org.osgi + org.osgi.core + + + org.osgi + osgi.cmpn + + + + org.opendaylight.yangtools + mockito-configuration + + + org.opendaylight.mdsal + mdsal-binding-test-model + + + org.opendaylight.mdsal + mdsal-binding-generator-impl + test + + + + + + + org.apache.felix + maven-bundle-plugin + + org.opendaylight.mdsal.binding.dom.codec.osgi + + + <_dsannotations-options>norequirements + + + + + + diff --git a/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/OSGiBindingDOMCodecServices.java b/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/OSGiBindingDOMCodecServices.java new file mode 100644 index 0000000000..5bbdcdf042 --- /dev/null +++ b/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/OSGiBindingDOMCodecServices.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.dom.codec.osgi; + +import com.google.common.annotations.Beta; +import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices; +import org.opendaylight.mdsal.dom.schema.osgi.ModelGenerationAware; + +@Beta +public interface OSGiBindingDOMCodecServices extends ModelGenerationAware { + +} diff --git a/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/GlobalBindingDOMCodecServices.java b/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/GlobalBindingDOMCodecServices.java new file mode 100644 index 0000000000..928d93339e --- /dev/null +++ b/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/GlobalBindingDOMCodecServices.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.dom.codec.osgi.impl; + +import static com.google.common.base.Verify.verifyNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.primitives.UnsignedLong; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingIdentityCodec; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingInstanceIdentifierCodec; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingLazyContainerNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeWriterFactory; +import org.opendaylight.mdsal.binding.dom.codec.osgi.OSGiBindingDOMCodecServices; +import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices; +import org.opendaylight.mdsal.binding.dom.codec.spi.ForwardingBindingDOMCodecServices; +import org.opendaylight.mdsal.binding.dom.codec.spi.LazyActionInputContainerNode; +import org.opendaylight.mdsal.binding.dom.codec.spi.LazyActionOutputContainerNode; +import org.opendaylight.yangtools.yang.binding.Action; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcInput; +import org.opendaylight.yangtools.yang.binding.RpcOutput; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A global {@link BindingDOMCodecServices}. It is injected with latest {@link OSGiBindingDOMCodecServices} generation. + */ +@Beta +@Component(immediate = true, + service = { + BindingDOMCodecServices.class, + BindingNormalizedNodeWriterFactory.class, + BindingNormalizedNodeSerializer.class, + BindingCodecTree.class + }) +public final class GlobalBindingDOMCodecServices extends ForwardingBindingDOMCodecServices { + private static final Logger LOG = LoggerFactory.getLogger(GlobalBindingDOMCodecServices.class); + + @Reference(updated = "update") + volatile OSGiBindingDOMCodecServices osgi = null; + + private BindingDOMCodecServices delegate; + private UnsignedLong generation; + + @Override + public BindingLazyContainerNode toLazyNormalizedNodeActionInput( + final Class> action, final NodeIdentifier identifier, final RpcInput input) { + return new LazyActionInputContainerNode(identifier, input, this, action); + } + + @Override + public BindingLazyContainerNode toLazyNormalizedNodeActionOutput( + final Class> action, final NodeIdentifier identifier, final RpcOutput output) { + return new LazyActionOutputContainerNode(identifier, output, this, action); + } + + @Override + public BindingDataObjectCodecTreeNode getSubtreeCodec(final InstanceIdentifier path) { + return delegate.getSubtreeCodec(path); + } + + @Override + public BindingCodecTreeNode getSubtreeCodec(final YangInstanceIdentifier path) { + return delegate.getSubtreeCodec(path); + } + + @Override + public BindingCodecTreeNode getSubtreeCodec(final Absolute path) { + return delegate.getSubtreeCodec(path); + } + + @Override + public BindingIdentityCodec getIdentityCodec() { + return delegate.getIdentityCodec(); + } + + @Override + public BindingInstanceIdentifierCodec getInstanceIdentifierCodec() { + return delegate.getInstanceIdentifierCodec(); + } + + @Override + protected BindingDOMCodecServices delegate() { + return verifyNotNull(delegate); + } + + void update() { + updateDelegate(); + LOG.info("Global Binding/DOM Codec updated to generation {}", generation); + } + + @Activate + void activate() { + updateDelegate(); + LOG.info("Global Binding/DOM Codec activated with generation {}", generation); + } + + @Deactivate + void deactivate() { + delegate = null; + LOG.info("Global Binding/DOM Codec deactivated"); + } + + private void updateDelegate() { + generation = osgi.getGeneration(); + delegate = osgi.getService(); + } +} diff --git a/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/OSGiBindingDOMCodec.java b/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/OSGiBindingDOMCodec.java new file mode 100644 index 0000000000..53774d1ec4 --- /dev/null +++ b/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/OSGiBindingDOMCodec.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.dom.codec.osgi.impl; + +import static com.google.common.base.Verify.verify; +import static java.util.Objects.requireNonNull; + +import java.util.Collections; +import java.util.Comparator; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; +import org.checkerframework.checker.lock.qual.GuardedBy; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecFactory; +import org.opendaylight.mdsal.binding.runtime.osgi.OSGiBindingRuntimeContext; +import org.osgi.service.component.ComponentFactory; +import org.osgi.service.component.ComponentInstance; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Component(immediate = true) +public final class OSGiBindingDOMCodec { + // TODO: can we get rid of this complexity? + private abstract static class AbstractInstances { + + abstract void add(OSGiBindingRuntimeContext runtimeContext); + + abstract void remove(OSGiBindingRuntimeContext runtimeContext); + + abstract @NonNull AbstractInstances toActive(BindingDOMCodecFactory codecFactory, ComponentFactory factory); + + abstract @NonNull AbstractInstances toInactive(); + } + + private static final class InactiveInstances extends AbstractInstances { + private final Set instances = Collections.newSetFromMap(new IdentityHashMap<>()); + + InactiveInstances() { + + } + + InactiveInstances(final Set keySet) { + instances.addAll(keySet); + } + + @Override + void add(final OSGiBindingRuntimeContext runtimeContext) { + verify(instances.add(runtimeContext), "Duplicate instance %s?!", runtimeContext); + } + + @Override + void remove(final OSGiBindingRuntimeContext runtimeContext) { + instances.remove(runtimeContext); + } + + @Override + AbstractInstances toActive(final BindingDOMCodecFactory codecFactory, final ComponentFactory factory) { + final ActiveInstances active = new ActiveInstances(codecFactory, factory); + instances.stream() + .sorted(Comparator.comparing(OSGiBindingRuntimeContext::getGeneration).reversed()) + .forEach(active::add); + return active; + } + + @Override + AbstractInstances toInactive() { + throw new IllegalStateException("Attempted to deactivate inactive instances"); + } + } + + private static final class ActiveInstances extends AbstractInstances { + private final Map instances = new IdentityHashMap<>(); + private final BindingDOMCodecFactory codecFactory; + private final ComponentFactory factory; + + ActiveInstances(final BindingDOMCodecFactory codecFactory, final ComponentFactory factory) { + this.codecFactory = requireNonNull(codecFactory); + this.factory = requireNonNull(factory); + } + + @Override + void add(final OSGiBindingRuntimeContext runtimeContext) { + final BindingRuntimeContext context = runtimeContext.getService(); + + instances.put(runtimeContext, factory.newInstance(OSGiBindingDOMCodecServicesImpl.props( + runtimeContext.getGeneration(), runtimeContext.getServiceRanking(), + codecFactory.createBindingDOMCodec(context)))); + } + + @Override + void remove(final OSGiBindingRuntimeContext runtimeContext) { + final ComponentInstance instance = instances.remove(runtimeContext); + if (instance != null) { + instance.dispose(); + } else { + LOG.warn("Instance for generation {} not found", runtimeContext.getGeneration()); + } + } + + @Override + AbstractInstances toActive(final BindingDOMCodecFactory ignoreCodecFactory, + final ComponentFactory ignoreFactory) { + throw new IllegalStateException("Attempted to activate active instances"); + } + + @Override + AbstractInstances toInactive() { + instances.values().forEach(ComponentInstance::dispose); + return new InactiveInstances(instances.keySet()); + } + + } + + private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingDOMCodec.class); + + @Reference + BindingDOMCodecFactory codecFactory = null; + + @Reference(target = "(component.factory=" + OSGiBindingDOMCodecServicesImpl.FACTORY_NAME + ")") + ComponentFactory contextFactory = null; + + @GuardedBy("this") + private AbstractInstances instances = new InactiveInstances(); + + @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) + synchronized void addModuleInfoSnapshot(final OSGiBindingRuntimeContext runtimeContext) { + instances.add(runtimeContext); + } + + synchronized void removeModuleInfoSnapshot(final OSGiBindingRuntimeContext runtimeContext) { + instances.remove(runtimeContext); + } + + @Activate + synchronized void activate() { + LOG.info("Binding/DOM Codec activating"); + instances = instances.toActive(codecFactory, contextFactory); + LOG.info("Binding/DOM Codec activated"); + } + + @Deactivate + synchronized void deactivate() { + LOG.info("Binding/DOM Codec deactivating"); + instances = instances.toInactive(); + LOG.info("Binding/DOM Codec deactivated"); + } +} diff --git a/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/OSGiBindingDOMCodecServicesImpl.java b/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/OSGiBindingDOMCodecServicesImpl.java new file mode 100644 index 0000000000..3ecca42830 --- /dev/null +++ b/binding/mdsal-binding-dom-codec-osgi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/osgi/impl/OSGiBindingDOMCodecServicesImpl.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.dom.codec.osgi.impl; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.primitives.UnsignedLong; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Map; +import org.eclipse.jdt.annotation.NonNull; +import org.gaul.modernizer_maven_annotations.SuppressModernizer; +import org.opendaylight.mdsal.binding.dom.codec.osgi.OSGiBindingDOMCodecServices; +import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices; +import org.osgi.framework.Constants; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A Factory Component which implements {@link OSGiBindingDOMCodecServices}. + */ +@Beta +@Component(factory = OSGiBindingDOMCodecServicesImpl.FACTORY_NAME, service = OSGiBindingDOMCodecServices.class) +public final class OSGiBindingDOMCodecServicesImpl implements OSGiBindingDOMCodecServices { + // OSGi DS Component Factory name + static final String FACTORY_NAME = + "org.opendaylight.mdsal.binding.dom.codec.osgi.impl.OSGiBindingDOMCodecServicesImpl"; + + // Keys to for activation properties + @VisibleForTesting + static final String GENERATION = "org.opendaylight.mdsal.binding.dom.codec.osgi.impl.Generation"; + @VisibleForTesting + static final String DELEGATE = "org.opendaylight.mdsal.binding.dom.codec.osgi.impl.BindingDOMCodecServices"; + + private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingDOMCodecServicesImpl.class); + + private BindingDOMCodecServices delegate; + private UnsignedLong generation; + + @Override + public UnsignedLong getGeneration() { + return verifyNotNull(generation); + } + + @Override + public BindingDOMCodecServices getService() { + return verifyNotNull(delegate); + } + + @Activate + void activate(final Map properties) { + generation = (UnsignedLong) verifyNotNull(properties.get(GENERATION)); + delegate = (BindingDOMCodecServices) verifyNotNull(properties.get(DELEGATE)); + LOG.info("Binding/DOM Codec generation {} activated", generation); + } + + @Deactivate + void deactivate() { + delegate = null; + LOG.info("Binding/DOM Codec generation {} deactivated", generation); + } + + @SuppressModernizer + static Dictionary props(final @NonNull UnsignedLong generation, final @NonNull Integer ranking, + final BindingDOMCodecServices delegate) { + final Dictionary ret = new Hashtable<>(4); + ret.put(Constants.SERVICE_RANKING, ranking); + ret.put(GENERATION, generation); + ret.put(DELEGATE, requireNonNull(delegate)); + return ret; + } +} diff --git a/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/BindingDOMCodecFactory.java b/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/BindingDOMCodecFactory.java new file mode 100644 index 0000000000..64e684217d --- /dev/null +++ b/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/BindingDOMCodecFactory.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.dom.codec.spi; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; + +@Beta +@NonNullByDefault +public interface BindingDOMCodecFactory { + + BindingDOMCodecServices createBindingDOMCodec(BindingRuntimeContext context); +} diff --git a/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java b/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java new file mode 100644 index 0000000000..1fe1ccd414 --- /dev/null +++ b/binding/mdsal-binding-dom-codec-spi/src/main/java/org/opendaylight/mdsal/binding/dom/codec/spi/ForwardingBindingDOMCodecServices.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.dom.codec.spi; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ForwardingObject; +import java.time.Instant; +import java.util.Map.Entry; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingLazyContainerNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingStreamEventWriter; +import org.opendaylight.yangtools.yang.binding.Action; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.opendaylight.yangtools.yang.binding.RpcInput; +import org.opendaylight.yangtools.yang.binding.RpcOutput; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; + +@Beta +public abstract class ForwardingBindingDOMCodecServices extends ForwardingObject implements BindingDOMCodecServices { + @Override + protected abstract BindingDOMCodecServices delegate(); + + @Override + public BindingLazyContainerNode toLazyNormalizedNodeActionInput( + final Class> action, final NodeIdentifier identifier, final RpcInput input) { + return delegate().toLazyNormalizedNodeActionInput(action, identifier, input); + } + + @Override + public BindingLazyContainerNode toLazyNormalizedNodeActionOutput( + final Class> action, final NodeIdentifier identifier, final RpcOutput output) { + return delegate().toLazyNormalizedNodeActionOutput(action, identifier, output); + } + + @Override + public YangInstanceIdentifier toYangInstanceIdentifier(final InstanceIdentifier binding) { + return delegate().toYangInstanceIdentifier(binding); + } + + @Override + public InstanceIdentifier fromYangInstanceIdentifier(final YangInstanceIdentifier dom) { + return delegate().getInstanceIdentifierCodec().toBinding(dom); + } + + @Override + public Entry> toNormalizedNode( + final InstanceIdentifier path, final T data) { + return delegate().toNormalizedNode(path, data); + } + + @Override + public ContainerNode toNormalizedNodeNotification(final Notification data) { + return delegate().toNormalizedNodeNotification(data); + } + + @Override + public ContainerNode toNormalizedNodeRpcData(final DataContainer data) { + return delegate().toNormalizedNodeRpcData(data); + } + + @Override + public ContainerNode toNormalizedNodeActionInput(final Class> action, + final RpcInput input) { + return delegate().toNormalizedNodeActionInput(action, input); + } + + @Override + public ContainerNode toNormalizedNodeActionOutput(final Class> action, + final RpcOutput output) { + return delegate().toNormalizedNodeActionOutput(action, output); + } + + @Override + public Entry, DataObject> fromNormalizedNode(final YangInstanceIdentifier path, + final NormalizedNode data) { + return delegate().fromNormalizedNode(path, data); + } + + @Override + public Notification fromNormalizedNodeNotification(final SchemaPath path, final ContainerNode data) { + return delegate().fromNormalizedNodeNotification(path, data); + } + + @Override + public Notification fromNormalizedNodeNotification(final SchemaPath path, final ContainerNode data, + final Instant eventInstant) { + return delegate().fromNormalizedNodeNotification(path, data, eventInstant); + } + + @Override + public DataObject fromNormalizedNodeRpcData(final SchemaPath path, final ContainerNode data) { + return delegate().fromNormalizedNodeRpcData(path, data); + } + + @Override + public T fromNormalizedNodeActionInput(final Class> action, + final ContainerNode input) { + return delegate().fromNormalizedNodeActionInput(action, input); + } + + @Override + public T fromNormalizedNodeActionOutput(final Class> action, + final ContainerNode output) { + return delegate().fromNormalizedNodeActionOutput(action, output); + } + + @Override + public Entry newWriterAndIdentifier( + final InstanceIdentifier path, final NormalizedNodeStreamWriter domWriter) { + return delegate().newWriterAndIdentifier(path, domWriter); + } + + @Override + public BindingStreamEventWriter newWriter(final InstanceIdentifier path, + final NormalizedNodeStreamWriter domWriter) { + return delegate().newWriter(path, domWriter); + } + + @Override + public BindingStreamEventWriter newNotificationWriter(final Class notification, + final NormalizedNodeStreamWriter streamWriter) { + return delegate().newNotificationWriter(notification, streamWriter); + } + + @Override + public BindingStreamEventWriter newActionInputWriter(final Class> action, + final NormalizedNodeStreamWriter domWriter) { + return delegate().newActionInputWriter(action, domWriter); + } + + @Override + public BindingStreamEventWriter newActionOutputWriter(final Class> action, + final NormalizedNodeStreamWriter domWriter) { + return delegate().newActionOutputWriter(action, domWriter); + } + + @Override + public BindingStreamEventWriter newRpcWriter(final Class rpcInputOrOutput, + final NormalizedNodeStreamWriter streamWriter) { + return delegate().newRpcWriter(rpcInputOrOutput,streamWriter); + } +} diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DefaultBindingDOMCodecFactory.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DefaultBindingDOMCodecFactory.java new file mode 100644 index 0000000000..fa7f08c47d --- /dev/null +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DefaultBindingDOMCodecFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.dom.codec.impl; + +import com.google.common.annotations.Beta; +import javax.inject.Singleton; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.kohsuke.MetaInfServices; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecFactory; +import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Beta +@NonNullByDefault +@MetaInfServices +@Singleton +@Component(immediate = true) +public final class DefaultBindingDOMCodecFactory implements BindingDOMCodecFactory { + private static final Logger LOG = LoggerFactory.getLogger(DefaultBindingDOMCodecFactory.class); + + @Override + public BindingDOMCodecServices createBindingDOMCodec(final BindingRuntimeContext context) { + return new BindingCodecContext(context); + } + + @Activate + @SuppressWarnings("static-method") + void activate() { + LOG.info("Binding/DOM Codec enabled"); + } + + @Deactivate + @SuppressWarnings("static-method") + void deactivate() { + LOG.info("Binding/DOM Codec disabled"); + } +} diff --git a/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/OSGiBindingRuntimeContext.java b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/OSGiBindingRuntimeContext.java new file mode 100644 index 0000000000..c5a15ec6ae --- /dev/null +++ b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/OSGiBindingRuntimeContext.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.runtime.osgi; + +import com.google.common.annotations.Beta; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.mdsal.dom.schema.osgi.ModelGenerationAware; + +@Beta +public interface OSGiBindingRuntimeContext extends ModelGenerationAware { + +} diff --git a/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/BindingRuntimeContextImpl.java b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/BindingRuntimeContextImpl.java deleted file mode 100644 index f177833c09..0000000000 --- a/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/BindingRuntimeContextImpl.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.mdsal.binding.runtime.osgi.impl; - -import com.google.common.primitives.UnsignedLong; -import org.opendaylight.binding.runtime.api.AbstractBindingRuntimeContext; -import org.opendaylight.binding.runtime.api.BindingRuntimeContext; -import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator; -import org.opendaylight.binding.runtime.api.BindingRuntimeTypes; -import org.opendaylight.binding.runtime.api.ClassLoadingStrategy; -import org.opendaylight.binding.runtime.api.DefaultBindingRuntimeContext; -import org.opendaylight.mdsal.dom.schema.osgi.OSGiModuleInfoSnapshot; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Deactivate; -import org.osgi.service.component.annotations.Reference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A Factory Component which implements {@link BindingRuntimeContext}. - */ -@Component(service = BindingRuntimeContext.class, immediate = true) -public final class BindingRuntimeContextImpl extends AbstractBindingRuntimeContext { - private static final Logger LOG = LoggerFactory.getLogger(BindingRuntimeContextImpl.class); - - @Reference - OSGiModuleInfoSnapshot effectiveModel = null; - @Reference - BindingRuntimeGenerator generator = null; - - private BindingRuntimeContext delegate; - private UnsignedLong generation; - - @Override - public ClassLoadingStrategy getStrategy() { - return delegate.getStrategy(); - } - - @Override - public BindingRuntimeTypes getTypes() { - return delegate.getTypes(); - } - - @Activate - void activate() { - generation = effectiveModel.getGeneration(); - delegate = DefaultBindingRuntimeContext.create( - generator.generateTypeMapping(effectiveModel.getEffectiveModelContext()), effectiveModel); - - LOG.debug("BindingRuntimeContext generation {} activated", generation); - } - - @Deactivate - void deactivate() { - delegate = null; - LOG.debug("BindingRuntimeContext generation {} deactivated", generation); - } -} diff --git a/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/GlobalBindingRuntimeContext.java b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/GlobalBindingRuntimeContext.java new file mode 100644 index 0000000000..049c69516c --- /dev/null +++ b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/GlobalBindingRuntimeContext.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.runtime.osgi.impl; + +import static com.google.common.base.Verify.verifyNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.primitives.UnsignedLong; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.binding.runtime.spi.ForwardingBindingRuntimeContext; +import org.opendaylight.mdsal.binding.runtime.osgi.OSGiBindingRuntimeContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A global {@link BindingRuntimeContext}. It is injected with latest {@link OSGiBindingRuntimeContext} generation. + */ +@Beta +@Component(service = BindingRuntimeContext.class, immediate = true) +public final class GlobalBindingRuntimeContext extends ForwardingBindingRuntimeContext { + private static final Logger LOG = LoggerFactory.getLogger(GlobalBindingRuntimeContext.class); + + @Reference + OSGiBindingRuntimeContext osgi = null; + + private BindingRuntimeContext delegate; + private UnsignedLong generation; + + @Override + protected BindingRuntimeContext delegate() { + return verifyNotNull(delegate); + } + + @Activate + void activate() { + generation = osgi.getGeneration(); + delegate = osgi.getService(); + LOG.info("Global BindingRuntimeContext generation {} activated", generation); + } + + @Deactivate + void deactivate() { + delegate = null; + LOG.info("Global BindingRuntimeContext generation {} deactivated", generation); + } +} diff --git a/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/OSGiBindingRuntime.java b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/OSGiBindingRuntime.java new file mode 100644 index 0000000000..1fc662dbd6 --- /dev/null +++ b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/OSGiBindingRuntime.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.runtime.osgi.impl; + +import static com.google.common.base.Verify.verify; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import java.util.Collections; +import java.util.Comparator; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; +import org.checkerframework.checker.lock.qual.GuardedBy; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator; +import org.opendaylight.binding.runtime.api.BindingRuntimeTypes; +import org.opendaylight.binding.runtime.api.DefaultBindingRuntimeContext; +import org.opendaylight.binding.runtime.api.ModuleInfoSnapshot; +import org.opendaylight.mdsal.dom.schema.osgi.OSGiModuleInfoSnapshot; +import org.osgi.service.component.ComponentFactory; +import org.osgi.service.component.ComponentInstance; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Beta +@Component(immediate = true) +public final class OSGiBindingRuntime { + // TODO: can we get rid of this complexity? + private abstract static class AbstractInstances { + + abstract void add(OSGiModuleInfoSnapshot snapshot); + + abstract void remove(OSGiModuleInfoSnapshot snapshot); + + abstract @NonNull AbstractInstances toActive(BindingRuntimeGenerator generator, ComponentFactory factory); + + abstract @NonNull AbstractInstances toInactive(); + } + + private static final class InactiveInstances extends AbstractInstances { + private final Set instances = Collections.newSetFromMap(new IdentityHashMap<>()); + + InactiveInstances() { + + } + + InactiveInstances(final Set keySet) { + instances.addAll(keySet); + } + + @Override + void add(final OSGiModuleInfoSnapshot snapshot) { + verify(instances.add(snapshot), "Duplicate instance %s?!", snapshot); + } + + @Override + void remove(final OSGiModuleInfoSnapshot snapshot) { + instances.remove(snapshot); + } + + @Override + AbstractInstances toActive(final BindingRuntimeGenerator generator, final ComponentFactory factory) { + final ActiveInstances active = new ActiveInstances(generator, factory); + instances.stream() + .sorted(Comparator.comparing(OSGiModuleInfoSnapshot::getGeneration).reversed()) + .forEach(active::add); + return active; + } + + @Override + AbstractInstances toInactive() { + throw new IllegalStateException("Attempted to deactivate inactive instances"); + } + } + + private static final class ActiveInstances extends AbstractInstances { + private final Map instances = new IdentityHashMap<>(); + private final BindingRuntimeGenerator generator; + private final ComponentFactory factory; + + ActiveInstances(final BindingRuntimeGenerator generator, final ComponentFactory factory) { + this.generator = requireNonNull(generator); + this.factory = requireNonNull(factory); + } + + @Override + void add(final OSGiModuleInfoSnapshot snapshot) { + final ModuleInfoSnapshot context = snapshot.getService(); + final BindingRuntimeTypes types = generator.generateTypeMapping(context.getEffectiveModelContext()); + + instances.put(snapshot, factory.newInstance(OSGiBindingRuntimeContextImpl.props( + snapshot.getGeneration(), snapshot.getServiceRanking(), + DefaultBindingRuntimeContext.create(types, context)))); + } + + @Override + void remove(final OSGiModuleInfoSnapshot snapshot) { + final ComponentInstance instance = instances.remove(snapshot); + if (instance != null) { + instance.dispose(); + } else { + LOG.warn("Instance for generation {} not found", snapshot.getGeneration()); + } + } + + @Override + AbstractInstances toActive(final BindingRuntimeGenerator ignoreGenerator, + final ComponentFactory ignoreFactory) { + throw new IllegalStateException("Attempted to activate active instances"); + } + + @Override + AbstractInstances toInactive() { + instances.values().forEach(ComponentInstance::dispose); + return new InactiveInstances(instances.keySet()); + } + + } + + private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingRuntime.class); + + @Reference + BindingRuntimeGenerator generator = null; + + @Reference(target = "(component.factory=" + OSGiBindingRuntimeContextImpl.FACTORY_NAME + ")") + ComponentFactory contextFactory = null; + + @GuardedBy("this") + private AbstractInstances instances = new InactiveInstances(); + + @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) + synchronized void addModuleInfoSnapshot(final OSGiModuleInfoSnapshot snapshot) { + instances.add(snapshot); + } + + synchronized void removeModuleInfoSnapshot(final OSGiModuleInfoSnapshot snapshot) { + instances.remove(snapshot); + } + + @Activate + synchronized void activate() { + LOG.info("Binding Runtime activating"); + instances = instances.toActive(generator, contextFactory); + LOG.info("Binding Runtime activated"); + } + + @Deactivate + synchronized void deactivate() { + LOG.info("Binding Runtime deactivating"); + instances = instances.toInactive(); + LOG.info("Binding Runtime deactivated"); + } +} diff --git a/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/OSGiBindingRuntimeContextImpl.java b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/OSGiBindingRuntimeContextImpl.java new file mode 100644 index 0000000000..9fe1a8496d --- /dev/null +++ b/binding/mdsal-binding-runtime-osgi/src/main/java/org/opendaylight/mdsal/binding/runtime/osgi/impl/OSGiBindingRuntimeContextImpl.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.runtime.osgi.impl; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.primitives.UnsignedLong; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Map; +import org.eclipse.jdt.annotation.NonNull; +import org.gaul.modernizer_maven_annotations.SuppressModernizer; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.mdsal.binding.runtime.osgi.OSGiBindingRuntimeContext; +import org.osgi.framework.Constants; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A Factory Component which implements {@link OSGiBindingRuntimeContext}. + */ +@Beta +@Component(factory = OSGiBindingRuntimeContextImpl.FACTORY_NAME, service = OSGiBindingRuntimeContext.class) +public final class OSGiBindingRuntimeContextImpl implements OSGiBindingRuntimeContext { + // OSGi DS Component Factory name + static final String FACTORY_NAME = "org.opendaylight.mdsal.binding.runtime.osgi.impl.OSGiBindingRuntimeContextImpl"; + + // Keys to for activation properties + @VisibleForTesting + static final String GENERATION = "org.opendaylight.mdsal.binding.runtime.osgi.impl.Generation"; + @VisibleForTesting + static final String DELEGATE = "org.opendaylight.mdsal.binding.runtime.osgi.impl.BindingRuntimeContext"; + + private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingRuntimeContextImpl.class); + + private BindingRuntimeContext delegate; + private UnsignedLong generation; + + @Override + public UnsignedLong getGeneration() { + return verifyNotNull(generation); + } + + @Override + public BindingRuntimeContext getService() { + return verifyNotNull(delegate); + } + + @Activate + void activate(final Map properties) { + generation = (UnsignedLong) verifyNotNull(properties.get(GENERATION)); + delegate = (BindingRuntimeContext) verifyNotNull(properties.get(DELEGATE)); + LOG.info("BindingRuntimeContext generation {} activated", generation); + } + + @Deactivate + void deactivate() { + delegate = null; + LOG.info("BindingRuntimeContext generation {} deactivated", generation); + } + + @SuppressModernizer + static Dictionary props(final @NonNull UnsignedLong generation, final @NonNull Integer ranking, + final BindingRuntimeContext delegate) { + final Dictionary ret = new Hashtable<>(4); + ret.put(Constants.SERVICE_RANKING, ranking); + ret.put(GENERATION, generation); + ret.put(DELEGATE, requireNonNull(delegate)); + return ret; + } +} diff --git a/binding/mdsal-binding-runtime-spi/src/main/java/org/opendaylight/binding/runtime/spi/ForwardingBindingRuntimeContext.java b/binding/mdsal-binding-runtime-spi/src/main/java/org/opendaylight/binding/runtime/spi/ForwardingBindingRuntimeContext.java new file mode 100644 index 0000000000..6935214b2b --- /dev/null +++ b/binding/mdsal-binding-runtime-spi/src/main/java/org/opendaylight/binding/runtime/spi/ForwardingBindingRuntimeContext.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.binding.runtime.spi; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ForwardingObject; +import com.google.common.collect.ImmutableMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.binding.runtime.api.BindingRuntimeTypes; +import org.opendaylight.binding.runtime.api.ClassLoadingStrategy; +import org.opendaylight.mdsal.binding.model.api.GeneratedType; +import org.opendaylight.mdsal.binding.model.api.Type; +import org.opendaylight.yangtools.yang.binding.Action; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.model.api.ActionDefinition; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; +import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; +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.SchemaNode; + +@Beta +public abstract class ForwardingBindingRuntimeContext extends ForwardingObject implements BindingRuntimeContext { + @Override + protected abstract BindingRuntimeContext delegate(); + + @Override + public ClassLoadingStrategy getStrategy() { + return delegate().getStrategy(); + } + + @Override + public BindingRuntimeTypes getTypes() { + return delegate().getTypes(); + } + + @Override + public AugmentationSchemaNode getAugmentationDefinition(final Class augClass) { + return delegate().getAugmentationDefinition(augClass); + } + + @Override + public DataSchemaNode getSchemaDefinition(final Class cls) { + return delegate().getSchemaDefinition(cls); + } + + @Override + public ActionDefinition getActionDefinition(final Class> cls) { + return delegate().getActionDefinition(cls); + } + + @Override + public Entry getResolvedAugmentationSchema( + final DataNodeContainer target, final Class> aug) { + return delegate().getResolvedAugmentationSchema(target, aug); + } + + @Override + public Optional getCaseSchemaDefinition(final ChoiceSchemaNode schema, final Class childClass) { + return delegate().getCaseSchemaDefinition(schema, childClass); + } + + @Override + public Entry getTypeWithSchema(final Class type) { + return delegate().getTypeWithSchema(type); + } + + @Override + public Map> getChoiceCaseChildren(final DataNodeContainer schema) { + return delegate().getChoiceCaseChildren(schema); + } + + @Override + public Set> getCases(final Class choice) { + return delegate().getCases(choice); + } + + @Override + public Class getClassForSchema(final SchemaNode childSchema) { + return delegate().getClassForSchema(childSchema); + } + + @Override + public ImmutableMap getAvailableAugmentationTypes(final DataNodeContainer container) { + return delegate().getAvailableAugmentationTypes(container); + } + + @Override + public Class getIdentityClass(final QName input) { + return delegate().getIdentityClass(input); + } +} diff --git a/binding/mdsal-binding-runtime-spi/src/main/java/org/opendaylight/binding/runtime/spi/ForwardingModuleInfoSnapshot.java b/binding/mdsal-binding-runtime-spi/src/main/java/org/opendaylight/binding/runtime/spi/ForwardingModuleInfoSnapshot.java new file mode 100644 index 0000000000..9abfb15b6b --- /dev/null +++ b/binding/mdsal-binding-runtime-spi/src/main/java/org/opendaylight/binding/runtime/spi/ForwardingModuleInfoSnapshot.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.binding.runtime.spi; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ForwardingObject; +import com.google.common.util.concurrent.ListenableFuture; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.binding.runtime.api.ModuleInfoSnapshot; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; + +@Beta +public abstract class ForwardingModuleInfoSnapshot extends ForwardingObject implements ModuleInfoSnapshot { + @Override + protected abstract ModuleInfoSnapshot delegate(); + + @Override + public Class loadClass(final String fullyQualifiedName) throws ClassNotFoundException { + return delegate().loadClass(fullyQualifiedName); + } + + @Override + public @NonNull EffectiveModelContext getEffectiveModelContext() { + return delegate().getEffectiveModelContext(); + } + + @Override + public ListenableFuture getSource(final SourceIdentifier sourceIdentifier) { + return delegate().getSource(sourceIdentifier); + } +} diff --git a/binding/pom.xml b/binding/pom.xml index 58de728158..0cde979d17 100644 --- a/binding/pom.xml +++ b/binding/pom.xml @@ -45,6 +45,7 @@ mdsal-binding-dom-codec mdsal-binding-dom-codec-api mdsal-binding-dom-codec-spi + mdsal-binding-dom-codec-osgi mdsal-binding-api mdsal-binding-spi diff --git a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/ModelGenerationAware.java b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/ModelGenerationAware.java new file mode 100644 index 0000000000..872dd1d6a7 --- /dev/null +++ b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/ModelGenerationAware.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.dom.schema.osgi; + +import com.google.common.annotations.Beta; +import com.google.common.primitives.UnsignedLong; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.concepts.Immutable; +import org.osgi.framework.Constants; + +/** + * Additional interface for exposing linear generation of the backing effective model. Implementations of this interface + * are expected to be effectively-immutable. + * + * @param service type + */ +@Beta +public interface ModelGenerationAware extends Immutable { + + @NonNull UnsignedLong getGeneration(); + + @NonNull S getService(); + + /** + * Get service ranking based on the generation. Higher generation results in a higher ranking. + * + * @return Ranging for use with {@link Constants#SERVICE_RANKING} + */ + default @NonNull Integer getServiceRanking() { + return computeServiceRanking(getGeneration().longValue()); + } + + /** + * Calculate service ranking based on generation. Higher generation results in a higher ranking. + * + * @param generation generation number, treated as an unsigned long + * @return Ranging for use with {@link Constants#SERVICE_RANKING} + */ + static @NonNull Integer computeServiceRanking(final long generation) { + return generation >= 0 && generation <= Integer.MAX_VALUE ? (int) generation : Integer.MAX_VALUE; + } +} diff --git a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/OSGiModuleInfoSnapshot.java b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/OSGiModuleInfoSnapshot.java index f68b197d55..d12a333818 100644 --- a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/OSGiModuleInfoSnapshot.java +++ b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/OSGiModuleInfoSnapshot.java @@ -8,15 +8,12 @@ package org.opendaylight.mdsal.dom.schema.osgi; import com.google.common.annotations.Beta; -import com.google.common.primitives.UnsignedLong; -import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.binding.runtime.api.ModuleInfoSnapshot; /** * Combination of a {@link ModuleInfoSnapshot} with a linear generation. */ @Beta -public interface OSGiModuleInfoSnapshot extends ModuleInfoSnapshot { +public interface OSGiModuleInfoSnapshot extends ModelGenerationAware { - @NonNull UnsignedLong getGeneration(); } diff --git a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiDOMSchemaService.java b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiDOMSchemaService.java index 768ad5f27c..38e4f2d2a3 100644 --- a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiDOMSchemaService.java +++ b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiDOMSchemaService.java @@ -12,6 +12,7 @@ import static java.util.Objects.requireNonNull; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.binding.runtime.api.ModuleInfoSnapshot; import org.opendaylight.mdsal.dom.api.DOMSchemaService; import org.opendaylight.mdsal.dom.schema.osgi.OSGiModuleInfoSnapshot; import org.opendaylight.mdsal.dom.spi.AbstractDOMSchemaService; @@ -44,11 +45,11 @@ public final class OSGiDOMSchemaService extends AbstractDOMSchemaService { private final List listeners = new CopyOnWriteArrayList<>(); - private volatile OSGiModuleInfoSnapshot currentContext; + private volatile ModuleInfoSnapshot currentSnapshot; @Override public EffectiveModelContext getGlobalContext() { - return currentContext.getEffectiveModelContext(); + return currentSnapshot.getEffectiveModelContext(); } @Override @@ -58,10 +59,11 @@ public final class OSGiDOMSchemaService extends AbstractDOMSchemaService { } @Reference(fieldOption = FieldOption.REPLACE) - void bindContext(final OSGiModuleInfoSnapshot newContext) { - final EffectiveModelContext ctx = newContext.getEffectiveModelContext(); - LOG.trace("Updating context to {}", ctx); - currentContext = newContext; + void bindSnapshot(final OSGiModuleInfoSnapshot newContext) { + LOG.trace("Updating context to generation {}", newContext.getGeneration()); + final ModuleInfoSnapshot snapshot = newContext.getService(); + final EffectiveModelContext ctx = snapshot.getEffectiveModelContext(); + currentSnapshot = snapshot; listeners.forEach(listener -> notifyListener(ctx, listener)); } diff --git a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiModelRuntime.java b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiModelRuntime.java index c7041d77eb..b77063f323 100644 --- a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiModelRuntime.java +++ b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiModelRuntime.java @@ -23,7 +23,7 @@ public final class OSGiModelRuntime { @Reference YangParserFactory parserFactory = null; - @Reference(target = "(component.factory=" + OSGiEffectiveModelImpl.FACTORY_NAME + ")") + @Reference(target = "(component.factory=" + OSGiModuleInfoSnapshotImpl.FACTORY_NAME + ")") ComponentFactory contextFactory = null; private YangModuleInfoScanner bundleTracker = null; diff --git a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiEffectiveModelImpl.java b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiModuleInfoSnapshotImpl.java similarity index 63% rename from dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiEffectiveModelImpl.java rename to dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiModuleInfoSnapshotImpl.java index 1608e5d032..cffdd2dc01 100644 --- a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiEffectiveModelImpl.java +++ b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/OSGiModuleInfoSnapshotImpl.java @@ -13,16 +13,13 @@ import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; import com.google.common.primitives.UnsignedLong; -import com.google.common.util.concurrent.ListenableFuture; import java.util.Dictionary; import java.util.Hashtable; import java.util.Map; import org.gaul.modernizer_maven_annotations.SuppressModernizer; import org.opendaylight.binding.runtime.api.ModuleInfoSnapshot; +import org.opendaylight.mdsal.dom.schema.osgi.ModelGenerationAware; import org.opendaylight.mdsal.dom.schema.osgi.OSGiModuleInfoSnapshot; -import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; -import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; -import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.osgi.framework.Constants; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -31,9 +28,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Beta -@Component(factory = OSGiEffectiveModelImpl.FACTORY_NAME, - service = { OSGiModuleInfoSnapshot.class, ModuleInfoSnapshot.class }) -public final class OSGiEffectiveModelImpl implements OSGiModuleInfoSnapshot { +@Component(factory = OSGiModuleInfoSnapshotImpl.FACTORY_NAME, service = OSGiModuleInfoSnapshot.class) +public final class OSGiModuleInfoSnapshotImpl implements OSGiModuleInfoSnapshot { // OSGi DS Component Factory name static final String FACTORY_NAME = "org.opendaylight.mdsal.dom.schema.osgi.impl.OSGiEffectiveModelImpl"; @@ -43,54 +39,40 @@ public final class OSGiEffectiveModelImpl implements OSGiModuleInfoSnapshot { @VisibleForTesting static final String DELEGATE = "org.opendaylight.mdsal.dom.schema.osgi.impl.ModuleInfoSnapshot"; - private static final Logger LOG = LoggerFactory.getLogger(OSGiEffectiveModelImpl.class); + private static final Logger LOG = LoggerFactory.getLogger(OSGiModuleInfoSnapshotImpl.class); private ModuleInfoSnapshot delegate; private UnsignedLong generation; @Override public UnsignedLong getGeneration() { - return generation; + return verifyNotNull(generation); } @Override - public EffectiveModelContext getEffectiveModelContext() { - return delegate.getEffectiveModelContext(); - } - - @Override - public ListenableFuture getSource(final SourceIdentifier sourceIdentifier) { - return delegate.getSource(sourceIdentifier); - } - - @Override - public Class loadClass(final String fullyQualifiedName) throws ClassNotFoundException { - return delegate.loadClass(fullyQualifiedName); + public ModuleInfoSnapshot getService() { + return verifyNotNull(delegate); } @Activate void activate(final Map properties) { generation = (UnsignedLong) verifyNotNull(properties.get(GENERATION)); delegate = (ModuleInfoSnapshot) verifyNotNull(properties.get(DELEGATE)); - LOG.debug("ClassLoadingEffectiveModelContext generation {} activated", generation); + LOG.info("EffectiveModelContext generation {} activated", generation); } @Deactivate void deactivate() { delegate = null; - LOG.debug("ClassLoadingEffectiveModelContext generation {} deactivated", generation); + LOG.info("EffectiveModelContext generation {} deactivated", generation); } @SuppressModernizer static Dictionary props(final long generation, final ModuleInfoSnapshot delegate) { final Dictionary ret = new Hashtable<>(4); - ret.put(Constants.SERVICE_RANKING, ranking(generation)); + ret.put(Constants.SERVICE_RANKING, ModelGenerationAware.computeServiceRanking(generation)); ret.put(GENERATION, UnsignedLong.fromLongBits(generation)); ret.put(DELEGATE, requireNonNull(delegate)); return ret; } - - private static Integer ranking(final long generation) { - return generation >= 0 && generation <= Integer.MAX_VALUE ? (int) generation : Integer.MAX_VALUE; - } } diff --git a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/RegularYangModuleInfoRegistry.java b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/RegularYangModuleInfoRegistry.java index aff0e1f8ea..09d922d4a9 100644 --- a/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/RegularYangModuleInfoRegistry.java +++ b/dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/RegularYangModuleInfoRegistry.java @@ -97,7 +97,7 @@ final class RegularYangModuleInfoRegistry extends YangModuleInfoRegistry { final ComponentInstance newInstance = contextFactory.newInstance( - OSGiEffectiveModelImpl.props(nextGeneration(), newSnapshot)); + OSGiModuleInfoSnapshotImpl.props(nextGeneration(), newSnapshot)); if (currentInstance != null) { currentInstance.dispose(); } diff --git a/features/odl-mdsal-binding-runtime/pom.xml b/features/odl-mdsal-binding-runtime/pom.xml index 3820001189..2c95927e04 100644 --- a/features/odl-mdsal-binding-runtime/pom.xml +++ b/features/odl-mdsal-binding-runtime/pom.xml @@ -61,6 +61,10 @@ + + org.opendaylight.mdsal + mdsal-binding-dom-codec-osgi + org.opendaylight.mdsal mdsal-binding-runtime-osgi -- 2.36.6