Enhancing SO SDC Controller to invoke ONAP-ETSI Catalog APIs

Change-Id: I9f0ba05c14478b9165c2c470559567513e1919cf
Issue-ID: SO-2406
Signed-off-by: waqas.ikram <waqas.ikram@est.tech>
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/ErrorCode.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/ErrorCode.java
new file mode 100644
index 0000000..1714e24
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/ErrorCode.java
@@ -0,0 +1,50 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public enum ErrorCode {
+
+    NORMAL("0"), PACKAGE_EXIST("1"), CATALOG_EXCEPTION("2"), SYSTEM_ERROR("3"), UNKNOWN("-1");
+
+    private String code;
+
+    private ErrorCode(final String code) {
+        this.code = code;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public static ErrorCode getErrorCode(final String code) {
+        for (final ErrorCode errorCode : ErrorCode.values()) {
+            if (errorCode.getCode().equalsIgnoreCase(code)) {
+                return errorCode;
+            }
+
+        }
+        return UNKNOWN;
+    }
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboadingJobStatus.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboadingJobStatus.java
new file mode 100644
index 0000000..772f81a
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboadingJobStatus.java
@@ -0,0 +1,63 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class EtsiCatalogPackageOnboadingJobStatus implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "jobId")
+    private String jobId;
+
+    @XmlElement(name = "responseDescriptor")
+    private EtsiCatalogPackageOnboardingJobDescriptor responseDescriptor;
+
+    public String getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(final String jobId) {
+        this.jobId = jobId;
+    }
+
+    public EtsiCatalogPackageOnboardingJobDescriptor getResponseDescriptor() {
+        return responseDescriptor;
+    }
+
+    public void setResponseDescriptor(final EtsiCatalogPackageOnboardingJobDescriptor responseDescriptor) {
+        this.responseDescriptor = responseDescriptor;
+    }
+
+    @Override
+    public String toString() {
+        return "EtsiCatalogPackageOnboadingJobStatus [jobId=" + jobId + ", responseDescriptor=" + responseDescriptor
+                + "]";
+    }
+
+
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingJob.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingJob.java
new file mode 100644
index 0000000..0c7bba6
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingJob.java
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class EtsiCatalogPackageOnboardingJob implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "jobId")
+    private String jobId;
+
+    public String getJobId() {
+        return jobId;
+    }
+
+    public void setJobId(final String jobId) {
+        this.jobId = jobId;
+    }
+
+    @Override
+    public String toString() {
+        return "EtsiCatalogPackageOnboardingJob [jobId=" + jobId + "]";
+    }
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingJobDescriptor.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingJobDescriptor.java
new file mode 100644
index 0000000..b0c07d6
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingJobDescriptor.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class EtsiCatalogPackageOnboardingJobDescriptor implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "status")
+    private String status;
+
+    @XmlElement(name = "statusDescription")
+    private String statusDescription;
+
+    @XmlElement(name = "errorCode")
+    private String errorCode;
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(final String status) {
+        this.status = status;
+    }
+
+    public String getStatusDescription() {
+        return statusDescription;
+    }
+
+    public void setStatusDescription(final String statusDescription) {
+        this.statusDescription = statusDescription;
+    }
+
+    public String getErrorCode() {
+        return errorCode;
+    }
+
+    public void setErrorCode(final String errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    @Override
+    public String toString() {
+        return "EtsiCatalogPackageOnboardingJobDescriptor [status=" + status + ", statusDescription="
+                + statusDescription + ", errorCode=" + errorCode + "]";
+    }
+
+
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingRequest.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingRequest.java
new file mode 100644
index 0000000..79fd139
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogPackageOnboardingRequest.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class EtsiCatalogPackageOnboardingRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "csarId")
+    private String csarId;
+
+    public EtsiCatalogPackageOnboardingRequest csarId(final String csarId) {
+        this.csarId = csarId;
+        return this;
+    }
+
+    public String getCsarId() {
+        return csarId;
+    }
+
+    public void setCsarId(final String csarId) {
+        this.csarId = csarId;
+    }
+
+    @Override
+    public String toString() {
+        return "EtsiCatalogPackageOnboardingRequest  [csarId=" + csarId + "]";
+    }
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogServiceProvider.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogServiceProvider.java
new file mode 100644
index 0000000..f6a3032
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiCatalogServiceProvider.java
@@ -0,0 +1,112 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import static org.onap.so.asdc.etsi.pkg.processor.HttpRestServiceProviderConfiguration.ETSI_CATALOG_HTTP_REST_SERVICE_PROVIDER_BEAN;
+import org.onap.so.asdc.etsi.pkg.processor.exceptions.EtsiCatalogManagerRequestFailureException;
+import org.onap.so.rest.exceptions.InvalidRestRequestException;
+import org.onap.so.rest.exceptions.RestProcessingException;
+import org.onap.so.rest.service.HttpRestServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Service
+public class EtsiCatalogServiceProvider {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(EtsiCatalogServiceProvider.class);
+
+    private final HttpRestServiceProvider httpServiceProvider;
+
+    @Value("${etsi-catalog-manager.endpoint:http://modeling-etsicatalog.onap:8806/api/catalog/v1}")
+    private String etsiCatalogManagerEndpoint;
+
+    @Autowired
+    public EtsiCatalogServiceProvider(
+            @Qualifier(ETSI_CATALOG_HTTP_REST_SERVICE_PROVIDER_BEAN) final HttpRestServiceProvider httpServiceProvider) {
+        this.httpServiceProvider = httpServiceProvider;
+    }
+
+    public EtsiCatalogPackageOnboardingJob onBoardResource(
+            final EtsiCatalogPackageOnboardingRequest packageOnboardingRequest) {
+        try {
+            final String url = etsiCatalogManagerEndpoint + "/vnfpackages";
+            final ResponseEntity<EtsiCatalogPackageOnboardingJob> responseEntity = httpServiceProvider.postHttpRequest(
+                    packageOnboardingRequest, url, getHeaders(), EtsiCatalogPackageOnboardingJob.class);
+
+            if (responseEntity.getStatusCode().is2xxSuccessful()) {
+                if (responseEntity.hasBody()) {
+                    return responseEntity.getBody();
+                }
+                LOGGER.error("Received response without body");
+            }
+            final String message = "Unexpected status code received " + responseEntity.getStatusCode();
+            LOGGER.error(message);
+            throw new EtsiCatalogManagerRequestFailureException(message);
+
+        } catch (final InvalidRestRequestException | RestProcessingException exception) {
+            final String message = "Unable to process onboarding request";
+            LOGGER.error(message, exception);
+            throw new EtsiCatalogManagerRequestFailureException(message);
+        }
+
+    }
+
+    public EtsiCatalogPackageOnboadingJobStatus getJobStatus(final String jobId) {
+        try {
+            final String url = etsiCatalogManagerEndpoint + "/jobs/" + jobId;
+
+            final ResponseEntity<EtsiCatalogPackageOnboadingJobStatus> responseEntity =
+                    httpServiceProvider.getHttpResponse(url, getHeaders(), EtsiCatalogPackageOnboadingJobStatus.class);
+
+            if (responseEntity.getStatusCode().is2xxSuccessful()) {
+                if (responseEntity.hasBody()) {
+                    return responseEntity.getBody();
+                }
+                LOGGER.error("Received response without body");
+            }
+            final String message =
+                    "Unexpected status code received while getting job status " + responseEntity.getStatusCode();
+            LOGGER.error(message);
+            throw new EtsiCatalogManagerRequestFailureException(message);
+        } catch (final InvalidRestRequestException | RestProcessingException exception) {
+            final String message = "Unable to get job status";
+            LOGGER.error(message, exception);
+            throw new EtsiCatalogManagerRequestFailureException(message);
+        }
+
+    }
+
+    private HttpHeaders getHeaders() {
+        final HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        return headers;
+    }
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiResourcePackageProcessor.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiResourcePackageProcessor.java
new file mode 100644
index 0000000..bb7197b
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/EtsiResourcePackageProcessor.java
@@ -0,0 +1,175 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import org.onap.so.asdc.etsi.pkg.processor.exceptions.SOL004ResourcePackageFailureException;
+import org.onap.so.asdc.etsi.pkg.processor.exceptions.SOL004ResourcePackageProcessingException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import com.google.common.collect.ImmutableSet;
+
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Service
+public class EtsiResourcePackageProcessor {
+
+    private final static Logger LOGGER = LoggerFactory.getLogger(EtsiResourcePackageProcessor.class);
+    private static final String ONBOARDED_PACKAGE_DIR_PATH = "Artifacts/Deployment/ONBOARDED_PACKAGE";
+    private final SdcResourceProvider sdcResourceProvider;
+    private final EtsiCatalogServiceProvider catalogServiceProvider;
+    private static final int SLEEP_TIME_IN_SECONDS = 5;
+
+    private static final ImmutableSet<JobStatus> JOB_FINISHED_STATES =
+            ImmutableSet.of(JobStatus.FINISHED, JobStatus.ERROR, JobStatus.TIMEOUT);
+
+    @Value("${etsi-catalog-manager.rest.timeoutInSeconds:300}")
+    private int timeOutInSeconds;
+
+    @Autowired
+    public EtsiResourcePackageProcessor(final SdcResourceProvider sdcResourceProvider,
+            final EtsiCatalogServiceProvider catalogServiceProvider) {
+        this.sdcResourceProvider = sdcResourceProvider;
+        this.catalogServiceProvider = catalogServiceProvider;
+    }
+
+    public void processPackageIfExists(final String vnfUuid) {
+        LOGGER.debug("Processing vnf with UUID: {} ", vnfUuid);
+        try {
+            final Optional<byte[]> optional = sdcResourceProvider.getVnfResource(vnfUuid);
+            if (optional.isPresent()) {
+                final byte[] resourceContent = optional.get();
+
+                if (containsOnBoardedSol004Package(resourceContent)) {
+                    final EtsiCatalogPackageOnboardingJob onboardingJob = catalogServiceProvider
+                            .onBoardResource(new EtsiCatalogPackageOnboardingRequest().csarId(vnfUuid));
+                    LOGGER.debug("Successfully created job with id: {} to onboard vnf with UUID: {}",
+                            onboardingJob.getJobId(), vnfUuid);
+
+                    if (onboardingJob.getJobId() == null) {
+                        throw new SOL004ResourcePackageFailureException(
+                                "Received invalid jobId " + onboardingJob.getJobId());
+                    }
+
+                    final Optional<EtsiCatalogPackageOnboadingJobStatus> jobStatusOptional =
+                            waitForJobToFinish(onboardingJob);
+
+                    if (!jobStatusOptional.isPresent()) {
+                        final String message = "Job status timeout reached failed to onboard vnf with UUID: " + vnfUuid;
+                        LOGGER.debug(message, vnfUuid);
+                        throw new SOL004ResourcePackageFailureException(message);
+                    }
+
+                    final EtsiCatalogPackageOnboadingJobStatus onboadingJobStatus = jobStatusOptional.get();
+                    final JobStatus jobStatus = getJobStatus(onboadingJobStatus);
+                    final ErrorCode errorCode = getErrorCode(onboadingJobStatus);
+
+                    LOGGER.debug("Final job status: {}, error code: {}", jobStatus, errorCode);
+                    if (!JobStatus.FINISHED.equals(jobStatus) && !ErrorCode.PACKAGE_EXIST.equals(errorCode)) {
+                        final String message = "Failed to onboard vnf with UUID: " + vnfUuid + " job status: "
+                                + jobStatus + " errorCode: " + errorCode;
+                        LOGGER.debug(message, vnfUuid);
+                        throw new SOL004ResourcePackageFailureException(message);
+                    }
+                    LOGGER.debug("Successfully onboarded package in ETSI catalog .. ");
+                }
+
+            }
+        } catch (final Exception exception) {
+            final String message = "Unable to process resource received from SDC";
+            LOGGER.error(message, exception);
+            throw new SOL004ResourcePackageProcessingException(message, exception);
+        }
+
+    }
+
+    private Optional<EtsiCatalogPackageOnboadingJobStatus> waitForJobToFinish(
+            final EtsiCatalogPackageOnboardingJob onboardingJob) throws InterruptedException {
+        JobStatus currentJobStatus = null;
+        final long startTimeInMillis = System.currentTimeMillis();
+        final long timeOutTime = startTimeInMillis + TimeUnit.SECONDS.toMillis(timeOutInSeconds);
+
+        LOGGER.debug("Will wait till {} for {} job to finish", Instant.ofEpochMilli(timeOutTime).toString(),
+                onboardingJob.getJobId());
+
+        while (timeOutTime > System.currentTimeMillis()) {
+
+            final EtsiCatalogPackageOnboadingJobStatus onboadingJobStatus =
+                    catalogServiceProvider.getJobStatus(onboardingJob.getJobId());
+            LOGGER.debug("Current job status {} ", onboadingJobStatus);
+
+            currentJobStatus = getJobStatus(onboadingJobStatus);
+            if (JOB_FINISHED_STATES.contains(currentJobStatus)) {
+                return Optional.of(onboadingJobStatus);
+            }
+
+            LOGGER.debug("Onboarding not finished yet, will try again in {} seconds", SLEEP_TIME_IN_SECONDS);
+            TimeUnit.SECONDS.sleep(SLEEP_TIME_IN_SECONDS);
+
+        }
+        LOGGER.warn("Timeout current job status: {}", currentJobStatus);
+        return Optional.empty();
+    }
+
+    private boolean containsOnBoardedSol004Package(final byte[] resourceContent) throws IOException {
+        try (final ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(resourceContent))) {
+            ZipEntry entry;
+            while ((entry = zipStream.getNextEntry()) != null) {
+                if (entry.getName() != null && entry.getName().contains(ONBOARDED_PACKAGE_DIR_PATH)) {
+                    LOGGER.debug("Found entry: {} that contains {} in name", entry.getName(),
+                            ONBOARDED_PACKAGE_DIR_PATH);
+                    return true;
+                }
+            }
+
+        }
+        LOGGER.debug("Unable to find {} dir in downloaded package", ONBOARDED_PACKAGE_DIR_PATH);
+        return false;
+    }
+
+    private JobStatus getJobStatus(final EtsiCatalogPackageOnboadingJobStatus onboadingJobStatus) {
+        if (onboadingJobStatus.getResponseDescriptor() != null) {
+            return JobStatus.getJobStatus(onboadingJobStatus.getResponseDescriptor().getStatus());
+        }
+        LOGGER.warn("Found null ResponseDescriptor {}", onboadingJobStatus);
+        return JobStatus.UNKNOWN;
+    }
+
+    private ErrorCode getErrorCode(final EtsiCatalogPackageOnboadingJobStatus onboadingJobStatus) {
+        if (onboadingJobStatus.getResponseDescriptor() != null) {
+            return ErrorCode.getErrorCode(onboadingJobStatus.getResponseDescriptor().getErrorCode());
+        }
+        LOGGER.warn("Found null ResponseDescriptor {}", onboadingJobStatus);
+        return ErrorCode.UNKNOWN;
+    }
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/HttpRestServiceProviderConfiguration.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/HttpRestServiceProviderConfiguration.java
new file mode 100644
index 0000000..1afda0d
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/HttpRestServiceProviderConfiguration.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import static org.onap.so.asdc.etsi.pkg.processor.SslBasedHttpClientConfiguration.SSL_BASED_CONFIGURABLE_REST_TEMPLATE;
+import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE;
+import org.onap.so.rest.service.HttpRestServiceProvider;
+import org.onap.so.rest.service.HttpRestServiceProviderImpl;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Configuration
+public class HttpRestServiceProviderConfiguration {
+
+    public static final String ETSI_CATALOG_HTTP_REST_SERVICE_PROVIDER_BEAN = "etsiCatalogHttpRestServiceProviderBean";
+    public static final String SDC_HTTP_REST_SERVICE_PROVIDER_BEAN = "sdcHttpRestServiceProviderBean";
+
+    @Bean
+    @Qualifier(ETSI_CATALOG_HTTP_REST_SERVICE_PROVIDER_BEAN)
+    public HttpRestServiceProvider etsiCataloghttpRestServiceProvider(
+            @Qualifier(CONFIGURABLE_REST_TEMPLATE) final RestTemplate restTemplate) {
+        return new HttpRestServiceProviderImpl(restTemplate);
+    }
+
+    @Bean
+    @Qualifier(SDC_HTTP_REST_SERVICE_PROVIDER_BEAN)
+    public HttpRestServiceProvider sdchttpRestServiceProvider(
+            @Qualifier(SSL_BASED_CONFIGURABLE_REST_TEMPLATE) final RestTemplate restTemplate) {
+        return new HttpRestServiceProviderImpl(restTemplate);
+    }
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/JobStatus.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/JobStatus.java
new file mode 100644
index 0000000..cf09b15
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/JobStatus.java
@@ -0,0 +1,60 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public enum JobStatus {
+
+    STARTED("started"),
+    TIMEOUT("timeout"),
+    FINISHED("finished"),
+    PARTLY_FINISHED("partly_finished"),
+    PROCESSING("processing"),
+    ERROR("error"),
+    UNKNOWN("unknown");
+
+    private String value;
+
+    private JobStatus(final String value) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return this.value;
+    }
+
+    public static JobStatus getJobStatus(final String jobStatus) {
+        for (final JobStatus status : JobStatus.values()) {
+            if (status.getValue().equalsIgnoreCase(jobStatus)) {
+                return status;
+            }
+        }
+        return JobStatus.UNKNOWN;
+    }
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SdcBasicHttpConfigurationProvider.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SdcBasicHttpConfigurationProvider.java
new file mode 100644
index 0000000..19375e2
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SdcBasicHttpConfigurationProvider.java
@@ -0,0 +1,60 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import org.apache.commons.codec.binary.Base64;
+import org.onap.so.utils.CryptoUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Configuration
+public class SdcBasicHttpConfigurationProvider {
+
+    @Value("${sdc.endpoint:https://sdc-be.onap:8443}")
+    private String endPoint;
+
+    @Value("${sdc.username:mso}")
+    private String username;
+
+    @Value(value = "${sdc.password:76966BDD3C7414A03F7037264FF2E6C8EEC6C28F2B67F2840A1ED857C0260FEE731D73F47F828E5527125D29FD25D3E0DE39EE44C058906BF1657DE77BF897EECA93BDC07FA64F}")
+    private String password;
+
+    @Value(value = "${sdc.key:566B754875657232314F5548556D3665}")
+    private String key;
+
+
+    public String getBasicAuthorization() throws GeneralSecurityException {
+        final String auth = username + ":" + CryptoUtils.decrypt(password, key);
+        final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
+        return "Basic " + new String(encodedAuth);
+    }
+
+    public String getEndPoint() {
+        return endPoint;
+    }
+
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SdcResourceProvider.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SdcResourceProvider.java
new file mode 100644
index 0000000..0cd0aba
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SdcResourceProvider.java
@@ -0,0 +1,96 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import static org.onap.so.asdc.etsi.pkg.processor.HttpRestServiceProviderConfiguration.SDC_HTTP_REST_SERVICE_PROVIDER_BEAN;
+import static org.springframework.http.HttpHeaders.ACCEPT;
+import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
+import java.security.GeneralSecurityException;
+import java.util.Optional;
+import org.onap.so.rest.service.HttpRestServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Service
+public class SdcResourceProvider {
+    private final static Logger LOGGER = LoggerFactory.getLogger(SdcResourceProvider.class);
+
+    private static final String SERVICE_NAME = "SO-SDC-CONTROLLER";
+
+    private final HttpRestServiceProvider httpRestServiceProvider;
+
+    private final SdcBasicHttpConfigurationProvider sdcBasicHttpConfigurationProvider;
+
+    @Autowired
+    public SdcResourceProvider(
+            @Qualifier(SDC_HTTP_REST_SERVICE_PROVIDER_BEAN) final HttpRestServiceProvider httpRestServiceProvider,
+            final SdcBasicHttpConfigurationProvider sdcBasicHttpConfigurationProvider) {
+        this.httpRestServiceProvider = httpRestServiceProvider;
+        this.sdcBasicHttpConfigurationProvider = sdcBasicHttpConfigurationProvider;
+    }
+
+    public Optional<byte[]> getVnfResource(final String resourceId) {
+        LOGGER.debug("Will get resource from SDC using resource id: {}", resourceId);
+        try {
+            final HttpHeaders headers = getHttpHeaders();
+            headers.add(ACCEPT, APPLICATION_OCTET_STREAM_VALUE);
+            final String url = getSdcResourceEndPoint(resourceId);
+            LOGGER.debug("will invoke url: {} to get resource ", url);
+            final ResponseEntity<byte[]> responseEntity =
+                    httpRestServiceProvider.getHttpResponse(url, headers, byte[].class);
+
+            if (responseEntity.getStatusCode().is2xxSuccessful()) {
+                if (responseEntity.hasBody()) {
+                    return Optional.of(responseEntity.getBody());
+                }
+                LOGGER.error("Received response without body");
+            }
+            LOGGER.error("Unexpected Status code received : {}", responseEntity.getStatusCode());
+            return Optional.empty();
+        } catch (final Exception exception) {
+            LOGGER.error("Unable to get {} resource from SDC", resourceId, exception);
+            return Optional.empty();
+        }
+    }
+
+    private String getSdcResourceEndPoint(final String resourceId) {
+        return sdcBasicHttpConfigurationProvider.getEndPoint() + "/sdc/v1/catalog/resources/" + resourceId
+                + "/toscaModel";
+    }
+
+
+    private HttpHeaders getHttpHeaders() throws GeneralSecurityException {
+        final HttpHeaders headers = new HttpHeaders();
+        headers.add(HttpHeaders.AUTHORIZATION, sdcBasicHttpConfigurationProvider.getBasicAuthorization());
+        headers.add("X-ECOMP-InstanceID", SERVICE_NAME);
+        headers.add("X-FromAppId", SERVICE_NAME);
+        return headers;
+    }
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SslBasedHttpClientConfiguration.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SslBasedHttpClientConfiguration.java
new file mode 100644
index 0000000..88c2152
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/SslBasedHttpClientConfiguration.java
@@ -0,0 +1,93 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.SSLContext;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.onap.logging.filter.spring.SpringClientPayloadFilter;
+import org.onap.so.configuration.rest.HttpClientConnectionConfiguration;
+import org.onap.so.logging.jaxrs.filter.SOSpringClientFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.BufferingClientHttpRequestFactory;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Configuration
+public class SslBasedHttpClientConfiguration {
+    private final static Logger LOGGER = LoggerFactory.getLogger(EtsiResourcePackageProcessor.class);
+
+
+    public static final String SSL_BASED_CONFIGURABLE_REST_TEMPLATE = "sslBasedConfigurableRestTemplate";
+    private final HttpClientConnectionConfiguration clientConnectionConfiguration;
+
+    @Autowired
+    public SslBasedHttpClientConfiguration(final HttpClientConnectionConfiguration clientConnectionConfiguration) {
+        this.clientConnectionConfiguration = clientConnectionConfiguration;
+    }
+
+    @Bean
+    @Qualifier(SSL_BASED_CONFIGURABLE_REST_TEMPLATE)
+    public RestTemplate sslBasedConfigurableRestTemplate() {
+        final RestTemplate restTemplate =
+                new RestTemplate(new BufferingClientHttpRequestFactory(httpComponentsClientHttpRequestFactory()));
+        restTemplate.getInterceptors().add(new SOSpringClientFilter());
+        restTemplate.getInterceptors().add((new SpringClientPayloadFilter()));
+        return restTemplate;
+    }
+
+    private HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() {
+        try {
+            LOGGER.debug("Setting up HttpComponentsClientHttpRequestFactory with default SSL Context");
+            return new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create()
+                    .setConnectionManager(getConnectionManager())
+                    .setMaxConnPerRoute(clientConnectionConfiguration.getMaxConnectionsPerRoute())
+                    .setMaxConnTotal(clientConnectionConfiguration.getMaxConnections())
+                    .setDefaultRequestConfig(getRequestConfig()).setSSLContext(SSLContext.getDefault()).build());
+
+        } catch (final NoSuchAlgorithmException exception) {
+            LOGGER.error("Failed to create HttpComponentsClientHttpRequestFactory with default SSL Context", exception);
+            throw new RuntimeException(exception);
+        }
+    }
+
+    private PoolingHttpClientConnectionManager getConnectionManager() {
+        return new PoolingHttpClientConnectionManager(clientConnectionConfiguration.getTimeToLiveInMins(),
+                TimeUnit.MINUTES);
+    }
+
+    private RequestConfig getRequestConfig() {
+        return RequestConfig.custom().setSocketTimeout(clientConnectionConfiguration.getSocketTimeOutInMiliSeconds())
+                .setConnectTimeout(clientConnectionConfiguration.getConnectionTimeOutInMilliSeconds()).build();
+    }
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/EtsiCatalogManagerRequestFailureException.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/EtsiCatalogManagerRequestFailureException.java
new file mode 100644
index 0000000..4f2e503
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/EtsiCatalogManagerRequestFailureException.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor.exceptions;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class EtsiCatalogManagerRequestFailureException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public EtsiCatalogManagerRequestFailureException(final String message) {
+        super(message);
+    }
+
+    @Override
+    public synchronized Throwable fillInStackTrace() {
+        return this;
+    }
+
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/SOL004ResourcePackageFailureException.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/SOL004ResourcePackageFailureException.java
new file mode 100644
index 0000000..8e05a50
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/SOL004ResourcePackageFailureException.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor.exceptions;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class SOL004ResourcePackageFailureException extends RuntimeException {
+
+    private static final long serialVersionUID = 5834657185124807797L;
+
+    public SOL004ResourcePackageFailureException(final String message) {
+        super(message);
+
+    }
+
+    @Override
+    public synchronized Throwable fillInStackTrace() {
+        return this;
+    }
+
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/SOL004ResourcePackageProcessingException.java b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/SOL004ResourcePackageProcessingException.java
new file mode 100644
index 0000000..0e9f1ea
--- /dev/null
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/etsi/pkg/processor/exceptions/SOL004ResourcePackageProcessingException.java
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.etsi.pkg.processor.exceptions;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class SOL004ResourcePackageProcessingException extends RuntimeException {
+
+    private static final long serialVersionUID = 4860501744379116092L;
+
+    public SOL004ResourcePackageProcessingException(final String message, final Throwable cause) {
+        super(message, cause);
+
+    }
+}
diff --git a/asdc-controller/src/main/java/org/onap/so/asdc/installer/heat/ToscaResourceInstaller.java b/asdc-controller/src/main/java/org/onap/so/asdc/installer/heat/ToscaResourceInstaller.java
index 240bb83..263118d 100644
--- a/asdc-controller/src/main/java/org/onap/so/asdc/installer/heat/ToscaResourceInstaller.java
+++ b/asdc-controller/src/main/java/org/onap/so/asdc/installer/heat/ToscaResourceInstaller.java
@@ -39,7 +39,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import org.onap.so.logger.LoggingAnchor;
 import org.hibernate.exception.ConstraintViolationException;
 import org.hibernate.exception.LockAcquisitionException;
 import org.onap.sdc.api.notification.IArtifactInfo;
@@ -63,6 +62,7 @@
 import org.onap.sdc.utils.DistributionStatusEnum;
 import org.onap.so.asdc.client.ASDCConfiguration;
 import org.onap.so.asdc.client.exceptions.ArtifactInstallerException;
+import org.onap.so.asdc.etsi.pkg.processor.EtsiResourcePackageProcessor;
 import org.onap.so.asdc.installer.ASDCElementInfo;
 import org.onap.so.asdc.installer.BigDecimalVersion;
 import org.onap.so.asdc.installer.IVfModuleData;
@@ -113,7 +113,6 @@
 import org.onap.so.db.catalog.data.repository.CollectionResourceRepository;
 import org.onap.so.db.catalog.data.repository.ConfigurationResourceCustomizationRepository;
 import org.onap.so.db.catalog.data.repository.ConfigurationResourceRepository;
-import org.onap.so.db.catalog.data.repository.CvnfcConfigurationCustomizationRepository;
 import org.onap.so.db.catalog.data.repository.CvnfcCustomizationRepository;
 import org.onap.so.db.catalog.data.repository.ExternalServiceToInternalServiceRepository;
 import org.onap.so.db.catalog.data.repository.HeatEnvironmentRepository;
@@ -140,6 +139,7 @@
 import org.onap.so.db.request.data.repository.WatchdogDistributionStatusRepository;
 import org.onap.so.db.request.data.repository.WatchdogServiceModVerIdLookupRepository;
 import org.onap.so.logger.ErrorCode;
+import org.onap.so.logger.LoggingAnchor;
 import org.onap.so.logger.MessageEnum;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -147,9 +147,9 @@
 import org.springframework.orm.ObjectOptimisticLockingFailureException;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.springframework.util.CollectionUtils;
 
 @Component
 public class ToscaResourceInstaller {
@@ -273,6 +273,9 @@
     @Autowired
     protected WorkflowResource workflowResource;
 
+    @Autowired
+    protected EtsiResourcePackageProcessor etsiResourcePackageProcessor;
+
     protected static final Logger logger = LoggerFactory.getLogger(ToscaResourceInstaller.class);
 
     public boolean isCsarAlreadyDeployed(ToscaResourceStructure toscaResourceStructure)
@@ -456,6 +459,8 @@
                 if (ALLOTTED_RESOURCE.equalsIgnoreCase(category)) {
                     arEntityDetails.add(vfEntityDetails);
                 }
+                final String vnfUuid = metadata.getValue(SdcPropertyNames.PROPERTY_NAME_UUID);
+                etsiResourcePackageProcessor.processPackageIfExists(vnfUuid);
 
                 processVfModules(vfEntityDetails, toscaResourceStruct, vfResourceStructure, service, metadata);
             }
diff --git a/asdc-controller/src/test/java/org/onap/so/asdc/TestApplication.java b/asdc-controller/src/test/java/org/onap/so/asdc/TestApplication.java
index e25de9c..1a2e385 100644
--- a/asdc-controller/src/test/java/org/onap/so/asdc/TestApplication.java
+++ b/asdc-controller/src/test/java/org/onap/so/asdc/TestApplication.java
@@ -31,12 +31,14 @@
 
 @SpringBootApplication
 @Profile("test")
-@ComponentScan(basePackages = {"org.onap.so.asdc", "org.onap.so.security"},
+@ComponentScan(
+        basePackages = {"org.onap.so.asdc", "org.onap.so.security", "org.onap.so.rest.service",
+                "org.onap.so.configuration.rest", "org.onap.so.client"},
         excludeFilters = {@Filter(type = FilterType.ANNOTATION, classes = SpringBootApplication.class),
                 @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = RequestsDBHelper.class),
                 @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = InfraActiveRequestsRepositoryImpl.class)})
 public class TestApplication {
-    public static void main(String... args) {
+    public static void main(final String... args) {
         SpringApplication.run(TestApplication.class, args);
         System.getProperties().setProperty("mso.db", "MARIADB");
         System.getProperties().setProperty("server.name", "Springboot");
diff --git a/asdc-controller/src/test/java/org/onap/so/asdc/client/SdcNotificationWithSol004PackageTest.java b/asdc-controller/src/test/java/org/onap/so/asdc/client/SdcNotificationWithSol004PackageTest.java
new file mode 100644
index 0000000..cb5bd0f
--- /dev/null
+++ b/asdc-controller/src/test/java/org/onap/so/asdc/client/SdcNotificationWithSol004PackageTest.java
@@ -0,0 +1,358 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Ericsson. All rights reserved.
+ * ================================================================================
+ * 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.
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.asdc.client;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.ok;
+import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.onap.sdc.utils.DistributionStatusEnum.COMPONENT_DONE_ERROR;
+import static org.onap.sdc.utils.DistributionStatusEnum.COMPONENT_DONE_OK;
+import static org.springframework.http.HttpHeaders.ACCEPT;
+import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.so.asdc.BaseTest;
+import org.onap.so.asdc.client.exceptions.ASDCControllerException;
+import org.onap.so.asdc.client.test.emulators.DistributionClientEmulator;
+import org.onap.so.asdc.client.test.emulators.NotificationDataImpl;
+import org.onap.so.db.catalog.data.repository.ServiceRepository;
+import org.onap.so.db.request.beans.WatchdogComponentDistributionStatus;
+import org.onap.so.db.request.beans.WatchdogComponentDistributionStatusId;
+import org.onap.so.db.request.data.repository.WatchdogComponentDistributionStatusRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import com.google.gson.GsonBuilder;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class SdcNotificationWithSol004PackageTest extends BaseTest {
+
+    private final static Logger LOGGER = LoggerFactory.getLogger(SdcNotificationWithSol004PackageTest.class);
+    private static final String ETSI_CATALOG_PACKAGE_ONBOARDING_URL = "/api/catalog/v1/vnfpackages";
+    private static final String COMPONENT_NAME = "SO";
+    private static final String CSAR_ID = "8f0b72e1-b6d6-42b6-a808-c60b17f04d7a";
+    private static final String SDC_GET_RESOURCE_URL = "/sdc/v1/catalog/resources/" + CSAR_ID + "/toscaModel";
+    private static final String ETSI_CATALOG_PACKAGE_ONBOARDING_REQUEST = "{\"csarId\": \"" + CSAR_ID + "\"}";
+    private static final String DISTRIBUTION_ID = "35f20eb9-238a-4cc2-96dc-0a08f71bc209";
+    private static final String VGW_RESOURCE_PATH = "src/test/resources/resource-examples/vgw";
+    private static final String SERVICE_UUID = "e051ff77-fb79-451c-8457-1cbf94e4db8f";
+    private static final String SERVICE_INVARIANT_UUID = "c2ce924f-0aa1-4777-9b42-c0fec006a883";
+    private static final String JOB_ID = "57c13120-0a03-4d2e-837a-7c41d61e4a30";
+    private static final String ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL = "/api/catalog/v1/jobs/" + JOB_ID;
+    private static final String ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_RESPONSE = "{\"jobId\": \"" + JOB_ID + "\"}";
+
+    @Autowired
+    private ASDCController asdcController;
+
+    private DistributionClientEmulator distributionClient;
+
+    @Autowired
+    private WatchdogComponentDistributionStatusRepository watchdogComponentDistributionStatusRepository;
+
+    @Autowired
+    protected ServiceRepository serviceRepository;
+
+    @Before
+    public void setUp() {
+        distributionClient = new DistributionClientEmulator();
+        distributionClient.setResourcePath(getAbsolutePath(VGW_RESOURCE_PATH));
+        asdcController.setDistributionClient(distributionClient);
+        try {
+            asdcController.initASDC();
+        } catch (final ASDCControllerException controllerException) {
+            LOGGER.error(controllerException.getMessage(), controllerException);
+            fail(controllerException.getMessage());
+        }
+    }
+
+    @After
+    public void shutDown() {
+        try {
+            if (serviceRepository.existsById(SERVICE_UUID)) {
+                LOGGER.debug("Deleting existing service using {} ", SERVICE_UUID);
+                serviceRepository.deleteById(SERVICE_UUID);
+            }
+
+            final WatchdogComponentDistributionStatusId distributionId = new WatchdogComponentDistributionStatusId();
+            distributionId.setDistributionId(DISTRIBUTION_ID);
+            distributionId.setComponentName(COMPONENT_NAME);
+            if (watchdogComponentDistributionStatusRepository.existsById(distributionId)) {
+                LOGGER.debug("Deleting existing WatchdogComponentDistributionStatus using {} ", distributionId);
+                watchdogComponentDistributionStatusRepository.deleteById(distributionId);
+            }
+            asdcController.closeASDC();
+        } catch (final ASDCControllerException asdcControllerException) {
+            LOGGER.error(asdcControllerException.getMessage(), asdcControllerException);
+            fail(asdcControllerException.getMessage());
+        }
+    }
+
+    @Test
+    public void testTreatNotification_vgwServiceContainingSol004Package_successfullyOnboard() throws IOException {
+        initMockAaiServer(SERVICE_UUID, SERVICE_INVARIANT_UUID);
+
+        wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL)
+                .willReturn(aResponse().withBody(getFileContent(
+                        Paths.get(getAbsolutePath(VGW_RESOURCE_PATH), "SDC_RESOURCE_CSAR", "vgw_sdc_resource.csar"))))
+                .withHeader(ACCEPT, equalTo(APPLICATION_OCTET_STREAM_VALUE)));
+
+        wireMockServer.stubFor(post(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .willReturn(okJson(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_RESPONSE)));
+
+        wireMockServer.stubFor(get(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL))
+                .willReturn(okJson(new String(getFileContent(Paths.get(getAbsolutePath(VGW_RESOURCE_PATH),
+                        "etsi-catalog-package-onboading-job-status-successful.json"))))));
+
+        asdcController.treatNotification(getNotificationDataImplObject());
+
+        final List<WatchdogComponentDistributionStatus> distributionList =
+                watchdogComponentDistributionStatusRepository.findByDistributionId(DISTRIBUTION_ID);
+        assertNotNull(distributionList);
+        assertEquals(1, distributionList.size());
+        final WatchdogComponentDistributionStatus distributionStatus = distributionList.get(0);
+        assertEquals(COMPONENT_DONE_OK.toString(), distributionStatus.getComponentDistributionStatus());
+        assertEquals(COMPONENT_NAME, distributionStatus.getComponentName());
+
+        verify(postRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .withRequestBody(equalToJson(ETSI_CATALOG_PACKAGE_ONBOARDING_REQUEST)));
+
+        verify(getRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL)));
+    }
+
+    @Test
+    public void testTreatNotification_vgwServiceUnableToGeSdcResource_successfullyOnboard() throws IOException {
+        initMockAaiServer(SERVICE_UUID, SERVICE_INVARIANT_UUID);
+
+        wireMockServer
+                .stubFor(get(SDC_GET_RESOURCE_URL).willReturn(aResponse().withStatus(HttpStatus.NOT_FOUND.value()))
+                        .withHeader(ACCEPT, equalTo(APPLICATION_OCTET_STREAM_VALUE)));
+
+        asdcController.treatNotification(getNotificationDataImplObject());
+
+        final List<WatchdogComponentDistributionStatus> distributionList =
+                watchdogComponentDistributionStatusRepository.findByDistributionId(DISTRIBUTION_ID);
+        assertNotNull(distributionList);
+        assertEquals(1, distributionList.size());
+        final WatchdogComponentDistributionStatus distributionStatus = distributionList.get(0);
+        assertEquals(COMPONENT_DONE_OK.toString(), distributionStatus.getComponentDistributionStatus());
+        assertEquals(COMPONENT_NAME, distributionStatus.getComponentName());
+    }
+
+    @Test
+    public void testTreatNotification_vgwServiceContainingNonEtsiSdcResource_successfullyOnboard() throws IOException {
+
+        initMockAaiServer(SERVICE_UUID, SERVICE_INVARIANT_UUID);
+
+        wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL)
+                .willReturn(aResponse().withBody(getFileContent(
+                        Paths.get(getAbsolutePath(VGW_RESOURCE_PATH), "service-Vgwservicev1-csar.csar"))))
+                .withHeader(ACCEPT, equalTo(APPLICATION_OCTET_STREAM_VALUE)));
+
+        asdcController.treatNotification(getNotificationDataImplObject());
+
+        final List<WatchdogComponentDistributionStatus> distributionList =
+                watchdogComponentDistributionStatusRepository.findByDistributionId(DISTRIBUTION_ID);
+        assertNotNull(distributionList);
+        assertEquals(1, distributionList.size());
+        final WatchdogComponentDistributionStatus distributionStatus = distributionList.get(0);
+        assertEquals(COMPONENT_DONE_OK.toString(), distributionStatus.getComponentDistributionStatus());
+        assertEquals(COMPONENT_NAME, distributionStatus.getComponentName());
+
+    }
+
+    @Test
+    public void testTreatNotification_vgwServiceContainingSol004Package_onnboardRequestToEtsiCatalogReturnsBadGatway_distributionStatusError()
+            throws IOException {
+        initMockAaiServer(SERVICE_UUID, SERVICE_INVARIANT_UUID);
+
+        wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL)
+                .willReturn(aResponse().withBody(getFileContent(
+                        Paths.get(getAbsolutePath(VGW_RESOURCE_PATH), "SDC_RESOURCE_CSAR", "vgw_sdc_resource.csar"))))
+                .withHeader(ACCEPT, equalTo(APPLICATION_OCTET_STREAM_VALUE)));
+
+        wireMockServer.stubFor(post(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .willReturn(aResponse().withStatus(HttpStatus.BAD_GATEWAY.value())));
+
+        asdcController.treatNotification(getNotificationDataImplObject());
+
+        final List<WatchdogComponentDistributionStatus> distributionList =
+                watchdogComponentDistributionStatusRepository.findByDistributionId(DISTRIBUTION_ID);
+        assertNotNull(distributionList);
+        assertEquals(1, distributionList.size());
+        final WatchdogComponentDistributionStatus distributionStatus = distributionList.get(0);
+        assertEquals(COMPONENT_DONE_ERROR.toString(), distributionStatus.getComponentDistributionStatus());
+        assertEquals(COMPONENT_NAME, distributionStatus.getComponentName());
+
+        verify(postRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .withRequestBody(equalToJson(ETSI_CATALOG_PACKAGE_ONBOARDING_REQUEST)));
+
+    }
+
+    @Test
+    public void testTreatNotification_vgwServiceContainingSol004Package_getJobStatusReturnsBadGatway_distributionStatusError()
+            throws IOException {
+        initMockAaiServer(SERVICE_UUID, SERVICE_INVARIANT_UUID);
+
+        wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL)
+                .willReturn(aResponse().withBody(getFileContent(
+                        Paths.get(getAbsolutePath(VGW_RESOURCE_PATH), "SDC_RESOURCE_CSAR", "vgw_sdc_resource.csar"))))
+                .withHeader(ACCEPT, equalTo(APPLICATION_OCTET_STREAM_VALUE)));
+
+        wireMockServer.stubFor(post(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .willReturn(okJson(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_RESPONSE)));
+
+        wireMockServer.stubFor(get(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL))
+                .willReturn(aResponse().withStatus(HttpStatus.BAD_GATEWAY.value())));
+
+        asdcController.treatNotification(getNotificationDataImplObject());
+
+        final List<WatchdogComponentDistributionStatus> distributionList =
+                watchdogComponentDistributionStatusRepository.findByDistributionId(DISTRIBUTION_ID);
+        assertNotNull(distributionList);
+        assertEquals(1, distributionList.size());
+        final WatchdogComponentDistributionStatus distributionStatus = distributionList.get(0);
+        assertEquals(COMPONENT_DONE_ERROR.toString(), distributionStatus.getComponentDistributionStatus());
+        assertEquals(COMPONENT_NAME, distributionStatus.getComponentName());
+
+        verify(postRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .withRequestBody(equalToJson(ETSI_CATALOG_PACKAGE_ONBOARDING_REQUEST)));
+
+        verify(getRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL)));
+
+    }
+
+    @Test
+    public void testTreatNotification_vgwServiceContainingSol004Package_getJobStatusBodyWithStatusError_distributionStatusError()
+            throws IOException {
+
+        initMockAaiServer(SERVICE_UUID, SERVICE_INVARIANT_UUID);
+
+        wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL)
+                .willReturn(aResponse().withBody(getFileContent(
+                        Paths.get(getAbsolutePath(VGW_RESOURCE_PATH), "SDC_RESOURCE_CSAR", "vgw_sdc_resource.csar"))))
+                .withHeader(ACCEPT, equalTo(APPLICATION_OCTET_STREAM_VALUE)));
+
+        wireMockServer.stubFor(post(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .willReturn(okJson(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_RESPONSE)));
+
+        wireMockServer.stubFor(get(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL))
+                .willReturn(okJson(new String(getFileContent(Paths.get(getAbsolutePath(VGW_RESOURCE_PATH),
+                        "etsi-catalog-package-onboading-job-status-error.json"))))));
+
+        asdcController.treatNotification(getNotificationDataImplObject());
+
+        final List<WatchdogComponentDistributionStatus> distributionList =
+                watchdogComponentDistributionStatusRepository.findByDistributionId(DISTRIBUTION_ID);
+        assertNotNull(distributionList);
+        assertEquals(1, distributionList.size());
+        final WatchdogComponentDistributionStatus distributionStatus = distributionList.get(0);
+        assertEquals(COMPONENT_DONE_ERROR.toString(), distributionStatus.getComponentDistributionStatus());
+        assertEquals(COMPONENT_NAME, distributionStatus.getComponentName());
+
+        verify(postRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .withRequestBody(equalToJson(ETSI_CATALOG_PACKAGE_ONBOARDING_REQUEST)));
+
+        verify(getRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL)));
+
+
+    }
+
+    @Test
+    public void testTreatNotification_vgwServiceContainingSol004PackageAndPackageAlreadyExistsInEtsiCatalog_successfullyOnboard()
+            throws IOException {
+        initMockAaiServer(SERVICE_UUID, SERVICE_INVARIANT_UUID);
+
+        wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL)
+                .willReturn(aResponse().withBody(getFileContent(
+                        Paths.get(getAbsolutePath(VGW_RESOURCE_PATH), "SDC_RESOURCE_CSAR", "vgw_sdc_resource.csar"))))
+                .withHeader(ACCEPT, equalTo(APPLICATION_OCTET_STREAM_VALUE)));
+
+        wireMockServer.stubFor(post(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .willReturn(okJson(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_RESPONSE)));
+
+        wireMockServer.stubFor(get(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL))
+                .willReturn(okJson(new String(getFileContent(Paths.get(getAbsolutePath(VGW_RESOURCE_PATH),
+                        "etsi-catalog-package-onboading-job-status-error-package-exists.json"))))));
+
+        asdcController.treatNotification(getNotificationDataImplObject());
+
+        final List<WatchdogComponentDistributionStatus> distributionList =
+                watchdogComponentDistributionStatusRepository.findByDistributionId(DISTRIBUTION_ID);
+        assertNotNull(distributionList);
+        assertEquals(1, distributionList.size());
+        final WatchdogComponentDistributionStatus distributionStatus = distributionList.get(0);
+        assertEquals(COMPONENT_DONE_OK.toString(), distributionStatus.getComponentDistributionStatus());
+        assertEquals(COMPONENT_NAME, distributionStatus.getComponentName());
+
+        verify(postRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_URL))
+                .withRequestBody(equalToJson(ETSI_CATALOG_PACKAGE_ONBOARDING_REQUEST)));
+
+        verify(getRequestedFor(urlEqualTo(ETSI_CATALOG_PACKAGE_ONBOARDING_JOB_STATUS_URL)));
+    }
+
+
+    private byte[] getFileContent(final Path path) throws IOException {
+        return Files.readAllBytes(path);
+    }
+
+    private NotificationDataImpl getNotificationDataImplObject() throws IOException {
+        final Path filePath = Paths.get(getAbsolutePath(VGW_RESOURCE_PATH), "dmaap-notification-message.json");
+        final byte[] bytes = Files.readAllBytes(filePath);
+
+        return new GsonBuilder().setPrettyPrinting().create().fromJson(new String(bytes), NotificationDataImpl.class);
+    }
+
+    /**
+     * Mock the AAI using wireshark.
+     */
+    private void initMockAaiServer(final String serviceUuid, final String serviceInvariantUuid) {
+        final String modelEndpoint = "/aai/v19/service-design-and-creation/models/model/" + serviceInvariantUuid
+                + "/model-vers/model-ver/" + serviceUuid + "?depth=0";
+
+        wireMockServer.stubFor(post(urlEqualTo(modelEndpoint)).willReturn(ok()));
+    }
+
+    private String getAbsolutePath(final String path) {
+        final File file = new File(path);
+        return file.getAbsolutePath();
+    }
+}
diff --git a/asdc-controller/src/test/resources/application-test.yaml b/asdc-controller/src/test/resources/application-test.yaml
index 9fa2055..60cd2d9 100644
--- a/asdc-controller/src/test/resources/application-test.yaml
+++ b/asdc-controller/src/test/resources/application-test.yaml
@@ -102,3 +102,11 @@
     endpoint: http://localhost:${wiremock.server.port}
   config:
     defaultpath: src/test/resources
