Add Default Method in SP
[aai/sparky-be.git] / sparkybe-onap-service / src / main / java / org / onap / aai / sparky / search / UnifiedSearchProcessor.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 Amdocs
7  * ================================================================================
8  * Licensed 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  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21 package org.onap.aai.sparky.search;
22
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Set;
28 import java.util.TreeMap;
29
30 import javax.servlet.http.HttpServletRequest;
31
32 import org.apache.camel.Exchange;
33 import org.onap.aai.cl.api.Logger;
34 import org.onap.aai.cl.eelf.LoggerFactory;
35 import org.onap.aai.sparky.logging.AaiUiMsgs;
36 import org.onap.aai.sparky.logging.util.ServletUtils;
37 import org.onap.aai.sparky.search.api.SearchProvider;
38 import org.onap.aai.sparky.search.entity.QuerySearchEntity;
39 import org.onap.aai.sparky.search.entity.SearchSuggestion;
40 import org.onap.aai.sparky.search.registry.SearchProviderRegistry;
41 import org.onap.aai.sparky.util.NodeUtils;
42
43 import com.fasterxml.jackson.databind.ObjectMapper;
44
45 public class UnifiedSearchProcessor {
46
47   protected static final String HASH_ID_KEY = "hashId";
48
49   private static final Logger LOG =
50       LoggerFactory.getInstance().getLogger(UnifiedSearchProcessor.class);
51
52   protected SearchProviderRegistry searchProviderRegistry;
53   protected ObjectMapper mapper;
54   protected boolean useOrderedSearchProviderKeys;
55
56   public UnifiedSearchProcessor() {
57     mapper = new ObjectMapper();
58     this.useOrderedSearchProviderKeys = false;
59   }
60
61   public boolean isUseOrderedSearchProviderKeys() {
62     return useOrderedSearchProviderKeys;
63   }
64
65   public void setUseOrderedSearchProviderKeys(boolean useOrderedSearchProviderKeys) {
66     this.useOrderedSearchProviderKeys = useOrderedSearchProviderKeys;
67   }
68
69   public void search(Exchange exchange) {
70     HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
71     ServletUtils.setUpMdcContext(exchange, request);
72
73     SearchResponse searchResponse = new SearchResponse();
74     long processTime = System.currentTimeMillis();
75     int totalAdded = 0;
76
77     try {
78
79       String payload = exchange.getIn().getBody(String.class);
80
81       if (payload == null || payload.isEmpty()) {
82
83         LOG.error(AaiUiMsgs.SEARCH_SERVLET_ERROR, "Request Payload is empty");
84         exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 404);
85         return;
86
87       } else {
88
89         QuerySearchEntity searchRequest = mapper.readValue(payload, QuerySearchEntity.class);
90         int maxResultsPerSearch = Integer.valueOf(searchRequest.getMaxResults());
91
92         Map<String, List<SearchSuggestion>> searchProviderSuggestions =
93             new HashMap<String, List<SearchSuggestion>>();
94
95         int totalSuggestionsFromProviders = 0;
96         List<SearchSuggestion> suggestions = null;
97         for (SearchProvider searchProvider : searchProviderRegistry.getSearchProviders()) {
98           if (searchProvider.isPassThrough()){
99             suggestions = searchProvider.searchPassThrough(payload);
100           } else {
101             suggestions = searchProvider.search(searchRequest);
102           }
103        
104           totalSuggestionsFromProviders += suggestions.size();
105           searchProviderSuggestions.put(searchProvider.getClass().getCanonicalName(), suggestions);
106         }
107
108         /*
109          * Using ordered search provider keys allows us to deterministically calculate how many
110          * results from each provider should be returned. At the moment, this behavior is primarily
111          * only beneficial to test classes. As there is a cost to sorted-collections in the call
112          * processing path, this behavior has been made optional.
113          */
114
115         if (useOrderedSearchProviderKeys) {
116           searchProviderSuggestions =
117               new TreeMap<String, List<SearchSuggestion>>(searchProviderSuggestions);
118         }
119
120         if (totalSuggestionsFromProviders > 0) {
121
122           int suggestionIndex = 0;
123
124           Set<Entry<String, List<SearchSuggestion>>> searchProviderResults =
125               searchProviderSuggestions.entrySet();
126
127           while (totalAdded < maxResultsPerSearch && (totalAdded < totalSuggestionsFromProviders)) {
128
129             for (Entry<String, List<SearchSuggestion>> searchProviderResultList : searchProviderResults) {
130
131               if ((suggestionIndex <= (searchProviderResultList.getValue().size() - 1))) {
132
133                 if (totalAdded < maxResultsPerSearch) {
134                   searchResponse
135                       .addSuggestion(searchProviderResultList.getValue().get(suggestionIndex));
136                   totalAdded++;
137                 }
138               }
139
140             }
141
142             suggestionIndex++;
143
144           }
145
146         }
147
148       }
149
150       searchResponse.addToTotalFound(totalAdded);
151
152       processTime = System.currentTimeMillis() - processTime;
153       searchResponse.setProcessingTimeInMs(processTime);
154       String searchResponseJson = NodeUtils.convertObjectToJson(searchResponse, true);
155       exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
156       exchange.getOut().setBody(searchResponseJson);
157
158     } catch (Exception exc) {
159       LOG.error(AaiUiMsgs.ERROR_PROCESSING_REQUEST, exc);
160
161       exchange.getOut().setHeader(Exchange.HTTP_RESPONSE_CODE, 500);
162       exchange.getOut().setBody(
163           ServletUtils.generateJsonErrorResponse("Processing error = " + exc.getMessage()),
164           String.class);
165
166     } finally {
167       /*
168        * Restore the txnId + appId from the current thread local via the MdcContext
169        */
170
171       ServletUtils.getTxnHeaders().forEach((key, value) -> {
172         exchange.getOut().setHeader(key, value);
173       });
174
175       exchange.getOut().setHeader("RequestUrl", request.getRequestURI());
176       exchange.getOut().setHeader("RequestPort", request.getLocalPort());
177
178     }
179   }
180
181   public SearchProviderRegistry getSearchProviderRegistry() {
182     return searchProviderRegistry;
183   }
184
185   public void setSearchProviderRegistry(SearchProviderRegistry searchProviderRegistry) {
186     this.searchProviderRegistry = searchProviderRegistry;
187   }
188
189 }