OAM operations 2 - oam 21/7421/3
authorbeili.zhou <beili.zhou@amdocs.com>
Sat, 12 Aug 2017 02:16:05 +0000 (22:16 -0400)
committerbeili.zhou <beili.zhou@amdocs.com>
Mon, 14 Aug 2017 17:33:08 +0000 (13:33 -0400)
OAM operations changes are large, need to break down to multiple
submissions based on size and compilability. This is the second set which
covers the following OAM operations: start, stop, restart,
maintenance-mode, and timeout of the operation along with error OAM
state.

Includes these user stories: APPC-39/41/43/44/45/46/52/77.

Issue Id: APPC-38
Change-Id: Iafad643c5ba2d2af24482b03db8f7a40397fa46e
Signed-off-by: beili.zhou <beili.zhou@amdocs.com>
19 files changed:
appc-oam/appc-oam-bundle/pom.xml
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/AppcOam.java
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/OAMCommandStatus.java
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/Converter.java
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/MessageAdapter.java
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseActionRunnable.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseCommon.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseProcessor.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamMmodeProcessor.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamRestartProcessor.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStartProcessor.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStopProcessor.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/AsyncTaskHelper.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleFilter.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleHelper.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/ConfigurationHelper.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/OperationHelper.java [new file with mode: 0644]
appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/StateHelper.java [new file with mode: 0644]
appc-oam/appc-oam-model/src/main/yang/appc-oam.yang

index 1da4a7e..20cfbf8 100644 (file)
@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+<project
+        xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
@@ -28,7 +30,7 @@
                             org.openecomp.appc.adapter.messaging.*,
                             org.openecomp.appc.adapter.message.*,
                             org.openecomp.appc.adapter.factory.*,
-                            org.openecomp.appc.listener.*,
+                            org.openecomp.appc.listener,
                             *;resolution:=optional
                         </Import-Package>
                         <Embed-Dependency>
             <artifactId>appc-request-handler-api</artifactId>
             <version>${project.version}</version>
         </dependency>
-
+        <dependency>
+            <groupId>org.openecomp.appc</groupId>
+            <artifactId>appc-lifecycle-management-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openecomp.appc</groupId>
+            <artifactId>appc-lifecycle-management-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openecomp.appc</groupId>
+            <artifactId>state-machine-lib</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.10.19</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito</artifactId>
+            <version>1.6.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>1.6.2</version>
+            <scope>test</scope>
+        </dependency>
         <!-- TEMP CODE -->
         <dependency>
             <groupId>org.json</groupId>
         </dependency>
 
 
-               <dependency>
-                       <groupId>org.openecomp.appc</groupId>
-                       <artifactId>appc-message-adapter-api</artifactId>
-                       <version>${project.version}</version>
+        <dependency>
+            <groupId>org.openecomp.appc</groupId>
+            <artifactId>appc-message-adapter-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openecomp.appc</groupId>
+            <artifactId>appc-message-adapter-factory</artifactId>
+            <version>${project.version}</version>
             <scope>provided</scope>
-               </dependency>
-               <dependency>
-                       <groupId>org.openecomp.appc</groupId>
-                       <artifactId>appc-message-adapter-factory</artifactId>
-                       <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openecomp.appc</groupId>
+            <artifactId>appc-dmaap-adapter-bundle</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openecomp.appc</groupId>
+            <artifactId>appc-event-listener-bundle</artifactId>
+            <version>${project.version}</version>
             <scope>provided</scope>
-               </dependency>
-       <dependency>
-         <groupId>org.openecomp.appc</groupId>
-         <artifactId>appc-dmaap-adapter-bundle</artifactId>
-         <version>${project.version}</version>
-         <scope>provided</scope>
-       </dependency>
-       <dependency>
-         <groupId>org.openecomp.appc</groupId>
-         <artifactId>appc-event-listener-bundle</artifactId>
-         <version>${project.version}</version>
-         <scope>provided</scope>
-       </dependency>
+        </dependency>
 
     </dependencies>
 
index 8fd6b2c..7ad3b62 100644 (file)
 
 package org.openecomp.appc.oam;
 
-import org.openecomp.appc.Constants;
-import org.openecomp.appc.configuration.Configuration;
-import org.openecomp.appc.configuration.ConfigurationFactory;
-import org.openecomp.appc.exceptions.APPCException;
-import org.openecomp.appc.executor.objects.Params;
-import org.openecomp.appc.i18n.Msg;
-import org.openecomp.appc.logging.LoggingConstants;
-import org.openecomp.appc.logging.LoggingUtils;
-import org.openecomp.appc.metricservice.MetricRegistry;
-import org.openecomp.appc.metricservice.MetricService;
-import org.openecomp.appc.metricservice.metric.Metric;
-import org.openecomp.appc.requesthandler.LCMStateManager;
-import org.openecomp.appc.requesthandler.RequestHandler;
 import com.att.eelf.configuration.EELFLogger;
 import com.att.eelf.configuration.EELFManager;
-import com.att.eelf.i18n.EELFResourceManager;
 import com.google.common.util.concurrent.Futures;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.*;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.AppcOamService;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.AppcState;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.GetAppcStateOutput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.GetAppcStateOutputBuilder;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.GetMetricsOutput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.GetMetricsOutputBuilder;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeInput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeOutput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeOutputBuilder;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartInput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartOutput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartOutputBuilder;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartInput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartOutput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartOutputBuilder;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopInput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopOutput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopOutputBuilder;
 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader;
 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.Metrics;
 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.MetricsBuilder;
 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.metrics.KpiValues;
 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.metrics.KpiValuesBuilder;
 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status;
