From: Robert Varga Date: Fri, 21 Feb 2020 19:15:14 +0000 (+0100) Subject: Remove blueprint component X-Git-Tag: v6.0.0~139 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=4e07ad0839cb36b1d54562683547a7e2fbd49608;p=mdsal.git Remove blueprint component A thorough review of MD-SAL lifecycle has shown we bend over backwards to maintain immutable service view for blueprint containers. The basic mindset behind blueprint goes directly against MD-SAL's view of immutable objects. Specifically, hides all dynamic services behind proxies, isolating us from the Service Registry. Hence we cannot use the registry to exchange state -- which defeats the point of having the service registry. OSGi Declarative Services use static binding (by default) and allow us to expose component lifecycle, so that it can be correctly responded to. We therefore remove any pretense we are endorsing blueprint -- because we are not. Everybody should decompose their application properly and use DS for OSGi. JIRA: MDSAL-413 Change-Id: I6a53e2f9da80a52d4d53371669158e9db7452c1e Signed-off-by: Robert Varga --- diff --git a/blueprint/mdsal-blueprint-binding/pom.xml b/blueprint/mdsal-blueprint-binding/pom.xml deleted file mode 100644 index 6c13afdeb6..0000000000 --- a/blueprint/mdsal-blueprint-binding/pom.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - - - 4.0.0 - - org.opendaylight.mdsal - dom-parent - 6.0.0-SNAPSHOT - ../../dom/dom-parent - - - mdsal-blueprint-binding - bundle - ${project.artifactId} - 6.0.0-SNAPSHOT - - - - com.google.guava - guava - - - org.apache.aries.blueprint - org.apache.aries.blueprint.core - provided - - - org.apache.aries - org.apache.aries.util - - - org.opendaylight.mdsal - mdsal-dom-api - - - org.opendaylight.mdsal - mdsal-dom-spi - - - org.opendaylight.mdsal - mdsal-binding-api - - - org.opendaylight.mdsal - mdsal-binding-dom-codec - - - org.opendaylight.yangtools - yang-data-codec-xml - - - org.osgi - org.osgi.core - - - org.osgi - org.osgi.compendium - - - org.slf4j - slf4j-api - - - org.osgi - org.osgi.service.event - - - com.google.truth - truth - - - - org.opendaylight.mdsal - mdsal-binding-dom-adapter - test-jar - test - - - org.opendaylight.mdsal - mdsal-binding-dom-adapter - test - - - - - - - org.apache.felix - maven-bundle-plugin - - - org.opendaylight.controller.blueprint.BlueprintBundleTracker - - - - - - diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintBundleTracker.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintBundleTracker.java deleted file mode 100644 index 8c45359103..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintBundleTracker.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Dictionary; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.List; -import javax.annotation.Nullable; -import org.apache.aries.blueprint.NamespaceHandler; -import org.apache.aries.blueprint.services.BlueprintExtenderService; -import org.apache.aries.quiesce.participant.QuiesceParticipant; -import org.apache.aries.util.AriesFrameworkUtil; -import org.opendaylight.controller.blueprint.ext.OpendaylightNamespaceHandler; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleEvent; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; -import org.osgi.framework.SynchronousBundleListener; -import org.osgi.service.blueprint.container.BlueprintContainer; -import org.osgi.service.blueprint.container.BlueprintEvent; -import org.osgi.service.blueprint.container.BlueprintListener; -import org.osgi.util.tracker.BundleTracker; -import org.osgi.util.tracker.BundleTrackerCustomizer; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class is created in bundle activation and scans ACTIVE bundles for blueprint XML files located under - * the well-known org/opendaylight/blueprint/ path and deploys the XML files via the Aries - * BlueprintExtenderService. This path differs from the standard OSGI-INF/blueprint path to allow for - * controlled deployment of blueprint containers in an orderly manner. - * - * @author Thomas Pantelis - */ -public class BlueprintBundleTracker implements BundleActivator, BundleTrackerCustomizer, BlueprintListener, - SynchronousBundleListener { - private static final Logger LOG = LoggerFactory.getLogger(BlueprintBundleTracker.class); - private static final String BLUEPRINT_FILE_PATH = "org/opendaylight/blueprint/"; - private static final String BLUEPRINT_FLE_PATTERN = "*.xml"; - private static final long SYSTEM_BUNDLE_ID = 0; - - private ServiceTracker blueprintExtenderServiceTracker; - private ServiceTracker quiesceParticipantTracker; - private BundleTracker bundleTracker; - private BundleContext bundleContext; - private volatile BlueprintExtenderService blueprintExtenderService; - private volatile QuiesceParticipant quiesceParticipant; - private volatile ServiceRegistration blueprintContainerRestartReg; - private volatile BlueprintContainerRestartServiceImpl restartService; - private volatile boolean shuttingDown; - private ServiceRegistration eventHandlerReg; - private ServiceRegistration namespaceReg; - - /** - * Implemented from BundleActivator. - */ - @Override - public void start(final BundleContext context) { - LOG.info("Starting {}", getClass().getSimpleName()); - - restartService = new BlueprintContainerRestartServiceImpl(); - - bundleContext = context; - - registerBlueprintEventHandler(context); - - registerNamespaceHandler(context); - - bundleTracker = new BundleTracker<>(context, Bundle.ACTIVE, this); - - blueprintExtenderServiceTracker = new ServiceTracker<>(context, BlueprintExtenderService.class.getName(), - new ServiceTrackerCustomizer() { - @Override - public BlueprintExtenderService addingService( - final ServiceReference reference) { - return onBlueprintExtenderServiceAdded(reference); - } - - @Override - public void modifiedService(final ServiceReference reference, - final BlueprintExtenderService service) { - } - - @Override - public void removedService(final ServiceReference reference, - final BlueprintExtenderService service) { - } - }); - blueprintExtenderServiceTracker.open(); - - quiesceParticipantTracker = new ServiceTracker<>(context, QuiesceParticipant.class.getName(), - new ServiceTrackerCustomizer() { - @Override - public QuiesceParticipant addingService( - final ServiceReference reference) { - return onQuiesceParticipantAdded(reference); - } - - @Override - public void modifiedService(final ServiceReference reference, - final QuiesceParticipant service) { - } - - @Override - public void removedService(final ServiceReference reference, - final QuiesceParticipant service) { - } - }); - quiesceParticipantTracker.open(); - } - - private QuiesceParticipant onQuiesceParticipantAdded(final ServiceReference reference) { - quiesceParticipant = reference.getBundle().getBundleContext().getService(reference); - - LOG.debug("Got QuiesceParticipant"); - - restartService.setQuiesceParticipant(quiesceParticipant); - - return quiesceParticipant; - } - - private BlueprintExtenderService onBlueprintExtenderServiceAdded( - final ServiceReference reference) { - blueprintExtenderService = reference.getBundle().getBundleContext().getService(reference); - bundleTracker.open(); - - bundleContext.addBundleListener(BlueprintBundleTracker.this); - - LOG.debug("Got BlueprintExtenderService"); - - restartService.setBlueprintExtenderService(blueprintExtenderService); - - blueprintContainerRestartReg = bundleContext.registerService( - BlueprintContainerRestartService.class, restartService, new Hashtable<>()); - - return blueprintExtenderService; - } - - private void registerNamespaceHandler(final BundleContext context) { - Dictionary props = new Hashtable<>(); - props.put("osgi.service.blueprint.namespace", OpendaylightNamespaceHandler.NAMESPACE_1_0_0); - namespaceReg = context.registerService(NamespaceHandler.class, new OpendaylightNamespaceHandler(), props); - } - - private void registerBlueprintEventHandler(final BundleContext context) { - eventHandlerReg = context.registerService(BlueprintListener.class, this, new Hashtable<>()); - } - - /** - * Implemented from BundleActivator. - */ - @Override - public void stop(final BundleContext context) { - bundleTracker.close(); - blueprintExtenderServiceTracker.close(); - quiesceParticipantTracker.close(); - - AriesFrameworkUtil.safeUnregisterService(eventHandlerReg); - AriesFrameworkUtil.safeUnregisterService(namespaceReg); - AriesFrameworkUtil.safeUnregisterService(blueprintContainerRestartReg); - } - - /** - * Implemented from SynchronousBundleListener. - */ - @Override - public void bundleChanged(final BundleEvent event) { - // If the system bundle (id 0) is stopping, do an orderly shutdown of all blueprint containers. On - // shutdown the system bundle is stopped first. - if (event.getBundle().getBundleId() == SYSTEM_BUNDLE_ID && event.getType() == BundleEvent.STOPPING) { - shutdownAllContainers(); - } - } - - /** - * Implemented from BundleActivator. - */ - @Override - public Bundle addingBundle(final Bundle bundle, final BundleEvent event) { - modifiedBundle(bundle, event, bundle); - return bundle; - } - - /** - * Implemented from BundleTrackerCustomizer. - */ - @Override - public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Bundle object) { - if (shuttingDown) { - return; - } - - if (bundle.getState() == Bundle.ACTIVE) { - List paths = findBlueprintPaths(bundle); - - if (!paths.isEmpty()) { - LOG.info("Creating blueprint container for bundle {} with paths {}", bundle, paths); - - blueprintExtenderService.createContainer(bundle, paths); - } - } - } - - /** - * Implemented from BundleTrackerCustomizer. - */ - @Override - public void removedBundle(final Bundle bundle, final BundleEvent event, final Bundle object) { - // BlueprintExtenderService will handle this. - } - - /** - * Implemented from BlueprintListener to listen for blueprint events. - * - * @param event the event to handle - */ - @Override - public void blueprintEvent(BlueprintEvent event) { - if (event.getType() == BlueprintEvent.CREATED) { - LOG.info("Blueprint container for bundle {} was successfully created", event.getBundle()); - return; - } - - // If the container timed out waiting for dependencies, we'll destroy it and start it again. This - // is indicated via a non-null DEPENDENCIES property containing the missing dependencies. The - // default timeout is 5 min and ideally we would set this to infinite but the timeout can only - // be set at the bundle level in the manifest - there's no way to set it globally. - if (event.getType() == BlueprintEvent.FAILURE && event.getDependencies() != null) { - Bundle bundle = event.getBundle(); - - List paths = findBlueprintPaths(bundle); - if (!paths.isEmpty()) { - LOG.warn("Blueprint container for bundle {} timed out waiting for dependencies - restarting it", - bundle); - - restartService.restartContainer(bundle, paths); - } - } - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - static List findBlueprintPaths(final Bundle bundle) { - Enumeration rntries = bundle.findEntries(BLUEPRINT_FILE_PATH, BLUEPRINT_FLE_PATTERN, false); - if (rntries == null) { - return Collections.emptyList(); - } else { - return Collections.list((Enumeration)rntries); - } - } - - private void shutdownAllContainers() { - shuttingDown = true; - - restartService.close(); - - LOG.info("Shutting down all blueprint containers..."); - - Collection containerBundles = new HashSet<>(Arrays.asList(bundleContext.getBundles())); - while (!containerBundles.isEmpty()) { - // For each iteration of getBundlesToDestroy, as containers are destroyed, other containers become - // eligible to be destroyed. We loop until we've destroyed them all. - for (Bundle bundle : getBundlesToDestroy(containerBundles)) { - containerBundles.remove(bundle); - BlueprintContainer container = blueprintExtenderService.getContainer(bundle); - if (container != null) { - blueprintExtenderService.destroyContainer(bundle, container); - } - } - } - - LOG.info("Shutdown of blueprint containers complete"); - } - - private List getBundlesToDestroy(final Collection containerBundles) { - List bundlesToDestroy = new ArrayList<>(); - - // Find all container bundles that either have no registered services or whose services are no - // longer in use. - for (Bundle bundle : containerBundles) { - ServiceReference[] references = bundle.getRegisteredServices(); - int usage = 0; - if (references != null) { - for (ServiceReference reference : references) { - usage += getServiceUsage(reference); - } - } - - LOG.debug("Usage for bundle {} is {}", bundle, usage); - if (usage == 0) { - bundlesToDestroy.add(bundle); - } - } - - if (!bundlesToDestroy.isEmpty()) { - bundlesToDestroy.sort((b1, b2) -> (int) (b2.getLastModified() - b1.getLastModified())); - - LOG.debug("Selected bundles {} for destroy (no services in use)", bundlesToDestroy); - } else { - // There's either no more container bundles or they all have services being used. For - // the latter it means there's either circular service usage or a service is being used - // by a non-container bundle. But we need to make progress so we pick the bundle with a - // used service with the highest service ID. Each service is assigned a monotonically - // increasing ID as they are registered. By picking the bundle with the highest service - // ID, we're picking the bundle that was (likely) started after all the others and thus - // is likely the safest to destroy at this point. - - Bundle bundle = findBundleWithHighestUsedServiceId(containerBundles); - if (bundle != null) { - bundlesToDestroy.add(bundle); - } - - LOG.debug("Selected bundle {} for destroy (lowest ranking service or highest service ID)", - bundlesToDestroy); - } - - return bundlesToDestroy; - } - - @Nullable - private Bundle findBundleWithHighestUsedServiceId(final Collection containerBundles) { - ServiceReference highestServiceRef = null; - for (Bundle bundle : containerBundles) { - ServiceReference[] references = bundle.getRegisteredServices(); - if (references == null) { - continue; - } - - for (ServiceReference reference : references) { - // We did check the service usage previously but it's possible the usage has changed since then. - if (getServiceUsage(reference) == 0) { - continue; - } - - // Choose 'reference' if it has a lower service ranking or, if the rankings are equal - // which is usually the case, if it has a higher service ID. For the latter the < 0 - // check looks backwards but that's how ServiceReference#compareTo is documented to work. - if (highestServiceRef == null || reference.compareTo(highestServiceRef) < 0) { - LOG.debug("Currently selecting bundle {} for destroy (with reference {})", bundle, reference); - highestServiceRef = reference; - } - } - } - - return highestServiceRef == null ? null : highestServiceRef.getBundle(); - } - - private static int getServiceUsage(final ServiceReference ref) { - Bundle[] usingBundles = ref.getUsingBundles(); - return usingBundles != null ? usingBundles.length : 0; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintContainerRestartService.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintContainerRestartService.java deleted file mode 100644 index 522415b6fb..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintContainerRestartService.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint; - -import org.osgi.framework.Bundle; - -/** - * Interface that restarts blueprint containers. - * - * @author Thomas Pantelis - */ -public interface BlueprintContainerRestartService { - - /** - * Restarts the blueprint container for the given bundle and all its dependent containers in an atomic - * and orderly manner. The dependent containers are identified by walking the OSGi service dependency - * hierarchies for the service(s) provided by the given bundle. - * - * @param bundle the bundle to restart - */ - void restartContainerAndDependents(Bundle bundle); -} \ No newline at end of file diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintContainerRestartServiceImpl.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintContainerRestartServiceImpl.java deleted file mode 100644 index 2b2af15df9..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/BlueprintContainerRestartServiceImpl.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Deque; -import java.util.Hashtable; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.apache.aries.blueprint.services.BlueprintExtenderService; -import org.apache.aries.quiesce.participant.QuiesceParticipant; -import org.apache.aries.util.AriesFrameworkUtil; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.blueprint.container.BlueprintEvent; -import org.osgi.service.blueprint.container.BlueprintListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implementation of the BlueprintContainerRestartService. - * - * @author Thomas Pantelis - */ -class BlueprintContainerRestartServiceImpl implements AutoCloseable, BlueprintContainerRestartService { - private static final Logger LOG = LoggerFactory.getLogger(BlueprintContainerRestartServiceImpl.class); - private static final int CONTAINER_CREATE_TIMEOUT_IN_MINUTES = 5; - - private final ExecutorService restartExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() - .setDaemon(true).setNameFormat("BlueprintContainerRestartService").build()); - - private BlueprintExtenderService blueprintExtenderService; - private QuiesceParticipant quiesceParticipant; - - void setBlueprintExtenderService(final BlueprintExtenderService blueprintExtenderService) { - this.blueprintExtenderService = blueprintExtenderService; - } - - void setQuiesceParticipant(final QuiesceParticipant quiesceParticipant) { - this.quiesceParticipant = quiesceParticipant; - } - - public void restartContainer(final Bundle bundle, final List paths) { - LOG.debug("restartContainer for bundle {}", bundle); - - if (restartExecutor.isShutdown()) { - LOG.debug("Already closed - returning"); - return; - } - - restartExecutor.execute(() -> { - blueprintExtenderService.destroyContainer(bundle, blueprintExtenderService.getContainer(bundle)); - blueprintExtenderService.createContainer(bundle, paths); - }); - } - - @Override - public void restartContainerAndDependents(final Bundle bundle) { - if (restartExecutor.isShutdown()) { - return; - } - - LOG.debug("restartContainerAndDependents for bundle {}", bundle); - - restartExecutor.execute(() -> restartContainerAndDependentsInternal(bundle)); - } - - private void restartContainerAndDependentsInternal(final Bundle forBundle) { - Preconditions.checkNotNull(blueprintExtenderService); - Preconditions.checkNotNull(quiesceParticipant); - - // We use a LinkedHashSet to preserve insertion order as we walk the service usage hierarchy. - Set containerBundlesSet = new LinkedHashSet<>(); - findDependentContainersRecursively(forBundle, containerBundlesSet); - - List containerBundles = new ArrayList<>(containerBundlesSet); - - LOG.info("Restarting blueprint containers for bundle {} and its dependent bundles {}", forBundle, - containerBundles.subList(1, containerBundles.size())); - - // The blueprint containers are created asynchronously so we register a handler for blueprint events - // that are sent when a container is complete, successful or not. The CountDownLatch tells when all - // containers are complete. This is done to ensure all blueprint containers are finished before we - // restart config modules. - final CountDownLatch containerCreationComplete = new CountDownLatch(containerBundles.size()); - ServiceRegistration eventHandlerReg = registerEventHandler(forBundle.getBundleContext(), event -> { - final Bundle bundle = event.getBundle(); - if (event.isReplay()) { - LOG.trace("Got replay BlueprintEvent {} for bundle {}", event.getType(), bundle); - return; - } - - LOG.debug("Got BlueprintEvent {} for bundle {}", event.getType(), bundle); - if (containerBundles.contains(bundle) - && (event.getType() == BlueprintEvent.CREATED || event.getType() == BlueprintEvent.FAILURE)) { - containerCreationComplete.countDown(); - LOG.debug("containerCreationComplete is now {}", containerCreationComplete.getCount()); - } - }); - - final Runnable createContainerCallback = () -> createContainers(containerBundles); - - // Destroy the container down-top recursively and once done, restart the container top-down - destroyContainers(new ArrayDeque<>(Lists.reverse(containerBundles)), createContainerCallback); - - - try { - if (!containerCreationComplete.await(CONTAINER_CREATE_TIMEOUT_IN_MINUTES, TimeUnit.MINUTES)) { - LOG.warn("Failed to restart all blueprint containers within {} minutes. Attempted to restart {} {} " - + "but only {} completed restart", CONTAINER_CREATE_TIMEOUT_IN_MINUTES, containerBundles.size(), - containerBundles, containerBundles.size() - containerCreationComplete.getCount()); - return; - } - } catch (final InterruptedException e) { - LOG.debug("CountDownLatch await was interrupted - returning"); - return; - } - - AriesFrameworkUtil.safeUnregisterService(eventHandlerReg); - - LOG.info("Finished restarting blueprint containers for bundle {} and its dependent bundles", forBundle); - } - - /** - * Recursively quiesce and destroy the bundles one by one in order to maintain synchronicity and ordering. - * @param remainingBundlesToDestroy the list of remaining bundles to destroy. - * @param createContainerCallback a {@link Runnable} to {@code run()} when the recursive function is completed. - */ - private void destroyContainers(final Deque remainingBundlesToDestroy, - final Runnable createContainerCallback) { - - final Bundle nextBundle; - synchronized (remainingBundlesToDestroy) { - if (remainingBundlesToDestroy.isEmpty()) { - LOG.debug("All blueprint containers were quiesced and destroyed"); - createContainerCallback.run(); - return; - } - - nextBundle = remainingBundlesToDestroy.poll(); - } - - // The Quiesce capability is a like a soft-stop, clean-stop. In the case of the Blueprint extender, in flight - // service calls are allowed to finish; they're counted in and counted out, and no new calls are allowed. When - // there are no in flight service calls, the bundle is told to stop. The Blueprint bundle itself doesn't know - // this is happening which is a key design point. In the case of Blueprint, the extender ensures no new Entity - // Managers(EMs) are created. Then when all those EMs are closed the quiesce operation reports that it is - // finished. - // To properly restart the blueprint containers, first we have to quiesce the list of bundles, and once done, it - // is safe to destroy their BlueprintContainer, so no reference is retained. - // - // Mail - thread explaining Quiesce API: - // https://www.mail-archive.com/dev@aries.apache.org/msg08403.html - - // Quiesced the bundle to unregister the associated BlueprintContainer - quiesceParticipant.quiesce(bundlesQuiesced -> { - - // Destroy the container once Quiesced - Arrays.stream(bundlesQuiesced).forEach(quiescedBundle -> { - LOG.debug("Quiesced bundle {}", quiescedBundle); - blueprintExtenderService.destroyContainer( - quiescedBundle, blueprintExtenderService.getContainer(quiescedBundle)); - }); - - destroyContainers(remainingBundlesToDestroy, createContainerCallback); - - }, Collections.singletonList(nextBundle)); - } - - private void createContainers(final List containerBundles) { - containerBundles.forEach(bundle -> { - List paths = BlueprintBundleTracker.findBlueprintPaths(bundle); - - LOG.info("Restarting blueprint container for bundle {} with paths {}", bundle, paths); - - blueprintExtenderService.createContainer(bundle, paths); - }); - } - - /** - * Recursively finds the services registered by the given bundle and the bundles using those services. - * User bundles that have an associated blueprint container are added to containerBundles. - * - * @param bundle the bundle to traverse - * @param containerBundles the current set of bundles containing blueprint containers - */ - private void findDependentContainersRecursively(final Bundle bundle, final Set containerBundles) { - if (!containerBundles.add(bundle)) { - // Already seen this bundle... - return; - } - - ServiceReference[] references = bundle.getRegisteredServices(); - if (references != null) { - for (ServiceReference reference : references) { - Bundle[] usingBundles = reference.getUsingBundles(); - if (usingBundles != null) { - for (Bundle usingBundle : usingBundles) { - if (blueprintExtenderService.getContainer(usingBundle) != null) { - findDependentContainersRecursively(usingBundle, containerBundles); - } - } - } - } - } - } - - private ServiceRegistration registerEventHandler(final BundleContext bundleContext, - final BlueprintListener listener) { - return bundleContext.registerService(BlueprintListener.class.getName(), listener, new Hashtable<>()); - } - - @Override - public void close() { - LOG.debug("Closing"); - - restartExecutor.shutdownNow(); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractDependentComponentFactoryMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractDependentComponentFactoryMetadata.java deleted file mode 100644 index 37343b9362..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractDependentComponentFactoryMetadata.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.Preconditions; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; -import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; -import org.apache.aries.blueprint.di.AbstractRecipe; -import org.apache.aries.blueprint.di.ExecutionContext; -import org.apache.aries.blueprint.di.Recipe; -import org.apache.aries.blueprint.ext.DependentComponentFactoryMetadata; -import org.apache.aries.blueprint.services.ExtendedBlueprintContainer; -import org.opendaylight.controller.blueprint.BlueprintContainerRestartService; -import org.osgi.framework.ServiceReference; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Abstract base class for a DependentComponentFactoryMetadata implementation. - * - * @author Thomas Pantelis - */ -abstract class AbstractDependentComponentFactoryMetadata implements DependentComponentFactoryMetadata { - @SuppressFBWarnings("SLF4J_LOGGER_SHOULD_BE_PRIVATE") - final Logger log = LoggerFactory.getLogger(getClass()); - private final String id; - private final AtomicBoolean started = new AtomicBoolean(); - private final AtomicBoolean satisfied = new AtomicBoolean(); - private final AtomicBoolean restarting = new AtomicBoolean(); - @GuardedBy("serviceRecipes") - private final List serviceRecipes = new ArrayList<>(); - private volatile ExtendedBlueprintContainer container; - private volatile SatisfactionCallback satisfactionCallback; - private volatile String failureMessage; - private volatile Throwable failureCause; - private volatile String dependencyDesc; - @GuardedBy("serviceRecipes") - private boolean stoppedServiceRecipes; - - protected AbstractDependentComponentFactoryMetadata(final String id) { - this.id = Preconditions.checkNotNull(id); - } - - @Override - public String getId() { - return id; - } - - @Override - public int getActivation() { - return ACTIVATION_EAGER; - } - - @Override - public List getDependsOn() { - return Collections.emptyList(); - } - - @Override - public String getDependencyDescriptor() { - return dependencyDesc; - } - - @Override - public boolean isSatisfied() { - return satisfied.get(); - } - - protected void setFailureMessage(final String failureMessage) { - setFailure(failureMessage, null); - } - - @SuppressWarnings("checkstyle:hiddenField") - protected void setFailure(final String failureMessage, final Throwable failureCause) { - this.failureMessage = failureMessage; - this.failureCause = failureCause; - } - - protected void setDependencyDesc(final String dependencyDesc) { - this.dependencyDesc = dependencyDesc; - } - - protected final ExtendedBlueprintContainer container() { - return container; - } - - protected void setSatisfied() { - if (satisfied.compareAndSet(false, true)) { - satisfactionCallback.notifyChanged(); - } - } - - protected void retrieveService(final String name, final Class interfaceClass, - final Consumer onServiceRetrieved) { - retrieveService(name, interfaceClass.getName(), onServiceRetrieved); - } - - protected void retrieveService(final String name, final String interfaceName, - final Consumer onServiceRetrieved) { - synchronized (serviceRecipes) { - if (stoppedServiceRecipes) { - return; - } - - StaticServiceReferenceRecipe recipe = new StaticServiceReferenceRecipe(getId() + "-" + name, - container, interfaceName); - setDependencyDesc(recipe.getOsgiFilter()); - serviceRecipes.add(recipe); - - recipe.startTracking(onServiceRetrieved); - } - } - - protected final String logName() { - return (container != null ? container.getBundleContext().getBundle().getSymbolicName() : "") + " (" + id + ")"; - } - - @Override - public void init(final ExtendedBlueprintContainer newContainer) { - this.container = newContainer; - - log.debug("{}: In init", logName()); - } - - protected void onCreate() throws ComponentDefinitionException { - if (failureMessage != null) { - throw new ComponentDefinitionException(failureMessage, failureCause); - } - - // The following code is a bit odd so requires some explanation. A little background... If a bean - // is a prototype then the corresponding Recipe create method does not register the bean as created - // with the BlueprintRepository and thus the destroy method isn't called on container destroy. We - // rely on destroy being called to close our DTCL registration. Unfortunately the default setting - // for the prototype flag in AbstractRecipe is true and the DependentComponentFactoryRecipe, which - // is created for DependentComponentFactoryMetadata types of which we are one, doesn't have a way for - // us to indicate the prototype state via our metadata. - // - // The ExecutionContext is actually backed by the BlueprintRepository so we access it here to call - // the removePartialObject method which removes any partially created instance, which does not apply - // in our case, and also has the side effect of registering our bean as created as if it wasn't a - // prototype. We also obtain our corresponding Recipe instance and clear the prototype flag. This - // doesn't look to be necessary but is done so for completeness. Better late than never. Note we have - // to do this here rather than in startTracking b/c the ExecutionContext is not available yet at that - // point. - // - // Now the stopTracking method is called on container destroy but startTracking/stopTracking can also - // be called multiple times during the container creation process for Satisfiable recipes as bean - // processors may modify the metadata which could affect how dependencies are satisfied. An example of - // this is with service references where the OSGi filter metadata can be modified by bean processors - // after the initial service dependency is satisfied. However we don't have any metadata that could - // be modified by a bean processor and we don't want to register/unregister our DTCL multiple times - // so we only process startTracking once and close the DTCL registration once on container destroy. - ExecutionContext executionContext = ExecutionContext.Holder.getContext(); - executionContext.removePartialObject(id); - - Recipe myRecipe = executionContext.getRecipe(id); - if (myRecipe instanceof AbstractRecipe) { - log.debug("{}: setPrototype to false", logName()); - ((AbstractRecipe)myRecipe).setPrototype(false); - } else { - log.warn("{}: Recipe is null or not an AbstractRecipe", logName()); - } - } - - protected abstract void startTracking(); - - @Override - public final void startTracking(final SatisfactionCallback newSatisfactionCallback) { - if (!started.compareAndSet(false, true)) { - return; - } - - log.debug("{}: In startTracking", logName()); - - this.satisfactionCallback = newSatisfactionCallback; - - startTracking(); - } - - @Override - public void stopTracking() { - log.debug("{}: In stopTracking", logName()); - - stopServiceRecipes(); - } - - @Override - public void destroy(final Object instance) { - log.debug("{}: In destroy", logName()); - - stopServiceRecipes(); - } - - private void stopServiceRecipes() { - synchronized (serviceRecipes) { - stoppedServiceRecipes = true; - for (StaticServiceReferenceRecipe recipe: serviceRecipes) { - recipe.stop(); - } - - serviceRecipes.clear(); - } - } - - protected void restartContainer() { - if (restarting.compareAndSet(false, true)) { - BlueprintContainerRestartService restartService = getOSGiService(BlueprintContainerRestartService.class); - if (restartService != null) { - log.debug("{}: Restarting container", logName()); - restartService.restartContainerAndDependents(container().getBundleContext().getBundle()); - } - } - } - - @SuppressWarnings("unchecked") - @Nullable - protected T getOSGiService(final Class serviceInterface) { - try { - ServiceReference serviceReference = - container().getBundleContext().getServiceReference(serviceInterface); - if (serviceReference == null) { - log.warn("{}: {} reference not found", logName(), serviceInterface.getSimpleName()); - return null; - } - - T service = (T)container().getService(serviceReference); - if (service == null) { - // This could happen on shutdown if the service was already unregistered so we log as debug. - log.debug("{}: {} was not found", logName(), serviceInterface.getSimpleName()); - } - - return service; - } catch (final IllegalStateException e) { - // This is thrown if the BundleContext is no longer valid which is possible on shutdown so we - // log as debug. - log.debug("{}: Error obtaining {}", logName(), serviceInterface.getSimpleName(), e); - } - - return null; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractInvokableServiceMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractInvokableServiceMetadata.java deleted file mode 100644 index 10ec16f1ab..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/AbstractInvokableServiceMetadata.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.MoreObjects; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; -import java.util.Collection; -import java.util.Set; -import java.util.function.Predicate; -import org.apache.aries.blueprint.services.ExtendedBlueprintContainer; -import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry; -import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener; -import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier; -import org.opendaylight.mdsal.dom.api.DOMRpcService; -import org.opendaylight.mdsal.dom.api.DOMSchemaService; -import org.opendaylight.mdsal.dom.spi.RpcRoutingStrategy; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.osgi.service.blueprint.container.ComponentDefinitionException; - -abstract class AbstractInvokableServiceMetadata extends AbstractDependentComponentFactoryMetadata { - private final String interfaceName; - - private ListenerRegistration rpcListenerReg; - private RpcConsumerRegistry rpcRegistry; - private Class rpcInterface; - private Set rpcSchemaPaths; - - AbstractInvokableServiceMetadata(final String id, final String interfaceName) { - super(id); - this.interfaceName = Preconditions.checkNotNull(interfaceName); - } - - Class rpcInterface() { - return rpcInterface; - } - - @SuppressWarnings({ "checkstyle:IllegalCatch", "unchecked" }) - @Override - public final void init(final ExtendedBlueprintContainer container) { - super.init(container); - - final Class interfaceClass; - try { - interfaceClass = container().getBundleContext().getBundle().loadClass(interfaceName); - } catch (final Exception e) { - throw new ComponentDefinitionException(String.format("%s: Error obtaining interface class %s", - logName(), interfaceName), e); - } - - if (!RpcService.class.isAssignableFrom(interfaceClass)) { - throw new ComponentDefinitionException(String.format( - "%s: The specified interface %s is not an RpcService", logName(), interfaceName)); - } - - rpcInterface = (Class)interfaceClass; - } - - @Override - protected final void startTracking() { - // Request RpcProviderRegistry first ... - retrieveService("RpcConsumerRegistry", RpcConsumerRegistry.class, this::onRpcRegistry); - } - - private void onRpcRegistry(final Object service) { - log.debug("{}: Retrieved RpcProviderRegistry {}", logName(), service); - rpcRegistry = (RpcConsumerRegistry)service; - - // Now acquire SchemaService... - retrieveService("SchemaService", DOMSchemaService.class, this::onSchemaService); - } - - private void onSchemaService(final Object service) { - log.debug("{}: Retrieved SchemaService {}", logName(), service); - - // Now get the SchemaContext and trigger RPC resolution - retrievedSchemaContext(((DOMSchemaService)service).getGlobalContext()); - } - - private void retrievedSchemaContext(final SchemaContext schemaContext) { - log.debug("{}: retrievedSchemaContext", logName()); - - final Collection schemaPaths = RpcUtil.decomposeRpcService(rpcInterface, schemaContext, - rpcFilter()); - if (schemaPaths.isEmpty()) { - log.debug("{}: interface {} has no acceptable entries, assuming it is satisfied", logName(), rpcInterface); - setSatisfied(); - return; - } - - rpcSchemaPaths = ImmutableSet.copyOf(schemaPaths); - log.debug("{}: Got SchemaPaths: {}", logName(), rpcSchemaPaths); - - // First get the DOMRpcService OSGi service. This will be used to register a listener to be notified - // when the underlying DOM RPC service is available. - retrieveService("DOMRpcService", DOMRpcService.class, this::retrievedDOMRpcService); - } - - private void retrievedDOMRpcService(final Object service) { - log.debug("{}: retrievedDOMRpcService {}", logName(), service); - final DOMRpcService domRpcService = (DOMRpcService)service; - - setDependencyDesc("Available DOM RPC for binding RPC: " + rpcInterface); - rpcListenerReg = domRpcService.registerRpcListener(new DOMRpcAvailabilityListener() { - @Override - public void onRpcAvailable(final Collection rpcs) { - onRpcsAvailable(rpcs); - } - - @Override - public void onRpcUnavailable(final Collection rpcs) { - } - }); - } - - abstract Predicate rpcFilter(); - - @SuppressWarnings("checkstyle:IllegalCatch") - @Override - public final Object create() throws ComponentDefinitionException { - log.debug("{}: In create: interfaceName: {}", logName(), interfaceName); - - super.onCreate(); - - try { - RpcService rpcService = rpcRegistry.getRpcService(rpcInterface); - - log.debug("{}: create returning service {}", logName(), rpcService); - - return rpcService; - } catch (final RuntimeException e) { - throw new ComponentDefinitionException("Error getting RPC service for " + interfaceName, e); - } - } - - protected final void onRpcsAvailable(final Collection rpcs) { - for (DOMRpcIdentifier identifier : rpcs) { - if (rpcSchemaPaths.contains(identifier.getType())) { - log.debug("{}: onRpcsAvailable - found SchemaPath {}", logName(), identifier.getType()); - setSatisfied(); - break; - } - } - } - - @Override - public final void stopTracking() { - super.stopTracking(); - closeRpcListenerReg(); - } - - private void closeRpcListenerReg() { - if (rpcListenerReg != null) { - rpcListenerReg.close(); - rpcListenerReg = null; - } - } - - @Override - public final void destroy(final Object instance) { - super.destroy(instance); - closeRpcListenerReg(); - } - - @Override - public final String toString() { - return MoreObjects.toStringHelper(this).add("id", getId()).add("interfaceName", interfaceName).toString(); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ActionProviderBean.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ActionProviderBean.java deleted file mode 100644 index af943f91de..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ActionProviderBean.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2017 Cisco Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableSet; -import java.util.Collection; -import java.util.Set; -import org.opendaylight.mdsal.binding.api.RpcProviderService; -import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier; -import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException; -import org.opendaylight.mdsal.dom.api.DOMRpcProviderService; -import org.opendaylight.mdsal.dom.api.DOMSchemaService; -import org.opendaylight.mdsal.dom.spi.RpcRoutingStrategy; -import org.opendaylight.yangtools.concepts.Registration; -import org.opendaylight.yangtools.util.concurrent.FluentFutures; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.osgi.framework.Bundle; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Blueprint bean corresponding to the "action-provider" element that registers the promise to instantiate action - * instances with RpcProviderRegistry. - * - *

