Associate Artifact 79/59379/4
authorayalaben <ayala.benzvi@amdocs.com>
Tue, 7 Aug 2018 08:38:59 +0000 (11:38 +0300)
committerayalaben <ayala.benzvi@amdocs.com>
Wed, 8 Aug 2018 06:58:41 +0000 (09:58 +0300)
Change-Id: Iba63c1a32c8ef7647874ea7234e853edc9d8d0d7
Issue-ID: SDC-1535
Signed-off-by: ayalaben <ayala.benzvi@amdocs.com>
README.md
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/ArtifactAssociationService.java [new file with mode: 0644]
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/WorkflowVersionController.java
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/dto/ArtifactDeliveriesRequestDto.java [new file with mode: 0644]
workflow-designer-be/src/main/resources/application.properties

index 7515380..557d453 100644 (file)
--- a/README.md
+++ b/README.md
@@ -32,6 +32,14 @@ or, if Cassandra authentication is not required
 `docker run -d -e JAVA_OPTIONS={JAVA_OPTIONS} -e CS_HOSTS={COMMA_SEPARATED_HOSTS} -e CS_PORT={PORT} 
 -e CS_AUTHENTICATE=false -p {HOST_PORT}:{APPLICATION_PORT} {BACKEND_IMAGE}`
 
+**optional parameters**
+
+For posting workflow artifact to external API
+
+`-e SDC_PROTOCOL={SDC_PROTOCOL} -e SDC_ENDPOINT={SDC_ENDPOINT}`
+SDC_PROTOCOL - HTTP\HTTPS
+SDC_ENDPOINT - <IP>:<PORT>
+
 The server listens on 8080 by default, but it is possible to change the application port by passing 
 `-e SERVER_PORT={PORT}` to Docker _run_ command.
 
diff --git a/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/ArtifactAssociationService.java b/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/ArtifactAssociationService.java
new file mode 100644 (file)
index 0000000..be32749
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright © 2018 European Support Limited
+ *
+ * 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.
+ */
+
+package org.onap.sdc.workflow.api;
+
+import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.onap.sdc.workflow.api.types.dto.ArtifactDeliveriesRequestDto;
+import org.onap.sdc.workflow.persistence.types.ArtifactEntity;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+
+@Component("ArtifactAssociationHandler")
+public class ArtifactAssociationService {
+
+    private static final String WORKFLOW_ARTIFACT_TYPE = "WORKFLOW";
+    private static final String WORKFLOW_ARTIFACT_DESCRIPTION = "Workflow Artifact Description";
+    private static final String USER_ID_HEADER = "USER_ID";
+    private static final String MD5_HEADER = "Content-MD5";
+    private static final String X_ECOMP_INSTANCE_ID_HEADER = "X-ECOMP-InstanceID";
+    private static final String INIT_ERROR_MSG = "Failed while attaching workflow artifact to Operation in SDC. Parameters were not initialized: %s";
+    private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactAssociationService.class);
+    @Value("${sdc.be.endpoint}")
+    private String sdcBeEndpoint;
+    @Value("${sdc.be.protocol}")
+    private String sdcBeProtocol;
+    @Value("${sdc.be.external.user}")
+    private String sdcUser;
+    @Value("${sdc.be.external.password}")
+    private String sdcPassword;
+
+    private final RestTemplate restClient;
+
+    @Autowired
+    public ArtifactAssociationService(RestTemplateBuilder builder) {
+        this.restClient = builder.build();
+    }
+
+
+    ResponseEntity<String> execute(String userId, ArtifactDeliveriesRequestDto deliveriesRequestDto,
+            ArtifactEntity artifactEntity) {
+
+        Optional<String> initializationState = parametersInitializationState();
+        if(initializationState.isPresent()){
+            LOGGER.error(String.format(INIT_ERROR_MSG,initializationState.get()));
+            return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(String.format(INIT_ERROR_MSG,initializationState.get()));
+        }
+
+        String formattedArtifact;
+        try {
+            formattedArtifact = getFormattedWorkflowArtifact(artifactEntity);
+        } catch (IOException e) {
+            LOGGER.error("Failed while attaching workflow artifact to Operation in SDC", e);
+            return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(e.getMessage());
+        }
+
+        HttpEntity<String> request = new HttpEntity<>(formattedArtifact, createHeaders(userId,formattedArtifact));
+
+        return restClient.exchange(sdcBeProtocol +"://" + sdcBeEndpoint + "/" + deliveriesRequestDto.getEndpoint(),
+                HttpMethod.valueOf(deliveriesRequestDto.getMethod()), request, String.class);
+    }
+
+    private Optional<String> parametersInitializationState() {
+        ArrayList<String> result=new ArrayList();
+        if (sdcBeEndpoint.equals("")) {
+            result.add("SDC_ENDPOINT");
+        }
+        if (sdcBeProtocol.equals("")) {
+            result.add("SDC_PROTOCOL");
+        }
+        if (sdcUser.equals("")) {
+            result.add("SDC_USER");
+        }
+        if (sdcPassword.equals("")) {
+            result.add("SDC_PASSWORD");
+        }
+
+        if(result.isEmpty()) {
+            return Optional.empty();
+        }
+        else return Optional.of(result.toString());
+    }
+
+
+    private String getFormattedWorkflowArtifact(ArtifactEntity artifactEntity) throws IOException {
+
+        byte[] encodeBase64 = Base64.encodeBase64(IOUtils.toByteArray(artifactEntity.getArtifactData()));
+        String encodedPayloadData = new String(encodeBase64);
+
+        Map<String, String> artifactInfo = new HashMap<>();
+        artifactInfo.put("artifactName", artifactEntity.getFileName());
+        artifactInfo.put("payloadData", encodedPayloadData);
+        artifactInfo.put("artifactType", WORKFLOW_ARTIFACT_TYPE);
+        artifactInfo.put("description", WORKFLOW_ARTIFACT_DESCRIPTION);
+
+        ObjectMapper mapper = new ObjectMapper();
+        return mapper.writeValueAsString(artifactInfo);
+    }
+
+    private HttpHeaders createHeaders(String userId, String formattedArtifact) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.add(USER_ID_HEADER, userId);
+        headers.add(HttpHeaders.AUTHORIZATION, createAuthorizationsHeaderValue(sdcUser,sdcPassword));
+        headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
+        headers.add(MD5_HEADER, calculateMD5Base64EncodedByString(formattedArtifact));
+        headers.add(X_ECOMP_INSTANCE_ID_HEADER, "InstanceId");
+        return headers;
+    }
+
+    private String calculateMD5Base64EncodedByString(String data) {
+        String calculatedMd5 = md5Hex(data);
+        // encode base-64 result
+        byte[] encodeBase64 = Base64.encodeBase64(calculatedMd5.getBytes());
+        return new String(encodeBase64);
+    }
+
+    private String createAuthorizationsHeaderValue(String username, String password) {
+        String auth = username + ":" + password;
+        byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
+        return "Basic " + new String(encodedAuth);
+    }
+}
\ No newline at end of file
index e7c9f63..35b4959 100644 (file)
@@ -25,6 +25,7 @@ import io.swagger.annotations.ApiParam;
 import javax.validation.Valid;
 import org.onap.sdc.workflow.api.types.CollectionResponse;
 import org.onap.sdc.workflow.api.types.VersionStateDto;