+
+sdc:
+  endpoint: http://localhost:${wiremock.server.port}
+  
+etsi-catalog-manager:
+  endpoint:  http://localhost:${wiremock.server.port}/api/catalog/v1
+  rest:
+    timeoutInSeconds: 5
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/VENDOR_LICENSE/vendor-license-model.xml b/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/VENDOR_LICENSE/vendor-license-model.xml
new file mode 100644
index 0000000..6499a58
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/VENDOR_LICENSE/vendor-license-model.xml
@@ -0,0 +1 @@
+<vendor-license-model xmlns="http://xmlns.openecomp.org/asdc/license-model/1.0"><vendor-name>VLM</vendor-name><entitlement-pool-list><entitlement-pool><entitlement-pool-invariant-uuid>d6dea4a3db6b415ba50f17cb3311d046</entitlement-pool-invariant-uuid><entitlement-pool-uuid>04B01ABDE6CA4A9FBA75ACC023C6FEDA</entitlement-pool-uuid><version>1.0</version><name>EP</name><description/><increments/><manufacturer-reference-number>2345</manufacturer-reference-number><operational-scope><value/></operational-scope><start-date/><expiry-date/><threshold-value><unit/><value/></threshold-value><sp-limits/><vendor-limits/></entitlement-pool></entitlement-pool-list><license-key-group-list><license-key-group><version>1.0</version><name>LKG</name><description/><type>Unique</type><increments/><manufacturerReferenceNumber/><license-key-group-invariant-uuid>55ddeb1a87be4fbb95a9bd74b4d745ca</license-key-group-invariant-uuid><license-key-group-uuid>81117C9B092C4C70AFF76833373CE7F4</license-key-group-uuid><operational-scope><value/></operational-scope><start-date/><expiry-date/><threshold-value><unit>Absolute</unit><value>23456789</value></threshold-value><sp-limits/><vendor-limits/></license-key-group></license-key-group-list></vendor-license-model>
\ No newline at end of file
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/VF_LICENSE/vf-license-model.xml b/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/VF_LICENSE/vf-license-model.xml
new file mode 100644
index 0000000..581a3ac
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/VF_LICENSE/vf-license-model.xml
@@ -0,0 +1 @@
+<vf-license-model xmlns="http://xmlns.openecomp.org/asdc/license-model/1.0"><vendor-name>VLM</vendor-name><vf-id>fa87b9536b704787981357393f36b3fc</vf-id><feature-group-list><feature-group><entitlement-pool-list><entitlement-pool><name>EP</name><description/><increments/><entitlement-pool-invariant-uuid>d6dea4a3db6b415ba50f17cb3311d046</entitlement-pool-invariant-uuid><entitlement-pool-uuid>04B01ABDE6CA4A9FBA75ACC023C6FEDA</entitlement-pool-uuid><manufacturer-reference-number>2345</manufacturer-reference-number><operational-scope><value/></operational-scope><start-date/><expiry-date/><threshold-value><unit/><value/></threshold-value><version>1.0</version><sp-limits/><vendor-limits/></entitlement-pool></entitlement-pool-list><license-key-group-list><license-key-group><name>LKG</name><description/><type>Unique</type><increments/><license-key-group-invariant-uuid>55ddeb1a87be4fbb95a9bd74b4d745ca</license-key-group-invariant-uuid><license-key-group-uuid>81117C9B092C4C70AFF76833373CE7F4</license-key-group-uuid><manufacturer-reference-number/><operational-scope><value/></operational-scope><start-date/><expiry-date/><threshold-value><unit>Absolute</unit><value>23456789</value></threshold-value><version>1.0</version><sp-limits/><vendor-limits/></license-key-group></license-key-group-list><name>FG</name><feature-group-uuid>2218d90f94944a94952be83354847631</feature-group-uuid><description/><part-number>234594</part-number></feature-group></feature-group-list></vf-license-model>
\ No newline at end of file
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/vgw6.csar b/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/vgw6.csar
new file mode 100644
index 0000000..56dbb2b
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/ONBOARDED_PACKAGE/vgw6.csar
Binary files differ
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/SDC_RESOURCE_CSAR/vgw_sdc_resource.csar b/asdc-controller/src/test/resources/resource-examples/vgw/SDC_RESOURCE_CSAR/vgw_sdc_resource.csar
new file mode 100644
index 0000000..7ddfb6e
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/SDC_RESOURCE_CSAR/vgw_sdc_resource.csar
Binary files differ
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/VENDOR_LICENSE/vendor-license-model.xml b/asdc-controller/src/test/resources/resource-examples/vgw/VENDOR_LICENSE/vendor-license-model.xml
new file mode 100644
index 0000000..6499a58
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/VENDOR_LICENSE/vendor-license-model.xml
@@ -0,0 +1 @@
+<vendor-license-model xmlns="http://xmlns.openecomp.org/asdc/license-model/1.0"><vendor-name>VLM</vendor-name><entitlement-pool-list><entitlement-pool><entitlement-pool-invariant-uuid>d6dea4a3db6b415ba50f17cb3311d046</entitlement-pool-invariant-uuid><entitlement-pool-uuid>04B01ABDE6CA4A9FBA75ACC023C6FEDA</entitlement-pool-uuid><version>1.0</version><name>EP</name><description/><increments/><manufacturer-reference-number>2345</manufacturer-reference-number><operational-scope><value/></operational-scope><start-date/><expiry-date/><threshold-value><unit/><value/></threshold-value><sp-limits/><vendor-limits/></entitlement-pool></entitlement-pool-list><license-key-group-list><license-key-group><version>1.0</version><name>LKG</name><description/><type>Unique</type><increments/><manufacturerReferenceNumber/><license-key-group-invariant-uuid>55ddeb1a87be4fbb95a9bd74b4d745ca</license-key-group-invariant-uuid><license-key-group-uuid>81117C9B092C4C70AFF76833373CE7F4</license-key-group-uuid><operational-scope><value/></operational-scope><start-date/><expiry-date/><threshold-value><unit>Absolute</unit><value>23456789</value></threshold-value><sp-limits/><vendor-limits/></license-key-group></license-key-group-list></vendor-license-model>
\ No newline at end of file
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/VF_LICENSE/vf-license-model.xml b/asdc-controller/src/test/resources/resource-examples/vgw/VF_LICENSE/vf-license-model.xml
new file mode 100644
index 0000000..581a3ac
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/VF_LICENSE/vf-license-model.xml
@@ -0,0 +1 @@
+<vf-license-model xmlns="http://xmlns.openecomp.org/asdc/license-model/1.0"><vendor-name>VLM</vendor-name><vf-id>fa87b9536b704787981357393f36b3fc</vf-id><feature-group-list><feature-group><entitlement-pool-list><entitlement-pool><name>EP</name><description/><increments/><entitlement-pool-invariant-uuid>d6dea4a3db6b415ba50f17cb3311d046</entitlement-pool-invariant-uuid><entitlement-pool-uuid>04B01ABDE6CA4A9FBA75ACC023C6FEDA</entitlement-pool-uuid><manufacturer-reference-number>2345</manufacturer-reference-number><operational-scope><value/></operational-scope><start-date/><expiry-date/><threshold-value><unit/><value/></threshold-value><version>1.0</version><sp-limits/><vendor-limits/></entitlement-pool></entitlement-pool-list><license-key-group-list><license-key-group><name>LKG</name><description/><type>Unique</type><increments/><license-key-group-invariant-uuid>55ddeb1a87be4fbb95a9bd74b4d745ca</license-key-group-invariant-uuid><license-key-group-uuid>81117C9B092C4C70AFF76833373CE7F4</license-key-group-uuid><manufacturer-reference-number/><operational-scope><value/></operational-scope><start-date/><expiry-date/><threshold-value><unit>Absolute</unit><value>23456789</value></threshold-value><version>1.0</version><sp-limits/><vendor-limits/></license-key-group></license-key-group-list><name>FG</name><feature-group-uuid>2218d90f94944a94952be83354847631</feature-group-uuid><description/><part-number>234594</part-number></feature-group></feature-group-list></vf-license-model>
\ No newline at end of file
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/dmaap-notification-message.json b/asdc-controller/src/test/resources/resource-examples/vgw/dmaap-notification-message.json
new file mode 100644
index 0000000..d936cd1
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/dmaap-notification-message.json
@@ -0,0 +1,66 @@
+{
+    "distributionID": "35f20eb9-238a-4cc2-96dc-0a08f71bc209",
+    "serviceName": "VgwServiceV1",
+    "serviceVersion": "1.0",
+    "serviceUUID": "e051ff77-fb79-451c-8457-1cbf94e4db8f",
+    "serviceDescription": "Test VGW Service",
+    "serviceInvariantUUID": "c2ce924f-0aa1-4777-9b42-c0fec006a883",
+    "resources": [
+        {
+            "resourceInstanceName": "VgwVspV1 0",
+            "resourceName": "VgwVspV1",
+            "resourceVersion": "1.0",
+            "resourceType": "VF",
+            "resourceUUID": "655aa939-d589-4333-8cc6-8fcb15db858a",
+            "resourceInvariantUUID": "c53a0c91-35f6-40ff-bcda-f75030cfaf2d",
+            "resourceCustomizationUUID": "db1673e1-351a-4d04-8e2f-84b2b4c52cc7",
+            "category": "Generic",
+            "subcategory": "Network Service",
+            "artifacts": [
+                {
+                    "artifactName": "vf-license-model.xml",
+                    "artifactType": "VF_LICENSE",
+                    "artifactURL": "/VF_LICENSE/vf-license-model.xml",
+                    "artifactChecksum": "NjMwZDc0YzhiNDRlZDAyYjIxMmFlM2M0MWRkZjFmNDA\u003d",
+                    "artifactDescription": "VF license file",
+                    "artifactTimeout": 120,
+                    "artifactUUID": "8dda263d-90bb-4b3d-b8e0-0048222dc658",
+                    "artifactVersion": "1"
+                },
+                {
+                    "artifactName": "vgw6.csar",
+                    "artifactType": "ONBOARDED_PACKAGE",
+                    "artifactURL": "/ONBOARDED_PACKAGE/vgw6.csar",
+                    "artifactChecksum": "NjdmNGU3ZDlkODQ0YTUzMTU5NjZmOThiYjMxNTJiNGI\u003d",
+                    "artifactDescription": "Artifact created from csar",
+                    "artifactTimeout": 120,
+                    "artifactUUID": "9e9930b8-898e-4b8b-999e-66c43e1611f4",
+                    "artifactVersion": "1"
+                },
+                {
+                    "artifactName": "vendor-license-model.xml",
+                    "artifactType": "VENDOR_LICENSE",
+                    "artifactURL": "/VENDOR_LICENSE/vendor-license-model.xml",
+                    "artifactChecksum": "NGNmNzU4MDhjN2FjMTJkNWIxMjNkZDZhOWQyYzU0ZjA\u003d",
+                    "artifactDescription": " Vendor license file",
+                    "artifactTimeout": 120,
+                    "artifactUUID": "b3f7a4cf-6a35-4f66-b800-cd4a9a0e9719",
+                    "artifactVersion": "1"
+                }
+            ]
+        }
+    ],
+    "serviceArtifacts": [
+        {
+            "artifactName": "service-Vgwservicev1-csar.csar",
+            "artifactType": "TOSCA_CSAR",
+            "artifactURL": "/service-Vgwservicev1-csar.csar",
+            "artifactChecksum": "MzcxNTMwMDhmNGY0MjRkMjFkNzk1MDNjOTVhNjQzMmE\u003d",
+            "artifactDescription": "TOSCA definition package of the asset",
+            "artifactTimeout": 0,
+            "artifactUUID": "0cc70c6e-6ddc-4ecc-8052-d9f1433c14b8",
+            "artifactVersion": "1"
+        }
+    ],
+    "workloadContext": "Production"
+}
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-error-package-exists.json b/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-error-package-exists.json
new file mode 100644
index 0000000..8dc07b9
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-error-package-exists.json
@@ -0,0 +1,20 @@
+{
+    "jobId": "57c13120-0a03-4d2e-837a-7c41d61e4a30",
+    "responseDescriptor": 
+    {
+        "status": "error",
+        "progress": "255",
+        "statusDescription": "VNF package() already exists.",
+        "errorCode": "1",
+        "responseId": "2",
+        "responseHistoryList": [
+            {
+                "status": "processing",
+                "progress": "5",
+                "statusDescription": "Start CSAR(8f0b72e1-b6d6-42b6-a808-c60b17f04d7a) distribute.",
+                "errorCode": "0",
+                "responseId": "1"
+            }
+        ]
+    }
+}
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-error.json b/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-error.json
new file mode 100644
index 0000000..13f346f
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-error.json
@@ -0,0 +1,20 @@
+{
+    "jobId": "57c13120-0a03-4d2e-837a-7c41d61e4a30",
+    "responseDescriptor": 
+    {
+        "status": "error",
+        "progress": "255",
+        "statusDescription": "Failed to query artifacts(resources) from sdc.",
+        "errorCode": "0",
+        "responseId": "2",
+        "responseHistoryList": [
+            {
+                "status": "processing",
+                "progress": "5",
+                "statusDescription": "Start CSAR(8f0b72e1-b6d6-42b6-a808-c60b17f04d7a) distribute.",
+                "errorCode": "0",
+                "responseId": "1"
+            }
+        ]
+    }
+}
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-successful.json b/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-successful.json
new file mode 100644
index 0000000..b5dc1fe
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/etsi-catalog-package-onboading-job-status-successful.json
@@ -0,0 +1,27 @@
+{
+    "jobId": "57c13120-0a03-4d2e-837a-7c41d61e4a30",
+    "responseDescriptor": 
+    {
+        "status": "finished",
+        "progress": "100",
+        "statusDescription": "CSAR(8f0b72e1-b6d6-42b6-a808-c60b17f04d7a) distribute successfully.",
+        "errorCode": "0",
+        "responseId": "3",
+        "responseHistoryList": [
+            {
+                "status": "processing",
+                "progress": "30",
+                "statusDescription": "Save CSAR(8f0b72e1-b6d6-42b6-a808-c60b17f04d7a) to database.",
+                "errorCode": "0",
+                "responseId": "2"
+            },
+            {
+                "status": "processing",
+                "progress": "5",
+                "statusDescription": "Start CSAR(8f0b72e1-b6d6-42b6-a808-c60b17f04d7a) distribute.",
+                "errorCode": "0",
+                "responseId": "1"
+            }
+        ]
+    }
+}
diff --git a/asdc-controller/src/test/resources/resource-examples/vgw/service-Vgwservicev1-csar.csar b/asdc-controller/src/test/resources/resource-examples/vgw/service-Vgwservicev1-csar.csar
new file mode 100644
index 0000000..51a9e19
--- /dev/null
+++ b/asdc-controller/src/test/resources/resource-examples/vgw/service-Vgwservicev1-csar.csar
Binary files differ
diff --git a/common/src/main/java/org/onap/so/rest/service/HttpRestServiceProvider.java b/common/src/main/java/org/onap/so/rest/service/HttpRestServiceProvider.java
index 69046a2..4434dce 100644
--- a/common/src/main/java/org/onap/so/rest/service/HttpRestServiceProvider.java
+++ b/common/src/main/java/org/onap/so/rest/service/HttpRestServiceProvider.java
@@ -21,6 +21,7 @@
 package org.onap.so.rest.service;
 
 import com.google.common.base.Optional;
