summaryrefslogtreecommitdiffstats
path: root/pomba/service-decomposition/src/main/java
diff options
context:
space:
mode:
authorBrad Benesch <brad.benesch@amdocs.com>2018-07-12 14:26:26 -0400
committerBrad Benesch <brad.benesch@amdocs.com>2018-07-23 15:02:36 -0400
commit92c73de0f57aee2ada5f5c85b960c4c8ce7adf85 (patch)
tree66038237e070b13a82b1ceb7e7b0d98ba15fe576 /pomba/service-decomposition/src/main/java
parent17ac3b089df1cc33ced623ab4150edcacd4381c6 (diff)
Initial code for network discovery microservice
Issue-ID: SDNC-317 Change-Id: I09d44de02283079471de0084da07793cb3d7820c Signed-off-by: Brad Benesch <brad.benesch@amdocs.com>
Diffstat (limited to 'pomba/service-decomposition/src/main/java')
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIConfiguration.java95
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/Application.java44
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AuthorizationConfiguration.java41
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/JerseyConfiguration.java66
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/WebConfiguration.java40
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/exception/DiscoveryException.java79
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringService.java30
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringServiceImpl.java58
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestService.java65
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestServiceImpl.java108
-rw-r--r--pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/util/RestUtil.java369
11 files changed, 995 insertions, 0 deletions
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIConfiguration.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIConfiguration.java
new file mode 100644
index 0000000..fedb64c
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIConfiguration.java
@@ -0,0 +1,95 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition;
+
+import org.onap.aai.restclient.client.RestClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AAIConfiguration {
+ @Autowired
+ @Value("${aai.host}")
+ private String host;
+
+ @Autowired
+ @Value("${aai.port}")
+ private String port;
+
+ @Autowired
+ @Value("${aai.httpProtocol}")
+ private String httpProtocol;
+
+ @Autowired
+ @Value("${aai.trustStorePath}")
+ private String trustStorePath;
+
+ @Autowired
+ @Value("${aai.keyStorePath}")
+ private String keyStorePath;
+
+ @Autowired
+ @Value("${aai.keyStorePassword}")
+ private String keyStorePassword;
+
+ @Autowired
+ @Value("${aai.keyManagerFactoryAlgorithm}")
+ private String keyManagerFactoryAlgorithm;
+
+ @Autowired
+ @Value("${aai.keyStoreType}")
+ private String keyStoreType;
+
+ @Autowired
+ @Value("${aai.securityProtocol}")
+ private String securityProtocol;
+
+ @Autowired
+ @Value("${aai.connectionTimeout}")
+ private Integer connectionTimeout;
+
+ @Autowired
+ @Value("${aai.readTimeout}")
+ private Integer readTimeout;
+
+ @Autowired
+ @Value("${aai.serviceInstancePath}")
+ private String serviceInstancePath;
+
+ @Bean(name="aaiClient")
+ public RestClient restClient() {
+ return new RestClient()
+ .validateServerHostname(false)
+ .validateServerCertChain(false)
+ .connectTimeoutMs(this.connectionTimeout)
+ .readTimeoutMs(this.readTimeout);
+ }
+
+ @Bean(name="aaiBaseUrl")
+ public String getURL() {
+ return this.httpProtocol + "://" + this.host + ":" + this.port;
+ }
+
+ @Bean(name="aaiServiceInstancePath")
+ public String getServiceInstancePath() {
+ return this.serviceInstancePath;
+ }
+
+}
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/Application.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/Application.java
new file mode 100644
index 0000000..58b00d8
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/Application.java
@@ -0,0 +1,44 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+@SpringBootApplication
+@ComponentScan(basePackages = "org.onap.sdnc.apps.pomba.servicedecomposition")
+@EnableAsync
+@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
+public class Application extends SpringBootServletInitializer {
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(Application.class);
+ }
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AuthorizationConfiguration.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AuthorizationConfiguration.java
new file mode 100644
index 0000000..f54f387
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AuthorizationConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+
+package org.onap.sdnc.apps.pomba.servicedecomposition;
+
+import java.util.Base64;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AuthorizationConfiguration {
+
+ @Value("${basicAuth.username:admin}")
+ private String username;
+
+ @Value("${basicAuth.password:admin}")
+ private String password;
+
+ @Bean(name="basicAuthHeader")
+ public String getBasicAuthHeader() {
+ return "Basic " + Base64.getEncoder().encodeToString((this.username + ":" + this.password).getBytes());
+ }
+
+
+}
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/JerseyConfiguration.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/JerseyConfiguration.java
new file mode 100644
index 0000000..815adf0
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/JerseyConfiguration.java
@@ -0,0 +1,66 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import java.util.logging.Logger;
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.servlet.ServletProperties;
+import org.onap.sdnc.apps.pomba.servicedecomposition.service.rs.RestServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+
+@Component
+@ApplicationPath("/")
+public class JerseyConfiguration extends ResourceConfig {
+ private static final Logger log = Logger.getLogger(JerseyConfiguration.class.getName());
+
+ @Bean
+ @Primary
+ public ObjectMapper objectMapper() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
+ objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+ return objectMapper;
+ }
+
+ @Autowired
+ public JerseyConfiguration() {
+ register(RestServiceImpl.class);
+ property(ServletProperties.FILTER_FORWARD_ON_404, true);
+ register(new LoggingFeature(log));
+ }
+
+ @Bean
+ public Client jerseyClient() {
+ return ClientBuilder.newClient(new ClientConfig());
+ }
+}
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/WebConfiguration.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/WebConfiguration.java
new file mode 100644
index 0000000..0d0c5db
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/WebConfiguration.java
@@ -0,0 +1,40 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+@Configuration
+public class WebConfiguration {
+
+ @Bean
+ public WebMvcConfigurerAdapter forwardToIndex() {
+ return new WebMvcConfigurerAdapter() {
+ @Override
+ public void addViewControllers(ViewControllerRegistry registry) {
+ registry.addViewController("/swagger").setViewName("redirect:/swagger/index.html");
+ registry.addViewController("/swagger/").setViewName("redirect:/swagger/index.html");
+ registry.addViewController("/docs").setViewName("redirect:/docs/html/index.html");
+ registry.addViewController("/docs/").setViewName("redirect:/docs/html/index.html");
+ }
+ };
+ }
+}
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/exception/DiscoveryException.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/exception/DiscoveryException.java
new file mode 100644
index 0000000..107f98b
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/exception/DiscoveryException.java
@@ -0,0 +1,79 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition.exception;
+
+import javax.ws.rs.core.Response.Status;
+
+public class DiscoveryException extends Exception {
+ public static enum Error {
+ FETCH_RESOURCE_FAILED("SD.0001", "A&AI query failed: %s"),
+ RELATIONSHIP_LINK_PARSE_ERROR("SD.0002", "Error in parsing relationship link"),
+ SERVICE_INSTANCE_NOT_FOUND("SD.0003", "Service Instance not Found"),
+ SERVICE_RELATIONSHIP_PARSE_ERROR("SD.0004", "Error in parsing service-instance relationships: %s"),
+ INVALID_URL("SD.0005", "Invalid request URL, missing parameter: service-instance-id"),
+ MISSING_HEADER("SD.0006", "Missing header parameter: %s"),
+ GENERAL_FAILURE("SD.0007", "An error occurred: %s"),
+ UNAUTHORIZED("SD.00008", "Unauthorized");
+
+ private final String responseCode;
+ private final String message;
+
+ private Error(String responseCode, String message) {
+ this.responseCode = responseCode;
+ this.message = message;
+ }
+
+ public String getMessage(Object... args) {
+ if (args == null || args.length == 0) {
+ return this.message;
+ }
+ return String.format(this.message, args);
+ }
+
+ public String getResponseCode() {
+ return this.responseCode;
+ }
+ }
+
+ private static final long serialVersionUID = -4874149714911165454L;
+
+ private final Status httpStatus;
+ private String responseCode;
+
+ public DiscoveryException(Error error, Status httpStatus, Object... args) {
+ super(error.getMessage(args));
+ if (httpStatus == null) {
+ throw new NullPointerException("httpStatus");
+ }
+ this.responseCode = error.getResponseCode();
+ this.httpStatus = httpStatus;
+ }
+
+ public DiscoveryException(Error error, Exception cause, Object... args) {
+ super(error.getMessage(args), cause);
+ this.httpStatus = Status.INTERNAL_SERVER_ERROR;
+ }
+
+ public String getResponseCode() {
+ return this.responseCode;
+ }
+
+ public Status getHttpStatus() {
+ return this.httpStatus;
+ }
+}
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringService.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringService.java
new file mode 100644
index 0000000..9d2fd84
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringService.java
@@ -0,0 +1,30 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition.service;
+
+import org.onap.logging.ref.slf4j.ONAPLogAdapter;
+import org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException;
+
+public interface SpringService {
+
+ public String decomposeService(String fromAppId,
+ String transactionId,
+ String serviceInstanceId,
+ ONAPLogAdapter adapter) throws DiscoveryException;
+
+}
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringServiceImpl.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringServiceImpl.java
new file mode 100644
index 0000000..4a0f0ed
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringServiceImpl.java
@@ -0,0 +1,58 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition.service;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.json.JSONObject;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.logging.ref.slf4j.ONAPLogAdapter;
+import org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException;
+import org.onap.sdnc.apps.pomba.servicedecomposition.util.RestUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+
+
+@org.springframework.stereotype.Service
+public class SpringServiceImpl implements SpringService {
+ private static EELFLogger log = EELFManager.getInstance().getLogger(SpringServiceImpl.class);
+ public static String APP_NAME = "ServiceDiscovery";
+
+ @Autowired
+ private RestClient aaiClient;
+
+ @Autowired
+ private String aaiBaseUrl;
+
+ @Autowired
+ private String aaiServiceInstancePath;
+
+ @Override
+ public String decomposeService(String fromAppId,
+ String transactionId,
+ String serviceInstanceId,
+ ONAPLogAdapter adapter) throws DiscoveryException {
+
+
+ log.info("Querying A&AI for service instance " + serviceInstanceId);
+ JSONObject serviceInstance = RestUtil.retrieveAAIModelData(aaiClient, aaiBaseUrl, aaiServiceInstancePath,
+ transactionId, serviceInstanceId, adapter);
+ return serviceInstance.toString();
+ }
+
+
+} \ No newline at end of file
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestService.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestService.java
new file mode 100644
index 0000000..f887d8f
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestService.java
@@ -0,0 +1,65 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition.service.rs;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.onap.logging.ref.slf4j.ONAPLogConstants;
+
+@Api(authorizations = @Authorization("basicAuth"))
+@Path("/service")
+@Produces(MediaType.APPLICATION_JSON)
+public interface RestService {
+
+ public static final String SERVICE_NAME = "service-decomposition";
+
+ @GET
+ @Path("/context")
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "Fetch network info for service",
+ notes = "Returns a A&AI JSON object augmented with related entities"
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = 200, message = "OK"),
+ @ApiResponse(code = 400, message = "Bad Request"),
+ @ApiResponse(code = 404, message = "Service not available"),
+ @ApiResponse(code = 500, message = "Unexpected Runtime error")
+ })
+ public Response getContext(
+ @Context HttpServletRequest request,
+ @HeaderParam(HttpHeaders.AUTHORIZATION) @ApiParam(hidden=true) String authorization,
+ @HeaderParam(ONAPLogConstants.Headers.PARTNER_NAME) @ApiParam(required=true) String xFromAppId,
+ @HeaderParam(ONAPLogConstants.Headers.REQUEST_ID) String xTransactionId,
+ @QueryParam("serviceInstanceId") @ApiParam(required=true) String serviceInstanceId);
+} \ No newline at end of file
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestServiceImpl.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestServiceImpl.java
new file mode 100644
index 0000000..19734f0
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestServiceImpl.java
@@ -0,0 +1,108 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition.service.rs;
+
+import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.*;
+
+import java.util.UUID;
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.Response.Status;
+import org.onap.logging.ref.slf4j.ONAPLogAdapter;
+import org.onap.logging.ref.slf4j.ONAPLogConstants;
+import org.onap.logging.ref.slf4j.ONAPLogConstants.ResponseStatus;
+import org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException;
+import org.onap.sdnc.apps.pomba.servicedecomposition.service.SpringService;
+import org.onap.sdnc.apps.pomba.servicedecomposition.util.RestUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RestServiceImpl implements RestService {
+ private static Logger log = LoggerFactory.getLogger(RestServiceImpl.class);
+ private static final String EMPTY_JSON_OBJECT = "{}";
+
+ @Autowired
+ private SpringService service;
+
+ @Resource(name="basicAuthHeader")
+ private String basicAuthHeader;
+
+ public RestServiceImpl() {}
+
+ @Override
+ public Response getContext(HttpServletRequest request,
+ String authorization,
+ String fromAppId,
+ String transactionId,
+ String serviceInstanceId) {
+
+ ONAPLogAdapter adapter = new ONAPLogAdapter(log);
+ adapter.getServiceDescriptor().setServiceName(SERVICE_NAME);
+ adapter.entering(request);
+ try {
+ if (!this.basicAuthHeader.equals(authorization)) {
+ throw new DiscoveryException(UNAUTHORIZED, Status.UNAUTHORIZED);
+ }
+
+ // Do some validation on Http headers and URL parameters
+ if ((fromAppId == null) || fromAppId.trim().isEmpty()) {
+ throw new DiscoveryException(MISSING_HEADER, Status.BAD_REQUEST, ONAPLogConstants.Headers.PARTNER_NAME);
+ }
+ if (transactionId == null || transactionId.isEmpty()) {
+ transactionId = UUID.randomUUID().toString();
+ log.debug(ONAPLogConstants.Headers.REQUEST_ID+ " is missing; using newly generated value: " + transactionId);
+ }
+ RestUtil.validateURL(serviceInstanceId);
+ String context = service.decomposeService(fromAppId, transactionId, serviceInstanceId, adapter);
+
+ if (context == null) {
+ context = EMPTY_JSON_OBJECT;
+ }
+ adapter.getResponseDescriptor().setResponseStatus(ResponseStatus.COMPLETED);
+ return Response.ok().entity(context).build();
+
+ } catch (DiscoveryException x) {
+ adapter.getResponseDescriptor()
+ .setResponseCode(x.getResponseCode())
+ .setResponseStatus(ResponseStatus.ERROR);
+
+ ResponseBuilder builder = Response.status(x.getHttpStatus()).entity(x.getMessage());
+ if (authorization == null) {
+ builder.header(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\""+ SERVICE_NAME + "\"");
+ }
+ return builder.build();
+
+ } catch (Exception e) {
+ adapter.getResponseDescriptor()
+ .setResponseCode(GENERAL_FAILURE.getResponseCode())
+ .setResponseStatus(ResponseStatus.ERROR);
+
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ } finally {
+ adapter.exiting();
+ }
+
+ }
+
+}
diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/util/RestUtil.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/util/RestUtil.java
new file mode 100644
index 0000000..8d74670
--- /dev/null
+++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/util/RestUtil.java
@@ -0,0 +1,369 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.sdnc.apps.pomba.servicedecomposition.util;
+
+import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.FETCH_RESOURCE_FAILED;
+import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.INVALID_URL;
+import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.RELATIONSHIP_LINK_PARSE_ERROR;
+import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.SERVICE_INSTANCE_NOT_FOUND;
+import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.SERVICE_RELATIONSHIP_PARSE_ERROR;
+
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response.Status;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.logging.ref.slf4j.ONAPLogAdapter;
+import org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class RestUtil {
+ // Parameters for Query AAI Model Data API
+ // HTTP headers
+ private static final String TRANSACTION_ID = "X-TransactionId";
+ private static final String FROM_APP_ID = "X-FromAppId";
+ private static final String APP_NAME = "aaiCtxBuilder";
+
+ // Service Catalog
+ public enum Catalog {
+
+ VNF("generic-vnf"), VNFC("vnfc"), VSERVER("vserver"), L3NETWORK("l3-network");
+
+ private final String resourceName;
+ private final String collectionName;
+
+ private Catalog(String objName) {
+ this.resourceName = objName;
+ this.collectionName = objName + "s"; // make plural
+ }
+
+ public String objName() {
+ return resourceName;
+ }
+ };
+
+
+ private static final String JSON_ATT_RELATED_TO = "related-to";
+ private static final String JSON_ATT_RELATED_LINK = "related-link";
+
+ private static final String EMPTY_JSON_STRING = "{}";
+
+ private static final String DEPTH = "?depth=2";
+ private static Logger logger = LoggerFactory.getLogger(RestUtil.class);
+
+ /**
+ * Validates the URL parameter.
+ *
+ * @throws DiscoveryException if there is missing parameter
+ */
+ public static void validateURL(String serviceInstanceId) throws DiscoveryException {
+
+ if (serviceInstanceId == null || serviceInstanceId.isEmpty()) {
+ throw new DiscoveryException(INVALID_URL, Status.BAD_REQUEST);
+ }
+ }
+
+ private static String generateServiceInstanceURL(String siPath, String serviceInstanceId) {
+ return MessageFormat.format(siPath, serviceInstanceId);
+ }
+
+
+ /*
+ * Trigger external API call to AAI to retrieve Service Instance data (i.e. genericVNF and VNFC)
+ */
+
+ /**
+ * @param aaiClient
+ * @param baseURL
+ * @param aaiServiceInstancePath
+ * @param transactionId
+ * @param serviceInstanceId
+ * @param modelVersionId
+ * @param modelInvariantId
+ * @return
+ * @throws DiscoveryException
+ */
+ public static JSONObject retrieveAAIModelData(RestClient aaiClient, String baseURL, String aaiServiceInstancePath,
+ String transactionId, String serviceInstanceId, ONAPLogAdapter adapter) throws DiscoveryException {
+
+ // Follow two variables for transform purpose
+ String url = baseURL + generateServiceInstanceURL(aaiServiceInstancePath, serviceInstanceId);
+ // Response from service instance API call
+ JSONObject serviceInstancePayload = new JSONObject(
+ getResource(aaiClient, url, transactionId, MediaType.valueOf(MediaType.APPLICATION_XML)));
+ // Handle the case if the service instance is not found in AAI
+ if (serviceInstancePayload == null || serviceInstancePayload.length() == 0) {
+ logger.info("Service Instance " + serviceInstanceId + " is not found from AAI");
+ // Only return the empty Json on the root level. i.e service instance
+ throw new DiscoveryException(SERVICE_INSTANCE_NOT_FOUND, Status.NOT_FOUND);
+ }
+
+ HashMap<String, List<String>> relationMap = extractServiceRelationShips(serviceInstancePayload);
+ logger.info("The number of the relationships for service instance id {} is: {}", serviceInstanceId,
+ relationMap.size());
+
+ JSONObject response = processVNFRelationMap(aaiClient, baseURL, transactionId, relationMap, serviceInstancePayload);
+ return response;
+ }
+
+
+ /**
+ * @param aaiClient
+ * @param baseURL
+ * @param transactionId
+ * @param relationMap
+ * @throws DiscoveryException
+ */
+ private static JSONObject processVNFRelationMap(RestClient aaiClient, String baseURL, String transactionId,
+ HashMap<String, List<String>> relationMap, JSONObject serviceInstancePayload) throws DiscoveryException {
+ List<JSONObject> vnfLst = new ArrayList<JSONObject>(); // List of the VNF JSON along with related resources
+
+ JSONObject response = serviceInstancePayload;
+
+
+ if (relationMap.get(Catalog.VNF.resourceName) != null) {
+ List<JSONObject> vnfList = processResourceList(aaiClient, baseURL, transactionId, Catalog.VNF.resourceName,
+ relationMap.get(Catalog.VNF.resourceName));
+ // Logic to Create the Generic VNF JSON and extract further relationships
+ for (JSONObject vnfPayload : vnfList) {
+ List<String> vnfcLinkLst = extractRelatedLink(vnfPayload, Catalog.VNFC.resourceName);
+ if (vnfcLinkLst != null && vnfcLinkLst.size() != 0) {
+ logger.info("The number of the API call for vnfc is:" + vnfcLinkLst.size());
+ List<JSONObject> vnfcList = processResourceList(aaiClient, baseURL, transactionId,
+ Catalog.VNFC.resourceName, vnfcLinkLst);
+ if (vnfcList != null) {
+ vnfPayload.put(Catalog.VNFC.collectionName, vnfcList);
+ }
+ } else {
+ logger.info("No vnfc found for vnf-id:" + vnfPayload.getString("vnf-id"));
+ }
+
+ List<String> networkLinkLst = extractRelatedLink(vnfPayload, Catalog.L3NETWORK.resourceName);
+ if (networkLinkLst != null && networkLinkLst.size() != 0) {
+ logger.info("The number of the API call for l3-network is:" + networkLinkLst.size());
+ List<JSONObject> networkList = processResourceList(aaiClient, baseURL, transactionId,
+ Catalog.L3NETWORK.resourceName, networkLinkLst);
+ if (networkList != null) {
+ vnfPayload.put(Catalog.L3NETWORK.collectionName, networkList);
+ }
+ } else {
+ logger.info("No l3-network found for vnf-id:" + vnfPayload.getString("vnf-id"));
+ }
+ List<String> vserverLinkLst = extractRelatedLink(vnfPayload, Catalog.VSERVER.resourceName);
+ if (vserverLinkLst != null && vserverLinkLst.size() != 0) {
+ logger.info("The number of the API call for vserver is:" + vserverLinkLst.size());
+ List<JSONObject> vserverList = processResourceList(aaiClient, baseURL, transactionId,
+ Catalog.VSERVER.resourceName, vserverLinkLst);
+ if (vserverList != null) {
+ vnfPayload.put(Catalog.VSERVER.collectionName, vserverList);
+ }
+ } else {
+ logger.info("No vserver found for vnf-id:" + vnfPayload.getString("vnf-id"));
+ }
+
+ // Add final vnf payload to list
+ vnfLst.add(vnfPayload);
+ }
+ } else {
+ logger.info("No generic vnf found for :" + serviceInstancePayload.getString("service-instance-id"));
+ }
+
+ // Add generic vnf with related resource payload to response
+ if (vnfLst != null && vnfLst.size() != 0) {
+ response.put(Catalog.VNF.collectionName, vnfLst);
+ }
+
+ return response;
+
+ }
+
+
+ /**
+ * @param aaiClient
+ * @param aaiBaseURL
+ * @param transactionId
+ * @param resourceType
+ * @param resourceList
+ * @return
+ * @throws DiscoveryException
+ */
+ private static List<JSONObject> processResourceList(RestClient aaiClient, String aaiBaseURL, String transactionId,
+ String resourceType, List<String> resourceList) throws DiscoveryException {
+ List<JSONObject> resourcePayloadList = new ArrayList<JSONObject>();
+ for (String resourceLink : resourceList) {
+ String resourceURL = aaiBaseURL + resourceLink;
+ // With latest AAI development, in order to retrieve the both generic VNF + vf_module, we can use
+ // one API call but with depth=2
+ if (resourceType.equals(Catalog.VNF.resourceName)) {
+ resourceURL += DEPTH;
+ }
+
+ // Response from generic VNF API call
+ JSONObject resourcePayload = new JSONObject(
+ getResource(aaiClient, resourceURL, transactionId, MediaType.valueOf(MediaType.APPLICATION_XML)));
+ if (resourcePayload == null || resourcePayload.length() == 0) {
+ logger.info("Resource with url " + resourceLink + " is not found from AAI");
+ } else {
+ resourcePayloadList.add(resourcePayload);
+ }
+ }
+ return resourcePayloadList;
+ }
+
+
+ /**
+ * @param serviceInstancePayload
+ * @param relationMap
+ * @return
+ * @throws DiscoveryException
+ */
+ private static HashMap<String, List<String>> extractServiceRelationShips(JSONObject payload)
+ throws DiscoveryException {
+
+ JSONArray relationships = null;
+ HashMap<String, List<String>> relationMap = new HashMap<String, List<String>>();
+ logger.info("Fetching Service Instance Relationships");
+ try {
+ JSONObject relationshipList = payload.getJSONObject("relationship-list");
+ if (relationshipList != null) {
+ relationships = relationshipList.getJSONArray("relationship");
+ }
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ throw new DiscoveryException(SERVICE_RELATIONSHIP_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR,
+ e.getMessage());
+ }
+
+ if (relationships != null && relationships.length() > 0) {
+ for (int i = 0; i < relationships.length(); i++) {
+ JSONObject obj = relationships.optJSONObject(i);
+ String relatedToObj = obj.getString(JSON_ATT_RELATED_TO);
+ String relatedLinkObj = obj.getString(JSON_ATT_RELATED_LINK);
+
+ if (relatedToObj == null) {
+ logger.info("Related-To Object found null");
+ continue;
+ }
+ List<String> relatedLinkList = relationMap.get(relatedToObj.toString());
+ if (relatedLinkList == null) {
+ relatedLinkList = new ArrayList<>();
+ relationMap.put(relatedToObj.toString(), relatedLinkList);
+ }
+ relatedLinkList.add(relatedLinkObj.toString());
+ }
+ }
+ return relationMap;
+ }
+
+ /**
+ * @param client
+ * @param url
+ * @param transId
+ * @param mediaType
+ * @return
+ * @throws DiscoveryException
+ */
+ private static String getResource(RestClient client, String url, String transId, MediaType mediaType)
+ throws DiscoveryException {
+ OperationResult result = client.get(url, buildHeaders(transId), MediaType.valueOf(MediaType.APPLICATION_JSON));
+
+ if (result.getResultCode() == 200) {
+ String jsonString = result.getResult();
+ return jsonString;
+ } else if (result.getResultCode() == 404) {
+ // Resource not found, generate empty JSON format
+ logger.info("Resource for " + url + " is not found " + "return empty Json format");
+ return EMPTY_JSON_STRING;
+ } else {
+ throw new DiscoveryException(FETCH_RESOURCE_FAILED, Status.INTERNAL_SERVER_ERROR, result.getFailureCause());
+ }
+ }
+
+ /**
+ * Extract the related-Link from Json payload. For example
+ * {
+ * "related-to": "vnfc",
+ * "related-link": "/aai/v11/network/vnfcs/vnfc/zrdm5aepdg01vmg003",
+ * "relationship-data": [
+ * {
+ * "relationship-key": "vnfc.vnfc-name",
+ * "relationship-value": "zrdm5aepdg01vmg003"
+ * }
+ * ]
+ * }
+ */
+ private static List<String> extractRelatedLink(JSONObject payload, String catalog) throws DiscoveryException {
+ List<String> relatedLinkList = new ArrayList<String>();
+ JSONArray relationships = null;
+ logger.info("Fetching relationships for resource type: " + catalog);
+ try {
+ JSONObject relationshipLst = payload.getJSONObject("relationship-list");
+ if (relationshipLst != null) {
+ relationships = relationshipLst.getJSONArray("relationship");
+ }
+
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ throw new DiscoveryException(RELATIONSHIP_LINK_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR, e.getMessage());
+ }
+
+ if (relationships != null && relationships.length() > 0) {
+ for (int i = 0; i < relationships.length(); i++) {
+ Object relatedToObj = null;
+ Object relatedLinkObj = null;
+
+ JSONObject obj = relationships.optJSONObject(i);
+ relatedToObj = obj.get(JSON_ATT_RELATED_TO);
+
+ if (relatedToObj.toString().equals(catalog)) {
+ relatedLinkObj = obj.get(JSON_ATT_RELATED_LINK);
+ if (relatedLinkObj != null) {
+ relatedLinkList.add(relatedLinkObj.toString());
+ }
+ }
+
+ }
+ }
+ if (relatedLinkList != null) {
+ logger.info(
+ "Number of relationships found for resource type: " + catalog + " are: " + relatedLinkList.size());
+ }
+ return relatedLinkList;
+ }
+
+
+
+ private static Map<String, List<String>> buildHeaders(String transactionId) {
+ MultivaluedMap<String, String> headers = new MultivaluedMapImpl();
+ headers.put(TRANSACTION_ID, Collections.singletonList(transactionId));
+ headers.put(FROM_APP_ID, Collections.singletonList(APP_NAME));
+ return headers;
+ }
+
+}