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