+import org.onap.sdc.workflow.api.types.dto.ArtifactDeliveriesRequestDto;
 import org.onap.sdc.workflow.api.types.VersionStatesFormatter;
 import org.onap.sdc.workflow.persistence.types.ArtifactEntity;
 import org.onap.sdc.workflow.persistence.types.WorkflowVersion;
@@ -56,11 +57,14 @@ import springfox.documentation.annotations.ApiIgnore;
 public class WorkflowVersionController {
 
     private final WorkflowVersionManager workflowVersionManager;
+    private final ArtifactAssociationService associationHandler;
 
     @Autowired
     public WorkflowVersionController(
-            @Qualifier("workflowVersionManager") WorkflowVersionManager workflowVersionManager) {
+            @Qualifier("workflowVersionManager") WorkflowVersionManager workflowVersionManager,
+            @Qualifier("ArtifactAssociationHandler") ArtifactAssociationService artifatcAssociationHandler) {
         this.workflowVersionManager = workflowVersionManager;
+        this.associationHandler = artifatcAssociationHandler;
     }
 
     @ApiImplicitParam(name = "state", dataType = "string", paramType = "query", allowableValues = "DRAFT,CERTIFIED",
@@ -113,6 +117,14 @@ public class WorkflowVersionController {
         return new VersionStateDto(state.getName());
     }
 
+    @PostMapping("/{versionId}/artifact-deliveries")
+    @ApiOperation("upload of artifact to VF operation workflow")
+    public ResponseEntity<String> artifactDeliveries(@RequestBody ArtifactDeliveriesRequestDto deliveriesRequestDto, @PathVariable("workflowId") String workflowId,
+            @PathVariable("versionId") String versionId, @RequestHeader(USER_ID_HEADER) String user) {
+        return associationHandler.execute(user, deliveriesRequestDto,
+                workflowVersionManager.getArtifact(workflowId, versionId));
+    }
+
     @PutMapping("/{versionId}/artifact")
     @ApiOperation("Create/update artifact of a version")
     public void uploadArtifact(@RequestBody MultipartFile fileToUpload, @PathVariable("workflowId") String workflowId,
diff --git a/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/dto/ArtifactDeliveriesRequestDto.java b/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/dto/ArtifactDeliveriesRequestDto.java
new file mode 100644 (file)
index 0000000..e3dc212
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2018 European Support Limited
+ *
+ * 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.
+ */
+package org.onap.sdc.workflow.api.types.dto;
+
+import lombok.Data;
+
+/**
+ * This class is a simple data object for the Artifact-Deliveries API
+ * It will be used to build a HTTP request to be sent to SDC external API
+ *
+ * method
+ *      the HTTP method (PUT, POST etc) that will be executed.
+ *
+ *  endpoint
+ *          the server to which the request will be sent.
+ *          correct format is <IP>:<PORT>
+ */
+@Data
+public class ArtifactDeliveriesRequestDto {
+
+    private String method;
+    private String endpoint;
+
+    public ArtifactDeliveriesRequestDto(){
+    }
+
+    public ArtifactDeliveriesRequestDto(String method, String endpoint){
+        this.method = method;
+        this.endpoint = endpoint;
+    }
+}
index 703d738..5149bdf 100644 (file)
 
 server.servlet.context-path=/wf
 server.port=${SERVER_PORT:8080}
+sdc.be.protocol=${SDC_PROTOCOL:}
+sdc.be.endpoint=${SDC_ENDPOINT:}
+sdc.be.external.user=${SDC_USER:}
+sdc.be.external.password=${SDC_PASSWORD:}
 
 #CASSANDRA
 spring.data.cassandra.contact-points=${CS_HOSTS}