Bump spotbugs to 4.7.3
[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             String diagText = bundleService.getDiag(bundle);
86             BundleState karafBundleState = karafBundleInfo.getState();
87             bundlesStateMap.put(bundleSymbolicNameWithVersion, karafBundleState);
88
89             String bundleStateDiagText = "OSGi state = " + bundleStateToText(bundle.getState())
90                 + ", Karaf bundleState = " + karafBundleState
91                 + (diagText.isEmpty() ? "" : ", due to: " + diagText);
92
93             if (WHITELISTED_BUNDLES.get(bundleSymbolicName) != null) {
94                 if (WHITELISTED_BUNDLES.get(bundleSymbolicName).equals(karafBundleState)) {
95                     String msg = "WHITELISTED " + bundleSymbolicNameWithVersion + ": " + bundleStateDiagText;
96                     whitelistedBundleStateInfoTexts.add(msg);
97                     continue;
98                 }
99             }
100
101             bundleStatesCounters.compute(karafBundleState, (key, counter) -> counter + 1);
102
103             // BundleState comparison as in Karaf's "diag" command,
104             // see https://github.com/apache/karaf/blob/master/bundle/core/src/main/java/org/apache/karaf/bundle/command/Diag.java
105             // but we intentionally, got a little further than Karaf's "diag" command,
106             // and instead of only checking some states, we check what's really Active,
107             // but accept that some remain just Resolved:
108             if (karafBundleState != Active && karafBundleState != BundleState.Resolved) {
109                 String msg = "NOK " + bundleSymbolicNameWithVersion + ": " + bundleStateDiagText;
110                 nokBundleStateInfoTexts.add(msg);
111             } else {
112                 String msg = "OK " + bundleSymbolicNameWithVersion + ": " + bundleStateDiagText;
113                 okBundleStateInfoTexts.add(msg);
114             }
115         }
116
117         return new BundleDiagInfosImpl(Collections.unmodifiableList(okBundleStateInfoTexts),
118                 Collections.unmodifiableList(nokBundleStateInfoTexts),
119                 Collections.unmodifiableList(whitelistedBundleStateInfoTexts),
120                 Collections.unmodifiableMap(bundleStatesCounters), Collections.unmodifiableMap(bundlesStateMap));
121     }
122
123     private static String bundleStateToText(int state) {
124         return switch (state) {
125             case Bundle.INSTALLED -> "Installed";
126             case Bundle.RESOLVED -> "Resolved";
127             case Bundle.STARTING -> "Starting";
128             case Bundle.ACTIVE -> "Active";
129             case Bundle.STOPPING -> "Stopping";
130             case Bundle.UNINSTALLED -> "Uninstalled";
131             default -> state + "???";
132         };
133     }
134
135     @Override
136     public SystemState getSystemState() {
137         if (bundleStatesCounters.get(BundleState.Failure) > 0) {
138             return SystemState.Failure;
139         } else if (bundleStatesCounters.get(BundleState.Stopping) > 0) {
140             return SystemState.Stopping;
141         } else if (bundleStatesCounters.get(BundleState.Installed) == 0
142                 // No, just Resolved is OK, so do not: && bundleStatesCounters.get(BundleState.Resolved) == 0
143                 && bundleStatesCounters.get(BundleState.Unknown) == 0
144                 && bundleStatesCounters.get(BundleState.GracePeriod) == 0
145                 && bundleStatesCounters.get(BundleState.Waiting) == 0
146                 && bundleStatesCounters.get(BundleState.Starting) == 0
147                 // BundleState.Active *should* be ~= total # of bundles (minus Resolved, and whitelisted installed)
148                 && bundleStatesCounters.get(BundleState.Stopping) == 0
149                 && bundleStatesCounters.get(BundleState.Failure) == 0) {
150             return SystemState.Active;
151         } else {
152             return SystemState.Booting;
153         }
154     }
155
156     @Override
157     public String getFullDiagnosticText() {
158         StringBuilder sb = new StringBuilder(getSummaryText());
159         int failureNumber = 1;
160         for (String nokBundleStateInfoText : getNokBundleStateInfoTexts()) {
161             sb.append('\n');
162             sb.append(failureNumber++);
163             sb.append(". ");
164             sb.append(nokBundleStateInfoText);
165         }
166         return sb.toString();
167     }
168
169     @Override
170     public String getSummaryText() {
171         return "diag: " + getSystemState() + " " + bundleStatesCounters.toString();
172     }
173
174     @Override
175     public Map<BundleSymbolicNameWithVersion, BundleState> getBundlesStateMap() {
176         return bundlesStateMap;
177     }
178
179     @Override
180     public List<String> getNokBundleStateInfoTexts() {
181         return nokBundleStateInfoTexts;
182     }
183
184     @Override
185     public List<String> getOkBundleStateInfoTexts() {
186         return okBundleStateInfoTexts;
187     }
188
189     @Override
190     public List<String> getWhitelistedBundleStateInfoTexts() {
191         return whitelistedBundleStateInfoTexts;
192     }
193
194     @Override
195     public String toString() {
196         return getFullDiagnosticText();
197     }
198
199 }