- * This bean has two distinct facets: - * - if a reference bean is provided, it registers it with {@link RpcProviderService} - * - if a reference bean is not provided, it registers the corresponding no-op implementation with - * {@link DOMRpcProviderService} for all action (Routed RPC) elements in the provided interface - * - * @author Robert Varga - */ -public class ActionProviderBean { - static final String ACTION_PROVIDER = "action-provider"; - - private static final Logger LOG = LoggerFactory.getLogger(ActionProviderBean.class); - - private DOMRpcProviderService domRpcProvider; - private RpcProviderService bindingRpcProvider; - private DOMSchemaService schemaService; - private RpcService implementation; - private String interfaceName; - private Registration reg; - private Bundle bundle; - - public void setBundle(final Bundle bundle) { - this.bundle = bundle; - } - - public void setInterfaceName(final String interfaceName) { - this.interfaceName = interfaceName; - } - - public void setImplementation(final RpcService implementation) { - this.implementation = implementation; - } - - public void setDomRpcProvider(final DOMRpcProviderService rpcProviderService) { - this.domRpcProvider = rpcProviderService; - } - - public void setBindingRpcProvider(final RpcProviderService rpcProvider) { - this.bindingRpcProvider = rpcProvider; - } - - public void setSchemaService(final DOMSchemaService schemaService) { - this.schemaService = schemaService; - } - - public void init() { - // First resolve the interface class - final Class interfaceClass = getRpcClass(); - - LOG.debug("{}: resolved interface {} to {}", ACTION_PROVIDER, interfaceName, interfaceClass); - - if (implementation != null) { - registerImplementation(interfaceClass); - } else { - registerFallback(interfaceClass); - } - } - - @SuppressWarnings("checkstyle:IllegalCatch") - public void destroy() { - if (reg != null) { - try { - reg.close(); - } catch (final Exception e) { - LOG.warn("{}: error while unregistering", ACTION_PROVIDER, e); - } finally { - reg = null; - } - } - } - - @SuppressWarnings("unchecked") - private Class getRpcClass() { - final Class iface; - - try { - iface = bundle.loadClass(interfaceName); - } catch (final ClassNotFoundException e) { - throw new ComponentDefinitionException(String.format( - "The specified \"interface\" for %s \"%s\" does not refer to an available class", interfaceName, - ACTION_PROVIDER), e); - } - if (!RpcService.class.isAssignableFrom(iface)) { - throw new ComponentDefinitionException(String.format( - "The specified \"interface\" %s for \"%s\" is not an RpcService", interfaceName, ACTION_PROVIDER)); - } - - return (Class) iface; - } - - private void registerFallback(final Class interfaceClass) { - final Collection paths = RpcUtil.decomposeRpcService(interfaceClass, - schemaService.getGlobalContext(), RpcRoutingStrategy::isContextBasedRouted); - if (paths.isEmpty()) { - LOG.warn("{}: interface {} has no actions defined", ACTION_PROVIDER, interfaceClass); - return; - } - - final Set rpcs = ImmutableSet.copyOf(Collections2.transform(paths, DOMRpcIdentifier::create)); - reg = domRpcProvider.registerRpcImplementation( - (rpc, input) -> FluentFutures.immediateFailedFluentFuture(new DOMRpcImplementationNotAvailableException( - "Action %s has no instance matching %s", rpc, input)), rpcs); - LOG.debug("Registered provider for {}", interfaceName); - } - - private void registerImplementation(final Class interfaceClass) { - if (!interfaceClass.isInstance(implementation)) { - throw new ComponentDefinitionException(String.format( - "The specified \"interface\" %s for \"%s\" is not implemented by RpcService \"ref\" %s", - interfaceName, ACTION_PROVIDER, implementation.getClass())); - } - - reg = bindingRpcProvider.registerRpcImplementation(interfaceClass, implementation); - LOG.debug("Registered implementation {} for {}", implementation, interfaceName); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ActionServiceMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ActionServiceMetadata.java deleted file mode 100644 index 5bb3f14d78..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ActionServiceMetadata.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017 Cisco Systems, Inc. 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.controller.blueprint.ext; - -import java.util.function.Predicate; -import org.opendaylight.mdsal.dom.spi.RpcRoutingStrategy; - -/** - * Factory metadata corresponding to the "action-service" element. It waits for a DOM promise of registration - * to appear in the {@link DOMRpcService} and then acquires a dynamic proxy via RpcProviderRegistry. - * - * @author Robert Varga - */ -final class ActionServiceMetadata extends AbstractInvokableServiceMetadata { - /* - * Implementation note: - * - * This implementation assumes Binding V1 semantics for actions, which means actions are packaged along with RPCs - * into a single interface. This has interesting implications on working with RpcServiceMetadata, which only - * handles the RPC side of the contract. - * - * Further interesting interactions stem from the fact that in DOM world each action is a separate entity, so the - * interface contract can let some actions to be invoked, while failing for others. This is a shortcoming of the - * Binding Specification and will be addressed in Binding V2 -- where each action is its own interface. - */ - ActionServiceMetadata(final String id, final String interfaceName) { - super(id, interfaceName); - } - - @Override - Predicate rpcFilter() { - return RpcRoutingStrategy::isContextBasedRouted; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/BindingContext.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/BindingContext.java deleted file mode 100644 index 93c46b4c30..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/BindingContext.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.URISyntaxException; -import java.util.List; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.stream.XMLStreamException; -import javax.xml.transform.dom.DOMSource; -import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult; -import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -/** - * Base class to abstract binding type-specific behavior. - * - * @author Thomas Pantelis (originally; re-factored by Michael Vorburger.ch) - */ -public abstract class BindingContext { - private static String GET_KEY_METHOD = "key"; - - public static BindingContext create(final String logName, final Class klass, - final String appConfigListKeyValue) { - if (Identifiable.class.isAssignableFrom(klass)) { - // The binding class corresponds to a yang list. - if (Strings.isNullOrEmpty(appConfigListKeyValue)) { - throw new ComponentDefinitionException(String.format( - "%s: App config binding class %s represents a yang list therefore \"%s\" must be specified", - logName, klass.getName(), DataStoreAppConfigMetadata.LIST_KEY_VALUE)); - } - - try { - return ListBindingContext.newInstance(klass, appConfigListKeyValue); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException - | InvocationTargetException | NoSuchMethodException | SecurityException e) { - throw new ComponentDefinitionException(String.format( - "%s: Error initializing for app config list binding class %s", - logName, klass.getName()), e); - } - - } else { - return new ContainerBindingContext(klass); - } - } - - public final InstanceIdentifier appConfigPath; - public final Class appConfigBindingClass; - public final Class schemaType; - public final QName bindingQName; - - private BindingContext(final Class appConfigBindingClass, - final InstanceIdentifier appConfigPath, final Class schemaType) { - this.appConfigBindingClass = appConfigBindingClass; - this.appConfigPath = appConfigPath; - this.schemaType = schemaType; - - bindingQName = BindingReflections.findQName(appConfigBindingClass); - } - - public NormalizedNode parseDataElement(final Element element, final DataSchemaNode dataSchema, - final SchemaContext schemaContext) throws XMLStreamException, IOException, ParserConfigurationException, - SAXException, URISyntaxException { - final NormalizedNodeResult resultHolder = new NormalizedNodeResult(); - final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder); - final XmlParserStream xmlParser = XmlParserStream.create(writer, schemaContext, dataSchema); - xmlParser.traverse(new DOMSource(element)); - - final NormalizedNode result = resultHolder.getResult(); - if (result instanceof MapNode) { - final MapNode mapNode = (MapNode) result; - final MapEntryNode mapEntryNode = mapNode.getValue().iterator().next(); - return mapEntryNode; - } - - return result; - } - - public abstract NormalizedNode newDefaultNode(DataSchemaNode dataSchema); - - /** - * BindingContext implementation for a container binding. - */ - private static class ContainerBindingContext extends BindingContext { - @SuppressWarnings("unchecked") - ContainerBindingContext(final Class appConfigBindingClass) { - super((Class) appConfigBindingClass, - InstanceIdentifier.create((Class) appConfigBindingClass), ContainerSchemaNode.class); - } - - @Override - public NormalizedNode newDefaultNode(final DataSchemaNode dataSchema) { - return ImmutableNodes.containerNode(bindingQName); - } - } - - /** - * BindingContext implementation for a list binding. - */ - private static class ListBindingContext extends BindingContext { - final String appConfigListKeyValue; - - @SuppressWarnings("unchecked") - ListBindingContext(final Class appConfigBindingClass, - final InstanceIdentifier appConfigPath, final String appConfigListKeyValue) { - super((Class) appConfigBindingClass, (InstanceIdentifier) appConfigPath, - ListSchemaNode.class); - this.appConfigListKeyValue = appConfigListKeyValue; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private static ListBindingContext newInstance(final Class bindingClass, - final String listKeyValue) throws InstantiationException, IllegalAccessException, - IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { - // We assume the yang list key type is string. - Identifier keyInstance = (Identifier) bindingClass.getMethod(GET_KEY_METHOD).getReturnType() - .getConstructor(String.class).newInstance(listKeyValue); - InstanceIdentifier appConfigPath = InstanceIdentifier.builder((Class)bindingClass, keyInstance).build(); - return new ListBindingContext(bindingClass, appConfigPath, listKeyValue); - } - - @Override - public NormalizedNode newDefaultNode(final DataSchemaNode dataSchema) { - // We assume there's only one key for the list. - List keys = ((ListSchemaNode)dataSchema).getKeyDefinition(); - Preconditions.checkArgument(keys.size() == 1, "Expected only 1 key for list %s", appConfigBindingClass); - QName listKeyQName = keys.get(0); - return ImmutableNodes.mapEntryBuilder(bindingQName, listKeyQName, appConfigListKeyValue).build(); - } - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ComponentProcessor.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ComponentProcessor.java deleted file mode 100644 index 84847a14b1..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ComponentProcessor.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.Strings; -import java.util.ArrayList; -import java.util.Dictionary; -import java.util.Hashtable; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.aries.blueprint.ComponentDefinitionRegistry; -import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor; -import org.apache.aries.blueprint.ext.AbstractPropertyPlaceholder; -import org.apache.aries.blueprint.mutable.MutableBeanMetadata; -import org.apache.aries.blueprint.mutable.MutableServiceReferenceMetadata; -import org.apache.aries.util.AriesFrameworkUtil; -import org.opendaylight.controller.blueprint.BlueprintContainerRestartService; -import org.osgi.framework.Bundle; -import org.osgi.framework.Constants; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.blueprint.reflect.BeanProperty; -import org.osgi.service.blueprint.reflect.ComponentMetadata; -import org.osgi.service.blueprint.reflect.ValueMetadata; -import org.osgi.service.cm.ManagedService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The singleton component processor that is invoked by the blueprint container to perform operations on - * various component definitions prior to component creation. - * - * @author Thomas Pantelis - */ -public class ComponentProcessor implements ComponentDefinitionRegistryProcessor { - static final String DEFAULT_TYPE_FILTER = "(|(type=default)(!(type=*)))"; - - private static final Logger LOG = LoggerFactory.getLogger(ComponentProcessor.class); - private static final String CM_PERSISTENT_ID_PROPERTY = "persistentId"; - - private final List> managedServiceRegs = new ArrayList<>(); - private Bundle bundle; - private BlueprintContainerRestartService blueprintContainerRestartService; - private boolean restartDependentsOnUpdates; - private boolean useDefaultForReferenceTypes; - - public void setBundle(final Bundle bundle) { - this.bundle = bundle; - } - - public void setBlueprintContainerRestartService(final BlueprintContainerRestartService restartService) { - this.blueprintContainerRestartService = restartService; - } - - public void setRestartDependentsOnUpdates(final boolean restartDependentsOnUpdates) { - this.restartDependentsOnUpdates = restartDependentsOnUpdates; - } - - public void setUseDefaultForReferenceTypes(final boolean useDefaultForReferenceTypes) { - this.useDefaultForReferenceTypes = useDefaultForReferenceTypes; - } - - public void destroy() { - for (ServiceRegistration reg: managedServiceRegs) { - AriesFrameworkUtil.safeUnregisterService(reg); - } - } - - @Override - public void process(final ComponentDefinitionRegistry registry) { - LOG.debug("{}: In process", logName()); - - for (String name : registry.getComponentDefinitionNames()) { - ComponentMetadata component = registry.getComponentDefinition(name); - if (component instanceof MutableBeanMetadata) { - processMutableBeanMetadata((MutableBeanMetadata) component); - } else if (component instanceof MutableServiceReferenceMetadata) { - processServiceReferenceMetadata((MutableServiceReferenceMetadata)component); - } - } - } - - private void processServiceReferenceMetadata(final MutableServiceReferenceMetadata serviceRef) { - if (!useDefaultForReferenceTypes) { - return; - } - - String filter = serviceRef.getFilter(); - String extFilter = serviceRef.getExtendedFilter() == null ? null : - serviceRef.getExtendedFilter().getStringValue(); - - LOG.debug("{}: processServiceReferenceMetadata for {}, filter: {}, ext filter: {}", logName(), - serviceRef.getId(), filter, extFilter); - - if (Strings.isNullOrEmpty(filter) && Strings.isNullOrEmpty(extFilter)) { - serviceRef.setFilter(DEFAULT_TYPE_FILTER); - - LOG.debug("{}: processServiceReferenceMetadata for {} set filter to {}", logName(), - serviceRef.getId(), serviceRef.getFilter()); - } - } - - private void processMutableBeanMetadata(final MutableBeanMetadata bean) { - if (restartDependentsOnUpdates && bean.getRuntimeClass() != null - && AbstractPropertyPlaceholder.class.isAssignableFrom(bean.getRuntimeClass())) { - LOG.debug("{}: Found PropertyPlaceholder bean: {}, runtime {}", logName(), bean.getId(), - bean.getRuntimeClass()); - - for (BeanProperty prop : bean.getProperties()) { - if (CM_PERSISTENT_ID_PROPERTY.equals(prop.getName())) { - if (prop.getValue() instanceof ValueMetadata) { - ValueMetadata persistentId = (ValueMetadata)prop.getValue(); - - LOG.debug("{}: Found {} property, value : {}", logName(), - CM_PERSISTENT_ID_PROPERTY, persistentId.getStringValue()); - - registerManagedService(persistentId.getStringValue()); - } else { - LOG.debug("{}: {} property metadata {} is not instanceof ValueMetadata", - logName(), CM_PERSISTENT_ID_PROPERTY, prop.getValue()); - } - - break; - } - } - } - } - - private void registerManagedService(final String persistentId) { - // Register a ManagedService so we get updates from the ConfigAdmin when the cfg file corresponding - // to the persistentId changes. - final ManagedService managedService = new ManagedService() { - private final AtomicBoolean initialUpdate = new AtomicBoolean(true); - private volatile Dictionary previousProperties; - - @Override - public void updated(final Dictionary properties) { - LOG.debug("{}: ManagedService updated for persistentId {}, properties: {}, initialUpdate: {}", - logName(), persistentId, properties, initialUpdate); - - // The first update occurs when the service is registered so ignore it as we want subsequent - // updates when it changes. The ConfigAdmin will send an update even if the cfg file doesn't - // yet exist. - if (!initialUpdate.compareAndSet(true, false) && !Objects.equals(previousProperties, properties)) { - blueprintContainerRestartService.restartContainerAndDependents(bundle); - } - - previousProperties = properties; - } - }; - - Dictionary props = new Hashtable<>(); - props.put(Constants.SERVICE_PID, persistentId); - props.put(Constants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName()); - props.put(Constants.BUNDLE_VERSION, bundle.getHeaders().get(Constants.BUNDLE_VERSION)); - managedServiceRegs.add(bundle.getBundleContext().registerService(ManagedService.class.getName(), - managedService, props)); - } - - private String logName() { - return bundle.getSymbolicName(); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ConfigXMLReaderException.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ConfigXMLReaderException.java deleted file mode 100644 index 12a547e08f..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/ConfigXMLReaderException.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat, Inc. 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.controller.blueprint.ext; - -/** - * Exception thrown by {@link DataStoreAppConfigDefaultXMLReader}. - * - * @author Michael Vorburger.ch - */ -public class ConfigXMLReaderException extends Exception { - private static final long serialVersionUID = 1L; - - public ConfigXMLReaderException(final String message) { - super(message); - } - - public ConfigXMLReaderException(final String message, final Throwable cause) { - super(message, cause); - } - -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/DataStoreAppConfigDefaultXMLReader.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/DataStoreAppConfigDefaultXMLReader.java deleted file mode 100644 index 9b55b360d6..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/DataStoreAppConfigDefaultXMLReader.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.Strings; -import com.google.common.io.Resources; -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.Optional; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.stream.XMLStreamException; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.mdsal.dom.api.DOMSchemaService; -import org.opendaylight.yangtools.util.xml.UntrustedXML; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -/** - * DataObject XML file reader used by {@link DataStoreAppConfigMetadata}. - * Available as a standalone class to make it easy to write unit tests which can - * catch malformed default "clustered-app-conf" config data XML files in - * downstream projects. - * - * @author Thomas Pantelis (originally; re-factored by Michael Vorburger.ch) - */ -public class DataStoreAppConfigDefaultXMLReader { - - private static final Logger LOG = LoggerFactory.getLogger(DataStoreAppConfigDefaultXMLReader.class); - - private final String logName; - private final String defaultAppConfigFileName; - private final DOMSchemaService schemaService; - private final BindingNormalizedNodeSerializer bindingSerializer; - private final BindingContext bindingContext; - private final ConfigURLProvider inputStreamProvider; - - @FunctionalInterface - public interface FallbackConfigProvider { - NormalizedNode get(SchemaContext schemaContext, DataSchemaNode dataSchema) throws IOException, - XMLStreamException, ParserConfigurationException, SAXException, URISyntaxException; - } - - @FunctionalInterface - public interface ConfigURLProvider { - Optional getURL(String appConfigFileName) throws IOException; - } - - public DataStoreAppConfigDefaultXMLReader( - final String logName, - final String defaultAppConfigFileName, - final DOMSchemaService schemaService, - final BindingNormalizedNodeSerializer bindingSerializer, - final BindingContext bindingContext, - final ConfigURLProvider inputStreamProvider) { - - this.logName = logName; - this.defaultAppConfigFileName = defaultAppConfigFileName; - this.schemaService = schemaService; - this.bindingSerializer = bindingSerializer; - this.bindingContext = bindingContext; - this.inputStreamProvider = inputStreamProvider; - } - - public DataStoreAppConfigDefaultXMLReader( - final Class testClass, - final String defaultAppConfigFileName, - final DOMSchemaService schemaService, - final BindingNormalizedNodeSerializer bindingSerializer, - final Class klass) { - this(testClass.getName(), defaultAppConfigFileName, schemaService, bindingSerializer, - BindingContext.create(testClass.getName(), klass, null), - appConfigFileName -> Optional.of(getURL(testClass, defaultAppConfigFileName))); - } - - private static URL getURL(final Class testClass, final String defaultAppConfigFileName) { - return Resources.getResource(testClass, defaultAppConfigFileName); - } - - public T createDefaultInstance() throws ConfigXMLReaderException, ParserConfigurationException, XMLStreamException, - IOException, SAXException, URISyntaxException { - return createDefaultInstance((schemaContext, dataSchema) -> { - throw new IllegalArgumentException("Failed to read XML " - + "(not creating model from defaults as runtime would, for better clarity in tests)"); - }); - } - - @SuppressWarnings("unchecked") - public T createDefaultInstance(final FallbackConfigProvider fallback) throws ConfigXMLReaderException, - URISyntaxException, ParserConfigurationException, XMLStreamException, SAXException, IOException { - YangInstanceIdentifier yangPath = bindingSerializer.toYangInstanceIdentifier(bindingContext.appConfigPath); - - LOG.debug("{}: Creating app config instance from path {}, Qname: {}", logName, yangPath, - bindingContext.bindingQName); - - checkNotNull(schemaService, "%s: Could not obtain the SchemaService OSGi service", logName); - - SchemaContext schemaContext = schemaService.getGlobalContext(); - - Module module = schemaContext.findModule(bindingContext.bindingQName.getModule()).orElse(null); - checkNotNull(module, "%s: Could not obtain the module schema for namespace %s, revision %s", - logName, bindingContext.bindingQName.getNamespace(), bindingContext.bindingQName.getRevision()); - - DataSchemaNode dataSchema = module.getDataChildByName(bindingContext.bindingQName); - checkNotNull(dataSchema, "%s: Could not obtain the schema for %s", logName, bindingContext.bindingQName); - - checkCondition(bindingContext.schemaType.isAssignableFrom(dataSchema.getClass()), - "%s: Expected schema type %s for %s but actual type is %s", logName, - bindingContext.schemaType, bindingContext.bindingQName, dataSchema.getClass()); - - NormalizedNode dataNode = parsePossibleDefaultAppConfigXMLFile(schemaContext, dataSchema); - if (dataNode == null) { - dataNode = fallback.get(schemaService.getGlobalContext(), dataSchema); - } - - DataObject appConfig = bindingSerializer.fromNormalizedNode(yangPath, dataNode).getValue(); - - // This shouldn't happen but need to handle it in case... - checkNotNull(appConfig, "%s: Could not create instance for app config binding %s", logName, - bindingContext.appConfigBindingClass); - - return (T) appConfig; - } - - private static void checkNotNull(final Object reference, final String errorMessageFormat, - final Object... formatArgs) throws ConfigXMLReaderException { - checkCondition(reference != null, errorMessageFormat, formatArgs); - } - - private static void checkCondition(final boolean expression, final String errorMessageFormat, - final Object... formatArgs) throws ConfigXMLReaderException { - if (!expression) { - throw new ConfigXMLReaderException(String.format(errorMessageFormat, formatArgs)); - } - } - - private NormalizedNode parsePossibleDefaultAppConfigXMLFile(final SchemaContext schemaContext, - final DataSchemaNode dataSchema) throws ConfigXMLReaderException { - - String appConfigFileName = defaultAppConfigFileName; - if (Strings.isNullOrEmpty(appConfigFileName)) { - String moduleName = findYangModuleName(bindingContext.bindingQName, schemaContext); - appConfigFileName = moduleName + "_" + bindingContext.bindingQName.getLocalName() + ".xml"; - } - - Optional optionalURL; - try { - optionalURL = inputStreamProvider.getURL(appConfigFileName); - } catch (final IOException e) { - String msg = String.format("%s: Could not getURL()", logName); - LOG.error(msg, e); - throw new ConfigXMLReaderException(msg, e); - } - if (!optionalURL.isPresent()) { - return null; - } - URL url = optionalURL.get(); - try (InputStream is = url.openStream()) { - Document root = UntrustedXML.newDocumentBuilder().parse(is); - NormalizedNode dataNode = bindingContext.parseDataElement(root.getDocumentElement(), dataSchema, - schemaContext); - - LOG.debug("{}: Parsed data node: {}", logName, dataNode); - - return dataNode; - } catch (final IOException | SAXException | XMLStreamException | ParserConfigurationException - | URISyntaxException e) { - String msg = String.format("%s: Could not read/parse app config %s", logName, url); - LOG.error(msg, e); - throw new ConfigXMLReaderException(msg, e); - } - } - - private String findYangModuleName(final QName qname, final SchemaContext schemaContext) - throws ConfigXMLReaderException { - for (Module m : schemaContext.getModules()) { - if (qname.getModule().equals(m.getQNameModule())) { - return m.getName(); - } - } - throw new ConfigXMLReaderException( - String.format("%s: Could not find yang module for QName %s", logName, qname)); - } - -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/DataStoreAppConfigMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/DataStoreAppConfigMetadata.java deleted file mode 100644 index 0a840063f4..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/DataStoreAppConfigMetadata.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.MoreExecutors; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Collection; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.stream.XMLStreamException; -import org.apache.aries.blueprint.services.ExtendedBlueprintContainer; -import org.opendaylight.controller.blueprint.ext.DataStoreAppConfigDefaultXMLReader.ConfigURLProvider; -import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener; -import org.opendaylight.mdsal.binding.api.DataBroker; -import org.opendaylight.mdsal.binding.api.DataObjectModification; -import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType; -import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; -import org.opendaylight.mdsal.binding.api.DataTreeModification; -import org.opendaylight.mdsal.binding.api.ReadTransaction; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.mdsal.common.api.LogicalDatastoreType; -import org.opendaylight.mdsal.dom.api.DOMSchemaService; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -/** - * Factory metadata corresponding to the "clustered-app-config" element that obtains an application's - * config data from the data store and provides the binding DataObject instance to the Blueprint container - * as a bean. In addition registers a DataTreeChangeListener to restart the Blueprint container when the - * config data is changed. - * - * @author Thomas Pantelis - */ -public class DataStoreAppConfigMetadata extends AbstractDependentComponentFactoryMetadata { - private static final Logger LOG = LoggerFactory.getLogger(DataStoreAppConfigMetadata.class); - - static final String BINDING_CLASS = "binding-class"; - static final String DEFAULT_CONFIG = "default-config"; - static final String DEFAULT_CONFIG_FILE_NAME = "default-config-file-name"; - static final String LIST_KEY_VALUE = "list-key-value"; - - private static final String DEFAULT_APP_CONFIG_FILE_PATH = "etc" + File.separator + "opendaylight" + File.separator - + "datastore" + File.separator + "initial" + File.separator + "config"; - - private final Element defaultAppConfigElement; - private final String defaultAppConfigFileName; - private final String appConfigBindingClassName; - private final String appConfigListKeyValue; - private final UpdateStrategy appConfigUpdateStrategy; - private final AtomicBoolean readingInitialAppConfig = new AtomicBoolean(true); - - private volatile BindingContext bindingContext; - private volatile ListenerRegistration appConfigChangeListenerReg; - private volatile DataObject currentAppConfig; - - // Note: the BindingNormalizedNodeSerializer interface is annotated as deprecated because there's an - // equivalent interface in the mdsal project but the corresponding binding classes in the controller - // project are still used - conversion to the mdsal binding classes hasn't occurred yet. - private volatile BindingNormalizedNodeSerializer bindingSerializer; - - public DataStoreAppConfigMetadata(@Nonnull final String id, @Nonnull final String appConfigBindingClassName, - @Nullable final String appConfigListKeyValue, @Nullable final String defaultAppConfigFileName, - @Nonnull final UpdateStrategy updateStrategyValue, @Nullable final Element defaultAppConfigElement) { - super(id); - this.defaultAppConfigElement = defaultAppConfigElement; - this.defaultAppConfigFileName = defaultAppConfigFileName; - this.appConfigBindingClassName = appConfigBindingClassName; - this.appConfigListKeyValue = appConfigListKeyValue; - this.appConfigUpdateStrategy = updateStrategyValue; - } - - @Override - @SuppressWarnings("unchecked") - public void init(final ExtendedBlueprintContainer container) { - super.init(container); - - Class appConfigBindingClass; - try { - Class bindingClass = container.getBundleContext().getBundle().loadClass(appConfigBindingClassName); - if (!DataObject.class.isAssignableFrom(bindingClass)) { - throw new ComponentDefinitionException(String.format( - "%s: Specified app config binding class %s does not extend %s", - logName(), appConfigBindingClassName, DataObject.class.getName())); - } - - appConfigBindingClass = (Class) bindingClass; - } catch (final ClassNotFoundException e) { - throw new ComponentDefinitionException(String.format("%s: Error loading app config binding class %s", - logName(), appConfigBindingClassName), e); - } - - bindingContext = BindingContext.create(logName(), appConfigBindingClass, appConfigListKeyValue); - } - - @Override - public Object create() throws ComponentDefinitionException { - LOG.debug("{}: In create - currentAppConfig: {}", logName(), currentAppConfig); - - super.onCreate(); - - return currentAppConfig; - } - - @Override - protected void startTracking() { - // First get the BindingNormalizedNodeSerializer OSGi service. This will be used to create a default - // instance of the app config binding class, if necessary. - - retrieveService("binding-codec", BindingNormalizedNodeSerializer.class, service -> { - bindingSerializer = (BindingNormalizedNodeSerializer)service; - retrieveDataBrokerService(); - }); - } - - private void retrieveDataBrokerService() { - LOG.debug("{}: In retrieveDataBrokerService", logName()); - // Get the binding DataBroker OSGi service. - retrieveService("data-broker", DataBroker.class, service -> retrieveInitialAppConfig((DataBroker)service)); - } - - private void retrieveInitialAppConfig(final DataBroker dataBroker) { - LOG.debug("{}: Got DataBroker instance - reading app config {}", logName(), bindingContext.appConfigPath); - - setDependencyDesc("Initial app config " + bindingContext.appConfigBindingClass.getSimpleName()); - - // We register a DTCL to get updates and also read the app config data from the data store. If - // the app config data is present then both the read and initial DTCN update will return it. If the - // the data isn't present, we won't get an initial DTCN update so the read will indicate the data - // isn't present. - - DataTreeIdentifier dataTreeId = DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION, - bindingContext.appConfigPath); - appConfigChangeListenerReg = dataBroker.registerDataTreeChangeListener(dataTreeId, - (ClusteredDataTreeChangeListener) this::onAppConfigChanged); - - readInitialAppConfig(dataBroker); - } - - private void readInitialAppConfig(final DataBroker dataBroker) { - try (ReadTransaction readOnlyTx = dataBroker.newReadOnlyTransaction()) { - readOnlyTx.read(LogicalDatastoreType.CONFIGURATION, bindingContext.appConfigPath).addCallback( - new FutureCallback>() { - @Override - public void onSuccess(final Optional possibleAppConfig) { - LOG.debug("{}: Read of app config {} succeeded: {}", logName(), bindingContext - .appConfigBindingClass.getName(), possibleAppConfig); - setInitialAppConfig(possibleAppConfig); - } - - @Override - public void onFailure(final Throwable failure) { - // We may have gotten the app config via the data tree change listener so only retry if not. - if (readingInitialAppConfig.get()) { - LOG.warn("{}: Read of app config {} failed - retrying", logName(), - bindingContext.appConfigBindingClass.getName(), failure); - - readInitialAppConfig(dataBroker); - } - } - }, MoreExecutors.directExecutor()); - } - } - - private void onAppConfigChanged(final Collection> changes) { - for (DataTreeModification change: changes) { - DataObjectModification changeRoot = change.getRootNode(); - ModificationType type = changeRoot.getModificationType(); - - LOG.debug("{}: onAppConfigChanged: {}, {}", logName(), type, change.getRootPath()); - - if (type == ModificationType.SUBTREE_MODIFIED || type == ModificationType.WRITE) { - DataObject newAppConfig = changeRoot.getDataAfter(); - - LOG.debug("New app config instance: {}, previous: {}", newAppConfig, currentAppConfig); - - if (!setInitialAppConfig(Optional.of(newAppConfig)) - && !Objects.equals(currentAppConfig, newAppConfig)) { - LOG.debug("App config was updated"); - - if (appConfigUpdateStrategy == UpdateStrategy.RELOAD) { - restartContainer(); - } - } - } else if (type == ModificationType.DELETE) { - LOG.debug("App config was deleted"); - - if (appConfigUpdateStrategy == UpdateStrategy.RELOAD) { - restartContainer(); - } - } - } - } - - private boolean setInitialAppConfig(final Optional possibleAppConfig) { - boolean result = readingInitialAppConfig.compareAndSet(true, false); - if (result) { - DataObject localAppConfig; - if (possibleAppConfig.isPresent()) { - localAppConfig = possibleAppConfig.get(); - } else { - // No app config data is present so create an empty instance via the bindingSerializer service. - // This will also return default values for leafs that haven't been explicitly set. - localAppConfig = createDefaultInstance(); - } - - LOG.debug("{}: Setting currentAppConfig instance: {}", logName(), localAppConfig); - - // Now publish the app config instance to the volatile field and notify the callback to let the - // container know our dependency is now satisfied. - currentAppConfig = localAppConfig; - setSatisfied(); - } - - return result; - } - - private DataObject createDefaultInstance() { - try { - ConfigURLProvider inputStreamProvider = appConfigFileName -> { - File appConfigFile = new File(DEFAULT_APP_CONFIG_FILE_PATH, appConfigFileName); - LOG.debug("{}: parsePossibleDefaultAppConfigXMLFile looking for file {}", logName(), - appConfigFile.getAbsolutePath()); - - if (!appConfigFile.exists()) { - return Optional.empty(); - } - - LOG.debug("{}: Found file {}", logName(), appConfigFile.getAbsolutePath()); - - return Optional.of(appConfigFile.toURI().toURL()); - }; - - DataStoreAppConfigDefaultXMLReader reader = new DataStoreAppConfigDefaultXMLReader<>(logName(), - defaultAppConfigFileName, getOSGiService(DOMSchemaService.class), bindingSerializer, bindingContext, - inputStreamProvider); - return reader.createDefaultInstance((schemaContext, dataSchema) -> { - // Fallback if file cannot be read, try XML from Config - NormalizedNode dataNode = parsePossibleDefaultAppConfigElement(schemaContext, dataSchema); - if (dataNode != null) { - return dataNode; - } - // or, as last resort, defaults from the model - return bindingContext.newDefaultNode(dataSchema); - }); - - } catch (final ConfigXMLReaderException | IOException | SAXException | XMLStreamException - | ParserConfigurationException | URISyntaxException e) { - if (e.getCause() == null) { - setFailureMessage(e.getMessage()); - } else { - setFailure(e.getMessage(), e); - } - return null; - } - } - - @Nullable - private NormalizedNode parsePossibleDefaultAppConfigElement(final SchemaContext schemaContext, - final DataSchemaNode dataSchema) throws URISyntaxException, IOException, ParserConfigurationException, - SAXException, XMLStreamException { - if (defaultAppConfigElement == null) { - return null; - } - - LOG.debug("{}: parsePossibleDefaultAppConfigElement for {}", logName(), bindingContext.bindingQName); - - LOG.debug("{}: Got app config schema: {}", logName(), dataSchema); - - NormalizedNode dataNode = bindingContext.parseDataElement(defaultAppConfigElement, dataSchema, - schemaContext); - - LOG.debug("{}: Parsed data node: {}", logName(), dataNode); - - return dataNode; - } - - @Override - public void destroy(final Object instance) { - super.destroy(instance); - - if (appConfigChangeListenerReg != null) { - appConfigChangeListenerReg.close(); - appConfigChangeListenerReg = null; - } - } - -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/MandatoryServiceReferenceMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/MandatoryServiceReferenceMetadata.java deleted file mode 100644 index 8139e1de52..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/MandatoryServiceReferenceMetadata.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.Preconditions; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import org.osgi.service.blueprint.reflect.ReferenceListener; -import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata; - -/** - * A ServiceReferenceMetadata implementation for a mandatory OSGi service. - * - * @author Thomas Pantelis - */ -class MandatoryServiceReferenceMetadata implements ServiceReferenceMetadata { - private final String interfaceClass; - private final String id; - - MandatoryServiceReferenceMetadata(final String id, final String interfaceClass) { - this.id = Preconditions.checkNotNull(id); - this.interfaceClass = interfaceClass; - } - - @Override - public String getId() { - return id; - } - - @Override - public int getActivation() { - return ACTIVATION_EAGER; - } - - @Override - public List getDependsOn() { - return Collections.emptyList(); - } - - @Override - public int getAvailability() { - return AVAILABILITY_MANDATORY; - } - - @Override - public String getInterface() { - return interfaceClass; - } - - @Override - public String getComponentName() { - return null; - } - - @Override - public String getFilter() { - return ComponentProcessor.DEFAULT_TYPE_FILTER; - } - - @Override - public Collection getReferenceListeners() { - return Collections.emptyList(); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/NotificationListenerBean.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/NotificationListenerBean.java deleted file mode 100644 index 74c2956621..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/NotificationListenerBean.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import org.opendaylight.mdsal.binding.api.NotificationService; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.NotificationListener; -import org.osgi.framework.Bundle; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Blueprint bean corresponding to the "notification-listener" element that registers a NotificationListener - * with the NotificationService. - * - * @author Thomas Pantelis - */ -public class NotificationListenerBean { - private static final Logger LOG = LoggerFactory.getLogger(NotificationListenerBean.class); - static final String NOTIFICATION_LISTENER = "notification-listener"; - - private Bundle bundle; - private NotificationService notificationService; - private NotificationListener notificationListener; - private ListenerRegistration registration; - - public void setNotificationService(final NotificationService notificationService) { - this.notificationService = notificationService; - } - - public void setNotificationListener(final NotificationListener notificationListener) { - this.notificationListener = notificationListener; - } - - public void setBundle(final Bundle bundle) { - this.bundle = bundle; - } - - public void init() { - LOG.debug("{}: init - registering NotificationListener {}", bundle.getSymbolicName(), notificationListener); - - registration = notificationService.registerNotificationListener(notificationListener); - } - - public void destroy() { - if (registration != null) { - LOG.debug("{}: destroy - closing ListenerRegistration {}", bundle.getSymbolicName(), notificationListener); - registration.close(); - } else { - LOG.debug("{}: destroy - listener was not registered", bundle.getSymbolicName()); - } - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/OpendaylightNamespaceHandler.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/OpendaylightNamespaceHandler.java deleted file mode 100644 index dbecdc3f70..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/OpendaylightNamespaceHandler.java +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.Strings; -import java.io.IOException; -import java.io.StringReader; -import java.net.URL; -import java.util.Collections; -import java.util.Set; -import org.apache.aries.blueprint.ComponentDefinitionRegistry; -import org.apache.aries.blueprint.NamespaceHandler; -import org.apache.aries.blueprint.ParserContext; -import org.apache.aries.blueprint.ext.ComponentFactoryMetadata; -import org.apache.aries.blueprint.mutable.MutableBeanMetadata; -import org.apache.aries.blueprint.mutable.MutableRefMetadata; -import org.apache.aries.blueprint.mutable.MutableReferenceMetadata; -import org.apache.aries.blueprint.mutable.MutableServiceMetadata; -import org.apache.aries.blueprint.mutable.MutableServiceReferenceMetadata; -import org.apache.aries.blueprint.mutable.MutableValueMetadata; -import org.opendaylight.controller.blueprint.BlueprintContainerRestartService; -import org.opendaylight.mdsal.binding.api.NotificationService; -import org.opendaylight.mdsal.binding.api.RpcProviderService; -import org.opendaylight.mdsal.dom.api.DOMRpcProviderService; -import org.opendaylight.mdsal.dom.api.DOMSchemaService; -import org.opendaylight.yangtools.util.xml.UntrustedXML; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.osgi.service.blueprint.reflect.BeanMetadata; -import org.osgi.service.blueprint.reflect.ComponentMetadata; -import org.osgi.service.blueprint.reflect.Metadata; -import org.osgi.service.blueprint.reflect.RefMetadata; -import org.osgi.service.blueprint.reflect.ReferenceMetadata; -import org.osgi.service.blueprint.reflect.ServiceMetadata; -import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata; -import org.osgi.service.blueprint.reflect.ValueMetadata; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * The NamespaceHandler for Opendaylight blueprint extensions. - * - * @author Thomas Pantelis - */ -public final class OpendaylightNamespaceHandler implements NamespaceHandler { - public static final String NAMESPACE_1_0_0 = "http://opendaylight.org/xmlns/blueprint/v1.0.0"; - static final String ROUTED_RPC_REG_CONVERTER_NAME = "org.opendaylight.blueprint.RoutedRpcRegConverter"; - static final String DOM_RPC_PROVIDER_SERVICE_NAME = "org.opendaylight.blueprint.DOMRpcProviderService"; - static final String BINDING_RPC_PROVIDER_SERVICE_NAME = "org.opendaylight.blueprint.RpcProviderService"; - static final String SCHEMA_SERVICE_NAME = "org.opendaylight.blueprint.SchemaService"; - static final String NOTIFICATION_SERVICE_NAME = "org.opendaylight.blueprint.NotificationService"; - static final String TYPE_ATTR = "type"; - static final String UPDATE_STRATEGY_ATTR = "update-strategy"; - - private static final Logger LOG = LoggerFactory.getLogger(OpendaylightNamespaceHandler.class); - private static final String COMPONENT_PROCESSOR_NAME = ComponentProcessor.class.getName(); - private static final String RESTART_DEPENDENTS_ON_UPDATES = "restart-dependents-on-updates"; - private static final String USE_DEFAULT_FOR_REFERENCE_TYPES = "use-default-for-reference-types"; - private static final String CLUSTERED_APP_CONFIG = "clustered-app-config"; - private static final String INTERFACE = "interface"; - private static final String REF_ATTR = "ref"; - private static final String ID_ATTR = "id"; - private static final String RPC_SERVICE = "rpc-service"; - private static final String ACTION_SERVICE = "action-service"; - private static final String SPECIFIC_SERVICE_REF_LIST = "specific-reference-list"; - private static final String STATIC_REFERENCE = "static-reference"; - - @SuppressWarnings("rawtypes") - @Override - public Set getManagedClasses() { - return Collections.emptySet(); - } - - @Override - public URL getSchemaLocation(final String namespace) { - if (NAMESPACE_1_0_0.equals(namespace)) { - URL url = getClass().getResource("/opendaylight-blueprint-ext-1.0.0.xsd"); - LOG.debug("getSchemaLocation for {} returning URL {}", namespace, url); - return url; - } - - return null; - } - - @Override - public Metadata parse(final Element element, final ParserContext context) { - LOG.debug("In parse for {}", element); - - if (nodeNameEquals(element, RpcImplementationBean.RPC_IMPLEMENTATION)) { - return parseRpcImplementation(element, context); - } else if (nodeNameEquals(element, RoutedRpcMetadata.ROUTED_RPC_IMPLEMENTATION)) { - return parseRoutedRpcImplementation(element, context); - } else if (nodeNameEquals(element, RPC_SERVICE)) { - return parseRpcService(element, context); - } else if (nodeNameEquals(element, NotificationListenerBean.NOTIFICATION_LISTENER)) { - return parseNotificationListener(element, context); - } else if (nodeNameEquals(element, CLUSTERED_APP_CONFIG)) { - return parseClusteredAppConfig(element, context); - } else if (nodeNameEquals(element, SPECIFIC_SERVICE_REF_LIST)) { - return parseSpecificReferenceList(element, context); - } else if (nodeNameEquals(element, STATIC_REFERENCE)) { - return parseStaticReference(element, context); - } else if (nodeNameEquals(element, ACTION_SERVICE)) { - return parseActionService(element, context); - } else if (nodeNameEquals(element, ActionProviderBean.ACTION_PROVIDER)) { - return parseActionProvider(element, context); - } - - throw new ComponentDefinitionException("Unsupported standalone element: " + element.getNodeName()); - } - - @Override - public ComponentMetadata decorate(final Node node, final ComponentMetadata component, final ParserContext context) { - if (node instanceof Attr) { - if (nodeNameEquals(node, RESTART_DEPENDENTS_ON_UPDATES)) { - return decorateRestartDependentsOnUpdates((Attr) node, component, context); - } else if (nodeNameEquals(node, USE_DEFAULT_FOR_REFERENCE_TYPES)) { - return decorateUseDefaultForReferenceTypes((Attr) node, component, context); - } else if (nodeNameEquals(node, TYPE_ATTR)) { - if (component instanceof ServiceReferenceMetadata) { - return decorateServiceReferenceType((Attr) node, component, context); - } else if (component instanceof ServiceMetadata) { - return decorateServiceType((Attr)node, component, context); - } - - throw new ComponentDefinitionException("Attribute " + node.getNodeName() - + " can only be used on a , or element"); - } - - throw new ComponentDefinitionException("Unsupported attribute: " + node.getNodeName()); - } else { - throw new ComponentDefinitionException("Unsupported node type: " + node); - } - } - - private static ComponentMetadata decorateServiceType(final Attr attr, final ComponentMetadata component, - final ParserContext context) { - if (!(component instanceof MutableServiceMetadata)) { - throw new ComponentDefinitionException("Expected an instanceof MutableServiceMetadata"); - } - - MutableServiceMetadata service = (MutableServiceMetadata)component; - - LOG.debug("decorateServiceType for {} - adding type property {}", service.getId(), attr.getValue()); - - service.addServiceProperty(createValue(context, TYPE_ATTR), createValue(context, attr.getValue())); - return component; - } - - private static ComponentMetadata decorateServiceReferenceType(final Attr attr, final ComponentMetadata component, - final ParserContext context) { - if (!(component instanceof MutableServiceReferenceMetadata)) { - throw new ComponentDefinitionException("Expected an instanceof MutableServiceReferenceMetadata"); - } - - // We don't actually need the ComponentProcessor for augmenting the OSGi filter here but we create it - // to workaround an issue in Aries where it doesn't use the extended filter unless there's a - // Processor or ComponentDefinitionRegistryProcessor registered. This may actually be working as - // designed in Aries b/c the extended filter was really added to allow the OSGi filter to be - // substituted by a variable via the "cm:property-placeholder" processor. If so, it's a bit funky - // but as long as there's at least one processor registered, it correctly uses the extended filter. - registerComponentProcessor(context); - - MutableServiceReferenceMetadata serviceRef = (MutableServiceReferenceMetadata)component; - String oldFilter = serviceRef.getExtendedFilter() == null ? null : - serviceRef.getExtendedFilter().getStringValue(); - - String filter; - if (Strings.isNullOrEmpty(oldFilter)) { - filter = String.format("(type=%s)", attr.getValue()); - } else { - filter = String.format("(&(%s)(type=%s))", oldFilter, attr.getValue()); - } - - LOG.debug("decorateServiceReferenceType for {} with type {}, old filter: {}, new filter: {}", - serviceRef.getId(), attr.getValue(), oldFilter, filter); - - serviceRef.setExtendedFilter(createValue(context, filter)); - return component; - } - - private static ComponentMetadata decorateRestartDependentsOnUpdates(final Attr attr, - final ComponentMetadata component, final ParserContext context) { - return enableComponentProcessorProperty(attr, component, context, "restartDependentsOnUpdates"); - } - - private static ComponentMetadata decorateUseDefaultForReferenceTypes(final Attr attr, - final ComponentMetadata component, final ParserContext context) { - return enableComponentProcessorProperty(attr, component, context, "useDefaultForReferenceTypes"); - } - - private static ComponentMetadata enableComponentProcessorProperty(final Attr attr, - final ComponentMetadata component, final ParserContext context, final String propertyName) { - if (component != null) { - throw new ComponentDefinitionException("Attribute " + attr.getNodeName() - + " can only be used on the root element"); - } - - LOG.debug("Property {} = {}", propertyName, attr.getValue()); - - if (!Boolean.parseBoolean(attr.getValue())) { - return component; - } - - MutableBeanMetadata metadata = registerComponentProcessor(context); - metadata.addProperty(propertyName, createValue(context, "true")); - - return component; - } - - private static MutableBeanMetadata registerComponentProcessor(final ParserContext context) { - ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry(); - MutableBeanMetadata metadata = (MutableBeanMetadata) registry.getComponentDefinition(COMPONENT_PROCESSOR_NAME); - if (metadata == null) { - metadata = createBeanMetadata(context, COMPONENT_PROCESSOR_NAME, ComponentProcessor.class, false, true); - metadata.setProcessor(true); - addBlueprintBundleRefProperty(context, metadata); - metadata.addProperty("blueprintContainerRestartService", createServiceRef(context, - BlueprintContainerRestartService.class, null)); - - LOG.debug("Registering ComponentProcessor bean: {}", metadata); - - registry.registerComponentDefinition(metadata); - } - - return metadata; - } - - private static Metadata parseActionProvider(final Element element, final ParserContext context) { - registerDomRpcProviderServiceRefBean(context); - registerBindingRpcProviderServiceRefBean(context); - registerSchemaServiceRefBean(context); - - MutableBeanMetadata metadata = createBeanMetadata(context, context.generateId(), ActionProviderBean.class, - true, true); - addBlueprintBundleRefProperty(context, metadata); - metadata.addProperty("domRpcProvider", createRef(context, DOM_RPC_PROVIDER_SERVICE_NAME)); - metadata.addProperty("bindingRpcProvider", createRef(context, BINDING_RPC_PROVIDER_SERVICE_NAME)); - metadata.addProperty("schemaService", createRef(context, SCHEMA_SERVICE_NAME)); - metadata.addProperty("interfaceName", createValue(context, element.getAttribute(INTERFACE))); - - if (element.hasAttribute(REF_ATTR)) { - metadata.addProperty("implementation", createRef(context, element.getAttribute(REF_ATTR))); - } - - LOG.debug("parseActionProvider returning {}", metadata); - return metadata; - } - - - private static Metadata parseRpcImplementation(final Element element, final ParserContext context) { - registerBindingRpcProviderServiceRefBean(context); - - MutableBeanMetadata metadata = createBeanMetadata(context, context.generateId(), RpcImplementationBean.class, - true, true); - addBlueprintBundleRefProperty(context, metadata); - metadata.addProperty("rpcProvider", createRef(context, BINDING_RPC_PROVIDER_SERVICE_NAME)); - metadata.addProperty("implementation", createRef(context, element.getAttribute(REF_ATTR))); - - if (element.hasAttribute(INTERFACE)) { - metadata.addProperty("interfaceName", createValue(context, element.getAttribute(INTERFACE))); - } - - LOG.debug("parseRpcImplementation returning {}", metadata); - return metadata; - } - - private static Metadata parseRoutedRpcImplementation(final Element element, final ParserContext context) { - registerBindingRpcProviderServiceRefBean(context); - registerRoutedRpcRegistrationConverter(context); - - ComponentFactoryMetadata metadata = new RoutedRpcMetadata(getId(context, element), - element.getAttribute(INTERFACE), element.getAttribute(REF_ATTR)); - - LOG.debug("parseRoutedRpcImplementation returning {}", metadata); - - return metadata; - } - - private static Metadata parseActionService(final Element element, final ParserContext context) { - ComponentFactoryMetadata metadata = new ActionServiceMetadata(getId(context, element), - element.getAttribute(INTERFACE)); - - LOG.debug("parseActionService returning {}", metadata); - - return metadata; - } - - private static Metadata parseRpcService(final Element element, final ParserContext context) { - ComponentFactoryMetadata metadata = new RpcServiceMetadata(getId(context, element), - element.getAttribute(INTERFACE)); - - LOG.debug("parseRpcService returning {}", metadata); - - return metadata; - } - - private static void registerRoutedRpcRegistrationConverter(final ParserContext context) { - ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry(); - if (registry.getComponentDefinition(ROUTED_RPC_REG_CONVERTER_NAME) == null) { - MutableBeanMetadata metadata = createBeanMetadata(context, ROUTED_RPC_REG_CONVERTER_NAME, - RoutedRpcRegistrationConverter.class, false, false); - metadata.setActivation(ReferenceMetadata.ACTIVATION_LAZY); - registry.registerTypeConverter(metadata); - } - } - - private static void registerDomRpcProviderServiceRefBean(final ParserContext context) { - registerRefBean(context, DOM_RPC_PROVIDER_SERVICE_NAME, DOMRpcProviderService.class); - } - - private static void registerBindingRpcProviderServiceRefBean(final ParserContext context) { - registerRefBean(context, BINDING_RPC_PROVIDER_SERVICE_NAME, RpcProviderService.class); - } - - private static void registerSchemaServiceRefBean(final ParserContext context) { - registerRefBean(context, SCHEMA_SERVICE_NAME, DOMSchemaService.class); - } - - private static void registerRefBean(final ParserContext context, final String name, final Class clazz) { - ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry(); - if (registry.getComponentDefinition(name) == null) { - MutableReferenceMetadata metadata = createServiceRef(context, clazz, null); - metadata.setId(name); - registry.registerComponentDefinition(metadata); - } - } - - private static Metadata parseNotificationListener(final Element element, final ParserContext context) { - registerNotificationServiceRefBean(context); - - MutableBeanMetadata metadata = createBeanMetadata(context, context.generateId(), NotificationListenerBean.class, - true, true); - addBlueprintBundleRefProperty(context, metadata); - metadata.addProperty("notificationService", createRef(context, NOTIFICATION_SERVICE_NAME)); - metadata.addProperty("notificationListener", createRef(context, element.getAttribute(REF_ATTR))); - - LOG.debug("parseNotificationListener returning {}", metadata); - - return metadata; - } - - private static void registerNotificationServiceRefBean(final ParserContext context) { - ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry(); - if (registry.getComponentDefinition(NOTIFICATION_SERVICE_NAME) == null) { - MutableReferenceMetadata metadata = createServiceRef(context, NotificationService.class, null); - metadata.setId(NOTIFICATION_SERVICE_NAME); - registry.registerComponentDefinition(metadata); - } - } - - private static Metadata parseClusteredAppConfig(final Element element, final ParserContext context) { - LOG.debug("parseClusteredAppConfig"); - - // Find the default-config child element representing the default app config XML, if present. - Element defaultConfigElement = null; - NodeList children = element.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - Node child = children.item(i); - if (nodeNameEquals(child, DataStoreAppConfigMetadata.DEFAULT_CONFIG)) { - defaultConfigElement = (Element) child; - break; - } - } - - Element defaultAppConfigElement = null; - if (defaultConfigElement != null) { - // Find the CDATA element containing the default app config XML. - children = defaultConfigElement.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - Node child = children.item(i); - if (child.getNodeType() == Node.CDATA_SECTION_NODE) { - defaultAppConfigElement = parseXML(DataStoreAppConfigMetadata.DEFAULT_CONFIG, - child.getTextContent()); - break; - } - } - } - - return new DataStoreAppConfigMetadata(getId(context, element), element.getAttribute( - DataStoreAppConfigMetadata.BINDING_CLASS), element.getAttribute( - DataStoreAppConfigMetadata.LIST_KEY_VALUE), element.getAttribute( - DataStoreAppConfigMetadata.DEFAULT_CONFIG_FILE_NAME), parseUpdateStrategy( - element.getAttribute(UPDATE_STRATEGY_ATTR)), defaultAppConfigElement); - } - - private static UpdateStrategy parseUpdateStrategy(final String updateStrategyValue) { - if (Strings.isNullOrEmpty(updateStrategyValue) - || updateStrategyValue.equalsIgnoreCase(UpdateStrategy.RELOAD.name())) { - return UpdateStrategy.RELOAD; - } else if (updateStrategyValue.equalsIgnoreCase(UpdateStrategy.NONE.name())) { - return UpdateStrategy.NONE; - } else { - LOG.warn("update-strategy {} not supported, using reload", updateStrategyValue); - return UpdateStrategy.RELOAD; - } - } - - private static Metadata parseSpecificReferenceList(final Element element, final ParserContext context) { - ComponentFactoryMetadata metadata = new SpecificReferenceListMetadata(getId(context, element), - element.getAttribute(INTERFACE)); - - LOG.debug("parseSpecificReferenceList returning {}", metadata); - - return metadata; - } - - private static Metadata parseStaticReference(final Element element, final ParserContext context) { - ComponentFactoryMetadata metadata = new StaticReferenceMetadata(getId(context, element), - element.getAttribute(INTERFACE)); - - LOG.debug("parseStaticReference returning {}", metadata); - - return metadata; - } - - private static Element parseXML(final String name, final String xml) { - try { - return UntrustedXML.newDocumentBuilder().parse(new InputSource(new StringReader(xml))).getDocumentElement(); - } catch (SAXException | IOException e) { - throw new ComponentDefinitionException(String.format("Error %s parsing XML: %s", name, xml), e); - } - } - - private static ValueMetadata createValue(final ParserContext context, final String value) { - MutableValueMetadata metadata = context.createMetadata(MutableValueMetadata.class); - metadata.setStringValue(value); - return metadata; - } - - private static MutableReferenceMetadata createServiceRef(final ParserContext context, final Class cls, - final String filter) { - MutableReferenceMetadata metadata = context.createMetadata(MutableReferenceMetadata.class); - metadata.setRuntimeInterface(cls); - metadata.setInterface(cls.getName()); - metadata.setActivation(ReferenceMetadata.ACTIVATION_EAGER); - metadata.setAvailability(ReferenceMetadata.AVAILABILITY_MANDATORY); - - if (filter != null) { - metadata.setFilter(filter); - } - - return metadata; - } - - private static RefMetadata createRef(final ParserContext context, final String id) { - MutableRefMetadata metadata = context.createMetadata(MutableRefMetadata.class); - metadata.setComponentId(id); - return metadata; - } - - private static String getId(final ParserContext context, final Element element) { - if (element.hasAttribute(ID_ATTR)) { - return element.getAttribute(ID_ATTR); - } else { - return context.generateId(); - } - } - - private static boolean nodeNameEquals(final Node node, final String name) { - return name.equals(node.getNodeName()) || name.equals(node.getLocalName()); - } - - private static void addBlueprintBundleRefProperty(final ParserContext context, final MutableBeanMetadata metadata) { - metadata.addProperty("bundle", createRef(context, "blueprintBundle")); - } - - private static MutableBeanMetadata createBeanMetadata(final ParserContext context, final String id, - final Class runtimeClass, final boolean initMethod, final boolean destroyMethod) { - MutableBeanMetadata metadata = context.createMetadata(MutableBeanMetadata.class); - metadata.setId(id); - metadata.setScope(BeanMetadata.SCOPE_SINGLETON); - metadata.setActivation(ReferenceMetadata.ACTIVATION_EAGER); - metadata.setRuntimeClass(runtimeClass); - - if (initMethod) { - metadata.setInitMethod("init"); - } - - if (destroyMethod) { - metadata.setDestroyMethod("destroy"); - } - - return metadata; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcMetadata.java deleted file mode 100644 index d9f464cff5..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcMetadata.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import java.util.Arrays; -import java.util.List; -import org.apache.aries.blueprint.ext.ComponentFactoryMetadata; -import org.apache.aries.blueprint.services.ExtendedBlueprintContainer; -import org.opendaylight.mdsal.binding.api.RpcProviderService; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Factory metadata corresponding to the "routed-rpc-implementation" element that registers an RPC - * implementation with the RpcProviderRegistry and provides the RoutedRpcRegistration instance to the - * Blueprint container. - * - * @author Thomas Pantelis - */ -class RoutedRpcMetadata implements ComponentFactoryMetadata { - private static final Logger LOG = LoggerFactory.getLogger(RoutedRpcMetadata.class); - static final String ROUTED_RPC_IMPLEMENTATION = "routed-rpc-implementation"; - - private final String id; - private final String interfaceName; - private final String implementationRefId; - private ExtendedBlueprintContainer container; - - RoutedRpcMetadata(final String id, final String interfaceName, final String implementationRefId) { - this.id = id; - this.interfaceName = interfaceName; - this.implementationRefId = implementationRefId; - } - - @Override - public String getId() { - return id; - } - - @Override - public int getActivation() { - return ACTIVATION_LAZY; - } - - @Override - public List getDependsOn() { - return Arrays.asList(OpendaylightNamespaceHandler.BINDING_RPC_PROVIDER_SERVICE_NAME, implementationRefId); - } - - @Override - public void init(final ExtendedBlueprintContainer newContainer) { - this.container = newContainer; - - LOG.debug("{}: In init", logName()); - } - - @SuppressWarnings("checkstyle:IllegalCatch") - @Override - public Object create() throws ComponentDefinitionException { - RpcProviderService rpcRegistry = (RpcProviderService) container.getComponentInstance( - OpendaylightNamespaceHandler.BINDING_RPC_PROVIDER_SERVICE_NAME); - - Object implementation = container.getComponentInstance(implementationRefId); - - try { - if (!RpcService.class.isAssignableFrom(implementation.getClass())) { - throw new ComponentDefinitionException(String.format( - "Implementation \"ref\" instance %s for \"%s\" is not an RpcService", - implementation.getClass(), ROUTED_RPC_IMPLEMENTATION)); - } - - List> rpcInterfaces = RpcImplementationBean.getImplementedRpcServiceInterfaces( - interfaceName, implementation.getClass(), container.getBundleContext().getBundle(), - ROUTED_RPC_IMPLEMENTATION); - - if (rpcInterfaces.size() > 1) { - throw new ComponentDefinitionException(String.format( - "Implementation \"ref\" instance %s for \"%s\" implements more than one RpcService " - + "interface (%s). Please specify the exact \"interface\"", implementation.getClass(), - ROUTED_RPC_IMPLEMENTATION, rpcInterfaces)); - } - - Class rpcInterface = rpcInterfaces.iterator().next(); - - LOG.debug("{}: create - adding routed implementation {} for RpcService {}", logName(), - implementation, rpcInterface); - - return rpcRegistry.addRoutedRpcImplementation(rpcInterface, (RpcService)implementation); - } catch (final ComponentDefinitionException e) { - throw e; - } catch (final Exception e) { - throw new ComponentDefinitionException(String.format( - "Error processing \"%s\" for %s", ROUTED_RPC_IMPLEMENTATION, implementation.getClass()), e); - } - } - - @Override - public void destroy(final Object instance) { - LOG.debug("{}: In destroy: instance: {}", logName(), instance); - - ((RoutedRpcRegistration)instance).close(); - } - - private String logName() { - return (container != null ? container.getBundleContext().getBundle().getSymbolicName() : "") + " (" + id + ")"; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcRegistrationConverter.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcRegistrationConverter.java deleted file mode 100644 index 66174438b2..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcRegistrationConverter.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; -import org.osgi.service.blueprint.container.Converter; -import org.osgi.service.blueprint.container.ReifiedType; - -/** - * Implements a Converter that converts RoutedRpcRegistration instances. This is to work around an issue - * when injecting a RoutedRpcRegistration instance into a bean where Aries is not able to convert the instance - * returned from the RpcRegistryProvider to the desired generic RoutedRpcRegistration type specified in the - * bean's setter method. This is because the actual instance class specifies a generic type variable T and, - * even though it extends RpcService and should match, Aries doesn't handle it correctly. - * - * @author Thomas Pantelis - */ -public class RoutedRpcRegistrationConverter implements Converter { - @Override - public boolean canConvert(final Object sourceObject, final ReifiedType targetType) { - return sourceObject instanceof RoutedRpcRegistration - && RoutedRpcRegistration.class.isAssignableFrom(targetType.getRawClass()); - } - - @Override - public Object convert(final Object sourceObject, final ReifiedType targetType) { - return sourceObject; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcImplementationBean.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcImplementationBean.java deleted file mode 100644 index 94d5b3b22f..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcImplementationBean.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.Strings; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import org.opendaylight.mdsal.binding.api.RpcProviderService; -import org.opendaylight.yangtools.concepts.ObjectRegistration; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.osgi.framework.Bundle; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Blueprint bean corresponding to the "rpc-implementation" element that registers an RPC implementation with - * the RpcProviderRegistry. - * - * @author Thomas Pantelis - */ -public class RpcImplementationBean { - private static final Logger LOG = LoggerFactory.getLogger(RpcImplementationBean.class); - static final String RPC_IMPLEMENTATION = "rpc-implementation"; - - private RpcProviderService rpcProvider; - private Bundle bundle; - private String interfaceName; - private RpcService implementation; - private final List> rpcRegistrations = new ArrayList<>(); - - public void setRpcProvider(final RpcProviderService rpcProvider) { - this.rpcProvider = rpcProvider; - } - - public void setBundle(final Bundle bundle) { - this.bundle = bundle; - } - - public void setInterfaceName(final String interfaceName) { - this.interfaceName = interfaceName; - } - - public void setImplementation(final RpcService implementation) { - this.implementation = implementation; - } - - @SuppressWarnings("checkstyle:IllegalCatch") - public void init() { - try { - List> rpcInterfaces = getImplementedRpcServiceInterfaces(interfaceName, - implementation.getClass(), bundle, RPC_IMPLEMENTATION); - - LOG.debug("{}: init - adding implementation {} for RpcService interface(s) {}", bundle.getSymbolicName(), - implementation, rpcInterfaces); - - for (Class rpcInterface : rpcInterfaces) { - rpcRegistrations.add(rpcProvider.registerRpcImplementation(rpcInterface, implementation)); - } - } catch (final ComponentDefinitionException e) { - throw e; - } catch (final Exception e) { - throw new ComponentDefinitionException(String.format( - "Error processing \"%s\" for %s", RPC_IMPLEMENTATION, implementation.getClass()), e); - } - } - - public void destroy() { - for (ObjectRegistration reg: rpcRegistrations) { - reg.close(); - } - } - - @SuppressWarnings("unchecked") - static List> getImplementedRpcServiceInterfaces(final String interfaceName, - final Class implementationClass, final Bundle bundle, final String logName) - throws ClassNotFoundException { - if (!Strings.isNullOrEmpty(interfaceName)) { - Class rpcInterface = bundle.loadClass(interfaceName); - - if (!rpcInterface.isAssignableFrom(implementationClass)) { - throw new ComponentDefinitionException(String.format( - "The specified \"interface\" %s for \"%s\" is not implemented by RpcService \"ref\" %s", - interfaceName, logName, implementationClass)); - } - - return Collections.singletonList((Class)rpcInterface); - } - - List> rpcInterfaces = new ArrayList<>(); - for (Class intface : implementationClass.getInterfaces()) { - if (RpcService.class.isAssignableFrom(intface)) { - rpcInterfaces.add((Class) intface); - } - } - - if (rpcInterfaces.isEmpty()) { - throw new ComponentDefinitionException(String.format( - "The \"ref\" instance %s for \"%s\" does not implemented any RpcService interfaces", - implementationClass, logName)); - } - - return rpcInterfaces; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcServiceMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcServiceMetadata.java deleted file mode 100644 index 4ab3867214..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcServiceMetadata.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import java.util.function.Predicate; -import org.opendaylight.mdsal.dom.spi.RpcRoutingStrategy; - -/** - * Factory metadata corresponding to the "rpc-service" element that gets an RPC service implementation from - * the RpcProviderRegistry and provides it to the Blueprint container. - * - * @author Thomas Pantelis - */ -final class RpcServiceMetadata extends AbstractInvokableServiceMetadata { - RpcServiceMetadata(final String id, final String interfaceName) { - super(id, interfaceName); - } - - @Override - Predicate rpcFilter() { - return s -> !s.isContextBasedRouted(); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcUtil.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcUtil.java deleted file mode 100644 index 97b816d567..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/RpcUtil.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2017 Cisco Systems, Inc. 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.controller.blueprint.ext; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Predicate; -import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; -import org.opendaylight.mdsal.dom.spi.RpcRoutingStrategy; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.RpcDefinition; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility methods for dealing with various aspects of RPCs and actions. - * - * @author Robert Varga - */ -final class RpcUtil { - private static final Logger LOG = LoggerFactory.getLogger(RpcUtil.class); - - private RpcUtil() { - throw new UnsupportedOperationException(); - } - - static Collection decomposeRpcService(final Class service, - final SchemaContext schemaContext, final Predicate filter) { - final QNameModule moduleName = BindingReflections.getQNameModule(service); - final Module module = schemaContext.findModule(moduleName).orElseThrow(() -> new IllegalArgumentException( - "Module not found in SchemaContext: " + moduleName + "; service: " + service)); - LOG.debug("Resolved service {} to module {}", service, module); - - final Collection rpcs = module.getRpcs(); - final Collection ret = new ArrayList<>(rpcs.size()); - for (RpcDefinition rpc : rpcs) { - final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(rpc); - if (filter.test(strategy)) { - ret.add(rpc.getPath()); - } - } - - return ret; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/SpecificReferenceListMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/SpecificReferenceListMetadata.java deleted file mode 100644 index e781ddd16a..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/SpecificReferenceListMetadata.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.collect.ImmutableList; -import com.google.common.io.Resources; -import java.io.IOException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentSkipListSet; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleEvent; -import org.osgi.framework.ServiceReference; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.osgi.util.tracker.BundleTracker; -import org.osgi.util.tracker.BundleTrackerCustomizer; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Factory metadata corresponding to the "specific-reference-list" element that obtains a specific list - * of service instances from the OSGi registry for a given interface. The specific list is learned by first - * extracting the list of expected service types by inspecting RESOLVED bundles for a resource file under - * META-INF/services with the same name as the given interface. The type(s) listed in the resource file - * must match the "type" property of the advertised service(s). In this manner, an app bundle announces the - * service type(s) that it will advertise so that this class knows which services to expect up front. Once - * all the expected services are obtained, the container is notified that all dependencies of this component - * factory are satisfied. - * - * @author Thomas Pantelis - */ -class SpecificReferenceListMetadata extends AbstractDependentComponentFactoryMetadata { - private static final Logger LOG = LoggerFactory.getLogger(SpecificReferenceListMetadata.class); - - private final String interfaceName; - private final String serviceResourcePath; - private final Collection expectedServiceTypes = new ConcurrentSkipListSet<>(); - private final Collection retrievedServiceTypes = new ConcurrentSkipListSet<>(); - private final Collection retrievedServices = Collections.synchronizedList(new ArrayList<>()); - private volatile BundleTracker bundleTracker; - private volatile ServiceTracker serviceTracker; - - SpecificReferenceListMetadata(final String id, final String interfaceName) { - super(id); - this.interfaceName = interfaceName; - serviceResourcePath = "META-INF/services/" + interfaceName; - } - - @Override - protected void startTracking() { - BundleTrackerCustomizer bundleListener = new BundleTrackerCustomizer() { - @Override - public Bundle addingBundle(final Bundle bundle, final BundleEvent event) { - bundleAdded(bundle); - return bundle; - } - - @Override - public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Bundle object) { - } - - @Override - public void removedBundle(final Bundle bundle, final BundleEvent event, final Bundle object) { - } - }; - - bundleTracker = new BundleTracker<>(container().getBundleContext(), Bundle.RESOLVED | Bundle.STARTING - | Bundle.STOPPING | Bundle.ACTIVE, bundleListener); - - // This will get the list of all current RESOLVED+ bundles. - bundleTracker.open(); - - if (expectedServiceTypes.isEmpty()) { - setSatisfied(); - return; - } - - ServiceTrackerCustomizer serviceListener = new ServiceTrackerCustomizer() { - @Override - public Object addingService(final ServiceReference reference) { - return serviceAdded(reference); - } - - @Override - public void modifiedService(final ServiceReference reference, final Object service) { - } - - @Override - public void removedService(final ServiceReference reference, final Object service) { - container().getBundleContext().ungetService(reference); - } - }; - - setDependencyDesc(interfaceName + " services with types " + expectedServiceTypes); - - serviceTracker = new ServiceTracker<>(container().getBundleContext(), interfaceName, serviceListener); - serviceTracker.open(); - } - - private void bundleAdded(final Bundle bundle) { - URL resource = bundle.getEntry(serviceResourcePath); - if (resource == null) { - return; - } - - LOG.debug("{}: Found {} resource in bundle {}", logName(), resource, bundle.getSymbolicName()); - - try { - for (String line : Resources.readLines(resource, StandardCharsets.UTF_8)) { - int ci = line.indexOf('#'); - if (ci >= 0) { - line = line.substring(0, ci); - } - - line = line.trim(); - if (line.isEmpty()) { - continue; - } - - String serviceType = line; - LOG.debug("{}: Retrieved service type {}", logName(), serviceType); - expectedServiceTypes.add(serviceType); - } - } catch (final IOException e) { - setFailure(String.format("%s: Error reading resource %s from bundle %s", logName(), resource, - bundle.getSymbolicName()), e); - } - } - - private Object serviceAdded(final ServiceReference reference) { - Object service = container().getBundleContext().getService(reference); - String serviceType = (String) reference.getProperty(OpendaylightNamespaceHandler.TYPE_ATTR); - - LOG.debug("{}: Service type {} added from bundle {}", logName(), serviceType, - reference.getBundle().getSymbolicName()); - - if (serviceType == null) { - LOG.error("{}: Missing OSGi service property '{}' for service interface {} in bundle {}", logName(), - OpendaylightNamespaceHandler.TYPE_ATTR, interfaceName, reference.getBundle().getSymbolicName()); - return service; - } - - if (!expectedServiceTypes.contains(serviceType)) { - LOG.error("{}: OSGi service property '{}' for service interface {} in bundle {} was not found in the " - + "expected service types {} obtained via {} bundle resources. Is the bundle resource missing or " - + "the service type misspelled?", logName(), OpendaylightNamespaceHandler.TYPE_ATTR, interfaceName, - reference.getBundle().getSymbolicName(), expectedServiceTypes, serviceResourcePath); - return service; - } - - // If already satisfied, meaning we got all initial services, then a new bundle must've been - // dynamically installed or a prior service's blueprint container was restarted, in which case we - // restart our container. - if (isSatisfied()) { - restartContainer(); - } else { - retrievedServiceTypes.add(serviceType); - retrievedServices.add(service); - - if (retrievedServiceTypes.equals(expectedServiceTypes)) { - LOG.debug("{}: Got all expected service types", logName()); - setSatisfied(); - } else { - Set remaining = new HashSet<>(expectedServiceTypes); - remaining.removeAll(retrievedServiceTypes); - setDependencyDesc(interfaceName + " services with types " + remaining); - } - } - - return service; - } - - @Override - public Object create() throws ComponentDefinitionException { - LOG.debug("{}: In create: interfaceName: {}", logName(), interfaceName); - - super.onCreate(); - - LOG.debug("{}: create returning service list {}", logName(), retrievedServices); - - synchronized (retrievedServices) { - return ImmutableList.copyOf(retrievedServices); - } - } - - @Override - public void destroy(final Object instance) { - super.destroy(instance); - - if (bundleTracker != null) { - bundleTracker.close(); - bundleTracker = null; - } - - if (serviceTracker != null) { - serviceTracker.close(); - serviceTracker = null; - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("SpecificReferenceListMetadata [interfaceName=").append(interfaceName) - .append(", serviceResourcePath=").append(serviceResourcePath).append("]"); - return builder.toString(); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/StaticReferenceMetadata.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/StaticReferenceMetadata.java deleted file mode 100644 index 97c04af56f..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/StaticReferenceMetadata.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Factory metadata corresponding to the "static-reference" element that obtains an OSGi service and - * returns the actual instance. This differs from the standard "reference" element that returns a dynamic - * proxy whose underlying service instance can come and go. - * - * @author Thomas Pantelis - */ -class StaticReferenceMetadata extends AbstractDependentComponentFactoryMetadata { - private static final Logger LOG = LoggerFactory.getLogger(StaticReferenceMetadata.class); - - private final String interfaceName; - private volatile Object retrievedService; - - StaticReferenceMetadata(final String id, final String interfaceName) { - super(id); - this.interfaceName = interfaceName; - } - - @Override - protected void startTracking() { - retrieveService(interfaceName, interfaceName, service -> { - retrievedService = service; - setSatisfied(); - }); - } - - @Override - public Object create() throws ComponentDefinitionException { - super.onCreate(); - - LOG.debug("{}: create returning service {}", logName(), retrievedService); - - return retrievedService; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("StaticReferenceMetadata [interfaceName=").append(interfaceName).append("]"); - return builder.toString(); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/StaticServiceReferenceRecipe.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/StaticServiceReferenceRecipe.java deleted file mode 100644 index 43ad997ea4..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/StaticServiceReferenceRecipe.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.controller.blueprint.ext; - -import com.google.common.base.Preconditions; -import java.util.Collections; -import java.util.function.Consumer; -import org.apache.aries.blueprint.container.AbstractServiceReferenceRecipe; -import org.apache.aries.blueprint.services.ExtendedBlueprintContainer; -import org.osgi.framework.ServiceReference; -import org.osgi.service.blueprint.container.ComponentDefinitionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A Blueprint bean recipe for a static OSGi service reference, meaning it obtains the service instance once - * and doesn't react to service removal. In addition the returned object is the actual service instance and - * not a proxy. - * - * @author Thomas Pantelis - */ -class StaticServiceReferenceRecipe extends AbstractServiceReferenceRecipe { - private static final Logger LOG = LoggerFactory.getLogger(StaticServiceReferenceRecipe.class); - - private static final SatisfactionListener NOOP_LISTENER = satisfiable -> { - // Intentional NOOP - }; - - private volatile ServiceReference trackedServiceReference; - private volatile Object trackedService; - private Consumer serviceSatisfiedCallback; - - StaticServiceReferenceRecipe(final String name, final ExtendedBlueprintContainer blueprintContainer, - final String interfaceClass) { - super(name, blueprintContainer, new MandatoryServiceReferenceMetadata(name, interfaceClass), null, null, - Collections.emptyList()); - } - - void startTracking(final Consumer newServiceSatisfiedCallback) { - this.serviceSatisfiedCallback = newServiceSatisfiedCallback; - super.start(NOOP_LISTENER); - } - - @SuppressWarnings("rawtypes") - @Override - protected void track(final ServiceReference reference) { - retrack(); - } - - @SuppressWarnings("rawtypes") - @Override - protected void untrack(final ServiceReference reference) { - LOG.debug("{}: In untrack {}", getName(), reference); - - if (trackedServiceReference == reference) { - LOG.debug("{}: Current reference {} has been untracked", getName(), trackedServiceReference); - } - } - - @Override - protected void retrack() { - LOG.debug("{}: In retrack", getName()); - - if (trackedServiceReference == null) { - trackedServiceReference = getBestServiceReference(); - - LOG.debug("{}: getBestServiceReference: {}", getName(), trackedServiceReference); - - if (trackedServiceReference != null && serviceSatisfiedCallback != null) { - serviceSatisfiedCallback.accept(internalCreate()); - } - } - } - - @Override - // Disables "Either log or rethrow this exception" sonar warning - @SuppressWarnings("squid:S1166") - protected void doStop() { - LOG.debug("{}: In doStop", getName()); - - if (trackedServiceReference != null && trackedService != null) { - try { - getBundleContextForServiceLookup().ungetService(trackedServiceReference); - } catch (final IllegalStateException e) { - // In case the service no longer exists, ignore. - } - - trackedServiceReference = null; - trackedService = null; - } - } - - @Override - protected Object internalCreate() throws ComponentDefinitionException { - ServiceReference localTrackedServiceReference = trackedServiceReference; - - LOG.debug("{}: In internalCreate: trackedServiceReference: {}", getName(), localTrackedServiceReference); - - // being paranoid - internalCreate should only get called once - if (trackedService != null) { - return trackedService; - } - - Preconditions.checkNotNull(localTrackedServiceReference, "trackedServiceReference is null"); - - trackedService = getServiceSecurely(localTrackedServiceReference); - - LOG.debug("{}: Returning service instance: {}", getName(), trackedService); - - Preconditions.checkNotNull(trackedService, "getService() returned null for %s", localTrackedServiceReference); - - return trackedService; - } - - @Override - public boolean isStaticLifecycle() { - return true; - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/UpdateStrategy.java b/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/UpdateStrategy.java deleted file mode 100644 index 2f83bc688f..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/java/org/opendaylight/controller/blueprint/ext/UpdateStrategy.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.controller.blueprint.ext; - -/** - * Enumerates possible strategies when a component is updated. - * - * @author Vishal Thapar - */ -public enum UpdateStrategy { - /* - * Restart container - */ - RELOAD, - /* - * Don't do anything - */ - NONE -} diff --git a/blueprint/mdsal-blueprint-binding/src/main/resources/opendaylight-blueprint-ext-1.0.0.xsd b/blueprint/mdsal-blueprint-binding/src/main/resources/opendaylight-blueprint-ext-1.0.0.xsd deleted file mode 100644 index 5bd8ed042c..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/main/resources/opendaylight-blueprint-ext-1.0.0.xsd +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/blueprint/mdsal-blueprint-binding/src/test/java/org/opendaylight/controller/blueprint/tests/DataStoreAppConfigDefaultXMLReaderTest.java b/blueprint/mdsal-blueprint-binding/src/test/java/org/opendaylight/controller/blueprint/tests/DataStoreAppConfigDefaultXMLReaderTest.java deleted file mode 100644 index a1cf3d729b..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/test/java/org/opendaylight/controller/blueprint/tests/DataStoreAppConfigDefaultXMLReaderTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat, Inc. 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.controller.blueprint.tests; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Test; -import org.opendaylight.controller.blueprint.ext.DataStoreAppConfigDefaultXMLReader; -import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.store.rev140422.Lists; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.store.rev140422.lists.unordered.container.UnorderedList; - -/** - * Example unit test using the {@link DataStoreAppConfigDefaultXMLReader}. - * - * @author Michael Vorburger.ch - */ -public class DataStoreAppConfigDefaultXMLReaderTest extends AbstractConcurrentDataBrokerTest { - - @Test - public void testConfigXML() throws Exception { - Lists lists = new DataStoreAppConfigDefaultXMLReader<>( - getClass(), "/opendaylight-sal-test-store-config.xml", - getDataBrokerTestCustomizer().getSchemaService(), - getDataBrokerTestCustomizer().getBindingToNormalized(), - Lists.class).createDefaultInstance(); - - UnorderedList element = lists.getUnorderedContainer().getUnorderedList().get(0); - assertThat(element.getName()).isEqualTo("someName"); - assertThat(element.getValue()).isEqualTo("someValue"); - } - - @Test(expected = IllegalArgumentException.class) - public void testBadXMLName() throws Exception { - new DataStoreAppConfigDefaultXMLReader<>( - getClass(), "/badname.xml", - getDataBrokerTestCustomizer().getSchemaService(), - getDataBrokerTestCustomizer().getBindingToNormalized(), - Lists.class).createDefaultInstance(); - } -} diff --git a/blueprint/mdsal-blueprint-binding/src/test/resources/opendaylight-sal-test-store-config.xml b/blueprint/mdsal-blueprint-binding/src/test/resources/opendaylight-sal-test-store-config.xml deleted file mode 100644 index b2744b2fea..0000000000 --- a/blueprint/mdsal-blueprint-binding/src/test/resources/opendaylight-sal-test-store-config.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - someName - someValue - - -