2 * ============LICENSE_START===================================================
3 * Copyright (c) 2018 Amdocs
4 * ============================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ============LICENSE_END=====================================================
18 package org.onap.sdnc.apps.pomba.networkdiscovery.service;
20 import com.bazaarvoice.jolt.JsonUtils;
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
23 import java.io.IOException;
24 import java.text.MessageFormat;
25 import java.util.ArrayList;
26 import java.util.List;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
31 import javax.annotation.PreDestroy;
32 import javax.ws.rs.client.Client;
33 import javax.ws.rs.client.Entity;
34 import javax.ws.rs.client.Invocation;
35 import javax.ws.rs.core.HttpHeaders;
36 import javax.ws.rs.core.MediaType;
37 import javax.ws.rs.core.MultivaluedHashMap;
38 import javax.ws.rs.core.MultivaluedMap;
39 import javax.ws.rs.core.Response;
40 import javax.ws.rs.core.Response.Status;
41 import javax.xml.parsers.ParserConfigurationException;
43 import org.onap.aai.restclient.client.OperationResult;
44 import org.onap.aai.restclient.client.RestClient;
45 import org.onap.logging.ref.slf4j.ONAPLogAdapter;
46 import org.onap.logging.ref.slf4j.ONAPLogAdapter.RequestBuilder;
47 import org.onap.logging.ref.slf4j.ONAPLogConstants;
48 import org.onap.logging.ref.slf4j.ONAPLogConstants.InvocationMode;
49 import org.onap.pomba.common.datatypes.DataQuality;
50 import org.onap.sdnc.apps.pomba.networkdiscovery.ApplicationException;
51 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.Attribute;
52 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.NetworkDiscoveryNotification;
53 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.NetworkDiscoveryResponse;
54 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.Resource;
55 import org.onap.sdnc.apps.pomba.networkdiscovery.service.util.TransformationUtil;
56 import org.slf4j.Logger;
57 import org.springframework.beans.factory.annotation.Autowired;
58 import org.springframework.stereotype.Service;
61 public class SpringServiceImpl implements SpringService {
62 private static final String OPENSTACK_HEADER_TOKEN = "X-Auth-Token";
63 private static final String OPENSTACK_HEADER_API_VERSION = "X-OpenStack-Nova-API-Version";
64 private static final int DEFAULT_WORKER_THREADS = 3;
66 private ExecutorService executor = Executors.newFixedThreadPool(
67 Integer.getInteger("discovery.threads", DEFAULT_WORKER_THREADS),
68 new ThreadFactoryBuilder().setNameFormat("discovery-worker-%d").build());
71 private RestClient openstackClient;
74 private String openstackIdentityUrl;
77 private String openstackIdentityUser;
80 private String openstackIdentityPassword;
83 private String openstackApiMicroversion;
85 @javax.annotation.Resource
86 private Client callbackClient;
88 @javax.annotation.Resource
89 private Map<String, String> openstackTypeURLs;
91 public SpringServiceImpl() throws ParserConfigurationException {
95 public NetworkDiscoveryResponse findbyResourceIdAndType(String transactionId, String requestId, String resourceType,
96 List<String> resourceIds, String notificationURL, String notificationAuthorization, ONAPLogAdapter adapter)
97 throws ApplicationException {
99 NetworkDiscoveryResponse response = new NetworkDiscoveryResponse();
100 response.setRequestId(requestId);
102 String openstackURL = this.openstackTypeURLs.get(resourceType);
103 // check if resourceType is supported
104 if (openstackURL == null) {
105 // don't know what to do with this - return empty response
106 response.setCode(Status.NO_CONTENT.getStatusCode());
107 response.setMessage("Unsupported resourceType " + resourceType);
108 response.setAckFinalIndicator(true);
112 // schedule discovery of specified resources
113 Runnable task = new ResourceTask(transactionId, requestId, resourceType, resourceIds, notificationURL,
114 notificationAuthorization, openstackURL, adapter);
115 this.executor.submit(task);
117 response.setCode(Status.ACCEPTED.getStatusCode());
118 response.setMessage(Status.ACCEPTED.getReasonPhrase());
119 response.setAckFinalIndicator(false);
124 public void shutdown() {
125 this.executor.shutdown();
128 private void sendNotification(String url, String transactionId, String authorization, Object notification,
129 ONAPLogAdapter adapter) {
131 Invocation.Builder request = this.callbackClient.target(url).request().accept(MediaType.TEXT_PLAIN_TYPE);
133 if (authorization != null) {
134 request.header(HttpHeaders.AUTHORIZATION, authorization);
135 request.header(ONAPLogConstants.Headers.REQUEST_ID, transactionId);
137 Logger log = adapter.unwrap();
138 adapter.invoke(new RequestBuilderWrapper(request), InvocationMode.SYNCHRONOUS);
140 adapter.unwrap().info("Posting notfication to url = {} , payload: {}", url,
141 JsonUtils.toJsonString(Entity.json(notification).getEntity()));
143 Response result = request.post(Entity.json(notification));
145 adapter.unwrap().info("request at url = {} resulted in http status {} and response: {}", url,
146 result.getStatus(), result.getEntity());
148 } catch (Exception x) {
149 log.error("Error during {} operation to endpoint at url = {} with error = {}", "POST", url,
150 x.getLocalizedMessage());
154 private class ResourceTask implements Runnable {
155 private final String transactionId;
156 private final String requestId;
157 private final String resourceType;
158 private final List<String> resourceIds;
159 private final String notificationURL;
160 private final String notificationAuthorization;
161 private final String resourceURL;
162 private final ONAPLogAdapter adapter;
164 public ResourceTask(String transactionId, String requestId, String resourceType, List<String> resourceIds,
165 String notificationURL, String notificationAuthorization, String resourceURL, ONAPLogAdapter adapter) {
166 this.transactionId = transactionId;
167 this.requestId = requestId;
168 this.resourceType = resourceType;
169 this.resourceIds = resourceIds;
170 this.notificationURL = notificationURL;
171 this.notificationAuthorization = notificationAuthorization;
172 this.resourceURL = resourceURL;
173 this.adapter = adapter;
179 runResourceDiscoveryTask();
180 } catch (Exception e) {
181 Logger log = adapter.unwrap();
182 log.error("Failure in resource task", e);
184 // Try to send out a notification of the failure:
185 NetworkDiscoveryNotification notification = new NetworkDiscoveryNotification();
186 notification.setRequestId(this.requestId);
187 notification.setCode(Status.INTERNAL_SERVER_ERROR.getStatusCode());
188 notification.setMessage(e.getMessage());
189 notification.setAckFinalIndicator(true);
191 // call client back with resource details
192 sendNotification(this.notificationURL, this.transactionId, this.notificationAuthorization, notification,
197 private void runResourceDiscoveryTask() throws IOException, ApplicationException {
199 String token = OSAuthentication.getToken(openstackIdentityUrl, openstackIdentityUser,
200 openstackIdentityPassword, openstackClient, adapter);
202 NetworkDiscoveryNotification notification = new NetworkDiscoveryNotification();
203 notification.setRequestId(this.requestId);
205 List<Resource> resources = null;
206 MessageFormat format = new MessageFormat(this.resourceURL);
207 MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
208 headers.add(OPENSTACK_HEADER_TOKEN, token);
209 headers.add(OPENSTACK_HEADER_API_VERSION, openstackApiMicroversion);
211 for (String resourceId : this.resourceIds) {
212 String url = format.format(new Object[] { resourceId });
213 OperationResult result = SpringServiceImpl.this.openstackClient.get(url, headers,
214 MediaType.APPLICATION_JSON_TYPE);
216 adapter.unwrap().info("Openstack GET result: {}", result.getResult());
218 Resource resource = new Resource();
219 resource.setType(this.resourceType);
220 resource.setId(resourceId);
221 if (resources == null) {
222 resources = new ArrayList<>();
223 notification.setResources(resources);
225 resources.add(resource);
227 if (result.wasSuccessful()) {
228 String transformedOutput = TransformationUtil.transform(result.getResult(), this.resourceType);
230 adapter.unwrap().info("Jolt transformed output: {}", transformedOutput);
232 resource.setDataQuality(DataQuality.ok());
233 List<Attribute> attributeList = TransformationUtil.toAttributeList(transformedOutput);
234 resource.setAttributeList(attributeList);
236 resource.setDataQuality(DataQuality.error(result.getFailureCause()));
239 notification.setCode(Status.OK.getStatusCode());
240 notification.setMessage(Status.OK.getReasonPhrase());
241 notification.setAckFinalIndicator(true);
243 // call client back with resource details
244 sendNotification(this.notificationURL, this.transactionId, this.notificationAuthorization, notification,
250 private static class RequestBuilderWrapper implements RequestBuilder<RequestBuilderWrapper> {
251 private Invocation.Builder builder;
253 private RequestBuilderWrapper(Invocation.Builder builder) {
254 this.builder = builder;
258 public RequestBuilderWrapper setHeader(String name, String value) {
259 this.builder.header(name, value);