Bump karaf to 4.4.2
[odlparent.git] / bundles-test-lib / src / main / java / org / opendaylight / odlparent / bundlestest / lib / BundleDiagInfosImpl.java
1 /*
2  * Copyright (c) 2016, 2017 Red Hat, 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.odlparent.bundlestest.lib;
9
10 import static org.apache.karaf.bundle.core.BundleState.Active;
11 import static org.apache.karaf.bundle.core.BundleState.Installed;
12 import static org.apache.karaf.bundle.core.BundleState.Waiting;
13
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.EnumMap;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import org.apache.karaf.bundle.core.BundleInfo;
21 import org.apache.karaf.bundle.core.BundleService;
22 import org.apache.karaf.bundle.core.BundleState;
23 import org.osgi.framework.Bundle;
24 import org.osgi.framework.BundleContext;
25
26 /**
27  * {@link BundleDiagInfos} implementation.
28  *
29  * @author Michael Vorburger.ch
30  */
31 // intentionally just package-local
32 final class BundleDiagInfosImpl implements BundleDiagInfos {
33     private static final long serialVersionUID = 1L;
34
35     private static final Map<String, BundleState> WHITELISTED_BUNDLES;
36
37     static {
38         WHITELISTED_BUNDLES = new HashMap<>();
39         WHITELISTED_BUNDLES.put("slf4j.log4j12", Installed);
40         WHITELISTED_BUNDLES.put("org.apache.karaf.scr.management", Waiting); // ODLPARENT-144
41     }
42
43     private final List<String> okBundleStateInfoTexts;
44     private final List<String> nokBundleStateInfoTexts;
45     private final List<String> whitelistedBundleStateInfoTexts;
46     private final Map<BundleState, Integer> bundleStatesCounters;
47     private final Map<BundleSymbolicNameWithVersion, BundleState> bundlesStateMap;
48
49     /**
50      * Create an instance. The collections provided as arguments will be kept as-is; it’s up to the caller
51      * to ensure they’re handled defensively, as appropriate.
52      *
53      * @param okBundleStateInfoTexts information about bundles in OK state.
54      * @param nokBundleStateInfoTexts information about bundles not in OK state.
55      * @param whitelistedBundleStateInfoTexts information about whitelisted bundles.
56      * @param bundleStatesCounters bundle state counters.
57      * @param bundlesStateMap bundle state map (state of each bundle).
58      */
59     private BundleDiagInfosImpl(List<String> okBundleStateInfoTexts, List<String> nokBundleStateInfoTexts,
60             List<String> whitelistedBundleStateInfoTexts, Map<BundleState, Integer> bundleStatesCounters,
61             Map<BundleSymbolicNameWithVersion, BundleState> bundlesStateMap) {
62         this.okBundleStateInfoTexts = okBundleStateInfoTexts;
63         this.nokBundleStateInfoTexts = nokBundleStateInfoTexts;
64         this.whitelistedBundleStateInfoTexts = whitelistedBundleStateInfoTexts;
65         this.bundleStatesCounters = bundleStatesCounters;
66         this.bundlesStateMap = bundlesStateMap;
67     }
68
69     public static BundleDiagInfos forContext(BundleContext bundleContext, BundleService bundleService) {
70         List<String> okBundleStateInfoTexts = new ArrayList<>();
71         List<String> nokBundleStateInfoTexts = new ArrayList<>();
72         List<String> whitelistedBundleStateInfoTexts = new ArrayList<>();
73         Map<BundleSymbolicNameWithVersion, BundleState> bundlesStateMap = new HashMap<>();
74         Map<BundleState, Integer> bundleStatesCounters = new EnumMap<>(BundleState.class);
75         for (BundleState bundleState : BundleState.values()) {
76             bundleStatesCounters.put(bundleState, 0);
77         }
78
79         for (Bundle bundle : bundleContext.getBundles()) {
80             String bundleSymbolicName = bundle.getSymbolicName();
81             BundleSymbolicNameWithVersion bundleSymbolicNameWithVersion
82                 = new BundleSymbolicNameWithVersion(bundleSymbolicName, bundle.getVersion().toString());
83
84             BundleInfo karafBundleInfo = bundleService.getInfo(bundle);
85             BundleState karafBundleState = karafBundleInfo.getState();
86             bundlesStateMap.put(bundleSymbolicNameWithVersion, karafBundleState);
87
88             String bundleStateDiagText = "OSGi state = " + bundleStateToText(bundle.getState())
89                 + ", Karaf bundleState = " + karafBundleState;
90             String diagText = bundleService.getDiag(bundle);
91             if (!diagText.isEmpty()) {
92                 bundleStateDiagText += ", due to: " + diagText;
93             }
94
95             if (WHITELISTED_BUNDLES.get(bundleSymbolicName) != null) {
96                 if (WHITELISTED_BUNDLES.get(bundleSymbolicName).equals(karafBundleState)) {
97                     String msg = "WHITELISTED " + bundleSymbolicNameWithVersion + ": " + bundleStateDiagText;
98                     whitelistedBundleStateInfoTexts.add(msg);
99                     continue;
100                 }
101             }
102
103             bundleStatesCounters.compute(karafBundleState, (key, counter) -> counter + 1);
104
105             // BundleState comparison as in Karaf's "diag" command,
106             // see https://github.com/apache/karaf/blob/master/bundle/core/src/main/java/org/apache/karaf/bundle/command/Diag.java
107             // but we intentionally, got a little further than Karaf's "diag" command,
108             // and instead of only checking some states, we check what's really Active,
109             // but accept that some remain just Resolved:
110             if (karafBundleState != Active && karafBundleState != BundleState.Resolved) {
111                 String msg = "NOK " + bundleSymbolicNameWithVersion + ": " + bundleStateDiagText;
112                 nokBundleStateInfoTexts.add(msg);
113             } else {
114                 String msg = "OK " + bundleSymbolicNameWithVersion + ": " + bundleStateDiagText;
115                 okBundleStateInfoTexts.add(msg);
116             }
117         }
118
119         return new BundleDiagInfosImpl(Collections.unmodifiableList(okBundleStateInfoTexts),
120                 Collections.unmodifiableList(nokBundleStateInfoTexts),
121                 Collections.unmodifiableList(whitelistedBundleStateInfoTexts),
122                 Collections.unmodifiableMap(bundleStatesCounters), Collections.unmodifiableMap(bundlesStateMap));
123     }
124
125     private static String bundleStateToText(int state) {
126         return switch (state) {
127             case Bundle.INSTALLED -> "Installed";
128             case Bundle.RESOLVED -> "Resolved";
129             case Bundle.STARTING -> "Starting";
130             case Bundle.ACTIVE -> "Active";
131             case Bundle.STOPPING -> "Stopping";
132             case Bundle.UNINSTALLED -> "Uninstalled";
133             default -> state + "???";
134         };
135     }
136
137     @Override
138     public SystemState getSystemState() {
139         if (bundleStatesCounters.get(BundleState.Failure) > 0) {
140             return SystemState.Failure;
141         } else if (bundleStatesCounters.get(BundleState.Stopping) > 0) {
142             return SystemState.Stopping;
143         } else if (bundleStatesCounters.get(BundleState.Installed) == 0
144                 // No, just Resolved is OK, so do not: && bundleStatesCounters.get(BundleState.Resolved) == 0
145                 && bundleStatesCounters.get(BundleState.Unknown) == 0
146                 && bundleStatesCounters.get(BundleState.GracePeriod) == 0
147                 && bundleStatesCounters.get(BundleState.Waiting) == 0
148                 && bundleStatesCounters.get(BundleState.Starting) == 0
149                 // BundleState.Active *should* be ~= total # of bundles (minus Resolved, and whitelisted installed)
150                 && bundleStatesCounters.get(BundleState.Stopping) == 0
151                 && bundleStatesCounters.get(BundleState.Failure) == 0) {
152             return SystemState.Active;
153         } else {
154             return SystemState.Booting;
155         }
156     }
157
158     @Override
159     public String getFullDiagnosticText() {
160         StringBuilder sb = new StringBuilder(getSummaryText());
161         int failureNumber = 1;
162         for (String nokBundleStateInfoText : getNokBundleStateInfoTexts()) {
163             sb.append('\n');
164             sb.append(failureNumber++);
165             sb.append(". ");
166             sb.append(nokBundleStateInfoText);
167         }
168         return sb.toString();
169     }
170
171     @Override
172     public String getSummaryText() {
173         return "diag: " + getSystemState() + " " + bundleStatesCounters.toString();
174     }
175
176     @Override
177     public Map<BundleSymbolicNameWithVersion, BundleState> getBundlesStateMap() {
178         return bundlesStateMap;
179     }
180
181     @Override
182     public List<String> getNokBundleStateInfoTexts() {
183         return nokBundleStateInfoTexts;
184     }
185
186     @Override
187     public List<String> getOkBundleStateInfoTexts() {
188         return okBundleStateInfoTexts;
189     }
190
191     @Override
192     public List<String> getWhitelistedBundleStateInfoTexts() {
193         return whitelistedBundleStateInfoTexts;
194     }
195
196     @Override
197     public String toString() {
198         return getFullDiagnosticText();
199     }
200
201 }