2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.onap.appc.simulator.client.impl;
27 import static java.lang.Character.toLowerCase;
28 import static java.lang.Character.toUpperCase;
30 import com.att.eelf.configuration.EELFLogger;
31 import com.att.eelf.configuration.EELFManager;
32 import com.fasterxml.jackson.databind.JsonNode;
33 import com.fasterxml.jackson.databind.ObjectMapper;
34 import com.fasterxml.jackson.databind.node.ObjectNode;
35 import java.io.BufferedReader;
37 import java.io.FileNotFoundException;
38 import java.io.FileReader;
39 import java.io.IOException;
40 import java.lang.reflect.InvocationTargetException;
41 import java.lang.reflect.Method;
42 import java.util.HashMap;
43 import java.util.Properties;
44 import org.onap.appc.client.lcm.api.AppcClientServiceFactoryProvider;
45 import org.onap.appc.client.lcm.api.AppcLifeCycleManagerServiceFactory;
46 import org.onap.appc.client.lcm.api.ApplicationContext;
47 import org.onap.appc.client.lcm.api.LifeCycleManagerStateful;
48 import org.onap.appc.client.lcm.api.ResponseHandler;
49 import org.onap.appc.client.lcm.exceptions.AppcClientException;
50 import org.onap.appc.simulator.client.RequestHandler;
52 public class JsonRequestHandler implements RequestHandler {
55 private final EELFLogger logger = EELFManager.getInstance().getLogger(JsonRequestHandler.class);
56 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
57 private static final String INPUT_PARAM = "input";
59 private String inputClassName = null;
60 private String actionName = null;
61 private String methodName = null;
62 private String packageName = null;
63 private LifeCycleManagerStateful service = null;
64 private Properties properties;
65 private HashMap<String, String> exceptRpcMap = null;
67 private AppcLifeCycleManagerServiceFactory appcLifeCycleManagerServiceFactory = null;
69 public JsonRequestHandler() {/*default constructor*/}
71 public JsonRequestHandler(Properties prop) throws AppcClientException {
73 packageName = properties.getProperty("ctx.model.package") + ".";
75 service = createService();
76 } catch (AppcClientException e) {
77 logger.error("An error occurred while instantiating JsonRequestHandler", e);
79 exceptRpcMap = prepareExceptionsMap();
82 private HashMap<String, String> prepareExceptionsMap() {
83 exceptRpcMap = new HashMap<>();
85 try (BufferedReader reader = new BufferedReader(
86 new FileReader(properties.getProperty(
87 "client.rpc.exceptions.map.file")))) {
89 while ((line = reader.readLine()) != null) {
90 String[] parts = line.split(":", 2);
91 if (parts.length >= 2) {
92 String key = parts[0];
93 String value = parts[1];
94 exceptRpcMap.put(key, value);
96 logger.info("ignoring line: " + line);
99 } catch (FileNotFoundException e) {
100 logger.error("Map file not found", e);
102 } catch (IOException e) {
103 logger.error("An error occurred while preparing exceptions map", e);
110 public void proceedFile(File source, File log) throws IOException {
111 final JsonNode inputNode = OBJECT_MAPPER.readTree(source);
114 // proceed with inputNode and get some xxxInput object, depends on action
115 prepareNames(inputNode);
117 Object input = prepareObject(inputNode);
119 JsonResponseHandler response = new JsonResponseHandler();
120 response.setFile(source.getPath());
121 switch (isSyncMode(inputNode)) {
123 processSync(input, response);
126 processAsync(input, response);
129 throw new InvalidRequestException("Unrecognized request mode");
131 } catch (Exception e) {
132 logger.error("An error occurred when proceeding file", e);
135 logger.debug("Action <" + actionName + "> from input file <" + source.getPath() + "> processed");
138 private void processAsync(Object input, JsonResponseHandler response)
139 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
140 logger.debug("Received input request will be processed in asynchronously mode");
141 Method rpc = LifeCycleManagerStateful.class
142 .getDeclaredMethod(methodName, input.getClass(), ResponseHandler.class);
143 rpc.invoke(service, input, response);
146 private void processSync(Object input, JsonResponseHandler response)
147 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
148 logger.debug("Received input request will be processed in synchronously mode");
149 Method rpc = LifeCycleManagerStateful.class.getDeclaredMethod(methodName, input.getClass());
150 response.onResponse(rpc.invoke(service, input));
153 private modeT isSyncMode(JsonNode inputNode) {
154 // The following solution is for testing purposes only
155 // the sync/async decision logic may change upon request
159 inputNode.findValue(INPUT_PARAM).findValue("common-header").findValue("sub-request-id").asText());
160 if ((mode % 2) == 0) {
163 } catch (Exception e) {
164 logger.error("Failed to parse sub-request-id", e);
165 //use ASYNC as default, if value is not integer.
170 private LifeCycleManagerStateful createService() throws AppcClientException {
171 appcLifeCycleManagerServiceFactory = AppcClientServiceFactoryProvider
172 .getFactory(AppcLifeCycleManagerServiceFactory.class);
173 return appcLifeCycleManagerServiceFactory.createLifeCycleManagerStateful(new ApplicationContext(), properties);
177 public void shutdown(boolean isForceShutdown) {
178 appcLifeCycleManagerServiceFactory.shutdownLifeCycleManager(isForceShutdown);
181 public Object prepareObject(JsonNode input) {
183 Class cls = Class.forName(inputClassName);
184 tryAlignPayload(input);
185 return OBJECT_MAPPER.treeToValue(input.get(INPUT_PARAM), cls);
186 } catch (Exception ex) {
187 logger.error("Failed to prepare object", ex);
192 private void tryAlignPayload(JsonNode input) {
194 // since payload is not mandatory field and not all actions contains payload
195 // so we have to check that during input parsing
197 } catch (NoSuchFieldException e) {
198 logger.debug("In " + actionName + " no payload defined", e);
202 private void prepareNames(JsonNode input) throws NoSuchFieldException {
203 JsonNode inputNode = input.findValue(INPUT_PARAM);
204 actionName = inputNode.findValue("action").asText();
205 if (actionName.isEmpty()) {
206 throw new NoSuchFieldException("Input doesn't contains field <action>");
208 inputClassName = packageName + actionName + "Input";
209 methodName = prepareMethodName(prepareRpcFromAction(actionName));
212 private void alignPayload(JsonNode input) throws NoSuchFieldException {
213 JsonNode inputNode = input.findValue(INPUT_PARAM);
214 JsonNode payload = inputNode.findValue("payload");
215 if (payload == null || payload.asText().isEmpty() || payload.toString().isEmpty()) {
216 throw new NoSuchFieldException("Input doesn't contains field <payload>");
219 String payloadData = payload.asText();
220 if (payloadData.isEmpty()) {
221 payloadData = payload.toString();
223 ((ObjectNode) inputNode).put("payload", payloadData);
226 private String prepareRpcFromAction(String action) {
227 String exRpc = checkExceptionalRpcList(action);
228 if (exRpc != null && !exRpc.isEmpty()) {
229 return exRpc; // we found exceptional rpc, so no need to format it
232 StringBuilder rpc = new StringBuilder();
233 boolean makeItLowerCase = true;
234 for (int i = 0; i < action.length(); i++) {
235 if (makeItLowerCase) // first character will make lower case
237 rpc.append(toLowerCase(action.charAt(i)));
238 makeItLowerCase = false;
239 } else if ((i + 1 < action.length()) && Character.isUpperCase(action.charAt(i + 1))) {
240 rpc.append(action.charAt(i)).append('-');
241 makeItLowerCase = true;
243 rpc.append(action.charAt(i));
244 makeItLowerCase = false;
247 return rpc.toString();
250 private String checkExceptionalRpcList(String action) {
251 if (exceptRpcMap.isEmpty()) {
254 return exceptRpcMap.get(action);
257 private String prepareMethodName(String inputRpcName) {
258 boolean makeItUpperCase = false;
259 StringBuilder method = new StringBuilder();
261 for (int i = 0; i < inputRpcName.length(); i++) //to check the characters of string..
263 if (Character.isLowerCase(inputRpcName.charAt(i))
264 && makeItUpperCase) // skip first character if it lower case
266 method.append(toUpperCase(inputRpcName.charAt(i)));
267 makeItUpperCase = false;
268 } else if (inputRpcName.charAt(i) == '-') {
269 makeItUpperCase = true;
271 method.append(inputRpcName.charAt(i));
272 makeItUpperCase = false;
275 return method.toString();