7639c4075f9c5ee4b10912a41e96fe6bd1a8c5e9
[appc.git] / appc-oam / appc-oam-bundle / src / main / java / org / onap / appc / oam / util / BundleHelper.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Copyright (C) 2017 Amdocs
8  * ================================================================================
9  * Modifications (C) 2018 Ericsson
10  * =============================================================================
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  * 
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  * 
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  * 
23  * ============LICENSE_END=========================================================
24  */
25
26 package org.onap.appc.oam.util;
27
28 import com.att.eelf.configuration.EELFLogger;
29 import org.apache.commons.lang3.ArrayUtils;
30 import org.onap.appc.exceptions.APPCException;
31 import org.onap.appc.oam.AppcOam;
32 import org.onap.appc.oam.processor.BaseCommon;
33 import org.onap.appc.statemachine.impl.readers.AppcOamStates;
34 import org.osgi.framework.Bundle;
35 import org.osgi.framework.BundleContext;
36 import org.osgi.framework.BundleException;
37 import org.osgi.framework.FrameworkUtil;
38
39 import java.util.Map;
40 import java.util.concurrent.Callable;
41 import java.util.concurrent.Future;
42
43 /**
44  * Utility class provides general bundle operational helps.
45  */
46 public class BundleHelper {
47     private final static String PROP_BUNDLE_TO_STOP = "appc.OAM.ToStop.properties";
48     private final static String PROP_BUNDLES_TO_NOT_STOP = "appc.OAM.ToNotStop.properties";
49
50     private final EELFLogger logger;
51     private final StateHelper stateHelper;
52     private final ConfigurationHelper configurationHelper;
53
54     /**
55      * Constructor
56      *
57      * @param eelfLogger of the logger
58      * @param configurationHelperIn of ConfigurationHelper instance
59      * @param stateHelperIn of StateHelper instance
60      */
61     public BundleHelper(EELFLogger eelfLogger,
62                         ConfigurationHelper configurationHelperIn,
63                         StateHelper stateHelperIn) {
64         logger = eelfLogger;
65         configurationHelper = configurationHelperIn;
66         stateHelper = stateHelperIn;
67     }
68
69     /**
70      * Handle bundle operations, such as stop or start bundle.
71      *
72      * @param rpc enum indicate if the operation is to stop, start or restart
73      * @return boolean to indicate if the operation is successful (true) or failed (false)
74      * @throws APPCException when error occurs
75      */
76     public boolean bundleOperations(AppcOam.RPC rpc,
77                                     Map<String, Future<?>> threads,
78                                     AsyncTaskHelper taskHelper,
79                                     BaseCommon baseCommon)
80         throws APPCException {
81         long mStartTime = System.currentTimeMillis();
82         logDebug(String.format("Entering OAM bundleOperations with rpc (%s).", rpc.name()));
83
84         String action = rpc.getAppcOperation().toString();
85         if (rpc != AppcOam.RPC.stop && rpc != AppcOam.RPC.start) {
86             throw new APPCException("rpc(" + rpc + ") is not supported by bundleOperation.");
87         }
88
89         AppcOamStates originalState = stateHelper.getState();
90
91         boolean isBundleOperationComplete = true;
92
93         Map<String, Bundle> appcLcmBundles = getAppcLcmBundles();
94         for (Map.Entry<String, Bundle> bundleEntry : appcLcmBundles.entrySet()) {
95             String bundleName = bundleEntry.getKey();
96             Bundle bundle = bundleEntry.getValue();
97
98             logDebug("OAM launch thread for %s bundle %s", action, bundleName);
99             if (rpc == AppcOam.RPC.start) {
100                 // Abort in the interruption case.
101                 // such as when a Stop request is receive while APPC is still trying to Start Up.
102                 if (!stateHelper.isSameState(originalState)) {
103                     logger.warn("OAM %s bundle operation aborted since OAM state is no longer %s!",
104                         originalState.name());
105                     isBundleOperationComplete = false;
106                     break;
107                 }
108             }
109
110             threads.put(bundleName,
111                 taskHelper.submitBaseSubCallable(new BundleTask(rpc, bundle,baseCommon)));
112         }
113
114         logDebug(String.format("Leaving OAM bundleOperations with rpc (%s) with complete(%s), elasped (%d) ms.",
115             rpc.name(), Boolean.toString(isBundleOperationComplete), getElapseTimeMs(mStartTime)));
116
117         return isBundleOperationComplete;
118     }
119
120     private long getElapseTimeMs(long mStartTime) {
121         return System.currentTimeMillis() - mStartTime;
122     }
123
124     /**
125      * Check if all BundleTasks are completed
126      * @param bundleNameFutureMap with bundle name and BundleTask Future object
127      * @return true if all are done, otherwise, false
128      */
129     public boolean isAllTaskDone(Map<String, Future<?>> bundleNameFutureMap) {
130         boolean anyNotDone = bundleNameFutureMap.values().stream().anyMatch((f) -> !f.isDone());
131         return !anyNotDone;
132     }
133
134     /**
135      * Cancel BundleTasks which are not finished
136      * @param bundleNameFutureMap with bundle name and BundleTask Future object
137      */
138     public void cancelUnfinished(Map<String, Future<?>> bundleNameFutureMap) {
139         bundleNameFutureMap.values().stream().filter((f)
140             -> !f.isDone()).forEach((f)
141             -> f.cancel(true));
142     }
143
144     /**
145      * Get number of failed BundleTasks
146      * @param bundleNameFutureMap with bundle name and BundleTask Future object
147      * @return number(long) of the failed BundleTasks
148      */
149     public long getFailedMetrics(Map<String, Future<?>> bundleNameFutureMap) {
150         return bundleNameFutureMap.values().stream().map((f) -> {
151             try {
152                 return f.get();
153             } catch (Exception e) {
154                 // should not get here
155                 throw new RuntimeException(e);
156             }
157         }).filter((b) -> ((BundleTask)b).failException != null).count();
158     }
159
160     /**
161      * Gets the list of Appc-bundles to be stopped/started
162      *
163      * @return Map of bundle symbolic name and bundle instance
164      */
165     Map<String, Bundle> getAppcLcmBundles() {
166         logDebug("In getAppcLcmBundles");
167
168         String[] bundlesToStop = readPropsFromPropListName(PROP_BUNDLE_TO_STOP);
169         String[] regExBundleNotStop = readPropsFromPropListName(PROP_BUNDLES_TO_NOT_STOP);
170
171         BundleFilter bundleList = getBundleFilter(bundlesToStop, regExBundleNotStop, getBundleList());
172
173         logger.info(String.format("(%d) APPC bundles to Stop/Start: %s.", bundleList.getBundlesToStop().size(),
174             bundleList.getBundlesToStop().toString()));
175
176         logger.debug(String.format("(%d) APPC bundles that won't be Stopped/Started: %s.",
177             bundleList.getBundlesToNotStop().size(), bundleList.getBundlesToNotStop().toString()));
178
179         return bundleList.getBundlesToStop();
180     }
181
182     /**
183      * Gets a list of all user desired bundles that should be stopped/Started as part of
184      * OAM Stop and Start API
185      *
186      * @param propListKey String of the properties list property name
187      * @return properties values of the related
188      */
189     String[] readPropsFromPropListName(String propListKey) {
190         // get properties list by properties list name
191         String[] propNames = configurationHelper.readProperty(propListKey);
192         // go through each property to get the property values
193         String[] propValue = ArrayUtils.EMPTY_STRING_ARRAY;
194         if (propNames != null) {
195             for (String aPropName : propNames) {
196                 propValue = ArrayUtils.addAll(propValue, configurationHelper.readProperty(aPropName));
197             }
198         }
199         return propValue;
200     }
201
202     /**
203      * Get all bundle list of APP-C
204      * @return Array of Bundle
205      */
206     Bundle[] getBundleList() {
207         BundleContext myBundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
208         if (myBundleContext != null) {
209             return myBundleContext.getBundles();
210         }
211         return null;
212     }
213
214     /**
215      * Genral debug log when debug logging level is enabled.
216      * @param message of the log message format
217      * @param args of the objects listed in the message format
218      */
219     private void logDebug(String message, Object... args) {
220         if (logger.isDebugEnabled()) {
221             logger.debug(String.format(message, args));
222         }
223     }
224
225     protected BundleFilter getBundleFilter(String[] stopRegexes, String[] exceptRegexes, Bundle[] bundles) {
226         return new BundleFilter(stopRegexes, exceptRegexes, bundles);
227     }
228
229     /**
230      * Runnable to execute bundle operations: start or stop
231      */
232     class BundleTask implements Callable<BundleTask> {
233         Exception failException;
234
235         private AppcOam.RPC rpc;
236         private Bundle bundle;
237         private String bundleName;
238         private String actionName;
239         private final BaseCommon baseCommon;
240
241         BundleTask(AppcOam.RPC rpcIn, Bundle bundleIn, BaseCommon baseCommon) {
242             rpc = rpcIn;
243             actionName = rpc.getAppcOperation().toString();
244             bundle = bundleIn;
245             bundleName = bundle.getSymbolicName();
246             this.baseCommon = baseCommon;
247         }
248
249         @Override
250         public BundleTask call() throws Exception {
251             try {
252                 baseCommon.setInitialLogProperties();
253
254                 long bundleOperStartTime = System.currentTimeMillis();
255                 logDebug(String.format("OAM %s bundle %s ===>", actionName, bundleName));
256                 switch (rpc) {
257                     case start:
258                         bundle.start();
259                         break;
260                     case stop:
261                         bundle.stop();
262                         break;
263                     default:
264                         // should do nothing
265                 }
266                 logDebug(String.format("OAM %s bundle %s completed <=== elasped %d",
267                     actionName, bundleName, getElapseTimeMs(bundleOperStartTime)));
268             } catch (BundleException e) {
269                 logger.error(String.format("Exception encountered when OAM %s bundle %s ",
270                     actionName, bundleName), e);
271                 failException = e;
272             }
273             finally {
274                 baseCommon.clearRequestLogProperties();
275             }
276             return this;
277         }
278     }
279 }