Federation 3.2.0 - Model Data api
[federation.git] / gateway / src / main / java / org / acumos / federation / gateway / GatewayController.java
1 /*-
2  * ===============LICENSE_START=======================================================
3  * Acumos
4  * ===================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
6  * ===================================================================================
7  * This Acumos software file is distributed by AT&T and Tech Mahindra
8  * under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * This file is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ===============LICENSE_END=========================================================
19  */
20 package org.acumos.federation.gateway;
21
22 import java.util.List;
23 import java.util.function.Function;
24 import java.lang.invoke.MethodHandles;
25
26 import javax.servlet.http.HttpServletResponse;
27
28 import io.swagger.annotations.ApiOperation;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import org.springframework.beans.factory.annotation.Autowired;
34 import org.springframework.http.MediaType;
35 import org.springframework.stereotype.Controller;
36 import org.springframework.web.bind.annotation.CrossOrigin;
37 import org.springframework.web.bind.annotation.GetMapping;
38 import org.springframework.web.bind.annotation.PathVariable;
39 import org.springframework.web.bind.annotation.PostMapping;
40 import org.springframework.web.bind.annotation.RequestBody;
41 import org.springframework.web.bind.annotation.RequestMapping;
42 import org.springframework.web.bind.annotation.RequestParam;
43 import org.springframework.web.bind.annotation.ResponseBody;
44 import org.springframework.web.client.RestClientResponseException;
45 import org.springframework.security.access.annotation.Secured;
46 import org.springframework.security.access.method.P;
47 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
48 import org.acumos.cds.domain.MLPCatalog;
49 import org.acumos.cds.domain.MLPSolution;
50 import org.acumos.cds.domain.MLPPeer;
51 import org.acumos.cds.domain.MLPPeerSubscription;
52
53 import org.acumos.federation.client.FederationClient;
54 import org.acumos.federation.client.GatewayClient;
55 import org.acumos.federation.client.data.JsonResponse;
56 import org.acumos.federation.client.data.ModelData;
57 import org.acumos.federation.client.data.ModelInfo;
58
59
60
61 /**
62  * Controller bean for the internal (gateway) API.
63  */
64 @Controller
65 @CrossOrigin
66 @Secured(Security.ROLE_INTERNAL)
67 @RequestMapping(value = GatewayClient.PEER_PFX, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
68 public class GatewayController {
69         private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
70
71         @Autowired
72         private Clients clients;
73
74         @Autowired
75         private PeerService peerService;
76
77         @Autowired
78         private SubscriptionPoller poller;
79
80         @Autowired
81         private WebSecurityConfigurerAdapter security;
82
83         @ApiOperation(value = "Invoked by local Acumos to get a list of catalogs available from a peer Acumos instance .", response = MLPCatalog.class, responseContainer = "List")
84         @GetMapping(FederationClient.CATALOGS_URI)
85         @ResponseBody
86         public JsonResponse<List<MLPCatalog>> getCatalogs(
87             HttpServletResponse response,
88             @PathVariable("peerId") String peerId) {
89                 log.debug("/peer/{}/catalogs", peerId);
90                 return callPeer(response, peerId, FederationClient::getCatalogs);
91         }
92
93         @ApiOperation(value = "Invoked by local Acumos to get a list of solutions available from a peer Acumos instance .", response = MLPSolution.class, responseContainer = "List")
94         @GetMapping(FederationClient.SOLUTIONS_URI)
95         @ResponseBody
96         public JsonResponse<List<MLPSolution>> getSolutions(
97             HttpServletResponse response,
98             @PathVariable("peerId") String peerId,
99             @RequestParam(value="catalogId", required=true) String catalogId) {
100                 log.debug("/peer/{}/solutions", peerId);
101                 return callPeer(response, peerId, peer -> peer.getSolutions(catalogId));
102         }
103
104         @ApiOperation(value = "Invoked by local Acumos to get detailed solution information from the catalog of a peer acumos Instance.", response = MLPSolution.class)
105         @GetMapping(FederationClient.SOLUTION_URI)
106         @ResponseBody
107         public JsonResponse<MLPSolution> getSolution(
108             HttpServletResponse response,
109             @PathVariable("peerId") String peerId,
110             @PathVariable("solutionId") String solutionId) {
111                 log.debug("/peer/{}/solutions/{}", peerId, solutionId);
112                 return callPeer(response, peerId, peer -> peer.getSolution(solutionId));
113         }
114
115         @ApiOperation(value = "Invoked by local Acumos to get peers information from remote Acumos peer.", response = MLPPeer.class, responseContainer = "List")
116         @GetMapping(FederationClient.PEERS_URI)
117         @ResponseBody
118         public JsonResponse<List<MLPPeer>> getPeers(
119             HttpServletResponse response,
120             @PathVariable("peerId") String peerId) {
121                 log.debug("/peer/{}/peers", peerId);
122                 return callPeer(response, peerId, FederationClient::getPeers);
123         }
124
125         @ApiOperation(value = "Invoked by local Acumos to get peer Acumos status and information.", response = MLPPeer.class)
126         @GetMapping(FederationClient.PING_URI)
127         @ResponseBody
128         public JsonResponse<MLPPeer> ping(
129             HttpServletResponse response,
130             @PathVariable("peerId") String peerId) {
131                 log.debug("/peer/{}/ping", peerId);
132                 return callPeer(response, peerId, FederationClient::ping);
133         }
134
135         @ApiOperation(value = "Invoked by local Acumos to register with a remote Acumos peer.", response = MLPPeer.class)
136         @PostMapping(FederationClient.REGISTER_URI)
137         @ResponseBody
138         public JsonResponse<MLPPeer> register(
139             HttpServletResponse response,
140             @PathVariable("peerId") String peerId) {
141                 log.debug("/peer/{}/peer/register", peerId);
142                 return callPeer(response, peerId, FederationClient::register);
143         }
144
145         @ApiOperation("Invoked by other Acumos components in order to trigger subscription execution")
146         @PostMapping(GatewayClient.SUBSCRIPTION_URI)
147         @ResponseBody
148         public JsonResponse<Void> triggerPeerSubscription(
149             HttpServletResponse response,
150             @PathVariable("peerId") String peerId,
151             @PathVariable("subscriptionId") long subscriptionId) {
152                 log.debug("/peer/{}/subscription/{}", peerId, subscriptionId);
153                 MLPPeerSubscription subscription = peerService.getSubscription(subscriptionId);
154                 JsonResponse<Void> ret = new JsonResponse();
155                 if (subscription == null || !peerId.equals(subscription.getPeerId())) {
156                         response.setStatus(HttpServletResponse.SC_NOT_FOUND);
157                         ret.setMessage(String.format("No subscription with id %s found.", subscriptionId));
158                 } else {
159                         poller.triggerSubscription(subscription);
160                         response.setStatus(HttpServletResponse.SC_OK);
161                 }
162                 return ret;
163         }
164         /**
165          * Receives incoming log message from logstash and Sends to {@link FederationController#receiveModelData(ModelData, HttpServletResponse)}
166          *
167          * @param payload model data payload The payload must have a model.solutionId
168          *
169          * @param theHttpResponse HttpServletResponse
170          * @param peerIdPathVar PeerID from url path param or USE_SOLUTION_SOURCE to lookup peer based on model.solutionId field
171          * @return success message in JSON format
172          *
173          */
174         @Secured(Security.ROLE_PEER)
175         @ApiOperation(
176                         value = "Invoked by local Acumos to post incoming model data to respective remote peer Acumos instance .",
177                         response = ModelData.class)
178         @PostMapping(FederationClient.MODEL_DATA)
179         @ResponseBody
180         public JsonResponse<Void> peerModelData(HttpServletResponse theHttpResponse,
181             @RequestBody ModelData payload, @PathVariable("peerId") String peerIdPathVar) {
182                 log.debug("/peer/{}/modeldata  payload: {}", peerIdPathVar, payload);
183                 ModelInfo modelInfo = payload.getModel();
184                 String peerId = peerIdPathVar;
185                 JsonResponse response = new JsonResponse();
186                 // peer id lookup from solution if peerid from path variable is null
187                 if(peerId.indexOf("USE_SOLUTION_SOURCE") != -1){
188                         String solutionId = modelInfo.getSolutionId();
189                         peerId = getPeerIdFromCds(solutionId);
190                 }
191                 
192                 MLPPeer self = ((Security) security).getSelf();
193                 modelInfo.setSubscriberName(self.getSubjectName());
194         
195                 try {
196
197                         // check if thePeerId matches to the
198                         // Ignore request if for local peer i.e. peerId same as local peer
199                         //
200                         log.debug("Attempting to connect to peer id {}", peerId);
201                         if (peerId == null) {
202                                 log.debug("ignore logging to self-peer {}", peerId);
203                                 return this.getSuccessResponse(theHttpResponse,
204                                                 "ignore logging to self-peer");
205                         }
206
207                         log.debug("calling peer with request {}", payload);
208                         callPeer(theHttpResponse, peerId, peer -> peer.receiveModelData(payload));
209                 } catch (Exception ex) {
210                         log.error("failed posting to remote peerId:" + peerId + " exception {}", ex);
211                         throw new BadRequestException(HttpServletResponse.SC_BAD_GATEWAY, "failed posting to remote peerId:" + peerId);
212                 }
213                 return response;
214
215         }
216
217         private JsonResponse getSuccessResponse(
218                 HttpServletResponse theHttpResponse,
219                 String message) {
220                 JsonResponse response = new JsonResponse();
221                 response.setMessage("modelData - " + message);
222                 return response;
223         }
224
225         private String getPeerIdFromCds(String solutionId) {
226                 try {
227                         String peerId = clients.getCDSClient().getSolution(solutionId).getSourceId();
228                         return peerId;
229                 } catch (RestClientResponseException ex) {
230                         log.error("getSolution failed, server reports: {}", ex);
231                         throw new BadRequestException(HttpServletResponse.SC_NOT_FOUND, "Not Found");
232                 }
233         }
234
235         private <T> JsonResponse<T> callPeer(HttpServletResponse response, String peerId, Function<FederationClient, T> fcn) {
236                 MLPPeer peer = peerService.getPeer(peerId);
237                 JsonResponse<T> ret = new JsonResponse();
238                 if (peer == null) {
239                         response.setStatus(HttpServletResponse.SC_NOT_FOUND);
240                         ret.setMessage(String.format("No peer with id %s found.", peerId));
241                 } else {
242                         response.setStatus(HttpServletResponse.SC_OK);
243                         ret.setContent(fcn.apply(clients.getFederationClient(peer.getApiUrl())));
244                 }
245                 return ret;
246         }
247 }