+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
- Copyright © 2019 Pantheon Technologies, s.r.o. and others. All rights reserved.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v1.0 which accompanies this distribution,
- and is available at http://www.eclipse.org/legal/epl-v10.html
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>dom-parent</artifactId>
- <version>6.0.0-SNAPSHOT</version>
- <relativePath>../../dom/dom-parent</relativePath>
- </parent>
-
- <artifactId>mdsal-blueprint-binding</artifactId>
- <packaging>bundle</packaging>
- <name>${project.artifactId}</name>
- <version>6.0.0-SNAPSHOT</version>
-
- <dependencies>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.aries.blueprint</groupId>
- <artifactId>org.apache.aries.blueprint.core</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.aries</groupId>
- <artifactId>org.apache.aries.util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-dom-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-dom-spi</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-binding-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-binding-dom-codec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-codec-xml</artifactId>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.compendium</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.service.event</artifactId>
- </dependency>
- <dependency>
- <groupId>com.google.truth</groupId>
- <artifactId>truth</artifactId>
- </dependency>
- <!--dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-test-model</artifactId>
- <scope>test</scope>
- </dependency-->
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-binding-dom-adapter</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-binding-dom-adapter</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Bundle-Activator>org.opendaylight.controller.blueprint.BlueprintBundleTracker</Bundle-Activator>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
+++ /dev/null
-/*
- * 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<Bundle>, 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<BlueprintExtenderService, BlueprintExtenderService> blueprintExtenderServiceTracker;
- private ServiceTracker<QuiesceParticipant, QuiesceParticipant> quiesceParticipantTracker;
- private BundleTracker<Bundle> 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<BlueprintExtenderService, BlueprintExtenderService>() {
- @Override
- public BlueprintExtenderService addingService(
- final ServiceReference<BlueprintExtenderService> reference) {
- return onBlueprintExtenderServiceAdded(reference);
- }
-
- @Override
- public void modifiedService(final ServiceReference<BlueprintExtenderService> reference,
- final BlueprintExtenderService service) {
- }
-
- @Override
- public void removedService(final ServiceReference<BlueprintExtenderService> reference,
- final BlueprintExtenderService service) {
- }
- });
- blueprintExtenderServiceTracker.open();
-
- quiesceParticipantTracker = new ServiceTracker<>(context, QuiesceParticipant.class.getName(),
- new ServiceTrackerCustomizer<QuiesceParticipant, QuiesceParticipant>() {
- @Override
- public QuiesceParticipant addingService(
- final ServiceReference<QuiesceParticipant> reference) {
- return onQuiesceParticipantAdded(reference);
- }
-
- @Override
- public void modifiedService(final ServiceReference<QuiesceParticipant> reference,
- final QuiesceParticipant service) {
- }
-
- @Override
- public void removedService(final ServiceReference<QuiesceParticipant> reference,
- final QuiesceParticipant service) {
- }
- });
- quiesceParticipantTracker.open();
- }
-
- private QuiesceParticipant onQuiesceParticipantAdded(final ServiceReference<QuiesceParticipant> reference) {
- quiesceParticipant = reference.getBundle().getBundleContext().getService(reference);
-
- LOG.debug("Got QuiesceParticipant");
-
- restartService.setQuiesceParticipant(quiesceParticipant);
-
- return quiesceParticipant;
- }
-
- private BlueprintExtenderService onBlueprintExtenderServiceAdded(
- final ServiceReference<BlueprintExtenderService> 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<String, Object> 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<Object> 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<Object> 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<Object> 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<Bundle> 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<Bundle> getBundlesToDestroy(final Collection<Bundle> containerBundles) {
- List<Bundle> 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<Bundle> 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;
- }
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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<Object> 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<Bundle> containerBundlesSet = new LinkedHashSet<>();
- findDependentContainersRecursively(forBundle, containerBundlesSet);
-
- List<Bundle> 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<Bundle> 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<Bundle> containerBundles) {
- containerBundles.forEach(bundle -> {
- List<Object> 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<Bundle> 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();
- }
-}
+++ /dev/null
-/*
- * 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<StaticServiceReferenceRecipe> 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<String> 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<Object> onServiceRetrieved) {
- retrieveService(name, interfaceClass.getName(), onServiceRetrieved);
- }
-
- protected void retrieveService(final String name, final String interfaceName,
- final Consumer<Object> 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> T getOSGiService(final Class<T> serviceInterface) {
- try {
- ServiceReference<T> 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;
- }
-}
+++ /dev/null
-/*
- * 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<DOMRpcAvailabilityListener> rpcListenerReg;
- private RpcConsumerRegistry rpcRegistry;
- private Class<RpcService> rpcInterface;
- private Set<SchemaPath> rpcSchemaPaths;
-
- AbstractInvokableServiceMetadata(final String id, final String interfaceName) {
- super(id);
- this.interfaceName = Preconditions.checkNotNull(interfaceName);
- }
-
- Class<RpcService> 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<RpcService>)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<SchemaPath> 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<DOMRpcIdentifier> rpcs) {
- onRpcsAvailable(rpcs);
- }
-
- @Override
- public void onRpcUnavailable(final Collection<DOMRpcIdentifier> rpcs) {
- }
- });
- }
-
- abstract Predicate<RpcRoutingStrategy> 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<DOMRpcIdentifier> 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();
- }
-}
+++ /dev/null
-/*
- * 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.
- *
- * <p>
- * 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<RpcService> 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<RpcService> 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<RpcService>) iface;
- }
-
- private void registerFallback(final Class<RpcService> interfaceClass) {
- final Collection<SchemaPath> paths = RpcUtil.decomposeRpcService(interfaceClass,
- schemaService.getGlobalContext(), RpcRoutingStrategy::isContextBasedRouted);
- if (paths.isEmpty()) {
- LOG.warn("{}: interface {} has no actions defined", ACTION_PROVIDER, interfaceClass);
- return;
- }
-
- final Set<DOMRpcIdentifier> 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<RpcService> 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);
- }
-}
+++ /dev/null
-/*
- * 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<RpcRoutingStrategy> rpcFilter() {
- return RpcRoutingStrategy::isContextBasedRouted;
- }
-}
+++ /dev/null
-/*
- * 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<? extends DataObject> 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<DataObject> appConfigPath;
- public final Class<DataObject> appConfigBindingClass;
- public final Class<? extends DataSchemaNode> schemaType;
- public final QName bindingQName;
-
- private BindingContext(final Class<DataObject> appConfigBindingClass,
- final InstanceIdentifier<DataObject> appConfigPath, final Class<? extends DataSchemaNode> 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<? extends DataObject> appConfigBindingClass) {
- super((Class<DataObject>) appConfigBindingClass,
- InstanceIdentifier.create((Class<DataObject>) 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<? extends DataObject> appConfigBindingClass,
- final InstanceIdentifier<? extends DataObject> appConfigPath, final String appConfigListKeyValue) {
- super((Class<DataObject>) appConfigBindingClass, (InstanceIdentifier<DataObject>) appConfigPath,
- ListSchemaNode.class);
- this.appConfigListKeyValue = appConfigListKeyValue;
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static ListBindingContext newInstance(final Class<? extends DataObject> 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<QName> 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();
- }
- }
-}
+++ /dev/null
-/*
- * 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<ServiceRegistration<?>> 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<String, ?> previousProperties;
-
- @Override
- public void updated(final Dictionary<String, ?> 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<String, Object> 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();
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-
-}
+++ /dev/null
-/*
- * 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<T extends DataObject> {
-
- 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<URL> 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<T> 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<URL> 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));
- }
-
-}
+++ /dev/null
-/*
- * 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<DataObject> 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<DataObject>) 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<DataObject> dataTreeId = DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
- bindingContext.appConfigPath);
- appConfigChangeListenerReg = dataBroker.registerDataTreeChangeListener(dataTreeId,
- (ClusteredDataTreeChangeListener<DataObject>) this::onAppConfigChanged);
-
- readInitialAppConfig(dataBroker);
- }
-
- private void readInitialAppConfig(final DataBroker dataBroker) {
- try (ReadTransaction readOnlyTx = dataBroker.newReadOnlyTransaction()) {
- readOnlyTx.read(LogicalDatastoreType.CONFIGURATION, bindingContext.appConfigPath).addCallback(
- new FutureCallback<Optional<DataObject>>() {
- @Override
- public void onSuccess(final Optional<DataObject> 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<DataTreeModification<DataObject>> changes) {
- for (DataTreeModification<DataObject> change: changes) {
- DataObjectModification<DataObject> 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<DataObject> 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;
- }
- }
-
-}
+++ /dev/null
-/*
- * 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<String> 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<ReferenceListener> getReferenceListeners() {
- return Collections.emptyList();
- }
-}
+++ /dev/null
-/*
- * 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());
- }
- }
-}
+++ /dev/null
-/*
- * 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<Class> 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 <reference>, <reference-list> or <service> 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 <blueprint> 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;
- }
-}
+++ /dev/null
-/*
- * 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<String> 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<Class<RpcService>> 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<RpcService> 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 + ")";
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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<ObjectRegistration<RpcService>> 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<Class<RpcService>> rpcInterfaces = getImplementedRpcServiceInterfaces(interfaceName,
- implementation.getClass(), bundle, RPC_IMPLEMENTATION);
-
- LOG.debug("{}: init - adding implementation {} for RpcService interface(s) {}", bundle.getSymbolicName(),
- implementation, rpcInterfaces);
-
- for (Class<RpcService> 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<RpcService> reg: rpcRegistrations) {
- reg.close();
- }
- }
-
- @SuppressWarnings("unchecked")
- static List<Class<RpcService>> 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<RpcService>)rpcInterface);
- }
-
- List<Class<RpcService>> rpcInterfaces = new ArrayList<>();
- for (Class<?> intface : implementationClass.getInterfaces()) {
- if (RpcService.class.isAssignableFrom(intface)) {
- rpcInterfaces.add((Class<RpcService>) 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;
- }
-}
+++ /dev/null
-/*
- * 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<RpcRoutingStrategy> rpcFilter() {
- return s -> !s.isContextBasedRouted();
- }
-}
+++ /dev/null
-/*
- * 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<SchemaPath> decomposeRpcService(final Class<RpcService> service,
- final SchemaContext schemaContext, final Predicate<RpcRoutingStrategy> 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<RpcDefinition> rpcs = module.getRpcs();
- final Collection<SchemaPath> 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;
- }
-}
+++ /dev/null
-/*
- * 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<String> expectedServiceTypes = new ConcurrentSkipListSet<>();
- private final Collection<String> retrievedServiceTypes = new ConcurrentSkipListSet<>();
- private final Collection<Object> retrievedServices = Collections.synchronizedList(new ArrayList<>());
- private volatile BundleTracker<Bundle> bundleTracker;
- private volatile ServiceTracker<Object, Object> serviceTracker;
-
- SpecificReferenceListMetadata(final String id, final String interfaceName) {
- super(id);
- this.interfaceName = interfaceName;
- serviceResourcePath = "META-INF/services/" + interfaceName;
- }
-
- @Override
- protected void startTracking() {
- BundleTrackerCustomizer<Bundle> bundleListener = new BundleTrackerCustomizer<Bundle>() {
- @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<Object, Object> serviceListener = new ServiceTrackerCustomizer<Object, Object>() {
- @Override
- public Object addingService(final ServiceReference<Object> reference) {
- return serviceAdded(reference);
- }
-
- @Override
- public void modifiedService(final ServiceReference<Object> reference, final Object service) {
- }
-
- @Override
- public void removedService(final ServiceReference<Object> 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<Object> 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<String> 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();
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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<Object> 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<Object> 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;
- }
-}
+++ /dev/null
-/*
- * 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
-}
+++ /dev/null
-<xsd:schema xmlns="http://opendaylight.org/xmlns/blueprint/v1.0.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
- targetNamespace="http://opendaylight.org/xmlns/blueprint/v1.0.0" elementFormDefault="qualified"
- attributeFormDefault="unqualified" version="1.0.0">
-
- <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0"/>
-
- <xsd:attribute name="restart-dependents-on-updates" type="xsd:boolean"/>
- <xsd:attribute name="use-default-for-reference-types" type="xsd:boolean"/>
- <xsd:attribute name="type" type="xsd:string"/>
-
- <!--
- String representation of an instance identifier. Precise string format
- is undefined just now.
- -->
- <xsd:simpleType name="Tpath">
- <xsd:restriction base="xsd:string"/>
- </xsd:simpleType>
-
- <!--
- A promise to instantiate actions of specified binding interface.
- Specified interface must define at least one action. In case a bean
- is specified, it will be used as the implementation of last resort
- for actions not otherwise bound. If a bean is not specified, a blank
- implementation will be substituted.
- -->
- <xsd:complexType name="TactionProvider">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="ref" type="bp:Tidref" use="optional"/>
- </xsd:complexType>
- <xsd:element name="action-provider" type="TactionProvider"/>
-
- <!--
- A reference to an action-provider providing specified interface.
- Specified interface must define at least one action.
- -->
- <xsd:complexType name="TactionService">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="action-service" type="TactionService"/>
-
- <!--
- Implementation of an action at specific instance. This is used
- to provide binding to actions on specific context, rather than
- to a more general contract of action-provider.
- <xsd:complexType name="TactionImplementation">
- <xsd:attribute name="interface" type="bp:Tclass" use="optional"/>
- <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
- <xsd:attribute name="path" type="Tpath" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="action-implementation" type="TactionImplementation"/ -->
-
- <!--
- A reference to a specific action-implementation.
- <xsd:complexType name="TactionInstance">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="path" type="Tpath" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="action-instance" type="TactionInstance"/ -->
-
- <xsd:complexType name="TrpcImplementation">
- <xsd:attribute name="interface" type="bp:Tclass" use="optional"/>
- <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
- </xsd:complexType>
- <xsd:element name="rpc-implementation" type="TrpcImplementation"/>
-
- <!--
- To be deprecated. This interface contract is fulfilled by
- action-implementation instead
- -->
- <xsd:complexType name="TroutedRpcImplementation">
- <xsd:attribute name="interface" type="bp:Tclass" use="optional"/>
- <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="routed-rpc-implementation" type="TroutedRpcImplementation"/>
-
- <xsd:complexType name="TrpcService">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="rpc-service" type="TrpcService"/>
-
- <xsd:complexType name="TnotificationListener">
- <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
- </xsd:complexType>
- <xsd:element name="notification-listener" type="TnotificationListener"/>
-
- <xsd:complexType name="TclusteredAppConfig">
- <xsd:sequence>
- <xsd:element name="default-config" type="xsd:string" minOccurs="0" maxOccurs="1"/>
- </xsd:sequence>
- <xsd:attribute name="binding-class" type="bp:Tclass" use="required"/>
- <xsd:attribute name="list-key-value" type="xsd:string" use="optional"/>
- <xsd:attribute name="default-config-file-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="id" type="xsd:ID" use="required"/>
- <xsd:attribute name="update-strategy" type="TupdateStrategy" use="optional" default="reload"/>
- </xsd:complexType>
- <xsd:element name="clustered-app-config" type="TclusteredAppConfig"/>
- <xsd:simpleType name="TupdateStrategy">
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="none"/>
- <xsd:enumeration value="reload"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:complexType name="TspecificReferenceList">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="specific-reference-list" type="TspecificReferenceList"/>
-
- <xsd:complexType name="TstaticReference">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="static-reference" type="TstaticReference"/>
-</xsd:schema>
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-<lists xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:store">
- <unordered-container>
- <unordered-list>
- <name>someName</name>
- <value>someValue</value>
- </unordered-list>
- </unordered-container>
-</lists>