Add restart-dependents-on-update blueprint extension
[controller.git] / opendaylight / blueprint / src / main / java / org / opendaylight / controller / blueprint / BlueprintContainerRestartServiceImpl.java
1 /*
2  * Copyright (c) 2016 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.blueprint;
9
10 import com.google.common.util.concurrent.ThreadFactoryBuilder;
11 import java.util.ArrayList;
12 import java.util.LinkedHashSet;
13 import java.util.List;
14 import java.util.Set;
15 import java.util.concurrent.ExecutorService;
16 import java.util.concurrent.Executors;
17 import org.apache.aries.blueprint.services.BlueprintExtenderService;
18 import org.osgi.framework.Bundle;
19 import org.osgi.framework.ServiceReference;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 /** Implementation of the BlueprintContainerRestartService.
24  *
25  * @author Thomas Pantelis
26  */
27 class BlueprintContainerRestartServiceImpl implements AutoCloseable, BlueprintContainerRestartService {
28     private static final Logger LOG = LoggerFactory.getLogger(BlueprintContainerRestartServiceImpl.class);
29
30     private final ExecutorService restartExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().
31             setDaemon(true).setNameFormat("BlueprintContainerRestartService").build());
32     private final BlueprintExtenderService blueprintExtenderService;
33
34     BlueprintContainerRestartServiceImpl(BlueprintExtenderService blueprintExtenderService) {
35         this.blueprintExtenderService = blueprintExtenderService;
36     }
37
38     @Override
39     public void restartContainerAndDependents(final Bundle bundle) {
40         LOG.debug("restartContainerAndDependents for bundle {}", bundle);
41
42         restartExecutor.execute(new Runnable() {
43             @Override
44             public void run() {
45                 restartContainerAndDependentsInternal(bundle);
46
47             }
48         });
49     }
50
51     private void restartContainerAndDependentsInternal(Bundle forBundle) {
52         Set<Bundle> containerBundlesSet = new LinkedHashSet<>();
53         findDependentContainersRecursively(forBundle, containerBundlesSet);
54
55         List<Bundle> containerBundles = new ArrayList<>(containerBundlesSet);
56
57         LOG.info("Restarting blueprint containers for bundle {} and its dependent bundles {}", forBundle,
58                 containerBundles.subList(1, containerBundles.size()));
59
60         // Destroy the containers in reverse order with 'forBundle' last, ie bottom-up in the service tree.
61         for(int i = containerBundles.size() - 1; i >= 0; i--) {
62             Bundle bundle = containerBundles.get(i);
63             blueprintExtenderService.destroyContainer(bundle, blueprintExtenderService.getContainer(bundle));
64         }
65
66         // Restart the containers top-down starting with 'forBundle'.
67         for(Bundle bundle: containerBundles) {
68             List<Object> paths = BlueprintBundleTracker.findBlueprintPaths(bundle);
69
70             LOG.info("Restarting blueprint container for bundle {} with paths {}", bundle, paths);
71
72             blueprintExtenderService.createContainer(bundle, paths);
73         }
74     }
75
76     /**
77      * Recursively finds the services registered by the given bundle and the bundles using those services.
78      * User bundles that have an associated blueprint container are added to containerBundles.
79      *
80      * @param bundle the bundle to traverse
81      * @param containerBundles the current set of bundles containing blueprint containers
82      */
83     private void findDependentContainersRecursively(Bundle bundle, Set<Bundle> containerBundles) {
84         if(containerBundles.contains(bundle)) {
85             return;
86         }
87
88         containerBundles.add(bundle);
89         ServiceReference<?>[] references = bundle.getRegisteredServices();
90         if (references != null) {
91             for (ServiceReference<?> reference : references) {
92                 Bundle[] usingBundles = reference.getUsingBundles();
93                 if(usingBundles != null) {
94                     for(Bundle usingBundle: usingBundles) {
95                         if(blueprintExtenderService.getContainer(usingBundle) != null) {
96                             findDependentContainersRecursively(usingBundle, containerBundles);
97                         }
98                     }
99                 }
100             }
101         }
102     }
103
104     @Override
105     public void close() {
106         restartExecutor.shutdownNow();
107     }
108 }