+import org.springframework.http.HttpHeaders;
 import org.springframework.http.ResponseEntity;
 
 /**
@@ -39,6 +40,16 @@
 
     /**
      * Execute the HTTP GET to the given URI template
+     * 
+     * @param url the URL
+     * @param headers request headers
+     * @param clazz the type of the return value
+     * @return Returns the body of this entity.
+     */
+    <T> Optional<T> get(final String url, final HttpHeaders headers, final Class<T> clazz);
+
+    /**
+     * Execute the HTTP GET to the given URI template
      *
      * @param url the URL
      * @param clazz the type of the return value
@@ -46,6 +57,15 @@
      */
     <T> ResponseEntity<T> getHttpResponse(final String url, final Class<T> clazz);
 
+    /**
+     * Execute the HTTP GET to the given URI template
+     *
+     * @param url the URL
+     * @param headers request headers
+     * @param clazz the type of the return value
+     * @return Returns the {@link ResponseEntity}.
+     */
+    <T> ResponseEntity<T> getHttpResponse(final String url, final HttpHeaders headers, final Class<T> clazz);
 
     /**
      * Execute the HTTP POST to the given URI template
@@ -68,6 +88,18 @@
     <T> ResponseEntity<T> postHttpRequest(final Object object, final String url, final Class<T> clazz);
 
     /**
+     * Execute the HTTP POST to the given URI template
+     *
+     * @param object the entity (i.e. body) to write to the request
+     * @param url the URL
+     * @param clazz the type of the return value
+     * @param headers request headers
+     * @return Returns the {@link ResponseEntity}.
+     */
+    <T> ResponseEntity<T> postHttpRequest(final Object object, final String url, final HttpHeaders headers,
+            final Class<T> clazz);
+
+    /**
      * Execute the HTTP PUT to the given URI template
      *
      * @param object the entity (i.e. body) to write to the request
diff --git a/common/src/main/java/org/onap/so/rest/service/HttpRestServiceProviderImpl.java b/common/src/main/java/org/onap/so/rest/service/HttpRestServiceProviderImpl.java
index 6211b76..04dd0bb 100644
--- a/common/src/main/java/org/onap/so/rest/service/HttpRestServiceProviderImpl.java
+++ b/common/src/main/java/org/onap/so/rest/service/HttpRestServiceProviderImpl.java
@@ -20,8 +20,6 @@
 
 package org.onap.so.rest.service;
 
-import com.google.common.base.Optional;
-import org.onap.so.configuration.rest.BasicHttpHeadersProvider;
 import org.onap.so.configuration.rest.HttpHeadersProvider;
 import org.onap.so.rest.exceptions.HttpResouceNotFoundException;
 import org.onap.so.rest.exceptions.InvalidRestRequestException;
@@ -36,6 +34,7 @@
 import org.springframework.web.client.HttpStatusCodeException;
 import org.springframework.web.client.RestClientException;
 import org.springframework.web.client.RestTemplate;
+import com.google.common.base.Optional;
 
 /**
  * A Service to perform HTTP requests
@@ -46,16 +45,27 @@
 
     private static final Logger LOGGER = LoggerFactory.getLogger(HttpRestServiceProviderImpl.class);
     private final RestTemplate restTemplate;
-    private final HttpHeadersProvider httpHeadersProvider;
+    private final HttpHeaders defaultHttpHeaders;
 
     public HttpRestServiceProviderImpl(final RestTemplate restTemplate) {
         this.restTemplate = restTemplate;
-        this.httpHeadersProvider = new BasicHttpHeadersProvider();
+        this.defaultHttpHeaders = new HttpHeaders();
     }
 
+    public HttpRestServiceProviderImpl(final RestTemplate restTemplate, final HttpHeaders defaultHttpHeaders) {
+        this.restTemplate = restTemplate;
+        this.defaultHttpHeaders = defaultHttpHeaders;
+    }
+
+    /**
+     * 
+     * @deprecated this constructor is deprecated in favor of using {@link HttpRestServiceProviderImpl(RestTemplate
+     *             restTemplate, HttpHeaders defaultHttpHeaders)}
+     */
+    @Deprecated
     public HttpRestServiceProviderImpl(final RestTemplate restTemplate, final HttpHeadersProvider httpHeadersProvider) {
         this.restTemplate = restTemplate;
-        this.httpHeadersProvider = httpHeadersProvider;
+        this.defaultHttpHeaders = httpHeadersProvider.getHttpHeaders();
     }
 
     @Override
