Fix Guard policy Push
[clamp.git] / src / main / java / org / onap / clamp / clds / client / req / policy / PolicyClient.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
6  *                             reserved.
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  *
22  */
23
24 package org.onap.clamp.clds.client.req.policy;
25
26 import com.att.eelf.configuration.EELFLogger;
27 import com.att.eelf.configuration.EELFManager;
28
29 import java.util.Collection;
30 import java.util.Date;
31 import java.util.Map;
32 import java.util.UUID;
33
34 import javax.ws.rs.BadRequestException;
35
36 import org.onap.clamp.clds.config.ClampProperties;
37 import org.onap.clamp.clds.config.PolicyConfiguration;
38 import org.onap.clamp.clds.exception.policy.PolicyClientException;
39 import org.onap.clamp.clds.model.properties.ModelProperties;
40 import org.onap.clamp.clds.model.properties.PolicyItem;
41 import org.onap.clamp.clds.util.LoggingUtils;
42 import org.onap.policy.api.AttributeType;
43 import org.onap.policy.api.ConfigRequestParameters;
44 import org.onap.policy.api.DeletePolicyCondition;
45 import org.onap.policy.api.DeletePolicyParameters;
46 import org.onap.policy.api.DictionaryType;
47 import org.onap.policy.api.PolicyChangeResponse;
48 import org.onap.policy.api.PolicyClass;
49 import org.onap.policy.api.PolicyConfigException;
50 import org.onap.policy.api.PolicyConfigType;
51 import org.onap.policy.api.PolicyEngine;
52 import org.onap.policy.api.PolicyEngineException;
53 import org.onap.policy.api.PolicyParameters;
54 import org.onap.policy.api.PolicyType;
55 import org.onap.policy.api.PushPolicyParameters;
56 import org.onap.policy.api.RuleProvider;
57 import org.springframework.beans.factory.annotation.Autowired;
58 import org.springframework.context.ApplicationContext;
59 import org.springframework.context.annotation.Primary;
60 import org.springframework.stereotype.Component;
61
62 /**
63  * Policy utility methods - specifically, send the policy.
64  */
65 @Component
66 @Primary
67 public class PolicyClient {
68
69     protected PolicyEngine policyEngine;
70     protected static final String LOG_POLICY_PREFIX = "Response is ";
71     protected static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyClient.class);
72     protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
73     public static final String POLICY_MSTYPE_PROPERTY_NAME = "policy.ms.type";
74     public static final String POLICY_ONAPNAME_PROPERTY_NAME = "policy.onap.name";
75     public static final String POLICY_BASENAME_PREFIX_PROPERTY_NAME = "policy.base.policyNamePrefix";
76     public static final String POLICY_OP_NAME_PREFIX_PROPERTY_NAME = "policy.op.policyNamePrefix";
77     public static final String POLICY_MS_NAME_PREFIX_PROPERTY_NAME = "policy.ms.policyNamePrefix";
78     public static final String POLICY_OP_TYPE_PROPERTY_NAME = "policy.op.type";
79     public static final String POLICY_GUARD_SUFFIX = "_Guard";
80
81     @Autowired
82     protected ApplicationContext appContext;
83     @Autowired
84     protected ClampProperties refProp;
85     @Autowired
86     private PolicyConfiguration policyConfiguration;
87
88     /**
89      * Perform Guard policy type.
90      *
91      * @param attributes
92      *        A map of attributes
93      * @param prop
94      *        The ModelProperties
95      * @param policyRequestUuid
96      *        PolicyRequest UUID
97      * @return The response message of policy
98      */
99     public String sendGuardPolicy(Map<AttributeType, Map<String, String>> attributes, ModelProperties prop,
100         String policyRequestUuid, PolicyItem policyItem) {
101         PolicyParameters policyParameters = new PolicyParameters();
102         // Set Policy Type(Mandatory)
103         policyParameters.setPolicyClass(PolicyClass.Decision);
104         // Set Policy Name(Mandatory)
105         policyParameters.setPolicyName(prop.getPolicyScopeAndNameWithUniqueGuardId());
106         // documentation says this is options, but when tested, got the
107         // following failure: java.lang.Exception: Policy send failed: PE300 -
108         // Data Issue: No policyDescription given.
109         policyParameters.setPolicyDescription(refProp.getStringValue("op.policyDescription"));
110         policyParameters.setOnapName("PDPD");
111         policyParameters.setRuleProvider(RuleProvider.valueOf(policyItem.getGuardPolicyType()));
112         policyParameters.setAttributes(attributes);
113         // Set a random UUID(Mandatory)
114         policyParameters.setRequestID(UUID.fromString(policyRequestUuid));
115
116         String rtnMsg = send(policyParameters, prop, null);
117         push(DictionaryType.Decision.toString(), prop);
118         return rtnMsg;
119     }
120
121     /**
122      * Perform BRMS policy type.
123      *
124      * @param attributes
125      *        A map of attributes
126      * @param prop
127      *        The ModelProperties
128      * @param policyRequestUuid
129      *        PolicyRequest UUID
130      * @return The response message of policy
131      */
132     public String sendBrmsPolicy(Map<AttributeType, Map<String, String>> attributes, ModelProperties prop,
133         String policyRequestUuid) {
134         PolicyParameters policyParameters = new PolicyParameters();
135         // Set Policy Type(Mandatory)
136         policyParameters.setPolicyConfigType(PolicyConfigType.BRMS_PARAM);
137         // Set Policy Name(Mandatory)
138         policyParameters.setPolicyName(prop.getPolicyScopeAndNameWithUniqueId());
139         // documentation says this is options, but when tested, got the
140         // following failure: java.lang.Exception: Policy send failed: PE300 -
141         // Data Issue: No policyDescription given.
142         policyParameters.setPolicyDescription(refProp.getStringValue("op.policyDescription"));
143         policyParameters.setAttributes(attributes);
144         // Set a random UUID(Mandatory)
145         policyParameters.setRequestID(UUID.fromString(policyRequestUuid));
146         String policyNamePrefix = refProp.getStringValue(POLICY_OP_NAME_PREFIX_PROPERTY_NAME);
147         String rtnMsg = send(policyParameters, prop, policyNamePrefix);
148         String policyType = refProp.getStringValue(POLICY_OP_TYPE_PROPERTY_NAME);
149         push(policyType, prop);
150         return rtnMsg;
151     }
152
153     /**
154      * Perform send of microservice policy in JSON.
155      *
156      * @param policyJson
157      *        The policy JSON
158      * @param prop
159      *        The ModelProperties
160      * @param policyRequestUuid
161      *        The policy Request UUID
162      * @return The response message of policy
163      */
164     public String sendMicroServiceInJson(String policyJson, ModelProperties prop, String policyRequestUuid) {
165         PolicyParameters policyParameters = new PolicyParameters();
166         // Set Policy Type
167         policyParameters.setPolicyConfigType(PolicyConfigType.MicroService);
168         policyParameters.setOnapName(refProp.getStringValue(POLICY_ONAPNAME_PROPERTY_NAME));
169         policyParameters.setPolicyName(prop.getCurrentPolicyScopeAndPolicyName());
170         policyParameters.setConfigBody(policyJson);
171         policyParameters.setConfigBodyType(PolicyType.JSON);
172         policyParameters.setRequestID(UUID.fromString(policyRequestUuid));
173         String policyNamePrefix = refProp.getStringValue(POLICY_MS_NAME_PREFIX_PROPERTY_NAME);
174         // Adding this line to clear the policy id from policy name while
175         // pushing to policy engine
176         prop.setPolicyUniqueId("");
177         String rtnMsg = send(policyParameters, prop, policyNamePrefix);
178         String policyType = refProp.getStringValue(POLICY_MSTYPE_PROPERTY_NAME);
179         push(policyType, prop);
180         return rtnMsg;
181     }
182
183     /**
184      * Perform send of base policy in OTHER type.
185      *
186      * @param configBody
187      *        The config policy string body
188      * @param configPolicyName
189      *        The config policy name of the component that has been pre-deployed in
190      *        DCAE
191      * @param prop
192      *        The ModelProperties
193      * @param policyRequestUuid
194      *        The policy request UUID
195      * @return The answer from policy call
196      */
197     public String sendBasePolicyInOther(String configBody, String configPolicyName, ModelProperties prop,
198         String policyRequestUuid) {
199         PolicyParameters policyParameters = new PolicyParameters();
200         // Set Policy Type
201         policyParameters.setPolicyConfigType(PolicyConfigType.Base);
202         policyParameters.setOnapName(refProp.getStringValue(POLICY_ONAPNAME_PROPERTY_NAME));
203         policyParameters.setPolicyName(prop.getCurrentPolicyScopeAndPolicyName());
204         policyParameters.setConfigBody(configBody);
205         policyParameters.setConfigBodyType(PolicyType.OTHER);
206         policyParameters.setConfigName("HolmesPolicy");
207         policyParameters.setPolicyName(configPolicyName);
208         policyParameters.setRequestID(UUID.fromString(policyRequestUuid));
209         // Adding this line to clear the policy id from policy name while
210         // pushing to policy engine
211         prop.setPolicyUniqueId("");
212         String rtnMsg = send(policyParameters, prop, refProp.getStringValue(POLICY_BASENAME_PREFIX_PROPERTY_NAME));
213         push(PolicyConfigType.Base.toString(), prop);
214         return rtnMsg;
215     }
216
217     /**
218      * Perform send of Microservice policy in OTHER type.
219      *
220      * @param configBody
221      *        The config policy string body
222      * @param prop
223      *        The ModelProperties
224      * @return The answer from policy call
225      */
226     public String sendMicroServiceInOther(String configBody, ModelProperties prop) {
227         PolicyParameters policyParameters = new PolicyParameters();
228         // Set Policy Type
229         policyParameters.setPolicyConfigType(PolicyConfigType.MicroService);
230         policyParameters.setOnapName(refProp.getStringValue(POLICY_ONAPNAME_PROPERTY_NAME));
231         policyParameters.setPolicyName(prop.getCurrentPolicyScopeAndPolicyName());
232         policyParameters.setConfigBody(configBody);
233         String policyNamePrefix = refProp.getStringValue(POLICY_MS_NAME_PREFIX_PROPERTY_NAME);
234         // Adding this line to clear the policy id from policy name while
235         // pushing to policy engine
236         prop.setPolicyUniqueId("");
237         String rtnMsg = send(policyParameters, prop, policyNamePrefix);
238         String policyType = refProp.getStringValue(POLICY_MSTYPE_PROPERTY_NAME);
239         push(policyType, prop);
240         return rtnMsg;
241     }
242
243     /**
244      * Perform send of Configuration or Decision policies.
245      *
246      * @param policyParameters
247      *        The PolicyParameters
248      * @param prop
249      *        The ModelProperties
250      * @return The response message of Policy
251      */
252     protected String send(PolicyParameters policyParameters, ModelProperties prop, String policyNamePrefix) {
253         // Verify whether it is triggered by Validation Test button from UI
254         if (prop.isTestOnly()) {
255             return "send not executed for test action";
256         }
257         // API method to create or update Policy.
258         PolicyChangeResponse response = null;
259         String responseMessage = "";
260         Date startTime = new Date();
261         try {
262             if ((PolicyClass.Decision.equals(policyParameters.getPolicyClass()) && !checkDecisionPolicyExists(prop))
263                 || (PolicyClass.Config.equals(policyParameters.getPolicyClass())
264                     && !checkPolicyExists(policyNamePrefix, prop))) {
265                 LoggingUtils.setTargetContext("Policy", "createPolicy");
266                 logger.info("Attempting to create policy for action=" + prop.getActionCd());
267                 response = getPolicyEngine().createPolicy(policyParameters);
268                 responseMessage = response.getResponseMessage();
269             } else {
270                 LoggingUtils.setTargetContext("Policy", "updatePolicy");
271                 logger.info("Attempting to update policy for action=" + prop.getActionCd());
272                 response = getPolicyEngine().updatePolicy(policyParameters);
273                 responseMessage = response.getResponseMessage();
274             }
275         } catch (Exception e) {
276             LoggingUtils.setResponseContext("900", "Policy send failed", this.getClass().getName());
277             LoggingUtils.setErrorContext("900", "Policy send error");
278             logger.error("Exception occurred during policy communication", e);
279             throw new PolicyClientException("Exception while communicating with Policy", e);
280         }
281         logger.info(LOG_POLICY_PREFIX + responseMessage);
282         LoggingUtils.setTimeContext(startTime, new Date());
283         if (response.getResponseCode() == 200) {
284             LoggingUtils.setResponseContext("0", "Policy send success", this.getClass().getName());
285             logger.info("Policy send successful");
286             metricsLogger.info("Policy send success");
287         } else {
288             LoggingUtils.setResponseContext("900", "Policy send failed", this.getClass().getName());
289             logger.warn("Policy send failed: " + responseMessage);
290             metricsLogger.info("Policy send failure");
291             throw new BadRequestException("Policy send failed: " + responseMessage);
292         }
293         return responseMessage;
294     }
295
296     /**
297      * Format and send push of policy.
298      *
299      * @param policyType
300      *        The policy Type
301      * @param prop
302      *        The ModelProperties
303      * @return The response message of policy
304      */
305     protected String push(String policyType, ModelProperties prop) {
306         // Verify whether it is triggered by Validation Test button from UI
307         if (prop.isTestOnly()) {
308             return "push not executed for test action";
309         }
310         PushPolicyParameters pushPolicyParameters = new PushPolicyParameters();
311         // Parameter arguments
312         if (prop.getPolicyUniqueId() != null && !prop.getPolicyUniqueId().isEmpty()) {
313             if (DictionaryType.Decision.toString().equals(policyType)) {
314                 pushPolicyParameters.setPolicyName(prop.getPolicyScopeAndNameWithUniqueGuardId());
315             } else {
316                 pushPolicyParameters.setPolicyName(prop.getPolicyScopeAndNameWithUniqueId());
317             }
318         } else {
319             pushPolicyParameters.setPolicyName(prop.getCurrentPolicyScopeAndPolicyName());
320         }
321         logger.info("Policy Name in Push policy method - " + pushPolicyParameters.getPolicyName());
322         pushPolicyParameters.setPolicyType(policyType);
323         pushPolicyParameters.setPdpGroup(refProp.getStringValue("policy.pdp.group"));
324         pushPolicyParameters.setRequestID(null);
325         // API method to create or update Policy.
326         PolicyChangeResponse response;
327         String responseMessage = "";
328         try {
329             LoggingUtils.setTargetContext("Policy", "pushPolicy");
330             logger.info("Attempting to push policy...");
331             response = getPolicyEngine().pushPolicy(pushPolicyParameters);
332             if (response != null) {
333                 responseMessage = response.getResponseMessage();
334             }
335         } catch (Exception e) {
336             LoggingUtils.setResponseContext("900", "Policy push failed", this.getClass().getName());
337             LoggingUtils.setErrorContext("900", "Policy push error");
338             logger.error("Exception occurred during policy communication", e);
339             throw new PolicyClientException("Exception while communicating with Policy", e);
340         }
341         logger.info(LOG_POLICY_PREFIX + responseMessage);
342         if (response != null && (response.getResponseCode() == 200 || response.getResponseCode() == 204)) {
343             LoggingUtils.setResponseContext("0", "Policy push success", this.getClass().getName());
344             logger.info("Policy push successful");
345             metricsLogger.info("Policy push success");
346         } else {
347             LoggingUtils.setResponseContext("900", "Policy push failed", this.getClass().getName());
348             logger.warn("Policy push failed: " + responseMessage);
349             metricsLogger.info("Policy push failure");
350             throw new BadRequestException("Policy push failed: " + responseMessage);
351         }
352         return responseMessage;
353     }
354
355     /**
356      * Use list Decision policy to know if the decision policy exists.
357      *
358      * @param prop
359      *        The model properties
360      * @return true if it exists, false otherwise
361      */
362     protected boolean checkDecisionPolicyExists(ModelProperties prop) {
363         boolean policyexists = false;
364
365         logger.info("Search in Policy Engine for DecisionpolicyName=" + prop.getPolicyScopeAndNameWithUniqueGuardId());
366         try {
367             // No other choice than pushing to see if it exists or not
368             String response = push(DictionaryType.Decision.toString(), prop);
369             if (response != null) {
370                 policyexists = true;
371             }
372         } catch (BadRequestException e) {
373             // just print warning - if no policy version found
374             logger.warn("Policy not found...policy name - " + prop.getPolicyScopeAndNameWithUniqueGuardId(), e);
375         }
376         return policyexists;
377     }
378
379     /**
380      * Use list Policy API to retrieve the policy. Return true if policy exists
381      * otherwise return false.
382      *
383      * @param policyNamePrefix
384      *        The Policy Name Prefix
385      * @param prop
386      *        The ModelProperties
387      * @return The response message from policy
388      * @throws PolicyConfigException
389      *         In case of issues with policy engine
390      */
391     protected boolean checkPolicyExists(String policyNamePrefix, ModelProperties prop) {
392         boolean policyexists = false;
393         String policyName = "";
394         try {
395
396             if (prop.getPolicyUniqueId() != null && !prop.getPolicyUniqueId().isEmpty()) {
397                 policyName = prop.getCurrentPolicyScopeAndFullPolicyName(policyNamePrefix) + "_"
398                     + prop.getPolicyUniqueId();
399             } else {
400                 policyName = prop.getCurrentPolicyScopeAndFullPolicyName(policyNamePrefix);
401             }
402             logger.info("Search in Policy Engine for policyName=" + policyName);
403
404             ConfigRequestParameters configRequestParameters = new ConfigRequestParameters();
405             configRequestParameters.setPolicyName(policyName);
406             Collection<String> response = getPolicyEngine().listConfig(configRequestParameters);
407             if (response != null && !response.isEmpty() && !response.contains("Policy Name: null")) {
408                 policyexists = true;
409             }
410         } catch (PolicyConfigException e1) {
411             // just print warning - if no policy version found
412             logger.warn("Policy not found...policy name - " + policyName, e1);
413         }
414         return policyexists;
415     }
416
417     /**
418      * This method create a new policy engine.
419      *
420      * @return A new policy engine
421      */
422     private synchronized PolicyEngine getPolicyEngine() {
423         try {
424             if (policyEngine == null) {
425                 policyEngine = new PolicyEngine(policyConfiguration.getProperties());
426             }
427         } catch (PolicyEngineException e) {
428             throw new PolicyClientException("Exception when creating a new policy engine", e);
429         }
430         return policyEngine;
431     }
432
433     /**
434      * Format and send delete Micro Service requests to Policy.
435      *
436      * @param prop
437      *        The ModelProperties
438      * @return The response message from Policy
439      */
440     public String deleteMicrosService(ModelProperties prop) {
441         String deletePolicyResponse = "";
442         try {
443             String policyNamePrefix = refProp.getStringValue(POLICY_MS_NAME_PREFIX_PROPERTY_NAME);
444             if (checkPolicyExists(policyNamePrefix, prop)) {
445                 String policyType = refProp.getStringValue(POLICY_MSTYPE_PROPERTY_NAME);
446                 deletePolicyResponse = deletePolicy(prop, policyType);
447             }
448         } catch (Exception e) {
449             logger.error("Exception occurred during policy communication", e);
450             throw new PolicyClientException("Exception while communicating with Policy", e);
451         }
452         return deletePolicyResponse;
453     }
454
455     /**
456      * This method delete the Base policy.
457      *
458      * @param prop
459      *        The model Properties
460      * @return A string with the answer from policy
461      */
462     public String deleteBasePolicy(ModelProperties prop) {
463         return deletePolicy(prop, PolicyConfigType.Base.toString());
464     }
465
466     /**
467      * Format and send delete Guard requests to Policy.
468      *
469      * @param prop
470      *        The ModelProperties
471      * @return The response message from policy
472      */
473     public String deleteGuard(ModelProperties prop) {
474         String deletePolicyResponse = "";
475         try {
476
477             if (checkDecisionPolicyExists(prop)) {
478                 deletePolicyResponse = deletePolicy(prop, DictionaryType.Decision.toString());
479             }
480         } catch (Exception e) {
481             logger.error("Exception occurred during policy communication", e);
482             throw new PolicyClientException("Exception while communicating with Policy", e);
483         }
484         return deletePolicyResponse;
485     }
486
487     /**
488      * Format and send delete BRMS requests to Policy.
489      *
490      * @param prop
491      *        The ModelProperties
492      * @return The response message from policy
493      */
494     public String deleteBrms(ModelProperties prop) {
495         String deletePolicyResponse = "";
496         try {
497             String policyNamePrefix = refProp.getStringValue(POLICY_OP_NAME_PREFIX_PROPERTY_NAME);
498             if (checkPolicyExists(policyNamePrefix, prop)) {
499                 String policyType = refProp.getStringValue(POLICY_OP_TYPE_PROPERTY_NAME);
500                 deletePolicyResponse = deletePolicy(prop, policyType);
501             }
502         } catch (Exception e) {
503             logger.error("Exception occurred during policy communication", e);
504             throw new PolicyClientException("Exception while communicating with Policy", e);
505         }
506         return deletePolicyResponse;
507     }
508
509     /**
510      * Format and send delete PAP and PDP requests to Policy.
511      *
512      * @param prop
513      *        The ModelProperties
514      * @return The response message from policy
515      */
516     protected String deletePolicy(ModelProperties prop, String policyType) {
517         DeletePolicyParameters deletePolicyParameters = new DeletePolicyParameters();
518         if (prop.getPolicyUniqueId() != null && !prop.getPolicyUniqueId().isEmpty()) {
519             if (DictionaryType.Decision.toString().equals(policyType)) {
520                 deletePolicyParameters.setPolicyName(prop.getPolicyScopeAndNameWithUniqueGuardId());
521             } else {
522                 deletePolicyParameters.setPolicyName(prop.getPolicyScopeAndNameWithUniqueId());
523             }
524         } else {
525             deletePolicyParameters.setPolicyName(prop.getCurrentPolicyScopeAndPolicyName());
526         }
527         logger.info("Policy Name in delete policy method - " + deletePolicyParameters.getPolicyName());
528         deletePolicyParameters.setPolicyComponent("PDP");
529         deletePolicyParameters.setDeleteCondition(DeletePolicyCondition.ALL);
530         deletePolicyParameters.setPdpGroup(refProp.getStringValue("policy.pdp.group"));
531         deletePolicyParameters.setPolicyType(policyType);
532         // send delete request
533         StringBuilder responseMessage = new StringBuilder(sendDeletePolicy(deletePolicyParameters, prop));
534         logger.info("Deleting policy from PAP...");
535         deletePolicyParameters.setPolicyComponent("PAP");
536         deletePolicyParameters.setDeleteCondition(DeletePolicyCondition.ALL);
537         // send delete request
538         responseMessage.append(sendDeletePolicy(deletePolicyParameters, prop));
539         return responseMessage.toString();
540     }
541
542     /**
543      * Send delete request to Policy.
544      *
545      * @param deletePolicyParameters
546      *        The DeletePolicyParameters
547      * @param prop
548      *        The ModelProperties
549      * @return The response message from policy
550      */
551     protected String sendDeletePolicy(DeletePolicyParameters deletePolicyParameters, ModelProperties prop) {
552         // Verify whether it is triggered by Validation Test button from UI
553         if (prop.isTestOnly()) {
554             return "delete not executed for test action";
555         }
556         // API method to create or update Policy.
557         PolicyChangeResponse response = null;
558         String responseMessage = "";
559         try {
560             logger.info("Attempting to delete policy...");
561             response = getPolicyEngine().deletePolicy(deletePolicyParameters);
562             responseMessage = response.getResponseMessage();
563         } catch (Exception e) {
564             logger.error("Exception occurred during policy communnication", e);
565         }
566         logger.info(LOG_POLICY_PREFIX + responseMessage);
567         if (response != null && response.getResponseCode() == 200) {
568             logger.info("Policy delete successful");
569         } else {
570             logger.warn("Policy delete failed: " + responseMessage);
571             throw new BadRequestException("Policy delete failed: " + responseMessage);
572         }
573         return responseMessage;
574     }
575 }