Add new class for DAO
[clamp.git] / src / main / java / org / onap / clamp / clds / dao / CldsDao.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2017 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  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23
24 package org.onap.clamp.clds.dao;
25
26 import com.att.eelf.configuration.EELFLogger;
27 import com.att.eelf.configuration.EELFManager;
28
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.ObjectInputStream;
32 import java.sql.Blob;
33 import java.sql.ResultSet;
34 import java.sql.SQLException;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39
40 import javax.sql.DataSource;
41
42 import org.onap.clamp.clds.model.CldsDBServiceCache;
43 import org.onap.clamp.clds.model.CldsEvent;
44 import org.onap.clamp.clds.model.CldsModel;
45 import org.onap.clamp.clds.model.CldsModelInstance;
46 import org.onap.clamp.clds.model.CldsModelProp;
47 import org.onap.clamp.clds.model.CldsServiceData;
48 import org.onap.clamp.clds.model.CldsTemplate;
49 import org.onap.clamp.clds.model.ValueItem;
50 import org.springframework.dao.EmptyResultDataAccessException;
51 import org.springframework.jdbc.core.JdbcTemplate;
52 import org.springframework.jdbc.core.RowMapper;
53 import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
54 import org.springframework.jdbc.core.namedparam.SqlParameterSource;
55 import org.springframework.jdbc.core.simple.SimpleJdbcCall;
56 import org.springframework.stereotype.Repository;
57
58 /**
59  * Data Access for CLDS Model tables.
60  */
61 @Repository("cldsDao")
62 public class CldsDao {
63
64     protected static final EELFLogger logger        = EELFManager.getInstance().getLogger(CldsDao.class);
65     protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
66
67     private JdbcTemplate              jdbcTemplateObject;
68     private SimpleJdbcCall            procGetModel;
69     private SimpleJdbcCall            procGetModelTemplate;
70     private SimpleJdbcCall            procSetModel;
71     private SimpleJdbcCall            procInsEvent;
72     private SimpleJdbcCall            procUpdEvent;
73     private SimpleJdbcCall            procSetTemplate;
74     private SimpleJdbcCall            procGetTemplate;
75     private SimpleJdbcCall            procDelAllModelInstances;
76     private SimpleJdbcCall            procInsModelInstance;
77     private SimpleJdbcCall            procDelModelInstance;
78
79     private static final String       HEALTHCHECK   = "Select 1";
80
81     /**
82      * Log message when instantiating
83      */
84     public CldsDao() {
85         logger.info("CldsDao instantiating...");
86     }
87
88     /**
89      * When dataSource is provided, instantiate spring jdbc objects.
90      *
91      * @param dataSource
92      */
93     public void setDataSource(DataSource dataSource) {
94         this.jdbcTemplateObject = new JdbcTemplate(dataSource);
95         this.procGetModel = new SimpleJdbcCall(dataSource).withProcedureName("get_model");
96         this.procGetModelTemplate = new SimpleJdbcCall(dataSource).withProcedureName("get_model_template");
97         this.procSetModel = new SimpleJdbcCall(dataSource).withProcedureName("set_model");
98         this.procInsEvent = new SimpleJdbcCall(dataSource).withProcedureName("ins_event");
99         this.procUpdEvent = new SimpleJdbcCall(dataSource).withProcedureName("upd_event");
100         this.procGetTemplate = new SimpleJdbcCall(dataSource).withProcedureName("get_template");
101         this.procSetTemplate = new SimpleJdbcCall(dataSource).withProcedureName("set_template");
102         this.procInsModelInstance = new SimpleJdbcCall(dataSource).withProcedureName("ins_model_instance");
103         this.procDelModelInstance = new SimpleJdbcCall(dataSource).withProcedureName("del_model_instance");
104         this.procDelAllModelInstances = new SimpleJdbcCall(dataSource).withProcedureName("del_all_model_instances");
105     }
106
107     /**
108      * Get a model from the database given the model name.
109      *
110      * @param modelName
111      * @return model
112      */
113     public CldsModel getModel(String modelName) {
114         return getModel(modelName, null);
115     }
116
117     /**
118      * Get a model from the database given the controlNameUuid.
119      *
120      * @param controlNameUuid
121      * @return model
122      */
123     public CldsModel getModelByUuid(String controlNameUuid) {
124         return getModel(null, controlNameUuid);
125     }
126
127     /**
128      * Get a model from the database given the model name or a controlNameUuid.
129      *
130      * @param modelName
131      * @return model
132      */
133     private CldsModel getModel(String modelName, String controlNameUuid) {
134         CldsModel model = new CldsModel();
135         model.setName(modelName);
136         SqlParameterSource in = new MapSqlParameterSource().addValue("v_model_name", modelName)
137                 .addValue("v_control_name_uuid", controlNameUuid);
138         Map<String, Object> out = logSqlExecution(procGetModel, in);
139         model.setControlNamePrefix((String) out.get("v_control_name_prefix"));
140         model.setControlNameUuid((String) out.get("v_control_name_uuid"));
141         model.setId((String) (out.get("v_model_id")));
142         model.setTemplateId((String) (out.get("v_template_id")));
143         model.setTemplateName((String) (out.get("v_template_name")));
144         model.setBpmnId((String) (out.get("v_template_bpmn_id")));
145         model.setBpmnUserid((String) out.get("v_template_bpmn_user_id"));
146         model.setBpmnText((String) out.get("v_template_bpmn_text"));
147         model.setPropId((String) (out.get("v_model_prop_id")));
148         model.setPropUserid((String) out.get("v_model_prop_user_id"));
149         model.setPropText((String) out.get("v_model_prop_text"));
150         model.setImageId((String) (out.get("v_template_image_id")));
151         model.setImageUserid((String) out.get("v_template_image_user_id"));
152         model.setImageText((String) out.get("v_template_image_text"));
153         model.setDocId((String) (out.get("v_template_doc_id")));
154         model.setDocUserid((String) out.get("v_template_doc_user_id"));
155         model.setDocText((String) out.get("v_template_doc_text"));
156         model.setBlueprintText((String) out.get("v_model_blueprint_text"));
157         model.getEvent().setId((String) (out.get("v_event_id")));
158         model.getEvent().setActionCd((String) out.get("v_action_cd"));
159         model.getEvent().setActionStateCd((String) out.get("v_action_state_cd"));
160         model.getEvent().setProcessInstanceId((String) out.get("v_event_process_instance_id"));
161         model.getEvent().setUserid((String) out.get("v_event_user_id"));
162         model.setTypeId((String) out.get("v_service_type_id"));
163         model.setDeploymentId((String) out.get("v_deployment_id"));
164         return model;
165     }
166
167     /**
168      * Get a model and template information from the database given the model
169      * name.
170      *
171      * @param modelName
172      * @return model
173      */
174     public CldsModel getModelTemplate(String modelName) {
175         CldsModel model = new CldsModel();
176         model.setName(modelName);
177         SqlParameterSource in = new MapSqlParameterSource().addValue("v_model_name", modelName);
178         Map<String, Object> out = logSqlExecution(procGetModelTemplate, in);
179         // todo : rationalize
180         model.setControlNamePrefix((String) out.get("v_control_name_prefix"));
181         model.setControlNameUuid((String) out.get("v_control_name_uuid"));
182         model.setId((String) (out.get("v_model_id")));
183         model.setTemplateId((String) (out.get("v_template_id")));
184         model.setTemplateName((String) (out.get("v_template_name")));
185         model.setBpmnId((String) (out.get("v_template_bpmn_id")));
186         model.setBpmnUserid((String) out.get("v_template_bpmn_user_id"));
187         model.setBpmnText((String) out.get("v_template_bpmn_text"));
188         model.setPropId((String) (out.get("v_model_prop_id")));
189         model.setPropUserid((String) out.get("v_model_prop_user_id"));
190         model.setPropText((String) out.get("v_model_prop_text"));
191         model.setImageId((String) (out.get("v_template_image_id")));
192         model.setImageUserid((String) out.get("v_template_image_user_id"));
193         model.setImageText((String) out.get("v_template_image_text"));
194         model.setDocId((String) (out.get("v_template_doc_id")));
195         model.setDocUserid((String) out.get("v_template_doc_user_id"));
196         model.setDocText((String) out.get("v_template_doc_text"));
197         model.setBlueprintText((String) out.get("v_model_blueprint_text"));
198         model.getEvent().setId((String) (out.get("v_event_id")));
199         model.getEvent().setActionCd((String) out.get("v_action_cd"));
200         model.getEvent().setActionStateCd((String) out.get("v_action_state_cd"));
201         model.getEvent().setProcessInstanceId((String) out.get("v_event_process_instance_id"));
202         model.getEvent().setUserid((String) out.get("v_event_user_id"));
203         model.setTypeId((String) out.get("v_service_type_id"));
204         model.setDeploymentId((String) out.get("v_deployment_id"));
205
206         Map<String, Object> modelResults = logSqlExecution(procGetModel, in);
207         Object modelResultObject = modelResults.get("#result-set-1");
208         if (modelResultObject != null && modelResultObject instanceof ArrayList) {
209             List<Object> modelInstanceRs = (List<Object>) modelResultObject;
210             for (Object currModelInstance : modelInstanceRs) {
211                 if (currModelInstance != null && currModelInstance instanceof HashMap) {
212                     HashMap<String, String> modelInstanceMap = (HashMap<String, String>) currModelInstance;
213                     CldsModelInstance modelInstance = new CldsModelInstance();
214                     modelInstance.setModelInstanceId(modelInstanceMap.get("model_instance_id"));
215                     modelInstance.setVmName(modelInstanceMap.get("vm_name"));
216                     modelInstance.setLocation(modelInstanceMap.get("location"));
217                     model.getCldsModelInstanceList().add(modelInstance);
218                     logger.info("value of currModel: {}", currModelInstance);
219                 }
220             }
221         }
222         return model;
223     }
224
225     /**
226      * Update model in the database using parameter values and return updated
227      * model object.
228      *
229      * @param model
230      * @param userid
231      * @return
232      */
233     public CldsModel setModel(CldsModel model, String userid) {
234         SqlParameterSource in = new MapSqlParameterSource().addValue("v_model_name", model.getName())
235                 .addValue("v_template_id", model.getTemplateId()).addValue("v_user_id", userid)
236                 .addValue("v_model_prop_text", model.getPropText())
237                 .addValue("v_model_blueprint_text", model.getBlueprintText())
238                 .addValue("v_service_type_id", model.getTypeId()).addValue("v_deployment_id", model.getDeploymentId())
239                 .addValue("v_control_name_prefix", model.getControlNamePrefix())
240                 .addValue("v_control_name_uuid", model.getControlNameUuid());
241         Map<String, Object> out = logSqlExecution(procSetModel, in);
242         model.setControlNamePrefix((String) out.get("v_control_name_prefix"));
243         model.setControlNameUuid((String) out.get("v_control_name_uuid"));
244         model.setId((String) (out.get("v_model_id")));
245         model.setPropId((String) (out.get("v_model_prop_id")));
246         model.setPropUserid((String) (out.get("v_model_prop_user_id")));
247         model.setBlueprintId((String) (out.get("v_model_blueprint_id")));
248         model.setBlueprintUserid((String) out.get("v_model_blueprint_user_id"));
249         model.getEvent().setId((String) (out.get("v_event_id")));
250         model.getEvent().setActionCd((String) out.get("v_action_cd"));
251         model.getEvent().setActionStateCd((String) out.get("v_action_state_cd"));
252         model.getEvent().setProcessInstanceId((String) out.get("v_event_process_instance_id"));
253         model.getEvent().setUserid((String) out.get("v_event_user_id"));
254         return model;
255     }
256
257     /**
258      * Inserts new modelInstance in the database using parameter values and
259      * return updated model object.
260      *
261      * @param model
262      * @param modelInstancesList
263      * @return
264      */
265     public void insModelInstance(CldsModel model, List<CldsModelInstance> modelInstancesList) {
266         // Delete all existing model instances for given controlNameUUID
267         logger.debug("deleting instances for: {}", model.getControlNameUuid());
268         delAllModelInstances(model.getControlNameUuid());
269
270         if (modelInstancesList == null) {
271             logger.debug("modelInstancesList == null");
272         } else {
273             for (CldsModelInstance currModelInstance : modelInstancesList) {
274                 logger.debug("v_control_name_uuid={}", model.getControlNameUuid());
275                 logger.debug("v_vm_name={}", currModelInstance.getVmName());
276                 logger.debug("v_location={}", currModelInstance.getLocation());
277                 SqlParameterSource in = new MapSqlParameterSource()
278                         .addValue("v_control_name_uuid", model.getControlNameUuid())
279                         .addValue("v_vm_name", currModelInstance.getVmName())
280                         .addValue("v_location", currModelInstance.getLocation());
281                 Map<String, Object> out = logSqlExecution(procInsModelInstance, in);
282                 model.setId((String) (out.get("v_model_id")));
283                 CldsModelInstance modelInstance = new CldsModelInstance();
284                 modelInstance.setLocation(currModelInstance.getLocation());
285                 modelInstance.setVmName(currModelInstance.getVmName());
286                 modelInstance.setModelInstanceId((String) (out.get("v_model_instance_id")));
287                 model.getCldsModelInstanceList().add(modelInstance);
288             }
289         }
290     }
291
292     /**
293      * Delete a list of modelInstance from the database using parameter values
294      * and returns updated model object. This method is defunct - DCAE Proxy
295      * will not undeploy individual instances. It will send an empty list of
296      * deployed instances to indicate all have been removed. Or it will send an
297      * updated list to indicate those that are still deployed with any not on
298      * the list considered undeployed.
299      *
300      * @param controlNameUUid
301      * @param modelInstancesList
302      * @return
303      */
304     private CldsModel delModelInstance(String controlNameUUid, List<CldsModelInstance> modelInstancesList) {
305         CldsModel model = new CldsModel();
306         for (CldsModelInstance currModelInstance : modelInstancesList) {
307             SqlParameterSource in = new MapSqlParameterSource().addValue("v_control_name_uuid", controlNameUUid)
308                     .addValue("v_vm_name", currModelInstance.getVmName());
309             Map<String, Object> out = logSqlExecution(procDelModelInstance, in);
310             model.setId((String) (out.get("v_model_id")));
311         }
312         return model;
313     }
314
315     /**
316      * Insert an event in the database - require either modelName or
317      * controlNamePrefix/controlNameUuid.
318      *
319      * @param modelName
320      * @param controlNamePrefix
321      * @param controlNameUuid
322      * @param cldsEvent
323      * @return
324      */
325     public CldsEvent insEvent(String modelName, String controlNamePrefix, String controlNameUuid, CldsEvent cldsEvent) {
326         CldsEvent event = new CldsEvent();
327         SqlParameterSource in = new MapSqlParameterSource().addValue("v_model_name", modelName)
328                 .addValue("v_control_name_prefix", controlNamePrefix).addValue("v_control_name_uuid", controlNameUuid)
329                 .addValue("v_user_id", cldsEvent.getUserid()).addValue("v_action_cd", cldsEvent.getActionCd())
330                 .addValue("v_action_state_cd", cldsEvent.getActionStateCd())
331                 .addValue("v_process_instance_id", cldsEvent.getProcessInstanceId());
332         Map<String, Object> out = logSqlExecution(procInsEvent, in);
333         event.setId((String) (out.get("v_event_id")));
334         return event;
335     }
336
337     /**
338      * Method to delete all model instances based on controlNameUUID
339      *
340      * @param controlNameUUid
341      * @return
342      */
343     private String delAllModelInstances(String controlNameUUid) {
344         SqlParameterSource in = new MapSqlParameterSource().addValue("v_control_name_uuid", controlNameUUid);
345         Map<String, Object> out = logSqlExecution(procDelAllModelInstances, in);
346         return (String) (out.get("v_model_id"));
347     }
348
349     /**
350      * Update event with process instance id.
351      *
352      * @param eventId
353      * @param processInstanceId
354      */
355     public void updEvent(String eventId, String processInstanceId) {
356         SqlParameterSource in = new MapSqlParameterSource().addValue("v_event_id", eventId)
357                 .addValue("v_process_instance_id", processInstanceId);
358         logSqlExecution(procUpdEvent, in);
359     }
360
361     /**
362      * Generic mapper for list of values
363      */
364     private static final class ValueItemMapper implements RowMapper<ValueItem> {
365         @Override
366         public ValueItem mapRow(ResultSet rs, int rowNum) throws SQLException {
367             ValueItem item = new ValueItem();
368             item.setValue(rs.getString(1));
369             return item;
370         }
371     }
372
373     /**
374      * Generic mapper for CldsDBServiceCache
375      */
376     private static final class CldsServiceDataMapper implements RowMapper<CldsServiceData> {
377         @Override
378         public CldsServiceData mapRow(ResultSet rs, int rowNum) throws SQLException {
379             CldsServiceData cldsServiceData = new CldsServiceData();
380             long age;
381             age = rs.getLong(5);
382             Blob blob = rs.getBlob(4);
383             InputStream is = blob.getBinaryStream();
384             ObjectInputStream oip;
385             try {
386                 oip = new ObjectInputStream(is);
387                 cldsServiceData = (CldsServiceData) oip.readObject();
388                 cldsServiceData.setAgeOfRecord(age);
389             } catch (IOException | ClassNotFoundException e) {
390                 logger.error("Error caught while retrieving cldsServiceData from database", e);
391             }
392             return cldsServiceData;
393         }
394     }
395
396     /**
397      * Return list of model names
398      *
399      * @return model names
400      */
401     public List<ValueItem> getBpmnNames() {
402         String sql = "SELECT model_name FROM model ORDER BY 1;";
403         return jdbcTemplateObject.query(sql, new ValueItemMapper());
404     }
405
406     /**
407      * Update template in the database using parameter values and return updated
408      * template object.
409      *
410      * @param template
411      * @param userid
412      */
413     public void setTemplate(CldsTemplate template, String userid) {
414         SqlParameterSource in = new MapSqlParameterSource().addValue("v_template_name", template.getName())
415                 .addValue("v_user_id", userid).addValue("v_template_bpmn_text", template.getBpmnText())
416                 .addValue("v_template_image_text", template.getImageText())
417                 .addValue("v_template_doc_text", template.getPropText());
418         Map<String, Object> out = logSqlExecution(procSetTemplate, in);
419         template.setId((String) (out.get("v_template_id")));
420         template.setBpmnUserid((String) (out.get("v_template_bpmn_user_id")));
421         template.setBpmnId((String) (out.get("v_template_bpmn_id")));
422         template.setBpmnText((String) (out.get("v_template_bpmn_text")));
423         template.setImageId((String) (out.get("v_template_image_id")));
424         template.setImageUserid((String) out.get("v_template_image_user_id"));
425         template.setImageText((String) out.get("v_template_image_text"));
426         template.setPropId((String) (out.get("v_template_doc_id")));
427         template.setPropUserid((String) out.get("v_template_doc_user_id"));
428         template.setPropText((String) out.get("v_template_doc_text"));
429     }
430
431     /**
432      * Return list of template names
433      *
434      * @return template names
435      */
436     public List<ValueItem> getTemplateNames() {
437         String sql = "SELECT template_name FROM template ORDER BY 1;";
438         return jdbcTemplateObject.query(sql, new ValueItemMapper());
439     }
440
441     /**
442      * Get a template from the database given the model name.
443      *
444      * @param templateName
445      * @return model
446      */
447     public CldsTemplate getTemplate(String templateName) {
448         CldsTemplate template = new CldsTemplate();
449         template.setName(templateName);
450         SqlParameterSource in = new MapSqlParameterSource().addValue("v_template_name", templateName);
451         Map<String, Object> out = logSqlExecution(procGetTemplate, in);
452         template.setId((String) (out.get("v_template_id")));
453         template.setBpmnUserid((String) (out.get("v_template_bpmn_user_id")));
454         template.setBpmnId((String) (out.get("v_template_bpmn_id")));
455         template.setBpmnText((String) (out.get("v_template_bpmn_text")));
456         template.setImageId((String) (out.get("v_template_image_id")));
457         template.setImageUserid((String) out.get("v_template_image_user_id"));
458         template.setImageText((String) out.get("v_template_image_text"));
459         template.setPropId((String) (out.get("v_template_doc_id")));
460         template.setPropUserid((String) out.get("v_template_doc_user_id"));
461         template.setPropText((String) out.get("v_template_doc_text"));
462         return template;
463     }
464
465     public CldsServiceData getCldsServiceCache(String invariantUUID) {
466         CldsServiceData cldsServiceData = null;
467         List<CldsServiceData> cldsServiceDataList = new ArrayList<>();
468         try {
469             String getCldsServiceSQL = "SELECT * , TIMESTAMPDIFF(SECOND, timestamp, CURRENT_TIMESTAMP()) FROM clds_service_cache where invariant_service_id  = ? ";
470             cldsServiceData = jdbcTemplateObject.queryForObject(getCldsServiceSQL, new Object[] { invariantUUID },
471                     new CldsServiceDataMapper());
472             logger.info("value of cldsServiceDataList: {}", cldsServiceDataList);
473         } catch (EmptyResultDataAccessException e) {
474             logger.info("cache row not found for invariantUUID: {}", invariantUUID);
475         }
476         return cldsServiceData;
477     }
478
479     public void setCldsServiceCache(CldsDBServiceCache cldsDBServiceCache) {
480         if (cldsDBServiceCache != null && cldsDBServiceCache.getInvariantId() != null
481                 && cldsDBServiceCache.getServiceId() != null) {
482             String invariantUuid = cldsDBServiceCache.getInvariantId();
483             String serviceUuid = cldsDBServiceCache.getServiceId();
484             InputStream is = cldsDBServiceCache.getCldsDataInstream();
485             String insertCldsServiceCacheSql = "INSERT INTO clds_service_cache"
486                     + "(invariant_service_id,service_id,timestamp,object_data) VALUES"
487                     + "(?,?,CURRENT_TIMESTAMP,?) ON DUPLICATE KEY UPDATE invariant_service_id = VALUES(invariant_service_id) , timestamp = CURRENT_TIMESTAMP , object_data = VALUES(object_data) ";
488             jdbcTemplateObject.update(insertCldsServiceCacheSql, invariantUuid, serviceUuid, is);
489         }
490     }
491
492     private static Map<String, Object> logSqlExecution(SimpleJdbcCall call, SqlParameterSource source) {
493         try {
494             return call.execute(source);
495         } catch (Exception e) {
496             logger.error("Exception occured in " + source.getClass().getCanonicalName() + ": " + e);
497             throw e;
498         }
499     }
500
501     public void doHealthCheck() {
502         jdbcTemplateObject.execute(HEALTHCHECK);
503     }
504
505     /**
506      * Method to get all models with model properties.
507      * 
508      * @return list of CldsModelProp
509      */
510     public List<CldsModelProp> getAllModelProperties() {
511         List<CldsModelProp> cldsModelPropList = new ArrayList<CldsModelProp>();
512         String modelsSql = "select m.model_id, m.model_name, mp.model_prop_id, mp.model_prop_text FROM model m, model_properties mp"
513                 + " WHERE m.model_prop_id = mp.model_prop_id";
514         List<Map<String, Object>> rows = jdbcTemplateObject.queryForList(modelsSql);
515         CldsModelProp cldsModelProp = null;
516         for (Map<String, Object> row : rows) {
517             cldsModelProp = new CldsModelProp();
518             cldsModelProp.setId((String) row.get("model_id"));
519             cldsModelProp.setName((String) row.get("model_name"));
520             cldsModelProp.setPropId((String) row.get("model_prop_id"));
521             cldsModelProp.setPropText((String) row.get("model_prop_text"));
522             cldsModelPropList.add(cldsModelProp);
523         }
524         return cldsModelPropList;
525     }
526
527 }