-import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.StatusBuilder;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.slf4j.MDC;
-
-import java.net.InetAddress;
-import java.util.*;
-import java.util.concurrent.*;
-
-import org.openecomp.appc.oam.messageadapter.*;
-
-
-import static com.att.eelf.configuration.Configuration.*;
-
-import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.appc.i18n.Msg;
+import org.openecomp.appc.metricservice.MetricRegistry;
+import org.openecomp.appc.metricservice.MetricService;
+import org.openecomp.appc.metricservice.metric.Metric;
+import org.openecomp.appc.oam.processor.OamMmodeProcessor;
+import org.openecomp.appc.oam.processor.OamRestartProcessor;
+import org.openecomp.appc.oam.processor.OamStartProcessor;
+import org.openecomp.appc.oam.processor.OamStopProcessor;
+import org.openecomp.appc.oam.util.AsyncTaskHelper;
+import org.openecomp.appc.oam.util.ConfigurationHelper;
+import org.openecomp.appc.oam.util.OperationHelper;
+import org.openecomp.appc.oam.util.StateHelper;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamMetaDataReader.AppcOperation;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 
-
+/**
+ * RPC class of APP-C OAM API.
+ * <p>Implement all the RPCs defined in AppcOamService through yang model definition.
+ * <p>All RPC methods' JAVADOC are using "inheritDoc" to use the description from the yang model file.
+ */
 public class AppcOam implements AutoCloseable, AppcOamService {
-
-    private Configuration configuration = ConfigurationFactory.getConfiguration();
-    private final EELFLogger logger = EELFManager.getInstance().getLogger(AppcOam.class);
-
-    private boolean isMetricEnabled = false;
-
-
-    private final ScheduledExecutorService scheduledExecutorService;
-
-    private volatile ScheduledFuture<?> outstandingLCMRequestMonitorSheduledFuture;
-
-
-    private MessageAdapter messageAdapter;
-
-
     /**
-     * The ODL data store broker. Provides access to a conceptual data tree store and also provides the ability to
-     * subscribe for changes to data under a given branch of the tree.
+     * Invalid state message format with fliexible operation, appc name and state values
      */
-    private DataBroker dataBroker;
+    public final static String INVALID_STATE_MESSAGE_FORMAT = "%s API is not allowed when %s is in the %s state.";
 
-    /**
-     * ODL Notification Service that provides publish/subscribe capabilities for YANG modeled notifications.
-     */
-    private NotificationProviderService notificationService;
+    private final EELFLogger logger = EELFManager.getInstance().getLogger(AppcOam.class);
 
-    /**
-     * Provides a registry for Remote Procedure Call (RPC) service implementations. The RPCs are defined in YANG models.
-     */
-    private RpcProviderRegistry rpcRegistry;
+    private boolean isMetricEnabled = false;
 
     /**
      * Represents our RPC implementation registration
@@ -123,61 +100,73 @@ public class AppcOam implements AutoCloseable, AppcOamService {
 
 
     /**
-     * The yang rpc names
+     * The yang rpc names with value mapping to AppcOperation
      */
     public enum RPC {
-        start,
-        stop,
-        ;
+        maintenance_mode(AppcOperation.MaintenanceMode),
+        start(AppcOperation.Start),
+        stop(AppcOperation.Stop),
+        restart(AppcOperation.Restart);
+
+        AppcOperation appcOperation;
+
+        RPC(AppcOperation appcOperation) {
+            this.appcOperation = appcOperation;
+        }
+
+        public AppcOperation getAppcOperation() {
+            return appcOperation;
+        }
     }
 
+    private AsyncTaskHelper asyncTaskHelper;
+    private ConfigurationHelper configurationHelper;
+    private OperationHelper operationHelper;
+    private StateHelper stateHelper;
 
     /**
-     * @param dataBroker
-     * @param notificationProviderService
-     * @param rpcProviderRegistry
+     * APP-C OAM contructor
+     *
+     * @param dataBroker                  object of The ODL data store broker. Provides access to a conceptual data
+     *                                    tree store
+     *                                    and also provides the ability to subscribe for changes to data under a
+     *                                    given branch
+     *                                    of the tree. Not used in this class.
+     * @param notificationProviderService object of ODL Notification Service that provides publish/subscribe
+     *                                    capabilities for YANG modeled notifications. Not used in this class.
+     * @param rpcProviderRegistry         object of RpcProviderResigstry. Used to register our RPCs.
      */
-    @SuppressWarnings({
-            "javadoc", "nls"
-    })
-    public AppcOam(DataBroker dataBroker, NotificationProviderService notificationProviderService,
+    @SuppressWarnings({"unused", "nls"})
+    public AppcOam(DataBroker dataBroker,
+                   NotificationProviderService notificationProviderService,
                    RpcProviderRegistry rpcProviderRegistry) {
 
-        String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
+        configurationHelper = new ConfigurationHelper(logger);
+        String appName = configurationHelper.getAppcName();
         logger.info(Msg.COMPONENT_INITIALIZING, appName, "oam");
 
-        this.dataBroker = dataBroker;
-        this.notificationService = notificationProviderService;
-        this.rpcRegistry = rpcProviderRegistry;
-
-        if (this.rpcRegistry != null) {
-            rpcRegistration = rpcRegistry.addRpcImplementation(AppcOamService.class, this);
+        if (rpcProviderRegistry != null) {
+            rpcRegistration = rpcProviderRegistry.addRpcImplementation(AppcOamService.class, this);
         }
 
-        Properties properties = configuration.getProperties();
-        if (properties != null && properties.getProperty("metric.enabled") != null) {
-            isMetricEnabled = Boolean.valueOf(properties.getProperty("metric.enabled"));
-        }
-
-
-        messageAdapter = new MessageAdapter();
-        messageAdapter.init();
+        isMetricEnabled = configurationHelper.isMetricEnabled();
 
-
-        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(
-                new ThreadFactory(){
-
-                    @Override
-                    public Thread newThread(Runnable runnable) {
-                        Bundle bundle = FrameworkUtil.getBundle(AppcOam.class);
-                        return new Thread(runnable,bundle.getSymbolicName() + " scheduledExecutor");
-                    }
-                }
-        );
+        initHelpers();
 
         logger.info(Msg.COMPONENT_INITIALIZED, appName, "oam");
     }
 
+    /**
+     * Initialize helper classes.
+     * <p>Note: ConfigurationHelper initializetion is in included here
+     * because it is needed for extracting the AppName used in the debug logs within the constructor.
+     */
+    private void initHelpers() {
+        operationHelper = new OperationHelper();
+        asyncTaskHelper = new AsyncTaskHelper(logger);
+        stateHelper = new StateHelper(logger, configurationHelper);
+    }
+
     /**
      * Implements the close of the service
      *
@@ -186,58 +175,65 @@ public class AppcOam implements AutoCloseable, AppcOamService {
     @SuppressWarnings("nls")
     @Override
     public void close() throws Exception {
-        String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
+        String appName = configurationHelper.getAppcName();
         logger.info(Msg.COMPONENT_TERMINATING, appName, "oam");
-        scheduledExecutorService.shutdown();
+
+        asyncTaskHelper.close();
+
         if (rpcRegistration != null) {
             rpcRegistration.close();
         }
         logger.info(Msg.COMPONENT_TERMINATED, appName, "oam");
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Future<RpcResult<GetMetricsOutput>> getMetrics() {
 
-        GetMetricsOutputBuilder outputBuilder = new GetMetricsOutputBuilder();
-
-        if (!isMetricEnabled){
+        if (!isMetricEnabled) {
             logger.error("Metric Service not enabled returning failure");
-            RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"Metric Service not enabled").build();
+            RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput>
+                    status(false).withError(RpcError.ErrorType.APPLICATION, "Metric Service not enabled").build();
             return Futures.immediateFuture(result);
         }
 
-        MetricService metricService = null;
+        MetricService metricService;
         try {
-            metricService = getService(MetricService.class);
-        } catch (APPCException e){
-            logger.error("MetricService not found",e);
-            RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"Metric Service not found").build();
+            metricService = operationHelper.getService(MetricService.class);
+        } catch (APPCException e) {
+            logger.error("MetricService not found", e);
+            RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput>
+                    status(false).withError(RpcError.ErrorType.APPLICATION, "Metric Service not found").build();
             return Futures.immediateFuture(result);
         }
-        Map<String,MetricRegistry> allMetricRegitry = metricService.getAllRegistry();
 
-        if(allMetricRegitry == null || allMetricRegitry.isEmpty()){
+        Map<String, MetricRegistry> allMetricRegitry = metricService.getAllRegistry();
+        if (allMetricRegitry == null || allMetricRegitry.isEmpty()) {
             logger.error("No metrics registered returning failure");
-            RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"No metrics Registered").build();
+            RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput>
+                    status(false).withError(RpcError.ErrorType.APPLICATION, "No metrics Registered").build();
             return Futures.immediateFuture(result);
         }
+
         List<Metrics> metricsList = new ArrayList<>();
 
         logger.debug("Iterating metric registry list");
-        for (MetricRegistry metricRegistry :  allMetricRegitry.values() ) {
+        for (MetricRegistry metricRegistry : allMetricRegitry.values()) {
             logger.debug("Iterating metric registry :" + metricRegistry.toString());
-            Metric[] metrics = metricRegistry.metrics() ;
-            if(metrics!= null && metrics.length >0) {
+            Metric[] metrics = metricRegistry.metrics();
+            if (metrics != null && metrics.length > 0) {
                 logger.debug("Iterating though metrics in registry");
                 for (Metric metric : metrics) {
-                    logger.debug("Iterating though metrics: "+ metric.name());
+                    logger.debug("Iterating though metrics: " + metric.name());
                     MetricsBuilder metricsBuilder = new MetricsBuilder();
                     metricsBuilder.setKpiName(metric.name());
                     metricsBuilder.setLastResetTime(metric.getLastModified());
                     List<KpiValues> kpiList = new ArrayList<>();
                     Map<String, String> metricsOutput = metric.getMetricsOutput();
                     for (Map.Entry<String, String> kpi : metricsOutput.entrySet()) {
-                       KpiValuesBuilder kpiValuesBuilder = new KpiValuesBuilder();
+                        KpiValuesBuilder kpiValuesBuilder = new KpiValuesBuilder();
                         kpiValuesBuilder.setName(kpi.getKey());
                         kpiValuesBuilder.setValue(kpi.getValue());
                         kpiList.add(kpiValuesBuilder.build());
@@ -247,339 +243,97 @@ public class AppcOam implements AutoCloseable, AppcOamService {
                 }
             }
         }
+
+        GetMetricsOutputBuilder outputBuilder = new GetMetricsOutputBuilder();
         outputBuilder.setMetrics(metricsList);
-        RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(true).withResult(outputBuilder.build()).build();
+        RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput>
+                status(true).withResult(outputBuilder.build()).build();
         return Futures.immediateFuture(result);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public Future<RpcResult<StopOutput>> stop(StopInput stopInput){
-        logger.debug("Input received : " + stopInput);
-        final Date startTime = new Date();
-        Status status = this.buildStatus(OAMCommandStatus.ACCEPTED);
-        final  CommonHeader commonHeader = stopInput.getCommonHeader();
+    public Future<RpcResult<StopOutput>> stop(StopInput stopInput) {
+        logger.debug("Entering Stop with Input : " + stopInput);
+        final CommonHeader commonHeader = stopInput.getCommonHeader();
 
-        try {
-            setInitialLogProperties(commonHeader,RPC.stop);
-
-            //Close the gate so that no more new LCM request will be excepted.
-            LCMStateManager lcmStateManager = getService(LCMStateManager.class);
-            lcmStateManager.disableLCMOperations();
-            //Begin monitoring outstanding LCM request
-            scheduleOutstandingLCMRequestMonitor(commonHeader,startTime);
-        } catch(Throwable t) {
-            status = unexpectedOAMError(t,RPC.stop);
-        }
-        finally {
-            LoggingUtils.auditWarn(startTime.toInstant(),
-                    new Date(System.currentTimeMillis()).toInstant(),
-                    String.valueOf(status.getCode()),
-                    status.getMessage(),
-                    this.getClass().getCanonicalName(),
-                    Msg.OAM_OPERATION_STOPPING,
-                    getAppcName()
-            );
-            this.clearRequestLogProperties();
-        }
+        OamStopProcessor oamStopProcessor =
+                new OamStopProcessor(logger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper);
+        Status status = oamStopProcessor.processRequest(stopInput);
 
         StopOutputBuilder stopOutputBuilder = new StopOutputBuilder();
         stopOutputBuilder.setStatus(status);
         stopOutputBuilder.setCommonHeader(commonHeader);
-        StopOutput stopOutput = stopOutputBuilder.build();
-        return RpcResultBuilder.success(stopOutput).buildFuture();
+        return RpcResultBuilder.success(stopOutputBuilder.build()).buildFuture();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public Future<RpcResult<StartOutput>> start(StartInput startInput){
-        logger.debug("Input received : " + startInput);
-        final Date startTime = new Date();
-        Status status = this.buildStatus(OAMCommandStatus.ACCEPTED);
-        final CommonHeader commonHeader = startInput.getCommonHeader();
-
-        try {
-
-
-            setInitialLogProperties(commonHeader,RPC.start);
-
-            this.scheduleStartingAPPC(commonHeader,startTime);
-        } catch(Throwable t) {
-            status = unexpectedOAMError(t,RPC.start);
-        }
-        finally {
-            LoggingUtils.auditWarn(startTime.toInstant(),
-                    new Date(System.currentTimeMillis()).toInstant(),
-                    String.valueOf(status.getCode()),
-                    status.getMessage(),
-                    this.getClass().getCanonicalName(),
-                    Msg.OAM_OPERATION_STARTING,
-                    getAppcName()
-            );
-            this.clearRequestLogProperties();
-        }
-
-        StartOutputBuilder startOutputBuilder = new StartOutputBuilder();
-        startOutputBuilder.setStatus(status);
-        startOutputBuilder.setCommonHeader(commonHeader);
-        StartOutput startOutput = startOutputBuilder.build();
-        return RpcResultBuilder.success(startOutput).buildFuture();
-    }
+    public Future<RpcResult<RestartOutput>> restart(RestartInput input) {
+        logger.debug("Entering restart with Input : " + input);
+        final CommonHeader commonHeader = input.getCommonHeader();
 
-    private <T> T getService(Class<T> _class) throws APPCException {
-        BundleContext bctx = FrameworkUtil.getBundle(_class).getBundleContext();
-        ServiceReference sref = bctx.getServiceReference(_class.getName());
-        if (sref != null) {
-            if(logger.isTraceEnabled()) {
-                logger.debug("Using the BundleContext to fetched the service reference for " + _class.getName());
+        OamRestartProcessor oamRestartProcessor =
+                new OamRestartProcessor(logger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper);
+        Status status = oamRestartProcessor.processRequest(input);
 
-            }
-            return (T) bctx.getService(sref);
-        } else {
-            throw new APPCException("Using the BundleContext failed to to fetch service reference for " + _class.getName());
-        }
-    }
-
-    private Status buildStatus(OAMCommandStatus osmCommandStatus){
-        StatusBuilder status = new StatusBuilder();
-        status.setCode(osmCommandStatus.getResponseCode());
-        status.setMessage(osmCommandStatus.getResponseMessage());
-        return status.build();
-    }
+        RestartOutputBuilder restartOutputBuilder = new RestartOutputBuilder();
+        restartOutputBuilder.setStatus(status);
+        restartOutputBuilder.setCommonHeader(commonHeader);
 
-    private Status buildStatus(OAMCommandStatus osmCommandStatus,Params params){
-        StatusBuilder status = new StatusBuilder();
-        status.setCode(osmCommandStatus.getResponseCode());
-        status.setMessage(osmCommandStatus.getFormattedMessage(params));
-        return status.build();
+        return RpcResultBuilder.success(restartOutputBuilder.build()).buildFuture();
     }
 
-
-
-    private void clearRequestLogProperties() {
-        try {
-            MDC.remove(MDC_KEY_REQUEST_ID);
-            MDC.remove(MDC_SERVICE_INSTANCE_ID);
-            MDC.remove(MDC_SERVICE_NAME);
-            MDC.remove(LoggingConstants.MDCKeys.PARTNER_NAME);
-            MDC.remove(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY);
-        } catch (Exception e) {
-
-        }
-    }
-
-    private void setInitialLogProperties(CommonHeader commonHeader,RPC action) {
-
-        try {
-            MDC.put(MDC_KEY_REQUEST_ID, commonHeader.getRequestId());
-            MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, commonHeader.getOriginatorId());
-            MDC.put(MDC_INSTANCE_UUID, ""); // value should be created in the future
-            try {
-                MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getCanonicalHostName()); //Don't change it to a .getHostName() again please. It's wrong!
-                MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
-                MDC.put(LoggingConstants.MDCKeys.SERVER_NAME, InetAddress.getLocalHost().getHostName());
-                MDC.put(MDC_SERVICE_NAME, action.name());
-            } catch (Exception e) {
-                logger.debug("MDC constant error",e);
-            }
-        } catch (RuntimeException e) {
-            //ignore
-        }
-    }
-
-
-    private void storeErrorMessageToLog(Status status, String additionalMessage) {
-        LoggingUtils.logErrorMessage(
-                String.valueOf(status.getCode()),
-                status.getMessage(),
-                LoggingConstants.TargetNames.APPC,
-                LoggingConstants.TargetNames.APPC_OAM_PROVIDER,
-                additionalMessage,
-                this.getClass().getCanonicalName());
-    }
-
-    private String getAppcName(){
-        return configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
-    }
-
-    private Status unexpectedOAMError(Throwable t,RPC action){
-        final String appName = getAppcName();
-
-        String exceptionMessage = t.getMessage() != null ? t.getMessage() : t.toString();
-
-        String errorMessage = EELFResourceManager.format(Msg.OAM_OPERATION_EXCEPTION, t, appName, t.getClass().getSimpleName(), action.name(), exceptionMessage);
-
-        Params params = new Params().addParam("errorMsg", exceptionMessage);
-        Status status = buildStatus(
-                OAMCommandStatus.UNEXPECTED_ERROR,
-                params
-        );
-
-        storeErrorMessageToLog(status,errorMessage);
-        return status;
-    }
-
-
-    private int getInprogressLCMRequestCount() throws APPCException {
-        RequestHandler requestHandler = getService(RequestHandler.class);
-
-        if(requestHandler == null) {
-            return 0;
-        }
-
-        int inprogressRequestCount = requestHandler.getInprogressRequestCount();
-        return inprogressRequestCount;
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Future<RpcResult<MaintenanceModeOutput>> maintenanceMode(MaintenanceModeInput maintenanceModeInput) {
+        logger.debug("Entering MaintenanceMode with Input : " + maintenanceModeInput);
+        final CommonHeader commonHeader = maintenanceModeInput.getCommonHeader();
+
+        OamMmodeProcessor oamMmodeProcessor =
+                new OamMmodeProcessor(logger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper);
+        Status status = oamMmodeProcessor.processRequest(maintenanceModeInput);
+
+        MaintenanceModeOutputBuilder maintenanceModeOutputBuilder = new MaintenanceModeOutputBuilder();
+        maintenanceModeOutputBuilder.setStatus(status);
+        maintenanceModeOutputBuilder.setCommonHeader(commonHeader);
+        return RpcResultBuilder.success(maintenanceModeOutputBuilder.build()).buildFuture();
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Future<RpcResult<GetAppcStateOutput>> getAppcState() {
+        AppcState appcState = stateHelper.getCurrentOamYangState();
 
-
-    private void scheduleOutstandingLCMRequestMonitor(final CommonHeader commonHeader,final Date startTime){
-
-
-        class MyCommand implements Runnable{
-
-            public ScheduledFuture<?> myScheduledFuture = null;
-
-            @Override
-            public void run() {
-                try {
-                    setInitialLogProperties(commonHeader, RPC.stop);
-
-
-                    logDebug("Executing stopping task ");
-
-                    ScheduledFuture<?> currentScheduledFuture = AppcOam.this.outstandingLCMRequestMonitorSheduledFuture;
-
-                    //cancel myself if I am not the current outstandingLCMRequestMonitor
-                    if(currentScheduledFuture != myScheduledFuture){
-                        myScheduledFuture.cancel(false);
-                        return;
-                    }
-
-                    Status status = buildStatus(OAMCommandStatus.SUCCESS);
-
-
-                    try {
-
-                        //log status and return if there are still LCM request in progress
-                        int inprogressRequestCount = getInprogressLCMRequestCount();
-                        if (inprogressRequestCount > 0) {
-                            logDebug("The application '%s' has '%s' outstanding LCM request to complete before coming to a complete stop.  ",
-                                                getAppcName(),
-                                                inprogressRequestCount
-                                        );
-                            return;
-                        }
-
-                    } catch (Throwable t) {
-                        status = unexpectedOAMError(t, RPC.stop);
-                        myScheduledFuture.cancel(false);
-                    }
-
-                    try {
-                        OAMContext oamContext = new OAMContext();
-                        oamContext.setRpcName(RPC.stop);
-                        oamContext.setCommonHeader(commonHeader);
-                        oamContext.setStatus(status);
-                        messageAdapter.post(oamContext);
-                    } catch(Throwable t) {
-                        status = unexpectedOAMError(t,RPC.stop);
-                    }
-
-                    LoggingUtils.auditWarn(startTime.toInstant(),
-                            new Date(System.currentTimeMillis()).toInstant(),
-                            String.valueOf(status.getCode()),
-                            status.getMessage(),
-                            this.getClass().getCanonicalName(),
-                            Msg.OAM_OPERATION_STOPPED,
-                            getAppcName()
-                    );
-                    myScheduledFuture.cancel(false);
-
-                } finally {
-                    clearRequestLogProperties();
-                }
-            }
-        };
-
-        MyCommand command = new MyCommand();
-
-        long initialDelay = 10000;
-        long delay = initialDelay;
-
-
-        command.myScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(
-                command,
-                initialDelay,
-                delay,
-                TimeUnit.MILLISECONDS
-        );
-        this.outstandingLCMRequestMonitorSheduledFuture = command.myScheduledFuture;
+        GetAppcStateOutputBuilder builder = new GetAppcStateOutputBuilder();
+        builder.setState(appcState);
+        return RpcResultBuilder.success(builder.build()).buildFuture();
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Future<RpcResult<StartOutput>> start(StartInput startInput) {
+        logger.debug("Input received : " + startInput);
+        final CommonHeader commonHeader = startInput.getCommonHeader();
 
+        OamStartProcessor oamStartProcessor =
+                new OamStartProcessor(logger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper);
+        Status status = oamStartProcessor.processRequest(startInput);
 
-
-    private void scheduleStartingAPPC(final CommonHeader commonHeader,final Date startTime){
-
-
-        class MyCommand implements Runnable{
-
-
-            @Override
-            public void run() {
-                try {
-                    setInitialLogProperties(commonHeader, RPC.start);
-
-                    logDebug("Executing starting task ");
-
-                    Status status = buildStatus(OAMCommandStatus.SUCCESS);
-
-                    try {
-                        LCMStateManager lcmStateManager = getService(LCMStateManager.class);
-                        lcmStateManager.enableLCMOperations();
-                        //cancel the current outstandingLCMRequestMonitor
-                        outstandingLCMRequestMonitorSheduledFuture = null;
-                    } catch(Throwable t) {
-                        status = unexpectedOAMError(t,RPC.start);
-                    }
-
-                    try {
-                       OAMContext oamContext = new OAMContext();
-                       oamContext.setRpcName(RPC.start);
-                       oamContext.setCommonHeader(commonHeader);
-                       oamContext.setStatus(status);
-                       messageAdapter.post(oamContext);
-                    } catch(Throwable t) {
-                      status = unexpectedOAMError(t,RPC.start);
-                    }
-
-                    LoggingUtils.auditWarn(startTime.toInstant(),
-                            new Date(System.currentTimeMillis()).toInstant(),
-                            String.valueOf(status.getCode()),
-                            status.getMessage(),
-                            this.getClass().getCanonicalName(),
-                            Msg.OAM_OPERATION_STARTED,
-                            getAppcName()
-                    );
-                } finally {
-                    clearRequestLogProperties();
-                }
-            }
-        };
-
-        MyCommand command = new MyCommand();
-        long initialDelay = 1000;
-
-        scheduledExecutorService.schedule(
-                command,
-                initialDelay,
-                TimeUnit.MILLISECONDS
-        );
-    }
-
-
-    private void logDebug(String message,Object... args){
-        if (logger.isDebugEnabled()) {
-            logger.debug(String.format(message,args));
-        }
+        StartOutputBuilder startOutputBuilder = new StartOutputBuilder();
+        startOutputBuilder.setStatus(status);
+        startOutputBuilder.setCommonHeader(commonHeader);
+        StartOutput startOutput = startOutputBuilder.build();
+        return RpcResultBuilder.success(startOutput).buildFuture();
     }
 }
index cef242c..378fa03 100644 (file)
@@ -34,17 +34,18 @@ public enum OAMCommandStatus {
 
     ACCEPTED(100,"ACCEPTED - request accepted"),
 
-    //ERROR(2xx) â€“ request can’t be handled due to some technical error
+    //ERROR(2xx) - request can't be handled due to some technical error
     UNEXPECTED_ERROR(200,"UNEXPECTED ERROR - ${errorMsg}"),
 
-    SUCCESS(400,"SUCCESS - request has been processed successfully"),
-        ;
-
+    REJECTED(300,"REJECTED - ${errorMsg}"),
+    INVALID_PARAMETER(302,"INVALID PARAMETER - ${errorMsg}" ),
+    TIMEOUT(303, "OPERATION TIMEOUT REACHED - ${errorMsg}"),
 
-    public static final String errorDgMessageParamName = "errorDgMessage";
+    SUCCESS(400,"SUCCESS - request has been processed successfully"),
+    ;
 
-       private int responseCode;
-       private String responseMessage;
+    private int responseCode;
+    private String responseMessage;
 
 
 
@@ -52,31 +53,25 @@ public enum OAMCommandStatus {
     OAMCommandStatus(int responseCode, String responseMessage) {
         this.responseCode = responseCode;
         this.responseMessage = responseMessage;
-            }
+    }
 
     public String getResponseMessage() {
-               return responseMessage;
-       }
+        return responseMessage;
+    }
 
-       public int getResponseCode() {
-               return responseCode;
-       }
+    public int getResponseCode() {
+        return responseCode;
+    }
 
 
-       /**
+    /**
      *
      * @return  messageTemplate
      */
-
-
     public String getFormattedMessage(Params params){
-            Map<String,Object> paramsMap = params != null ? params.getParams() : null;
-            return MessageFormatter.format(getResponseMessage(),paramsMap);
+        Map<String,Object> paramsMap = params != null ? params.getParams() : null;
+        return MessageFormatter.format(getResponseMessage(),paramsMap);
 
-        }
-
-    public String getFormattedMessageWithCode(Params params){
-        return getResponseCode()+"-" + getFormattedMessage(params);
     }
 
     @Override
@@ -87,4 +82,3 @@ public enum OAMCommandStatus {
                 '}';
     }
 }
-
index e9ccfdd..a70d120 100644 (file)
@@ -1,4 +1,4 @@
-/*-
+/*-/*-
  * ============LICENSE_START=======================================================
  * ONAP : APPC
  * ================================================================================
@@ -24,9 +24,6 @@
 
 package org.openecomp.appc.oam.messageadapter;
 
-import org.openecomp.appc.oam.AppcOam;
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -35,12 +32,15 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.MapperFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectWriter;
-import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.*;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeOutputBuilder;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartOutputBuilder;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartOutputBuilder;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopOutputBuilder;
 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader;
 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
-
+import org.openecomp.appc.oam.AppcOam;
 
 import java.text.SimpleDateFormat;
 import java.util.TimeZone;
@@ -48,61 +48,81 @@ import java.util.TimeZone;
 public class Converter {
     private static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
     private static final SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT);
-    private static final EELFLogger logger = EELFManager.getInstance().getLogger(Converter.class);
+
     static {
         isoFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
     }
 
 
-    private static Builder<?> convAsyncResponseToBuilder1(AppcOam.RPC rpcName, CommonHeader commonHeader, Status status) {
-        Builder<?> outObj = null;
-        if(rpcName == null){
+    private static Builder<?> convAsyncResponseToBuilder1(AppcOam.RPC rpcName,
+                                                          CommonHeader commonHeader,
+                                                          Status status) {
+        Builder<?> outObj;
+        if (rpcName == null) {
             throw new IllegalArgumentException("empty asyncResponse.rpcName");
         }
-        if(commonHeader == null){
+        if (commonHeader == null) {
             throw new IllegalArgumentException("empty asyncResponse.commonHeader");
         }
-        if(status == null){
+        if (status == null) {
             throw new IllegalArgumentException("empty asyncResponse.status");
         }
-        switch (rpcName){
-            case stop:
-                outObj = new StopOutputBuilder();
-                ((StopOutputBuilder)outObj).setCommonHeader(commonHeader);
-                ((StopOutputBuilder)outObj).setStatus(status);
+        switch (rpcName) {
+            case maintenance_mode:
+                outObj = new MaintenanceModeOutputBuilder();
+                ((MaintenanceModeOutputBuilder) outObj).setCommonHeader(commonHeader);
+                ((MaintenanceModeOutputBuilder) outObj).setStatus(status);
                 return outObj;
 
             case start:
                 outObj = new StartOutputBuilder();
-                ((StartOutputBuilder)outObj).setCommonHeader(commonHeader);
-                ((StartOutputBuilder)outObj).setStatus(status);
+                ((StartOutputBuilder) outObj).setCommonHeader(commonHeader);
+                ((StartOutputBuilder) outObj).setStatus(status);
+                return outObj;
+
+            case stop:
+                outObj = new StopOutputBuilder();
+                ((StopOutputBuilder) outObj).setCommonHeader(commonHeader);
+                ((StopOutputBuilder) outObj).setStatus(status);
+                return outObj;
+
+            case restart:
+                outObj = new RestartOutputBuilder();
+                ((RestartOutputBuilder) outObj).setCommonHeader(commonHeader);
+                ((RestartOutputBuilder) outObj).setStatus(status);
                 return outObj;
+
             default:
-                throw new IllegalArgumentException(rpcName+" action is not supported");
+                throw new IllegalArgumentException(rpcName + " action is not supported");
         }
     }
 
-    public static String convAsyncResponseToUebOutgoingMessageJsonString(OAMContext oamContext) throws JsonProcessingException {
+    static String convAsyncResponseToUebOutgoingMessageJsonString(OAMContext oamContext) throws
+            JsonProcessingException {
         AppcOam.RPC rpcName = oamContext.getRpcName();
         CommonHeader commonHeader = oamContext.getCommonHeader();
         Status status = oamContext.getStatus();
 
-        DmaapOutgoingMessage dmaapOutgoingMessage = convAsyncResponseToUebOutgoingMessage(rpcName,commonHeader,status);
+        DmaapOutgoingMessage dmaapOutgoingMessage = convAsyncResponseToUebOutgoingMessage(rpcName, commonHeader,
+                status);
         ObjectMapper objectMapper = new ObjectMapper();
-        objectMapper.addMixInAnnotations(dmaapOutgoingMessage.getBody().getOutput().getClass(), MixInFlagsMessage.class);
+        objectMapper.addMixInAnnotations(dmaapOutgoingMessage.getBody().getOutput().getClass(),
+                MixInFlagsMessage.class);
         objectMapper.addMixInAnnotations(Status.class, MixIn.class);
         objectMapper.addMixInAnnotations(CommonHeader.class, MixInCommonHeader.class);
-        ObjectWriter writer = objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true).writer();
+        ObjectWriter writer = objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).configure
+                (MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true).writer();
         return writer.writeValueAsString(dmaapOutgoingMessage);
     }
 
-    private static DmaapOutgoingMessage convAsyncResponseToUebOutgoingMessage(AppcOam.RPC rpcName, CommonHeader commonHeader, Status status) throws JsonProcessingException {
+    private static DmaapOutgoingMessage convAsyncResponseToUebOutgoingMessage(AppcOam.RPC rpcName, CommonHeader
+            commonHeader, Status status) throws JsonProcessingException {
         DmaapOutgoingMessage outObj = new DmaapOutgoingMessage();
         String correlationID = commonHeader.getRequestId();
         outObj.setCorrelationID(correlationID);
         outObj.setType("response");
         outObj.setRpcName(rpcName.name());
-        Builder<?> builder = Converter.convAsyncResponseToBuilder1(rpcName,commonHeader,status);
+        Builder<?> builder = Converter.convAsyncResponseToBuilder1(rpcName, commonHeader, status);
         Object messageBody = builder.build();
 
         DmaapOutgoingMessage.Body body = new DmaapOutgoingMessage.Body(messageBody);
@@ -112,12 +132,14 @@ public class Converter {
 
 
     abstract class MixIn {
+        // to be removed during serialization
         @JsonIgnore
-        abstract Class<? extends DataContainer> getImplementedInterface(); // to be removed during serialization
+        abstract Class<? extends DataContainer> getImplementedInterface();
 
         @JsonValue
         abstract java.lang.String getValue();
     }
+
     abstract class MixInCommonHeader extends MixIn {
         @JsonProperty("request-id")
         abstract java.lang.String getRequestId();
@@ -126,11 +148,9 @@ public class Converter {
         abstract java.lang.String getOriginatorId();
 
     }
+
     abstract class MixInFlagsMessage extends MixIn {
         @JsonProperty("common-header")
-        abstract  CommonHeader getCommonHeader();
+        abstract CommonHeader getCommonHeader();
     }
-
-
-
 }
index 21f0966..d93feab 100644 (file)
@@ -32,7 +32,6 @@ import org.openecomp.appc.adapter.message.MessageAdapterFactory;
 import org.openecomp.appc.adapter.message.Producer;
 import org.openecomp.appc.configuration.Configuration;
 import org.openecomp.appc.configuration.ConfigurationFactory;
-import org.openecomp.appc.listener.impl.EventHandlerImpl;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceReference;
@@ -42,56 +41,84 @@ import java.util.Properties;
 
 public class MessageAdapter {
 
+    private final EELFLogger logger = EELFManager.getInstance().getLogger(MessageAdapter.class);
+
+    private final String PROP_APPC_OAM_DISABLED = "appc.OAM.disabled";
+    private final String PROP_APPC_OAM_TOPIC_WRITE = "appc.OAM.topic.write";
+    private String PROP_APPC_OAM_CLIENT_KEY = "appc.OAM.client.key";
+    private String PROP_APPC_OAM_CLIENT_SECRET = "appc.OAM.client.secret";
+    private String PROP_APPC_OAM_POOLMEMBERS = "appc.OAM.poolMembers";
+
     private Producer producer;
-    private String partition ;
+    private String partition;
     private Configuration configuration;
     private HashSet<String> pool;
     private String writeTopic;
     private String apiKey;
     private String apiSecret;
-
-    private static final EELFLogger logger = EELFManager.getInstance().getLogger(MessageAdapter.class);
+    private boolean isDisabled;
 
     /**
-     * Initialize producer client to post messages using configuration properties
+     * Initialize producer client to post messages using configuration properties.
      */
-    public void init(){
-        this.producer = getProducer();
-    }
-
-    private Producer getProducer() {
+    public void init() {
         configuration = ConfigurationFactory.getConfiguration();
-        Properties properties=configuration.getProperties();
+        Properties properties = configuration.getProperties();
         updateProperties(properties);
-        Producer localProducer = null;
-        
+
+        if (isAppcOamPropsListenerEnabled()) {
+            createProducer();
+        } else {
+            logger.warn(String.format("The listener %s is disabled and will not be run", "appc.OAM"));
+        }
+    }
+
+    /**
+     * Create producer using MessageAdapterFactory which is found through bundle context.
+     */
+    void createProducer() {
         BundleContext ctx = FrameworkUtil.getBundle(MessageAdapter.class).getBundleContext();
-        if (ctx != null) {
-               ServiceReference svcRef = ctx.getServiceReference(MessageAdapterFactory.class.getName());
-               if (svcRef != null) {
-                       localProducer = ((MessageAdapterFactory) ctx.getService(svcRef)).createProducer(pool, writeTopic, apiKey, apiSecret);
-                       for (String url : pool) {
-                           if (url.contains("3905") || url.contains("https")) {
-                               localProducer.useHttps(true);
-                               break;
-                           }
-                       }
-               }
+        if (ctx == null) {
+            logger.warn("MessageAdapter cannot create producer due to no bundle context.");
+            return;
         }
 
-        return localProducer;
+        ServiceReference svcRef = ctx.getServiceReference(MessageAdapterFactory.class.getName());
+        if (svcRef == null) {
+            logger.warn("MessageAdapter cannot create producer due to no MessageAdapterFactory service reference.");
+            return;
+        }
+
+        Producer localProducer = ((MessageAdapterFactory) ctx.getService(svcRef)).createProducer(pool, writeTopic,
+                apiKey, apiSecret);
+
+        for (String url : pool) {
+            if (url.contains("3905") || url.contains("https")) {
+                localProducer.useHttps(true);
+                break;
+            }
+        }
+
+        producer = localProducer;
+
+        logger.debug("MessageAdapter created producer.");
     }
 
+    /**
+     * Read property value to set writeTopic, apiKey, apiSecret and pool.
+     *
+     * @param props of configuration
+     */
     private void updateProperties(Properties props) {
-        if (logger.isTraceEnabled()) {
-            logger.trace("Entering to updateProperties with Properties = "+ ObjectUtils.toString(props));
-        }
+        logger.trace("Entering to updateProperties with Properties = " + ObjectUtils.toString(props));
+
         pool = new HashSet<>();
         if (props != null) {
-            writeTopic = props.getProperty("appc.OAM.topic.write");
-            apiKey = props.getProperty("appc.OAM.client.key");
-            apiSecret = props.getProperty("appc.OAM.client.secret");
-            String hostnames = props.getProperty("appc.OAM.poolMembers");
+            isDisabled = Boolean.parseBoolean(props.getProperty(PROP_APPC_OAM_DISABLED));
+            writeTopic = props.getProperty(PROP_APPC_OAM_TOPIC_WRITE);
+            apiKey = props.getProperty(PROP_APPC_OAM_CLIENT_KEY);
+            apiSecret = props.getProperty(PROP_APPC_OAM_CLIENT_SECRET);
+            String hostnames = props.getProperty(PROP_APPC_OAM_POOLMEMBERS);
             if (hostnames != null && !hostnames.isEmpty()) {
                 for (String name : hostnames.split(",")) {
                     pool.add(name);
@@ -101,33 +128,56 @@ public class MessageAdapter {
     }
 
     /**
-     * Posts message to UEB. As UEB accepts only json messages this method first convert uebMessage to json format and post it to UEB.
-     * @param oamContext response data that based on it a message will be send to UEB (the format of the message that will be sent to UEB based on the action and its YANG domainmodel).
-     * @return True if message is postes successfully else False
+     * Get producer. If it is null, call createProducer to create it again.
+     *
+     * @return Producer
      */
-    public boolean post(OAMContext oamContext){
-        boolean success;
+    Producer getProducer() {
+        if (producer == null) {
+            // In case, producer was not properly set yet, set it again.
+            logger.info("Calling createProducer as producer is null.");
+            createProducer();
+        }
+
+        return producer;
+    }
+
+    /**
+     * Posts message to UEB. As UEB accepts only json messages this method first convert uebMessage to json format
+     * and post it to UEB.
+     *
+     * @param oamContext response data that based on it a message will be send to UEB (the format of the message that
+     *                   will be sent to UEB based on the action and its YANG domainmodel).
+     */
+    public void post(OAMContext oamContext) {
         if (logger.isTraceEnabled()) {
             logger.trace("Entering to post with AsyncResponse = " + ObjectUtils.toString(oamContext));
         }
 
+        boolean success;
         String jsonMessage;
         try {
             jsonMessage = Converter.convAsyncResponseToUebOutgoingMessageJsonString(oamContext);
             if (logger.isDebugEnabled()) {
                 logger.debug("UEB Response = " + jsonMessage);
             }
-            success  = producer.post(this.partition, jsonMessage);
+
+            Producer myProducer = getProducer();
+            success = myProducer != null && myProducer.post(this.partition, jsonMessage);
         } catch (JsonProcessingException e1) {
-            logger.error("Error generating Jason from UEB message "+ e1.getMessage());
-            success= false;
-        }catch (Exception e){
-            logger.error("Error sending message to UEB "+e.getMessage());
-            success= false;
+            logger.error("Error generating Json from UEB message " + e1.getMessage());
+            success = false;
+        } catch (Exception e) {
+            logger.error("Error sending message to UEB " + e.getMessage(), e);
+            success = false;
         }
+
         if (logger.isTraceEnabled()) {
-            logger.trace("Exiting from post with (success = "+ ObjectUtils.toString(success)+")");
+            logger.trace("Exiting from post with (success = " + ObjectUtils.toString(success) + ")");
         }
-        return success;
+    }
+
+    private boolean isAppcOamPropsListenerEnabled() {
+        return !isDisabled;
     }
 }
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseActionRunnable.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseActionRunnable.java
new file mode 100644 (file)
index 0000000..5df2c80
--- /dev/null
@@ -0,0 +1,207 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.processor;
+
+import org.openecomp.appc.i18n.Msg;
+import org.openecomp.appc.oam.OAMCommandStatus;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Future;
+
+/**
+ * Base runnable actions for OAM APIs, such as maintenance mode, restart, start and stop API.
+ *
+ * <p>This class holds the general action async handling methods for all OAM APIs.
+ * <p>Specific API action runnable will overwrite the general methods to add specific behaviors.
+ *
+ * <p>Subclass constructor must set the following class variables:
+ *   <br>  - actionName
+ *   <br>  - auditMsg
+ *   <br>  - finalState
+ */
+abstract class BaseActionRunnable extends BaseCommon implements Runnable {
+    final String OAM_OPERATION_TIMEOUT_SECOND = "appc.OAM.api.timeout";
+    /** Default operation tiemout set to 1 minute */
+    final int DEFAULT_OAM_OPERATION_TIMEOUT = 60;
+    /** Abort message format with flexible operation name */
+    final String ABORT_MESSAGE_FORMAT = "Aborting %s operation.";
+    /** Timeout message format with flexible operation name */
+    final String TIMEOUT_MESSAGE_FORMAT = "%s operation has reached timeout %d milliseconds.";
+
+    private boolean isWaiting = false;
+    private AppcOamStates currentState;
+    long startTimeMs = 0;
+    long timeoutMs = 0;
+    boolean doTimeoutChecking = false;
+
+    String actionName = "Need to be reset";
+    Msg auditMsg;
+    AppcOamStates finalState;
+
+    BaseProcessor myParent;
+    Map<String, Future<?>> bundleNameToFuture = new HashMap<>();
+
+    BaseActionRunnable(BaseProcessor parent) {
+        super(parent.logger, parent.configurationHelper, parent.stateHelper, parent.operationHelper);
+
+        rpc = parent.rpc;
+        commonHeader = parent.commonHeader;
+        startTime = parent.startTime;
+        myParent = parent;
+
+        setTimeoutValues();
+    }
+
+    void setTimeoutValues() {
+        Integer timeoutSeconds = myParent.timeoutSeconds;
+        if (timeoutSeconds == null) {
+            timeoutMs = configurationHelper.getConfig().getIntegerProperty(
+                    OAM_OPERATION_TIMEOUT_SECOND, DEFAULT_OAM_OPERATION_TIMEOUT) * 1000;
+        } else {
+            timeoutMs = timeoutSeconds.longValue() * 1000;
+        }
+
+        doTimeoutChecking = timeoutMs != 0;
+        if (doTimeoutChecking) {
+            startTimeMs = startTime.getTime();
+        }
+        logDebug("%s action runnable check timeout (%s) with timeout (%d)ms, and startMs (%d)",
+                rpc.name(), Boolean.toString(doTimeoutChecking), timeoutMs, startTimeMs);
+    }
+
+    @Override
+    public void run() {
+        try {
+            setInitialLogProperties();
+            logDebug(String.format("===========in %s run (waiting: %s)=======",
+                    actionName, Boolean.toString(isWaiting)));
+
+            if (isWaiting) {
+                if (!checkState()) {
+                    keepWaiting();
+                }
+            } else {
+                if (doAction()) {
+                    isWaiting = !checkState();
+                } else {
+                    postDoAction(false);
+                }
+            }
+        } catch (Exception e) {
+            logDebug(String.format("%s got exception %s", actionName, e.getMessage()));
+            logger.error(actionName + " exception", e);
+
+        } finally {
+            clearRequestLogProperties();
+        }
+    }
+
+    void keepWaiting() {
+        logDebug(String.format("%s runnable waiting, current state is %s.",
+                actionName, currentState == null ? "null" : currentState.toString()));
+
+        isTimeout("keepWaiting");
+    }
+
+    boolean isTimeout(String parentName) {
+        logDebug(String.format("%s task isTimeout called from %s", actionName, parentName));
+        if (doTimeoutChecking
+                && System.currentTimeMillis() - startTimeMs > timeoutMs) {
+            logger.error(String.format("%s operation timeout (%d) ms has reached, abort with error state.",
+                    actionName, timeoutMs));
+
+            setStatus(OAMCommandStatus.TIMEOUT, String.format(TIMEOUT_MESSAGE_FORMAT, rpc.name(), timeoutMs));
+            postAction(AppcOamStates.Error);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Set class <b>status</b> to REJECTED with abort message.
+     */
+    void setAbortStatus() {
+        setStatus(OAMCommandStatus.REJECTED, String.format(ABORT_MESSAGE_FORMAT, rpc.name()));
+    }
+
+    /**
+     * Final handling. The thread is cancelled.
+     * @param setState boolean to indicate if set OAM state or not
+     */
+    void postDoAction(boolean setState) {
+        logDebug(String.format("Finished %s task", actionName));
+    }
+
+    /**
+     * Handling for after doAction. does post notification,  issue audit log and set OAM state based on input
+     * @param state of AppcOamState to be set as OAM state when it is not null.
+     */
+    void postAction(AppcOamStates state) {
+        operationHelper.sendNotificationMessage(rpc, commonHeader, status);
+
+        if (state != null) {
+            stateHelper.setState(state);
+        }
+
+        auditInfoLog(auditMsg);
+
+        myParent.cancelAsyncTask();
+    }
+
+    /**
+     * Check state
+     * @return true if final state reached, otherwise return false
+     */
+    boolean checkState() {
+        if (isTimeout("checkState")) {
+            myParent.bundleHelper.cancelUnfinished(bundleNameToFuture);
+            return true;
+        }
+
+        if (!myParent.bundleHelper.isAllTaskDone(bundleNameToFuture)) {
+            return false;
+        }
+
+        long failedTask = myParent.bundleHelper.getFailedMetrics(bundleNameToFuture);
+        if (failedTask != 0) {
+            String errorMsg = failedTask + " bundle(s) failed, see logs for details.";
+            setStatus(OAMCommandStatus.UNEXPECTED_ERROR, errorMsg);
+            postAction(AppcOamStates.Error);
+            return true;
+        }
+
+        currentState = stateHelper.getBundlesState();
+        if (currentState == finalState) {
+            setStatus(OAMCommandStatus.SUCCESS);
+            postDoAction(true);
+            return true;
+        }
+        return false;
+    }
+
+    abstract boolean doAction();
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseCommon.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseCommon.java
new file mode 100644 (file)
index 0000000..cc725e7
--- /dev/null
@@ -0,0 +1,216 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.processor;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.i18n.EELFResourceManager;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.StatusBuilder;
+import org.openecomp.appc.exceptions.InvalidInputException;
+import org.openecomp.appc.exceptions.InvalidStateException;
+import org.openecomp.appc.executor.objects.Params;
+import org.openecomp.appc.i18n.Msg;
+import org.openecomp.appc.logging.LoggingConstants;
+import org.openecomp.appc.logging.LoggingUtils;
+import org.openecomp.appc.oam.AppcOam;
+import org.openecomp.appc.oam.OAMCommandStatus;
+import org.openecomp.appc.oam.util.ConfigurationHelper;
+import org.openecomp.appc.oam.util.OperationHelper;
+import org.openecomp.appc.oam.util.StateHelper;
+import org.slf4j.MDC;
+
+import java.net.InetAddress;
+import java.util.Date;
+
+import static com.att.eelf.configuration.Configuration.MDC_INSTANCE_UUID;
+import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
+import static com.att.eelf.configuration.Configuration.MDC_SERVER_FQDN;
+import static com.att.eelf.configuration.Configuration.MDC_SERVER_IP_ADDRESS;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_INSTANCE_ID;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
+
+/**
+ * Common handling methods of <br>
+ *     - BaseProcessor (for REST sync handling) <br>
+ *     - BaseActionRunnable (for REST async handling)
+ */
+abstract class BaseCommon {
+    final EELFLogger logger;
+    final ConfigurationHelper configurationHelper;
+    final StateHelper stateHelper;
+    final OperationHelper operationHelper;
+
+    Status status;
+    Date startTime;
+
+    AppcOam.RPC rpc;
+    CommonHeader commonHeader;
+
+    /**
+     * Constructor
+     *
+     * @param eelfLogger            for logging
+     * @param configurationHelperIn for property reading
+     * @param stateHelperIn         for APP-C OAM state checking
+     * @param operationHelperIn for operational helper
+     */
+    BaseCommon(EELFLogger eelfLogger,
+               ConfigurationHelper configurationHelperIn,
+               StateHelper stateHelperIn,
+               OperationHelper operationHelperIn) {
+        logger = eelfLogger;
+        configurationHelper = configurationHelperIn;
+        stateHelper = stateHelperIn;
+        operationHelper = operationHelperIn;
+    }
+
+    /**
+     * Audit log the passed in message at INFO level.
+     * @param msg the Msg to be audit logged.
+     */
+    void auditInfoLog(Msg msg) {
+        LoggingUtils.auditInfo(startTime.toInstant(),
+                new Date(System.currentTimeMillis()).toInstant(),
+                String.valueOf(status.getCode()),
+                status.getMessage(),
+                getClass().getCanonicalName(),
+                msg,
+                configurationHelper.getAppcName(),
+                stateHelper.getCurrentOamState().toString()
+        );
+    }
+
+    /**
+     * Set MDC properties.
+     */
+    void setInitialLogProperties() {
+        MDC.put(MDC_KEY_REQUEST_ID, commonHeader.getRequestId());
+        MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, commonHeader.getOriginatorId());
+        MDC.put(MDC_INSTANCE_UUID, ""); // value should be created in the future
+        MDC.put(MDC_SERVICE_NAME, rpc.name());
+        try {
+            //!!!Don't change the following to a .getHostName() again please. It's wrong!MDC.put(MDC_SERVER_FQDN,
+            // InetAddress.getLocalHost().getCanonicalHostName());
+            MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getCanonicalHostName());
+            MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
+            MDC.put(LoggingConstants.MDCKeys.SERVER_NAME, InetAddress.getLocalHost().getHostName());
+        } catch (Exception e) {
+            logger.error("MDC constant error", e);
+        }
+    }
+
+    /**
+     * Clear MDC properties.
+     */
+    void clearRequestLogProperties() {
+        try {
+            MDC.remove(MDC_KEY_REQUEST_ID);
+            MDC.remove(MDC_SERVICE_INSTANCE_ID);
+            MDC.remove(MDC_SERVICE_NAME);
+            MDC.remove(LoggingConstants.MDCKeys.PARTNER_NAME);
+            MDC.remove(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY);
+        } catch (Exception e) {
+            logger.error("Unable to clear the Request Log properties" + e.getMessage());
+        }
+    }
+
+    /**
+     * Set class <b>status</b> by calling setStatus(OAMCommandStatus, Params) with null paramter.
+     * @see #setStatus(OAMCommandStatus, String)
+     *
+     * @param oamCommandStatus of the to be set new state
+     */
+    void setStatus(OAMCommandStatus oamCommandStatus) {
+        setStatus(oamCommandStatus, null);
+    }
+
+    /**
+     * Create Status based on the passed in parameter, then set the class <b>status</b> with it.
+     *
+     * @param oamCommandStatus of the current OAM command status
+     * @param message to be set in the new status
+     */
+    void setStatus(OAMCommandStatus oamCommandStatus, String message) {
+        Params params = new Params().addParam("errorMsg", message);
+
+        StatusBuilder statusBuilder = new StatusBuilder();
+        statusBuilder.setCode(oamCommandStatus.getResponseCode());
+        if (params != null) {
+            statusBuilder.setMessage(oamCommandStatus.getFormattedMessage(params));
+        } else {
+            statusBuilder.setMessage(oamCommandStatus.getResponseMessage());
+        }
+
+        status = statusBuilder.build();
+    }
+
+    /**
+     * Set class <b>status</b> with error status calculated from the passed in paremeter
+     * and audit log the error message.
+     * @param t of the erro Throwable.
+     */
+    void setErrorStatus(Throwable t) {
+        final String appName = configurationHelper.getAppcName();
+        String exceptionMessage = t.getMessage() != null ? t.getMessage() : t.toString();
+
+        OAMCommandStatus oamCommandStatus;
+        String errorMessage;
+        if (t instanceof InvalidInputException) {
+            oamCommandStatus = OAMCommandStatus.INVALID_PARAMETER;
+            errorMessage = EELFResourceManager.format(Msg.OAM_OPERATION_INVALID_INPUT, t.getMessage());
+        } else if (t instanceof InvalidStateException) {
+            exceptionMessage = String.format(AppcOam.INVALID_STATE_MESSAGE_FORMAT,
+                    rpc.getAppcOperation(), appName, stateHelper.getCurrentOamState());
+            oamCommandStatus = OAMCommandStatus.REJECTED;
+            errorMessage = EELFResourceManager.format(Msg.INVALID_STATE_TRANSITION, exceptionMessage);
+        } else {
+            oamCommandStatus = OAMCommandStatus.UNEXPECTED_ERROR;
+            errorMessage = EELFResourceManager.format(Msg.OAM_OPERATION_EXCEPTION, t,
+                    appName, t.getClass().getSimpleName(), rpc.name(), exceptionMessage);
+        }
+
+        setStatus(oamCommandStatus, exceptionMessage);
+
+        LoggingUtils.logErrorMessage(
+                String.valueOf(status.getCode()),
+                status.getMessage(),
+                LoggingConstants.TargetNames.APPC,
+                LoggingConstants.TargetNames.APPC_OAM_PROVIDER,
+                errorMessage,
+                AppcOam.class.getCanonicalName());
+    }
+
+    /**
+     * Genral debug log when debug logging level is enabled.
+     * @param message of the log message format
+     * @param args of the objects listed in the message format
+     */
+    void logDebug(String message, Object... args) {
+        if (logger.isDebugEnabled()) {
+            logger.debug(String.format(message, args));
+        }
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseProcessor.java
new file mode 100644 (file)
index 0000000..6c70111
--- /dev/null
@@ -0,0 +1,166 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.processor;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.appc.exceptions.InvalidInputException;
+import org.openecomp.appc.exceptions.InvalidStateException;
+import org.openecomp.appc.i18n.Msg;
+import org.openecomp.appc.oam.OAMCommandStatus;
+import org.openecomp.appc.oam.util.AsyncTaskHelper;
+import org.openecomp.appc.oam.util.BundleHelper;
+import org.openecomp.appc.oam.util.ConfigurationHelper;
+import org.openecomp.appc.oam.util.OperationHelper;
+import org.openecomp.appc.oam.util.StateHelper;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+
+import java.util.Date;
+import java.util.concurrent.Future;
+
+/**
+ * Base processor for OAM APIs, such as maintenance mode, restart, start and stop API.
+ *
+ * <p>This class holds the general API request sync handling methods for all OAM APIs.
+ * <p>Specific API processor will overwrite the general methods to add specific behaviors.
+ */
+public abstract class BaseProcessor extends BaseCommon {
+    final AsyncTaskHelper asyncTaskHelper;
+    final BundleHelper bundleHelper;
+
+
+    Integer timeoutSeconds;
+    Msg auditMsg;
+    Runnable runnable;
+    private Future<?> scheduledRunnable = null;
+
+    /**
+     * Constructor
+     *
+     * @param eelfLogger for logging
+     * @param configurationHelperIn for property reading
+     * @param stateHelperIn for APP-C OAM state checking
+     * @param asyncTaskHelperIn for scheduling async task
+     * @param operationHelperIn for operational helper
+     */
+    BaseProcessor(EELFLogger eelfLogger,
+                  ConfigurationHelper configurationHelperIn,
+                  StateHelper stateHelperIn,
+                  AsyncTaskHelper asyncTaskHelperIn,
+                  OperationHelper operationHelperIn) {
+        super(eelfLogger, configurationHelperIn, stateHelperIn, operationHelperIn);
+
+        asyncTaskHelper = asyncTaskHelperIn;
+        bundleHelper = new BundleHelper(eelfLogger, configurationHelper, stateHelper);
+    }
+
+    /**
+     * Process synch handling and schedule asynch task
+     *
+     * @param requestInput of REST API request
+     * @return Status of new APP-C OAM state
+     */
+    public Status processRequest(final Object requestInput) {
+        startTime = new Date();
+        commonHeader = operationHelper.getCommonHeader(requestInput);
+        setStatus(OAMCommandStatus.ACCEPTED);
+
+        try {
+            preProcess(requestInput);
+            timeoutSeconds = operationHelper.getParamRequestTimeout(requestInput);
+            scheduleAsyncTask();
+        } catch (Throwable t) {
+            setErrorStatus(t);
+        } finally {
+            postProcess();
+        }
+
+        return status;
+    }
+
+    /**
+     * Preprocess before actual handling of the REST API call. Does:
+     * <p> - commonHeader validation
+     * <p> - get NextState as well as validate if next state is valid
+     * <p> - set logging properties
+     * <p> - set appcCurrentState to next state
+     *
+     * @throws InvalidInputException when commonHeader validation failed
+     * @throws APPCException         when state validation failed
+     */
+    protected void preProcess(final Object requestInput)
+            throws InvalidInputException, APPCException, InvalidStateException {
+        operationHelper.isInputValid(requestInput);
+
+        AppcOamStates nextState = operationHelper.getNextState(
+                rpc.getAppcOperation(), stateHelper.getCurrentOamState());
+        setInitialLogProperties();
+        stateHelper.setState(nextState);
+    }
+
+    /**
+     * Post process includes audit logging as well as clear MDC properties.
+     */
+    private void postProcess() {
+        auditInfoLog(auditMsg);
+        clearRequestLogProperties();
+    }
+
+    /**
+     * Schedule async task through AsyncTaskHelper.
+     */
+    protected void scheduleAsyncTask() {
+        if (runnable == null) {
+            logger.error(String.format(
+                    "Skipped schedule async task for rpc(%s) due to runnable is null", rpc.name()));
+            return;
+        }
+
+        scheduledRunnable = asyncTaskHelper.scheduleAsyncTask(rpc, runnable);
+    }
+
+    /**
+     * Check if current running task is the same as schedule task
+     * @return true if they are the same, otherwise false.
+     */
+    boolean isSameAsyncTask() {
+        return asyncTaskHelper.getCurrentAsyncTask() == scheduledRunnable;
+    }
+
+    /**
+     * Cancel schedueled async task through AsyncTaskHelper
+     */
+    void cancelAsyncTask() {
+        if (scheduledRunnable == null) {
+            logger.error(String.format(
+                    "Skipped cancel schedule async task for rpc(%s) due to scheduledRunnable is null", rpc.name()));
+            return;
+        }
+
+        asyncTaskHelper.cancelAsyncTask(scheduledRunnable);
+        scheduledRunnable = null;
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamMmodeProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamMmodeProcessor.java
new file mode 100644 (file)
index 0000000..d0d946a
--- /dev/null
@@ -0,0 +1,163 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.processor;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.appc.exceptions.InvalidInputException;
+import org.openecomp.appc.exceptions.InvalidStateException;
+import org.openecomp.appc.i18n.Msg;
+import org.openecomp.appc.oam.AppcOam;
+import org.openecomp.appc.oam.OAMCommandStatus;
+import org.openecomp.appc.oam.util.AsyncTaskHelper;
+import org.openecomp.appc.oam.util.ConfigurationHelper;
+import org.openecomp.appc.oam.util.OperationHelper;
+import org.openecomp.appc.oam.util.StateHelper;
+import org.openecomp.appc.requesthandler.LCMStateManager;
+import org.openecomp.appc.requesthandler.RequestHandler;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+
+/**
+ * Processor to handle maintenance mode OAM API.
+ */
+public class OamMmodeProcessor extends BaseProcessor {
+    /**
+     * Constructor
+     *
+     * @param eelfLogger          for logging
+     * @param configurationHelper for property reading
+     * @param stateHelper         for APP-C OAM state checking
+     * @param asyncTaskHelper     for scheduling async task
+     * @param operationHelper     for operational helper
+     */
+    public OamMmodeProcessor(EELFLogger eelfLogger,
+                             ConfigurationHelper configurationHelper,
+                             StateHelper stateHelper,
+                             AsyncTaskHelper asyncTaskHelper,
+                             OperationHelper operationHelper) {
+        super(eelfLogger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper);
+
+        rpc = AppcOam.RPC.maintenance_mode;
+        auditMsg = Msg.OAM_OPERATION_ENTERING_MAINTENANCE_MODE;
+    }
+
+    @Override
+    protected void preProcess(final Object requestInput)
+            throws InvalidInputException, InvalidStateException, APPCException {
+        super.preProcess(requestInput);
+
+        //Close the gate so that no more new LCM request will be excepted.
+        LCMStateManager lcmStateManager = operationHelper.getService(LCMStateManager.class);
+        lcmStateManager.disableLCMOperations();
+    }
+
+    @Override
+    protected void scheduleAsyncTask() {
+        runnable = new MyRunnable(this);
+        super.scheduleAsyncTask();
+    }
+
+    /**
+     * This runnable does the async handling for the maintenance mode REST API, and will be scheduled to run
+     * until terminating condition reaches.
+     *
+     * <p>The runnable will conintue run if: <br>
+     *   - the runnable is not canceled outside <br>
+     *   - the in progress LCM request count is not zero<br>
+     * <p> When LCM request count reaches to zero, this runnable will: <br>
+     *     - post message through operatonHelper <br>
+     *     - set APP-C OAM state to maintenance mode <br>
+     *     - audit log the state <br>
+     *     - terminate this runnable itself <br>
+     */
+    class MyRunnable extends BaseActionRunnable {
+        private int inprogressRequestCount;
+
+        MyRunnable(BaseProcessor parent) {
+            super(parent);
+
+            actionName = "OAM Maintanence mode";
+            auditMsg = Msg.OAM_OPERATION_MAINTENANCE_MODE;
+            finalState = AppcOamStates.MaintenanceMode;
+        }
+
+        @Override
+        boolean doAction() {
+            // always return true, so that we can check the LCM request count
+            return true;
+        }
+
+        @Override
+        boolean checkState() {
+            logDebug(String.format("Executing %s task", actionName));
+
+            if (!myParent.isSameAsyncTask()) {
+                // cancel myself if I am not the current backgroundOamTask
+                myParent.cancelAsyncTask();
+                logDebug(String.format("Finished %s task due to task removed", actionName));
+                return true;
+            }
+
+            boolean hasError = false;
+            try {
+                inprogressRequestCount = getInprogressLCMRequestCount();
+                if (inprogressRequestCount > 0) {
+                    // if there are still LCM request in progress, keep waiting
+                    return false;
+                }
+
+                setStatus(OAMCommandStatus.SUCCESS);
+            } catch (Throwable t) {
+                setErrorStatus(t);
+                hasError = true;
+            }
+
+            postAction(hasError ? AppcOamStates.Error : finalState);
+            return true;
+        }
+
+        /**
+         * Get in progress LCM request count through RequestHandler.
+         * @return thecount of in progress LCM request
+         * @throws APPCException if RequestHandler throws it.
+         */
+        private int getInprogressLCMRequestCount() throws APPCException {
+            RequestHandler requestHandler = operationHelper.getService(RequestHandler.class);
+
+            if (requestHandler == null) {
+                return 0;
+            }
+
+            return requestHandler.getInprogressRequestCount();
+        }
+
+        @Override
+        void keepWaiting() {
+            logDebug("The application '%s' has '%s' outstanding LCM request to complete" +
+                            " before coming to a complete maintenance_mode.",
+                    configurationHelper.getAppcName(), inprogressRequestCount);
+        }
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamRestartProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamRestartProcessor.java
new file mode 100644 (file)
index 0000000..529d250
--- /dev/null
@@ -0,0 +1,207 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.processor;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.appc.i18n.Msg;
+import org.openecomp.appc.oam.AppcOam;
+import org.openecomp.appc.oam.util.AsyncTaskHelper;
+import org.openecomp.appc.oam.util.ConfigurationHelper;
+import org.openecomp.appc.oam.util.OperationHelper;
+import org.openecomp.appc.oam.util.StateHelper;
+import org.openecomp.appc.requesthandler.LCMStateManager;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+
+/**
+ * Processor to handle restart OAM API.
+ */
+public class OamRestartProcessor extends BaseProcessor {
+    /**
+     * Action phases:
+     * <br> -ToStop: call bundles stop
+     * <br> -Stopped: check if all bundle state reached stopped
+     * <br> -ToStart: call bundles start
+     * <br> -Started: action is full completed
+     * <br> -Timeout: indication of timeout reached
+     */
+    private enum ActionPhases {
+        ToStop,
+        Stopped,
+        ToStart,
+        Started,
+        Timeout
+    }
+
+    /**
+     * Constructor
+     *
+     * @param eelfLogger          for logging
+     * @param configurationHelper for property reading
+     * @param stateHelper         for APP-C OAM state checking
+     * @param asyncTaskHelper     for scheduling async task
+     * @param operationHelper     for operational helper
+     */
+    public OamRestartProcessor(EELFLogger eelfLogger,
+                               ConfigurationHelper configurationHelper,
+                               StateHelper stateHelper,
+                               AsyncTaskHelper asyncTaskHelper,
+                               OperationHelper operationHelper) {
+        super(eelfLogger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper);
+
+        rpc = AppcOam.RPC.restart;
+        auditMsg = Msg.OAM_OPERATION_RESTARTING;
+    }
+
+    @Override
+    protected void scheduleAsyncTask() {
+        runnable = new MyRunnable(this);
+        super.scheduleAsyncTask();
+    }
+
+    /**
+     * This runnable does the async handling for the restart REST API. And it will be scheduled to run one time.
+     *
+     * <p>This runnable will the following operations: <br>
+     *     - do APP-C OAM bundle stop and then start through BundlerHelper<br>
+     *     - and always enable LCM operation handling (which can be disabled through maintenance mode API).<br>
+     * <p>Once above operations are done, the runnale will <br>
+     *     - post message through operatonHelper <br>
+     *     - set APP-C OAM state to started <br>
+     *     - audit log the state <br>
+     */
+    class MyRunnable extends BaseActionRunnable {
+
+        ActionPhases currentPhase = ActionPhases.ToStop;
+        private LCMStateManager lcmStateManager;
+
+        MyRunnable(BaseProcessor parent) {
+            super(parent);
+
+            actionName = "OAM Restart";
+            auditMsg = Msg.OAM_OPERATION_RESTARTED;
+            finalState = AppcOamStates.Started;
+        }
+
+        /**
+         * Do restart action, include stop then start and always enable LCM operation.
+         * @return true if action is successful, false when aciton is failed or aborted
+         */
+        @Override
+        boolean doAction() {
+            logDebug(String.format("Executing %s task at phase (%s)",
+                    actionName, currentPhase == null ? "null" : currentPhase.name()));
+
+            boolean isBundleOperationCompleted = true;
+            try {
+                switch (currentPhase) {
+                    case ToStop:
+                        isBundleOperationCompleted = bundleHelper.bundleOperations(
+                                AppcOam.RPC.stop, bundleNameToFuture, myParent.asyncTaskHelper);
+                        currentPhase = ActionPhases.Stopped;
+                        break;
+                    case Stopped:
+                        // check state
+                        AppcOamStates currentState = stateHelper.getBundlesState();
+                        if (currentState == AppcOamStates.Stopped) {
+                            currentPhase = ActionPhases.ToStart;
+                        } else {
+                            logDebug(String.format("%s task is waiting in stopped phase, current state is %s",
+                                    actionName, currentState));
+                        }
+                        break;
+                    case ToStart:
+                        isBundleOperationCompleted = bundleHelper.bundleOperations(
+                                AppcOam.RPC.start, bundleNameToFuture, myParent.asyncTaskHelper);
+                        currentPhase = ActionPhases.Started;
+                        break;
+                    case Timeout:
+                        // do nothing
+                        break;
+                    default:
+                        // Should not reach log it and return false;
+                        logger.error("%s task doAction reached %s phase. not supported. return false.",
+                                actionName, currentPhase.name());
+                        stateHelper.setState(AppcOamStates.Error);
+                        return false;
+                }
+
+                if (isTimeout("restart doAction")) {
+                    currentPhase = ActionPhases.Timeout;
+                    return true;
+                }
+                if (isBundleOperationCompleted) {
+                    return true;
+                }
+
+                setAbortStatus();
+            } catch (APPCException e) {
+                setErrorStatus(e);
+                stateHelper.setState(AppcOamStates.Error);
+            }
+
+            return false;
+        }
+
+        /**
+         * With additional to get the LCMStateManager service
+         * @see BaseActionRunnable#checkState()
+         */
+        @Override
+        boolean checkState() {
+            switch (currentPhase) {
+                case Started:
+                    try {
+                        lcmStateManager = operationHelper.getService(LCMStateManager.class);
+                        return super.checkState();
+                    } catch (APPCException e) {
+                        logDebug("LCMStateManager is not available.");
+                    }
+                    break;
+                default:
+                    // in all the other ActionPhase, we want the run go back to doAction
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Final handling. The thread is cancelled.
+         * @param setState boolean to indicate if set OAM state or not
+         */
+        @Override
+        void postDoAction(boolean setState) {
+            AppcOamStates newState = null;
+            if (setState) {
+                logDebug("Always enable LCM operation");
+                lcmStateManager.enableLCMOperations();
+                newState = finalState;
+            }
+            postAction(newState);
+            super.postDoAction(setState);
+        }
+
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStartProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStartProcessor.java
new file mode 100644 (file)
index 0000000..0060bfc
--- /dev/null
@@ -0,0 +1,151 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.processor;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.appc.i18n.Msg;
+import org.openecomp.appc.oam.AppcOam;
+import org.openecomp.appc.oam.util.AsyncTaskHelper;
+import org.openecomp.appc.oam.util.ConfigurationHelper;
+import org.openecomp.appc.oam.util.OperationHelper;
+import org.openecomp.appc.oam.util.StateHelper;
+import org.openecomp.appc.requesthandler.LCMStateManager;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+
+/**
+ * Processor to handle start OAM API.
+ */
+public class OamStartProcessor extends BaseProcessor {
+
+    /**
+     * Constructor
+     *
+     * @param eelfLogger          for logging
+     * @param configurationHelper for property reading
+     * @param stateHelper         for APP-C OAM state checking
+     * @param asyncTaskHelper     for scheduling async task
+     * @param operationHelper     for operational helper
+     */
+    public OamStartProcessor(EELFLogger eelfLogger,
+                             ConfigurationHelper configurationHelper,
+                             StateHelper stateHelper,
+                             AsyncTaskHelper asyncTaskHelper,
+                             OperationHelper operationHelper) {
+        super(eelfLogger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper);
+
+        rpc = AppcOam.RPC.start;
+        auditMsg = Msg.OAM_OPERATION_STARTING;
+    }
+
+    @Override
+    protected void scheduleAsyncTask() {
+        runnable = new MyRunnable(this);
+        super.scheduleAsyncTask();
+    }
+
+    /**
+     * This runnable does the async handling for the start REST API. And it will be scheduled to run one time.
+     *
+     * <p>This runnable will the following operations: <br>
+     *     - do APP-C OAM bundle start through BundlerHelper<br>
+     *     - and always enable LCM operation handling (which can be disabled through maintenance mode API).<br>
+     * <p>Once above operations are done, the runnale will <br>
+     *     - post message through operatonHelper <br>
+     *     - set APP-C OAM state to started <br>
+     *     - audit log the state <br>
+     */
+    class MyRunnable extends BaseActionRunnable {
+
+        private LCMStateManager lcmStateManager;
+
+        MyRunnable(BaseProcessor parent) {
+            super(parent);
+            actionName = "OAM Start";
+            auditMsg = Msg.OAM_OPERATION_STARTED;
+            finalState = AppcOamStates.Started;
+        }
+
+        /**
+         * Do start action, include start bundle if needed and always enable LCM operation.
+         * @return true if action is successful, false when aciton is failed or aborted
+         */
+        @Override
+        boolean doAction() {
+            logDebug(String.format("Executing %s task", actionName));
+
+            boolean isBundleOperationCompleted = true;
+            try {
+                if (stateHelper.getState() != AppcOamStates.Started) {
+                    logDebug("Start - APPC OAM state is not started, start the bundles");
+                    isBundleOperationCompleted = bundleHelper.bundleOperations(
+                            rpc, bundleNameToFuture, myParent.asyncTaskHelper);
+                }
+
+                if (isBundleOperationCompleted) {
+                    return true;
+                }
+
+                setAbortStatus();
+            } catch (APPCException e) {
+                setErrorStatus(e);
+                stateHelper.setState(AppcOamStates.Error);
+            }
+
+            return false;
+        }
+
+        /**
+         * With additional to get the LCMStateManager service
+         * @see BaseActionRunnable#checkState()
+         */
+        @Override
+        boolean checkState() {
+            try {
+                lcmStateManager = operationHelper.getService(LCMStateManager.class);
+                return super.checkState();
+            } catch (APPCException e) {
+                logDebug("LCMStateManager is not available.");
+                return false;
+            }
+        }
+
+        /**
+         * Final handling
+         * @param setState boolean to indicate if set OAM state or not
+         */
+        @Override
+        void postDoAction(boolean setState) {
+            AppcOamStates newState = null;
+            if (setState) {
+                logDebug("Always enable LCM operation");
+                lcmStateManager.enableLCMOperations();
+                newState = finalState;
+            }
+            postAction(newState);
+            super.postDoAction(setState);
+        }
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStopProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStopProcessor.java
new file mode 100644 (file)
index 0000000..d819016
--- /dev/null
@@ -0,0 +1,120 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.processor;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.appc.i18n.Msg;
+import org.openecomp.appc.oam.AppcOam;
+import org.openecomp.appc.oam.util.AsyncTaskHelper;
+import org.openecomp.appc.oam.util.ConfigurationHelper;
+import org.openecomp.appc.oam.util.OperationHelper;
+import org.openecomp.appc.oam.util.StateHelper;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+
+/**
+ * Processor to handle stop OAM API.
+ */
+public class OamStopProcessor extends BaseProcessor {
+    /**
+     * Constructor
+     *
+     * @param eelfLogger          for logging
+     * @param configurationHelper for property reading
+     * @param stateHelper         for APP-C OAM state checking
+     * @param asyncTaskHelper     for scheduling async task
+     * @param operationHelper     for operational helper
+     */
+    public OamStopProcessor(EELFLogger eelfLogger,
+                            ConfigurationHelper configurationHelper,
+                            StateHelper stateHelper,
+                            AsyncTaskHelper asyncTaskHelper,
+                            OperationHelper operationHelper) {
+        super(eelfLogger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper);
+
+        rpc = AppcOam.RPC.stop;
+        auditMsg = Msg.OAM_OPERATION_STOPPING;
+    }
+
+
+    @Override
+    protected void scheduleAsyncTask() {
+        runnable = new MyRunnable(this);
+        super.scheduleAsyncTask();
+    }
+
+    /**
+     * This runnable does the async handling for the stop REST API. And it will be scheduled to run one time.
+     *
+     * <p>This runnable will the following operations: <br>
+     *     - do APP-C OAM bundle stop and then refresh through BundlerHelper<br>
+     * <p>Once above operations are done, the runnale will <br>
+     *     - post message through operatonHelper <br>
+     *     - set APP-C OAM state to started <br>
+     *     - audit log the state <br>
+     */
+    class MyRunnable  extends BaseActionRunnable {
+
+        MyRunnable(BaseProcessor parent) {
+            super(parent);
+            actionName = "OAM Stop";
+            auditMsg = Msg.OAM_OPERATION_STOPPED;
+            finalState = AppcOamStates.Stopped;
+        }
+
+        /**
+         * Do stop action, include stop bundle .
+         * @return true if action is successful, false when aciton is failed.
+         */
+        @Override
+        boolean doAction() {
+            logDebug(String.format("Executing %s task", actionName));
+
+            try {
+                boolean isBundleOperationCompleted = bundleHelper.bundleOperations(
+                        rpc, bundleNameToFuture, myParent.asyncTaskHelper);
+                if (isBundleOperationCompleted) {
+                    return true;
+                }
+
+                setAbortStatus();
+            } catch (APPCException e) {
+                setErrorStatus(e);
+                stateHelper.setState(AppcOamStates.Error);
+            }
+            return false;
+        }
+
+        /**
+         * Final handling
+         * @param setState boolean to indicate if set OAM state or not
+         */
+        @Override
+        void postDoAction(boolean setState) {
+            postAction(setState ? finalState : null);
+            super.postDoAction(setState);
+        }
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/AsyncTaskHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/AsyncTaskHelper.java
new file mode 100644 (file)
index 0000000..ff28e99
--- /dev/null
@@ -0,0 +1,165 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.openecomp.appc.oam.AppcOam;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Utility class provides general async task related help.
+ */
+@SuppressWarnings("unchecked")
+public class AsyncTaskHelper {
+    final int MMODE_TASK_DELAY = 10000;
+    final int COMMON_INITIAL_DELAY = 0;
+    final int COMMON_INTERVAL = 1000;
+
+    private final EELFLogger logger;
+    private final ScheduledExecutorService scheduledExecutorService;
+    private final ThreadPoolExecutor bundleOperationService;
+
+    /** Reference to the Async task */
+    private volatile Future<?> backgroundOamTask;
+
+    /**
+     * Constructor
+     * @param eelfLogger of the logger
+     */
+    public AsyncTaskHelper(EELFLogger eelfLogger) {
+        logger = eelfLogger;
+
+        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(
+                (runnable) -> {
+                    Bundle bundle = FrameworkUtil.getBundle(AppcOam.class);
+                    return new Thread(runnable, bundle.getSymbolicName() + " scheduledExecutor");
+                }
+        );
+
+        bundleOperationService = new ThreadPoolExecutor(
+                0,
+                10,
+                10,
+                TimeUnit.SECONDS,
+                new LinkedBlockingQueue(),// BlockingQueue<Runnable> workQueue
+                (runnable) -> new Thread(runnable, "OAM bundler operation executor")//ThreadFactory
+        );
+    }
+
+    void addThreadsToPool() {
+        bundleOperationService.setCorePoolSize(bundleOperationService.getMaximumPoolSize());
+    }
+
+    void removeThreadsFromPoolWhenDone() {
+        bundleOperationService.setCorePoolSize(0);
+    }
+
+    /**
+     * Terminate the class <bS>ScheduledExecutorService</b>
+     */
+    public void close() {
+        logDebug("Start shutdown scheduleExcutorService.");
+        scheduledExecutorService.shutdown();
+        bundleOperationService.shutdown();
+        logDebug("Completed shutdown scheduleExcutorService.");
+    }
+
+    /**
+     * Get current async task refernce
+     * @return the class <b>backgroundOamTask</b>
+     */
+    public Future<?> getCurrentAsyncTask() {
+        return backgroundOamTask;
+    }
+
+    /**
+     * Schedule a service for async task with the passed in parameters
+     * @param rpc of the REST API call, decides how to schedule the service
+     * @param runnable of the to be scheduled service.
+     * @return the refernce of the scheduled task
+     */
+    public Future<?> scheduleAsyncTask(final AppcOam.RPC rpc, final Runnable runnable) {
+        int initialDelay, interval;
+        switch (rpc) {
+            case maintenance_mode:
+                initialDelay = interval =MMODE_TASK_DELAY;
+                break;
+            case start:
+            case stop:
+            case restart:
+                initialDelay = COMMON_INITIAL_DELAY;
+                interval = COMMON_INTERVAL;
+                break;
+            default:
+                // should not get here. Log it and return null
+                logDebug(String.format("Cannot scheudle task for unsupported RPC(%s).", rpc.name()));
+                return null;
+        }
+
+        // Always cancel existing  async task
+        if (backgroundOamTask != null) {
+            backgroundOamTask.cancel(true);
+        }
+        backgroundOamTask = scheduledExecutorService.scheduleWithFixedDelay(
+                runnable, initialDelay, interval, TimeUnit.MILLISECONDS);
+
+        return backgroundOamTask;
+    }
+
+    Future<?> submitBundleLcOperation(final Callable callable) {
+        return bundleOperationService.submit(callable);
+    }
+
+    /**
+     * Cancle a previously schedule task. If the task is the same as backgroundOamTask, set it to null.
+     * @param task to be canceled
+     */
+    public void cancelAsyncTask(Future<?> task) {
+        task.cancel(false);
+        if (task == backgroundOamTask) {
+            backgroundOamTask = null;
+        }
+    }
+
+    /**
+     * Genral debug log when debug logging level is enabled.
+     * @param message of the log message format
+     * @param args of the objects listed in the message format
+     */
+    private void logDebug(String message, Object... args) {
+        if (logger.isDebugEnabled()) {
+            logger.debug(String.format(message, args));
+        }
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleFilter.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleFilter.java
new file mode 100644 (file)
index 0000000..1e9f9b6
--- /dev/null
@@ -0,0 +1,128 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.util;
+
+import org.osgi.framework.Bundle;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+
+
+/**
+ *
+ * Utility Class that splits a given bundleSet into two sets: bundleToStopSet and
+ * bundleToNotStopSet
+ *
+ * The bundleToStopSet is defined as: all bundles which match at least one of
+ * the stopRegexes but exceptRegexes none of the
+ *
+ * The bundleToNotStopSet is defined as all bundles which are not a member of
+ * the bundleToStopSet
+ *
+ */
+class BundleFilter {
+
+    private final Map<String, Bundle> bundleToStopSet;
+    private final Map<String, Bundle> bundleToNotStopSet;
+
+
+    /**
+     * BundleFilter a bundle filter
+     * @param stopRegexes  - An array of regular expression used to pick out which bundles are candidates for stopping
+     * @param exceptRegexes - An array of regular expression used to override which bundles are candidates for stopping
+     * @param bundles - An array of the bundle to be split into {@link #getBundlesToStop()} {@link #getBundlesToNotStop()}
+     */
+    BundleFilter(String[] stopRegexes, String[] exceptRegexes, Bundle[] bundles) {
+
+        Pattern[] stopPatterns = toPattern(stopRegexes);
+        Pattern[] exceptPatterns = toPattern(exceptRegexes);
+
+        Map<String, Bundle> bundleToStop = new HashMap<>();
+        Map<String, Bundle>  bundleToNotStop = new HashMap<>();
+
+        for (Bundle bundle : bundles) {
+            String symbolicName = bundle.getSymbolicName();
+            if (isMatch(symbolicName,stopPatterns) && !isMatch(symbolicName,exceptPatterns)) {
+                bundleToStop.put(symbolicName, bundle);
+            } else {
+                bundleToNotStop.put(symbolicName, bundle);
+            }
+        }
+
+        this.bundleToStopSet = Collections.unmodifiableMap(bundleToStop);
+        this.bundleToNotStopSet = Collections.unmodifiableMap(bundleToNotStop);
+    }
+
+    /**
+     * Determines if the value matches any of the regular expressions.
+     *
+     * @param value
+     *            - the value that is to be matched
+     * @param patterns
+     *            - the array of {@link Pattern} to match the value against
+     * @return boolean true if there is a match
+     */
+    private boolean isMatch(String value,Pattern[] patterns) {
+        for (Pattern pattern : patterns) {
+            if (pattern.matcher(value).matches()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This method converts an Array of regular expression in String form into a
+     * Array of {@link Pattern}
+     *
+     * @param regex
+     *            - A string array of regular expressions
+     * @return Pattern Array of compiled regular expressions
+     */
+    private Pattern[] toPattern(String[] regex) {
+        Pattern[] pattern = new Pattern[regex.length];
+        for (int i = 0; i < regex.length; i++ ) {
+            pattern[i] = Pattern.compile(regex[i]);
+        }
+        return pattern;
+    }
+
+
+    /**@return Map of bundles that are to be stopped  */
+    Map<String, Bundle> getBundlesToStop(){
+        return bundleToStopSet;
+    }
+
+    /**
+     *
+     * @return Map of bundles that are not to be stopped
+     */
+    Map<String, Bundle> getBundlesToNotStop() {
+        return bundleToNotStopSet;
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleHelper.java
new file mode 100644 (file)
index 0000000..7fbb3c4
--- /dev/null
@@ -0,0 +1,265 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.apache.commons.lang3.ArrayUtils;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.appc.oam.AppcOam;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkUtil;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+/**
+ * Utility class provides general bundle operational helps.
+ */
+public class BundleHelper {
+    private final static String PROP_BUNDLE_TO_STOP = "appc.OAM.ToStop.properties";
+    private final static String PROP_BUNDLES_TO_NOT_STOP = "appc.OAM.ToNotStop.properties";
+
+    private final EELFLogger logger;
+    private final StateHelper stateHelper;
+    private final ConfigurationHelper configurationHelper;
+
+    /**
+     * Constructor
+     *
+     * @param eelfLogger of the logger
+     * @param configurationHelperIn of ConfigurationHelper instance
+     * @param stateHelperIn of StateHelper instance
+     */
+    public BundleHelper(EELFLogger eelfLogger,
+                        ConfigurationHelper configurationHelperIn,
+                        StateHelper stateHelperIn) {
+        logger = eelfLogger;
+        configurationHelper = configurationHelperIn;
+        stateHelper = stateHelperIn;
+    }
+
+    /**
+     * Handle bundle operations, such as stop or start bundle.
+     *
+     * @param rpc enum indicate if the operation is to stop, start or restart
+     * @return boolean to indicate if the operation is successful (true) or failed (false)
+     * @throws APPCException when error occurs
+     */
+    public boolean bundleOperations(AppcOam.RPC rpc,
+                                    Map<String, Future<?>> threads,
+                                    AsyncTaskHelper taskHelper)
+            throws APPCException {
+        long mStartTime = System.currentTimeMillis();
+        logDebug(String.format("Entering OAM bundleOperations with rpc (%s).", rpc.name()));
+
+        String action = rpc.getAppcOperation().toString();
+        if (rpc != AppcOam.RPC.stop && rpc != AppcOam.RPC.start) {
+            throw new APPCException("rpc(" + rpc + ") is not supported by bundleOperation.");
+        }
+
+        AppcOamStates originalState = stateHelper.getState();
+
+        boolean isBundleOperationComplete = true;
+
+        Map<String, Bundle> appcLcmBundles = getAppcLcmBundles();
+        taskHelper.addThreadsToPool();
+        for (Map.Entry<String, Bundle> bundleEntry : appcLcmBundles.entrySet()) {
+            String bundleName = bundleEntry.getKey();
+            Bundle bundle = bundleEntry.getValue();
+
+            logDebug("OAM launch thread for %s bundle %s", action, bundleName);
+            if (rpc == AppcOam.RPC.start) {
+                // Abort in the interruption case.
+                // such as when a Stop request is receive while APPC is still trying to Start Up.
+                if (!stateHelper.isSameState(originalState)) {
+                    logger.warn("OAM %s bundle operation aborted since OAM state is no longer %s!",
+                            originalState.name());
+                    isBundleOperationComplete = false;
+                    break;
+                }
+            }
+
+            threads.put(bundleName,
+                    taskHelper.submitBundleLcOperation(new BundleTask(rpc, bundle)));
+        }
+        taskHelper.removeThreadsFromPoolWhenDone();
+
+        logDebug(String.format("Leaving OAM bundleOperations with rpc (%s) with complete(%s), elasped (%d) ms.",
+                rpc.name(), Boolean.toString(isBundleOperationComplete), getElaspeTimeMs(mStartTime)));
+
+        return isBundleOperationComplete;
+    }
+
+    private long getElaspeTimeMs(long mStartTime) {
+        return System.currentTimeMillis() - mStartTime;
+    }
+
+    /**
+     * Check if all BundleTasks are completed
+     * @param bundleNameFutureMap with bundler name and BundleTask Future object
+     * @return true if all are done, otherwise, false
+     */
+    public boolean isAllTaskDone(Map<String, Future<?>> bundleNameFutureMap) {
+        boolean anyNotDone = bundleNameFutureMap.values().stream().anyMatch((f) -> !f.isDone());
+        return !anyNotDone;
+    }
+
+    /**
+     * Cancel BunldeTasks which are not finished
+     * @param bundleNameFutureMap with bundler name and BundleTask Future object
+     */
+    public void cancelUnfinished(Map<String, Future<?>> bundleNameFutureMap) {
+        bundleNameFutureMap.values().stream().filter((f) -> !f.isDone()).forEach((f) -> f.cancel(true));
+    }
+
+    /**
+     * Get number of failed BundleTasks
+     * @param bundleNameFurtureMap with bundler name and BundleTask Future object
+     * @return number(long) of the failed BundleTasks
+     */
+    public long getFailedMetrics(Map<String, Future<?>> bundleNameFurtureMap) {
+        return bundleNameFurtureMap.values().stream().map((f) -> {
+            try {
+                return f.get();
+            } catch (Exception e) {
+                // should not get here
+                throw new RuntimeException(e);
+            }
+        }).filter((b) -> ((BundleTask)b).failException != null).count();
+    }
+
+    /**
+     * Gets the list of Appc-bundles to be stopped/started
+     *
+     * @return Map of bundle symbolic name and bundle instance
+     */
+    Map<String, Bundle> getAppcLcmBundles() {
+        logDebug("In getAppcLcmBundles");
+
+        String[] bundlesToStop = readPropsFromPropListName(PROP_BUNDLE_TO_STOP);
+        String[] regExBundleNotStop = readPropsFromPropListName(PROP_BUNDLES_TO_NOT_STOP);
+
+        BundleFilter bundleList = new BundleFilter(bundlesToStop, regExBundleNotStop, getBundleList());
+
+        logger.info(String.format("(%d) APPC bundles to Stop/Start: %s.", bundleList.getBundlesToStop().size(),
+                bundleList.getBundlesToStop().toString()));
+
+        logger.debug(String.format("(%d) APPC bundles that won't be Stopped/Started: %s.",
+                bundleList.getBundlesToNotStop().size(), bundleList.getBundlesToNotStop().toString()));
+
+        return bundleList.getBundlesToStop();
+    }
+
+    /**
+     * Gets a list of all user desired bundles that should be stopped/Started as part of
+     * OAM Stop and Start API
+     *
+     * @param propListKey String of the properties list property name
+     * @return properties values of the related
+     */
+    String[] readPropsFromPropListName(String propListKey) {
+        // get properties list by properties list name
+        String[] propNames = configurationHelper.readProperty(propListKey);
+        // go through each property to get the property values
+        String[] propValue = ArrayUtils.EMPTY_STRING_ARRAY;
+        if (propNames != null) {
+            for (String aPropName : propNames) {
+                propValue = ArrayUtils.addAll(propValue, configurationHelper.readProperty(aPropName));
+            }
+        }
+        return propValue;
+    }
+
+    /**
+     * Get all bundle list of APP-C
+     * @return Array of Bundle
+     */
+    Bundle[] getBundleList() {
+        BundleContext myBundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+        if (myBundleContext != null) {
+            return myBundleContext.getBundles();
+        }
+        return null;
+    }
+
+    /**
+     * Genral debug log when debug logging level is enabled.
+     * @param message of the log message format
+     * @param args of the objects listed in the message format
+     */
+    private void logDebug(String message, Object... args) {
+        if (logger.isDebugEnabled()) {
+            logger.debug(String.format(message, args));
+        }
+    }
+
+    /**
+     * Runnable to execute bundle operations: start or stop
+     */
+    class BundleTask implements Callable<BundleTask> {
+        Exception failException;
+
+        private AppcOam.RPC rpc;
+        private Bundle bundle;
+        private String bundleName;
+        private String actionName;
+
+        BundleTask(AppcOam.RPC rpcIn, Bundle bundleIn) {
+            rpc = rpcIn;
+            actionName = rpc.getAppcOperation().toString();
+            bundle = bundleIn;
+            bundleName = bundle.getSymbolicName();
+        }
+
+        @Override
+        public BundleTask call() throws Exception {
+            try {
+                long bundleOperStartTime = System.currentTimeMillis();
+                logDebug(String.format("OAM %s bundle %s ===>", actionName, bundleName));
+                switch (rpc) {
+                    case start:
+                        bundle.start();
+                        break;
+                    case stop:
+                        bundle.stop();
+                        break;
+                    default:
+                        // should do nothing
+                }
+                logDebug(String.format("OAM %s bundle %s completed <=== elasped %d",
+                        actionName, bundleName, getElaspeTimeMs(bundleOperStartTime)));
+            } catch (BundleException e) {
+                logger.error(String.format("Exception encountered when OAM %s bundle %s ",
+                        actionName, bundleName), e);
+                failException = e;
+            }
+            return this;
+        }
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/ConfigurationHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/ConfigurationHelper.java
new file mode 100644 (file)
index 0000000..c465b9b
--- /dev/null
@@ -0,0 +1,80 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.apache.commons.lang3.ArrayUtils;
+import org.openecomp.appc.Constants;
+import org.openecomp.appc.configuration.Configuration;
+import org.openecomp.appc.configuration.ConfigurationFactory;
+
+/**
+ * Utility class provides general configuration helps
+ */
+public class ConfigurationHelper {
+    final static String PROP_KEY_APPC_NAME = Constants.PROPERTY_APPLICATION_NAME;
+    final static String PROP_KEY_METRIC_STATE = "metric.enabled";
+
+    private final EELFLogger logger;
+    private Configuration configuration = ConfigurationFactory.getConfiguration();
+
+    public ConfigurationHelper(EELFLogger eelfLogger) {
+        logger = eelfLogger;
+    }
+
+    public String getAppcName() {
+        return configuration.getProperty(PROP_KEY_APPC_NAME);
+    }
+
+    public boolean isMetricEnabled() {
+        return configuration.getBooleanProperty(PROP_KEY_METRIC_STATE, false);
+    }
+
+    public Configuration getConfig() {
+        return configuration;
+    }
+
+    /**
+     * Read property value of a specified proeprty key
+     *
+     * @param propertyKey string of the property key
+     * @return String[] of the property values associated with the propertyKey
+     */
+    String[] readProperty(String propertyKey) {
+        String propertyValue = configuration.getProperty(propertyKey);
+        if (propertyValue == null) {
+            return ArrayUtils.EMPTY_STRING_ARRAY;
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(String.format("Property[%s] has value (%s).", propertyKey, propertyValue));
+        }
+
+        if (propertyValue.contains(",")) {
+            return propertyValue.split("\\s*,\\s*");
+        }
+        return new String[]{propertyValue};
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/OperationHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/OperationHelper.java
new file mode 100644 (file)
index 0000000..0b20104
--- /dev/null
@@ -0,0 +1,205 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeInput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartInput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartInput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopInput;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.common.header.Flags;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.appc.exceptions.InvalidInputException;
+import org.openecomp.appc.exceptions.InvalidStateException;
+import org.openecomp.appc.lifecyclemanager.LifecycleManager;
+import org.openecomp.appc.lifecyclemanager.objects.LifecycleException;
+import org.openecomp.appc.lifecyclemanager.objects.NoTransitionDefinedException;
+import org.openecomp.appc.oam.AppcOam;
+import org.openecomp.appc.oam.messageadapter.MessageAdapter;
+import org.openecomp.appc.oam.messageadapter.OAMContext;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamMetaDataReader;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Utility class provides general operational helps.
+ */
+@SuppressWarnings("unchecked")
+public class OperationHelper {
+    final String MISSING_COMMON_HEADER_MESSAGE = "Missing common header";
+    final String MISSING_FIELD_MESSAGE = "Common header must have both originatorId and requestId";
+    final String NOT_SUPPORT_FLAG = "Flags is not supported by this operation";
+    final String NO_SERVICE_REF_FORMAT = "Using the BundleContext failed to get service reference for %s";
+
+    private final EELFLogger logger = EELFManager.getInstance().getLogger(OperationHelper.class);
+    private LifecycleManager lifecycleMgr;
+    private MessageAdapter messageAdapter;
+
+    public OperationHelper() {
+        // do nothing
+    }
+
+    /**
+     * This method is used to validate OAM REST API input due to the following ODL bugs results no validation : </tt>
+     * <p>  - <a href="https://bugs.opendaylight.org/show_bug.cgi?id=8088">
+     *       Bug 8088 - Mandatory attributes in RPC input are not honoured</a>
+     * <p>  - <a href="https://bugs.opendaylight.org/show_bug.cgi?id=5830">
+     *       Bug 5830 - Mandatory leaf enforcement is not correct with presence container</a>
+     *
+     * @param inputObject object from the OAM REST API input object
+     * @throws InvalidInputException is thrown when the commonHeader is invalid
+     */
+    public void isInputValid(final Object inputObject) throws InvalidInputException {
+        CommonHeader commonHeader = getCommonHeader(inputObject);
+        if (commonHeader == null) {
+            throw new InvalidInputException(MISSING_COMMON_HEADER_MESSAGE);
+        }
+
+        if (commonHeader.getOriginatorId() == null
+                || commonHeader.getRequestId() == null) {
+            throw new InvalidInputException(MISSING_FIELD_MESSAGE);
+        }
+
+        // check Flags
+        if (inputObject instanceof MaintenanceModeInput
+                && commonHeader.getFlags() != null) {
+            throw new InvalidInputException(NOT_SUPPORT_FLAG);
+        }
+    }
+
+    /**
+     * Get commonHead of the inputObject (expecting the inputObject of OAM REST API)
+     * @param inputObject the OAM REST API input object
+     * @return CommonHeader of the inputObject. If the inputObject is not a OAM REST API input, null is returned.
+     */
+    public CommonHeader getCommonHeader(final Object inputObject) {
+        if (inputObject instanceof StartInput) {
+            return ((StartInput)inputObject).getCommonHeader();
+        }
+        if (inputObject instanceof StopInput) {
+            return ((StopInput)inputObject).getCommonHeader();
+        }
+        if (inputObject instanceof MaintenanceModeInput) {
+            return ((MaintenanceModeInput)inputObject).getCommonHeader();
+        }
+        if (inputObject instanceof RestartInput) {
+            return ((RestartInput)inputObject).getCommonHeader();
+        }
+        return null;
+    }
+
+    public Integer getParamRequestTimeout(final Object inputObject) {
+        if (inputObject instanceof MaintenanceModeInput) {
+            // maintanence mode, we do not support request timeout
+            return 0;
+        }
+
+        CommonHeader commonHeader = getCommonHeader(inputObject);
+        if (commonHeader == null) {
+            return 0;
+        }
+
+        Flags inputFlags = commonHeader.getFlags();
+        if (inputFlags == null) {
+            return null;
+        }
+        return inputFlags.getRequestTimeout();
+    }
+    /**
+     * Get service instance using bundle context.
+     *
+     * @param _class of the expected service instance
+     * @param <T> of the expected service instance
+     * @return service instance of the expected
+     * @throws APPCException when cannot find service reference or service isntance
+     */
+    public <T> T getService(Class<T> _class) throws APPCException {
+        BundleContext bctx = FrameworkUtil.getBundle(_class).getBundleContext();
+        if (bctx != null) {
+            ServiceReference sref = bctx.getServiceReference(_class.getName());
+            if (sref != null) {
+                if (logger.isTraceEnabled()) {
+                    logger.debug("Using the BundleContext got the service reference for " + _class.getName());
+                }
+                return (T) bctx.getService(sref);
+            }
+        }
+
+        throw new APPCException(String.format(NO_SERVICE_REF_FORMAT, _class.getName()));
+    }
+
+    /**
+     * Get next valid state from life cycle manager.
+     *
+     * @param operation of the AppcOperation for the state changes
+     * @param currentState of AppcOamStates
+     * @return next AppcOamStates based on the currentState and operation
+     * @throws APPCException If life cycle manager instance cannot be retrieved
+     * @throws InvalidStateException when the operation is not supported on the currentState
+     */
+    public AppcOamStates getNextState(AppcOamMetaDataReader.AppcOperation operation, AppcOamStates currentState)
+            throws APPCException, InvalidStateException {
+        if (lifecycleMgr == null) {
+            lifecycleMgr = getService(LifecycleManager.class);
+        }
+
+        try {
+            String nextState = lifecycleMgr.getNextState("APPC", currentState.name(), operation.toString());
+            if (nextState != null) {
+                return AppcOamStates.valueOf(nextState);
+            }
+        } catch (LifecycleException |NoTransitionDefinedException ex) {
+            logger.error("Invalid next state based on the current state and attempted Operation " + ex.getMessage());
+        }
+
+        throw new InvalidStateException(String.format(AppcOam.INVALID_STATE_MESSAGE_FORMAT, operation, "APPC", currentState));
+    }
+
+    /**
+     * Post notification through MessageAdapter.
+     *
+     * @param rpc of REST API RPC
+     * @param commonHeader of REST API request common header
+     * @param status of the to be post message
+     */
+    public void sendNotificationMessage(AppcOam.RPC rpc, CommonHeader commonHeader, Status status) {
+        if (messageAdapter == null) {
+            messageAdapter = new MessageAdapter();
+            messageAdapter.init();
+
+        }
+
+        OAMContext oamContext = new OAMContext();
+        oamContext.setRpcName(rpc);
+        oamContext.setCommonHeader(commonHeader);
+        oamContext.setStatus(status);
+        messageAdapter.post(oamContext);
+    }
+}
diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/StateHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/StateHelper.java
new file mode 100644 (file)
index 0000000..a9ccc26
--- /dev/null
@@ -0,0 +1,144 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.oam.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.AppcState;
+import org.openecomp.appc.statemachine.impl.readers.AppcOamStates;
+import org.osgi.framework.Bundle;
+
+import java.util.Map;
+
+/*
+ * Utility class provides general state helps
+ */
+public class StateHelper {
+    /** logger inherited from AppcOam */
+    private final EELFLogger logger;
+    private ConfigurationHelper configurationHelper;
+    /** APP-C OAM current state in AppcOamStates value */
+    private volatile AppcOamStates appcOamCurrentState;
+
+    /**
+     * Constructor
+     *
+     * @param eelfLogger of the logger
+     */
+    public StateHelper(EELFLogger eelfLogger, ConfigurationHelper cHelper) {
+        logger = eelfLogger;
+        configurationHelper = cHelper;
+        appcOamCurrentState = AppcOamStates.Unknown;
+    }
+
+    /**
+     * Set the passed in state to the class <b>appOamCurrentState</b>.
+     *
+     * @param appcOamStates of the new state
+     */
+    public void setState(AppcOamStates appcOamStates) {
+        appcOamCurrentState = appcOamStates;
+    }
+
+    /**
+     * Get the state
+     * @return the class <b>appOamCurrentState</b>
+     */
+    public AppcOamStates getState() {
+        return appcOamCurrentState;
+    }
+
+    /**
+     * Validate if the passed in state is the same as the class <b>appOamCurrentState</b>.
+     *
+     * @param appcOamStates of the to be compared state
+     * @return true if they are the same, otherwise false
+     */
+    boolean isSameState(AppcOamStates appcOamStates) {
+        return appcOamCurrentState == appcOamStates;
+    }
+
+    /**
+     * Get APP-C OAM current state
+     *
+     * <p>When appcOamCurrentState is null or unknown, reset it with APPC LCM bundle state.
+     *
+     * @return AppcOamStates of the current APP-C OAM state
+     */
+    public AppcOamStates getCurrentOamState() {
+        if (appcOamCurrentState == null || appcOamCurrentState.equals(AppcOamStates.Unknown)) {
+            appcOamCurrentState = getBundlesState();
+        }
+        return appcOamCurrentState;
+    }
+
+    /**
+     * Use getCurrentOamState to get current OAM AppcOamStates and then convert to AppcState of Yang.
+     *
+     * @return AppcState of current OAM state
+     */
+    public AppcState getCurrentOamYangState() {
+        try {
+            AppcOamStates appcOamStates = getCurrentOamState();
+            return AppcState.valueOf(appcOamStates.name());
+        } catch (Exception ex) {
+            logger.error(String.format("Unable to determine the current APP-C OAM state due to %s.", ex.getMessage()));
+        }
+        return AppcState.Unknown;
+    }
+
+    /**
+     * Get APPC state from the state of the set of APPC LCM bundles.
+     * <p>The state of each bundle will be checked and the lowest state will be uses as the returning AppcOamStates.
+     * <p>The bundle state order are defined in OSGI bundle (@see org.osgi.framework.Bundle) class
+     * as the int value assigned to each state as the following: <br>
+     *   -  UNINSTALLED (1) <br>
+     *   -  INSTALLED   (2) <br>
+     *   -  RESOLVED    (4) <br>
+     *   -  STARTING    (8) <br>
+     *   -  STOPPING    (16) <br>
+     *   -  ACTIVE      (32) <br>
+     *
+     * @return AppcOamStates
+     */
+    public AppcOamStates getBundlesState() {
+        BundleHelper bundleHelper = new BundleHelper(logger, configurationHelper, this);
+        Map<String, Bundle> lcmBundleMap = bundleHelper.getAppcLcmBundles();
+        if (lcmBundleMap == null || lcmBundleMap.isEmpty()) {
+            return AppcOamStates.Unknown;
+        }
+
+        // As we are picking up the lowest bundle state as general APP-C state, we will start with ACTIVE
+        int currentState = Bundle.ACTIVE;
+        for (Bundle bundle : lcmBundleMap.values()) {
+            int bundleState = bundle.getState();
+            logger.trace(String.format("getBundlesState: [%s] has state (%d)", bundle.getSymbolicName(), bundleState));
+            if (bundleState < currentState) {
+                currentState = bundleState;
+            }
+        }
+        return AppcOamStates.getOamStateFromBundleState(currentState);
+    }
+
+}
index d84d8ce..03675c8 100644 (file)
@@ -77,6 +77,17 @@ module appc-oam {
                 mandatory true;
             }
 
+            container flags {
+                 leaf request-timeout {
+                     description "The allowed time in seconds to perform the request.  If the request cannot
+                                  be completed in this amount of time, the request is aborted with OAM state set
+                                  to Error.  If set to zero, no timeout exists and the request will be handled
+                                  continue until operation completes or fails.  If omitted, the default value of
+                                  20 is used.";
+                      type uint16;
+                      mandatory false;
+                 }
+            }
         }
     }
 
@@ -103,6 +114,23 @@ module appc-oam {
         }
     }
 
+    typedef appc-state {
+        type enumeration {
+            enum "Error";
+            enum "Unknown";
+            enum "Not_Instantiated"; // Equivalent to Bundle's UNINSTALL
+            enum "Instantiated"; // Equivalent to Bundle's INSTALL
+            enum "Starting";
+            enum "Started";
+            enum "EnteringMaintenanceMode";
+            enum "MaintenanceMode";
+            enum "Stopping";
+            enum "Stopped";
+            enum "Restarting";
+        }
+        description "Refers to the various states an APP-C instance can be in";
+    }
+
     rpc get-metrics {
         description "An operation to get list of registered Metrics in APP-C";
         output {
@@ -135,10 +163,10 @@ module appc-oam {
         }
     }
 
-    rpc stop {
+    rpc maintenance-mode {
         description "An operation that disables appc-provider-lcm so that it no longer accepts LCM request.  This
                          operation has no impact on queued and currently executing LCM request.  A notification will be
-                         sent out indicating the APP-C  is idle once all LCM request have completed execution.  ";
+                         sent out indicating the APP-C is idle once all LCM request have completed execution.";
         input {
            uses common-header;
         }
@@ -149,13 +177,46 @@ module appc-oam {
     }
 
     rpc start {
-        description "An operation that enables appc-provider-lcm so that it can begin to accepts LCM request. ";
+        description "An operation that enables appc-provider-lcm so that it can begin to accepts LCM request. This
+                     includes starting any appc bundles which are stopped.";
         input {
-           uses common-header;
+            uses common-header;
         }
         output {
             uses common-header;
             uses status;
         }
     }
+
+    rpc get-appc-state {
+        description "Returns the current state of the running APPC LCM instance";
+        output {
+            leaf state {
+                 type appc-state;
+            }
+        }
+    }
+
+    rpc stop {
+        description "Force stops the APPC bundles that accept LCM requests";
+        // Note: OAM feature bundles and it's dependencies (Appc-common and LifeCycle Manager) would continue to run
+        input {
+            uses common-header;
+        }
+        output {
+            uses common-header;
+            uses status;
+        }
+    }
+
+     rpc restart {
+         description "An operation that restarts APPC by invoking the stop rpc followed by the start rpc.";
+         input {
+             uses common-header;
+         }
+         output {
+             uses common-header;
+             uses status;
+         }
+     }
 }