@@ -64,10 +74,21 @@
         return createOptional(response, url, HttpMethod.GET);
     }
 
+    @Override
+    public <T> Optional<T> get(final String url, final HttpHeaders headers, final Class<T> clazz) {
+        final ResponseEntity<T> response = invokeHttpRequest(new HttpEntity<>(headers), HttpMethod.GET, url, clazz);
+        return createOptional(response, url, HttpMethod.GET);
+    }
 
     @Override
     public <T> ResponseEntity<T> getHttpResponse(final String url, final Class<T> clazz) {
-        final HttpEntity<?> request = new HttpEntity<>(getHttpHeaders());
+        final HttpEntity<?> request = new HttpEntity<>(getDefaultHttpHeaders());
+        return invokeHttpRequest(request, HttpMethod.GET, url, clazz);
+    }
+
+    @Override
+    public <T> ResponseEntity<T> getHttpResponse(final String url, final HttpHeaders headers, final Class<T> clazz) {
+        final HttpEntity<?> request = new HttpEntity<>(headers);
         return invokeHttpRequest(request, HttpMethod.GET, url, clazz);
     }
 
@@ -79,7 +100,14 @@
 
     @Override
     public <T> ResponseEntity<T> postHttpRequest(final Object object, final String url, final Class<T> clazz) {
-        final HttpEntity<?> request = new HttpEntity<>(object, getHttpHeaders());
+        final HttpEntity<?> request = new HttpEntity<>(object, getDefaultHttpHeaders());
+        return invokeHttpRequest(request, HttpMethod.POST, url, clazz);
+    }
+
+    @Override
+    public <T> ResponseEntity<T> postHttpRequest(final Object object, final String url, final HttpHeaders headers,
+            final Class<T> clazz) {
+        final HttpEntity<?> request = new HttpEntity<>(object, headers);
         return invokeHttpRequest(request, HttpMethod.POST, url, clazz);
     }
 
@@ -91,7 +119,7 @@
 
     @Override
     public <T> ResponseEntity<T> putHttpRequest(final Object object, final String url, final Class<T> clazz) {
-        final HttpEntity<?> request = new HttpEntity<>(object, getHttpHeaders());
+        final HttpEntity<?> request = new HttpEntity<>(object, getDefaultHttpHeaders());
         return invokeHttpRequest(request, HttpMethod.PUT, url, clazz);
     }
 
@@ -140,7 +168,7 @@
     @Override
     public <T> ResponseEntity<T> deleteHttpRequest(final String url, final Class<T> clazz) {
         try {
-            final HttpEntity<?> request = new HttpEntity<>(getHttpHeaders());
+            final HttpEntity<?> request = new HttpEntity<>(getDefaultHttpHeaders());
             return restTemplate.exchange(url, HttpMethod.DELETE, request, clazz);
 
         } catch (final HttpStatusCodeException httpStatusCodeException) {
@@ -162,7 +190,7 @@
         }
     }
 
-    private HttpHeaders getHttpHeaders() {
-        return httpHeadersProvider.getHttpHeaders();
+    private HttpHeaders getDefaultHttpHeaders() {
+        return defaultHttpHeaders;
     }
 }