942bc43fd8f5f4e41fca521d1a3906a69321f4c9
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License 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
21 package org.openecomp.sdc.healing.impl;
22
23 import org.openecomp.core.utilities.CommonMethods;
24 import org.openecomp.core.utilities.file.FileUtils;
25 import org.openecomp.core.utilities.json.JsonUtil;
26 import org.openecomp.sdc.common.errors.CoreException;
27 import org.openecomp.sdc.common.errors.ErrorCategory;
28 import org.openecomp.sdc.common.errors.ErrorCode;
29 import org.openecomp.sdc.common.errors.Messages;
30 import org.openecomp.sdc.common.session.SessionContextProviderFactory;
31 import org.openecomp.sdc.datatypes.model.ItemType;
32 import org.openecomp.sdc.healing.api.HealingManager;
33 import org.openecomp.sdc.healing.dao.HealingDao;
34 import org.openecomp.sdc.healing.interfaces.Healer;
35 import org.openecomp.sdc.healing.types.HealerType;
36 import org.openecomp.sdc.versioning.VersioningManager;
37 import org.openecomp.sdc.versioning.dao.types.Version;
38 import org.openecomp.sdc.versioning.dao.types.VersionStatus;
39 import org.openecomp.sdc.versioning.types.VersionCreationMethod;
40
41 import java.util.Collection;
42 import java.util.LinkedList;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Objects;
46 import java.util.Optional;
47 import java.util.stream.Collectors;
48 import java.util.stream.Stream;
49
50 public class HealingManagerImpl implements HealingManager {
51
52   private static final String HEALERS_BY_ENTITY_TYPE_FILE = "entityHealingConfiguration.json";
53   private static final String HEALING_USER_SUFFIX = "_healer";
54   private static final String PUBLIC_USER = "public";
55
56   private HealingDao healingDao;
57   private VersioningManager versioningManager;
58
59   public HealingManagerImpl(VersioningManager versioningManager, HealingDao healingDao) {
60     this.versioningManager = versioningManager;
61     this.healingDao = healingDao;
62   }
63
64   @Override
65   public Optional<Version> healItemVersion(final String itemId, final Version version,
66                                            final ItemType itemType, final boolean force) {
67     String user = getUser();
68     if (!force && !isPrivateHealingNeededByFlags(itemId, version.getId(), user)) {
69       return Optional.empty();
70     }
71
72     Map<String, Collection<String>> healersByType = getItemHealers(itemType);
73     List<String> failureMessages = new LinkedList<>();
74     List<Healer> structureHealersToRun =
75         getHealersToRun(healersByType.get(HealerType.structure.name()), itemId, version,
76             failureMessages);
77     List<Healer> dataHealersToRun =
78         getHealersToRun(healersByType.get(HealerType.data.name()), itemId, version,
79             failureMessages);
80
81     if (structureHealersToRun.isEmpty() && dataHealersToRun.isEmpty()) {
82       markAsHealed(itemId, version.getId(), user);
83       markAsHealed(itemId, version.getId(), PUBLIC_USER);
84       return Optional.empty();
85     }
86
87     Optional<Version> healVersion = getHealVersion(itemId, version);
88     if (!healVersion.isPresent()) {
89       // do NOT turn off flag here (in thought of saving version calculate performance next
90       // time) because maybe next time the next version will be available (due to deletion of
91       // the taken one)
92       return Optional.empty();
93     }
94
95     failureMessages.addAll(
96         doHeal(itemId, healVersion.get(), version, structureHealersToRun, dataHealersToRun, user,
97             force));
98     handleFailures(failureMessages);
99
100     return healVersion;
101   }
102
103   private Optional<Version> getHealVersion(String itemId, Version version) {
104     version.setStatus(versioningManager.get(itemId, version).getStatus());
105     return version.getStatus() == VersionStatus.Certified
106         ? createNewVersion(itemId, version.getId())
107         : Optional.of(version);
108   }
109
110   private Optional<Version> createNewVersion(String itemId, String versionId) {
111     Version newVersion = new Version();
112     newVersion.setBaseId(versionId);
113     newVersion.setDescription("Version is created by healing process");
114     try {
115       return Optional.of(versioningManager.create(itemId, newVersion, VersionCreationMethod.major));
116     } catch (Exception e) {
117       return Optional.empty();
118     }
119   }
120
121   private List<String> doHeal(String itemId, Version version, Version origVersion,
122                               List<Healer> structureHealersToRun,
123                               List<Healer> dataHealersToRun, String user,
124                               boolean force) {
125     List<String> failureMessages =
126         force || origVersion.getStatus() == VersionStatus.Certified ||
127             isPublicHealingNeededByFlag(itemId, origVersion.getId())
128             ? healPublic(itemId, version, origVersion, structureHealersToRun, dataHealersToRun,
129             user)
130             : new LinkedList<>();
131
132     failureMessages.addAll(
133         healPrivate(itemId, version, origVersion, structureHealersToRun, dataHealersToRun, user));
134
135     return failureMessages;
136   }
137
138   private List<String> healPrivate(String itemId, Version version, Version origVersion,
139                                    List<Healer> structureHealersToRun,
140                                    List<Healer> dataHealersToRun, String user) {
141     List<String> failureMessages;
142     if (origVersion.getStatus() == VersionStatus.Certified) {
143       failureMessages = executeHealers(itemId, version,
144           Stream.concat(structureHealersToRun.stream(), dataHealersToRun.stream())
145               .collect(Collectors.toList()));
146     } else {
147       if (structureHealersToRun.isEmpty()) {
148         failureMessages = executeHealers(itemId, version, dataHealersToRun);
149       } else {
150         versioningManager.forceSync(itemId, version);
151         failureMessages = new LinkedList<>();
152       }
153     }
154     markAsHealed(itemId, origVersion.getId(), user);
155     return failureMessages;
156   }
157
158   private List<String> healPublic(String itemId, Version version, Version origVersion,
159                                   List<Healer> structureHealersToRun,
160                                   List<Healer> dataHealersToRun, String user) {
161     List<String> failureMessages = origVersion.getStatus() == VersionStatus.Certified
162         ? new LinkedList<>()
163         : healPublic(itemId, version,
164             Stream.concat(structureHealersToRun.stream(), dataHealersToRun.stream())
165                 .collect(Collectors.toList()), user);
166
167     markAsHealed(itemId, origVersion.getId(), PUBLIC_USER);
168     return failureMessages;
169   }
170
171   private List<String> healPublic(String itemId, Version version, List<Healer> healers,
172                                   String user) {
173     String tenant = SessionContextProviderFactory.getInstance().createInterface().get().getTenant();
174     SessionContextProviderFactory.getInstance().createInterface()
175         .create(user + HEALING_USER_SUFFIX, tenant);
176
177     versioningManager.forceSync(itemId, version);
178
179     List<String> failureMessages = executeHealers(itemId, version, healers);
180     Version publicVersion = versioningManager.get(itemId, version);
181
182     if (Objects.nonNull(publicVersion.getState()) && publicVersion.getState().isDirty()) {
183       versioningManager.publish(itemId, version, "Healing vsp");
184     }
185
186     SessionContextProviderFactory.getInstance().createInterface().create(user, tenant);
187     return failureMessages;
188   }
189
190   private List<String> executeHealers(String itemId, Version version, List<Healer> healers) {
191     List<String> failureMessages = new LinkedList<>();
192     for (Healer healer : healers) {
193       try {
194         healer.heal(itemId, version);
195       } catch (Exception e) {
196         failureMessages.add(
197             String.format("Failure in healer %s: %s", healer.getClass().getName(), e.getMessage()));
198       }
199     }
200
201     return failureMessages;
202   }
203
204   private boolean isPrivateHealingNeededByFlags(String itemId, String version, String user) {
205     Optional<Boolean> userHealingFlag = getHealingFlag(itemId, version, user);
206     return userHealingFlag.orElseGet(() -> isPublicHealingNeededByFlag(itemId, version));
207   }
208
209   private boolean isPublicHealingNeededByFlag(String itemId, String versionId) {
210     Optional<Boolean> publicHealingFlag = getHealingFlag(itemId, versionId, PUBLIC_USER);
211     return publicHealingFlag.isPresent() && publicHealingFlag.get();
212   }
213
214   private Optional<Boolean> getHealingFlag(String itemId, String version, String user) {
215     return healingDao.getItemHealingFlag(user, itemId, version);
216   }
217
218   private void markAsHealed(String itemId, String versionId, String user) {
219     healingDao.setItemHealingFlag(false, user, itemId, versionId);
220   }
221
222   private void handleFailures(List<String> failureMessages) {
223     if (!failureMessages.isEmpty()) {
224       throw new CoreException(new ErrorCode.ErrorCodeBuilder()
225           .withCategory(ErrorCategory.APPLICATION)
226           .withMessage(CommonMethods.listToSeparatedString(failureMessages, '\n')).build());
227     }
228   }
229
230   private List<Healer> getHealersToRun(Collection<String> healersClassNames, String itemId,
231                                        Version version, List<String> failureMessages) {
232     return healersClassNames.stream()
233         .map(healerClassName -> getHealerInstance(healerClassName, failureMessages))
234         .filter(Optional::isPresent)
235         .map(Optional::get)
236         .filter(healer -> healer.isHealingNeeded(itemId, version))
237         .collect(Collectors.toList());
238   }
239
240   private Optional<Healer> getHealerInstance(String healerClassName, List<String> failureMessages) {
241     try {
242       return Optional.of((Healer) Class.forName(healerClassName).getConstructor().newInstance());
243     } catch (Exception e) {
244       failureMessages
245           .add(String.format(Messages.CANT_LOAD_HEALING_CLASS.getErrorMessage(), healerClassName));
246       return Optional.empty();
247     }
248   }
249
250   private Map<String, Collection<String>> getItemHealers(ItemType itemType) {
251     Map healingConfig = FileUtils
252         .readViaInputStream(HEALERS_BY_ENTITY_TYPE_FILE,
253             stream -> JsonUtil.json2Object(stream, Map.class));
254     return (Map<String, Collection<String>>) healingConfig.get(itemType.name());
255   }
256
257   private String getUser() {
258     return SessionContextProviderFactory.getInstance().createInterface().get().getUser()
259         .getUserId();
260   }
261 }