9fb6ebd8b8b9d586edfe15a0f37ce3d5913ad400
[sdc.git] /
1 /*
2  * Copyright © 2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.openecomp.sdcrests.item.rest.services;
17
18 import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
19 import static javax.ws.rs.core.Response.Status.NOT_FOUND;
20 import static org.openecomp.sdc.itempermissions.notifications.NotificationConstants.PERMISSION_USER;
21 import static org.openecomp.sdc.versioning.VersioningNotificationConstansts.ITEM_ID;
22 import static org.openecomp.sdc.versioning.VersioningNotificationConstansts.ITEM_NAME;
23
24 import com.google.common.annotations.VisibleForTesting;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.EnumMap;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Optional;
33 import java.util.Set;
34 import java.util.function.Predicate;
35 import java.util.stream.Collectors;
36 import javax.annotation.PostConstruct;
37 import javax.inject.Named;
38 import javax.ws.rs.core.Response;
39 import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity;
40 import org.openecomp.sdc.activitylog.dao.type.ActivityType;
41 import org.openecomp.sdc.be.csar.storage.StorageFactory;
42 import org.openecomp.sdc.common.errors.ErrorCode.ErrorCodeBuilder;
43 import org.openecomp.sdc.common.errors.ErrorCodeAndMessage;
44 import org.openecomp.sdc.datatypes.model.ItemType;
45 import org.openecomp.sdc.itempermissions.impl.types.PermissionTypes;
46 import org.openecomp.sdc.logging.api.Logger;
47 import org.openecomp.sdc.logging.api.LoggerFactory;
48 import org.openecomp.sdc.notification.dtos.Event;
49 import org.openecomp.sdc.versioning.dao.types.Version;
50 import org.openecomp.sdc.versioning.dao.types.VersionStatus;
51 import org.openecomp.sdc.versioning.types.Item;
52 import org.openecomp.sdc.versioning.types.ItemStatus;
53 import org.openecomp.sdc.versioning.types.NotificationEventTypes;
54 import org.openecomp.sdcrests.item.rest.Items;
55 import org.openecomp.sdcrests.item.rest.mapping.MapItemToDto;
56 import org.openecomp.sdcrests.item.rest.models.SyncEvent;
57 import org.openecomp.sdcrests.item.rest.services.catalog.notification.NotifierFactory;
58 import org.openecomp.sdcrests.item.types.ItemAction;
59 import org.openecomp.sdcrests.item.types.ItemActionRequestDto;
60 import org.openecomp.sdcrests.item.types.ItemDto;
61 import org.openecomp.sdcrests.wrappers.GenericCollectionWrapper;
62 import org.springframework.context.annotation.Scope;
63 import org.springframework.stereotype.Service;
64 import org.springframework.validation.annotation.Validated;
65
66 @Named
67 @Service("items")
68 @Scope(value = "prototype")
69 @Validated
70 public class ItemsImpl implements Items {
71
72     private static final String ONBOARDING_METHOD = "onboardingMethod";
73     private static final Logger LOGGER = LoggerFactory.getLogger(ItemsImpl.class);
74     private Map<ItemAction, ActionSideAffects> actionSideAffectsMap = new EnumMap<>(ItemAction.class);
75     private ManagersProvider managersProvider;
76
77     @PostConstruct
78     public void initActionSideAffectsMap() {
79         actionSideAffectsMap.put(ItemAction.ARCHIVE, new ActionSideAffects(ActivityType.Archive, NotificationEventTypes.ARCHIVE));
80         actionSideAffectsMap.put(ItemAction.RESTORE, new ActionSideAffects(ActivityType.Restore, NotificationEventTypes.RESTORE));
81     }
82
83     @Override
84     public Response actOn(final ItemActionRequestDto request, final String itemId, final String user) {
85         final var item = getManagersProvider().getItemManager().get(itemId);
86         if (item == null) {
87             return Response.status(NOT_FOUND).entity(new Exception("Item does not exist.")).build();
88         }
89         final var action = request.getAction();
90         switch (action) {
91             case ARCHIVE:
92                 getManagersProvider().getItemManager().archive(item);
93                 break;
94             case RESTORE:
95                 if (ItemType.vsp.getName().equalsIgnoreCase(item.getType())) {
96                     final var artifactStorageManager = new StorageFactory().createArtifactStorageManager();
97                     if (artifactStorageManager.isEnabled() && !artifactStorageManager.exists(itemId)) {
98                         LOGGER.error("Unable to restore partially deleted item '{}'", itemId);
99                         final var errorCode =
100                             new ErrorCodeBuilder().withId(INTERNAL_SERVER_ERROR.name()).withMessage("Unable to restore partially deleted VSP, re-try VSP deletion").build();
101                         return Response.status(INTERNAL_SERVER_ERROR).entity(new ErrorCodeAndMessage(INTERNAL_SERVER_ERROR, errorCode)).build();
102                     }
103                 }
104                 getManagersProvider().getItemManager().restore(item);
105                 break;
106             default:
107         }
108         actionSideAffectsMap.get(action).execute(item, user);
109         try {
110             NotifierFactory.getInstance().execute(Collections.singleton(itemId), action);
111         } catch (Exception e) {
112             LOGGER.error("Failed to send catalog notification on item {}", itemId, e);
113         }
114         return Response.ok().build();
115     }
116
117     @Override
118     public Response list(String itemStatusFilter, String versionStatusFilter, String itemTypeFilter, String permissionFilter,
119                          String onboardingMethodFilter, String user) {
120         Predicate<Item> itemPredicate = createItemPredicate(itemStatusFilter, versionStatusFilter, itemTypeFilter, onboardingMethodFilter,
121             permissionFilter, user);
122         GenericCollectionWrapper<ItemDto> results = new GenericCollectionWrapper<>();
123         MapItemToDto mapper = new MapItemToDto();
124         getManagersProvider().getItemManager().list(itemPredicate).stream()
125             .sorted((o1, o2) -> o2.getModificationTime().compareTo(o1.getModificationTime()))
126             .forEach(item -> results.add(mapper.applyMapping(item, ItemDto.class)));
127         return Response.ok(results).build();
128     }
129
130     @Override
131     public Response getItem(String itemId, String user) {
132         Item item = getManagersProvider().getItemManager().get(itemId);
133         ItemDto itemDto = new MapItemToDto().applyMapping(item, ItemDto.class);
134         return Response.ok(itemDto).build();
135     }
136
137     private Predicate<Item> createItemPredicate(String itemStatusFilter, String versionStatusFilter, String itemTypeFilter,
138                                                 String onboardingMethodFilter, String permissionsFilter, String user) {
139         Predicate<Item> itemPredicate = item -> true;
140         if (itemStatusFilter != null) {
141             validateItemStatusValue(itemStatusFilter);
142             itemPredicate = itemPredicate.and(createItemStatusPredicate(itemStatusFilter));
143         }
144         if (versionStatusFilter != null) {
145             validateVersionStatusValue(versionStatusFilter);
146             itemPredicate = itemPredicate.and(createVersionStatusPredicate(versionStatusFilter));
147         }
148         if (itemTypeFilter != null) {
149             validateItemTypeValue(itemTypeFilter);
150             itemPredicate = itemPredicate.and(createItemTypePredicate(itemTypeFilter));
151         }
152         if (onboardingMethodFilter != null) {
153             validateOnboardingMethodValue(onboardingMethodFilter);
154             itemPredicate = itemPredicate.and(createOnboardingMethodPredicate(onboardingMethodFilter));
155         }
156         if (permissionsFilter != null) {
157             validatePermissionValue(permissionsFilter);
158             itemPredicate = itemPredicate.and(createPermissionsPredicate(user, permissionsFilter));
159         }
160         return itemPredicate;
161     }
162
163     private String formatFilter(String filterValue) {
164         return filterValue.replace(",", "|");
165     }
166
167     private Predicate<Item> createItemStatusPredicate(String filterValue) {
168         return item -> item.getStatus().name().matches(formatFilter(filterValue));
169     }
170
171     private Predicate<Item> createVersionStatusPredicate(String filterValue) {
172         Set<VersionStatus> versionStatuses = Arrays.stream(filterValue.split(",")).map(VersionStatus::valueOf).collect(Collectors.toSet());
173         return item -> item.getVersionStatusCounters().keySet().stream().anyMatch(versionStatuses::contains);
174     }
175
176     private Predicate<Item> createItemTypePredicate(String filterValue) {
177         return item -> item.getType().matches(formatFilter(filterValue));
178     }
179
180     private Predicate<Item> createOnboardingMethodPredicate(String filterValue) {
181         return item -> !ItemType.vsp.name().equals(item.getType()) || ((String) item.getProperties().get(ONBOARDING_METHOD))
182             .matches(formatFilter(filterValue));
183     }
184
185     private Predicate<Item> createPermissionsPredicate(String user, String filterValue) {
186         String[] permissions = filterValue.split(",");
187         Set<String> itemIds = new HashSet<>();
188         for (String permission : permissions) {
189             itemIds.addAll(getManagersProvider().getPermissionsManager().listUserPermittedItems(user, permission));
190         }
191         return item -> itemIds.contains(item.getId());
192     }
193
194     private void validateItemStatusValue(String itemStatusFilter) {
195         String[] values = itemStatusFilter.split(",");
196         for (String value : values) {
197             ItemStatus.valueOf(value);
198         }
199     }
200
201     private void validateVersionStatusValue(String versionStatusFilter) {
202         String[] values = versionStatusFilter.split(",");
203         for (String value : values) {
204             VersionStatus.valueOf(value);
205         }
206     }
207
208     private void validateItemTypeValue(String itemTypeFilter) {
209         String[] values = itemTypeFilter.split(",");
210         for (String value : values) {
211             ItemType.valueOf(value);
212         }
213     }
214
215     private void validateOnboardingMethodValue(String onboardingMethodFilter) {
216         String[] values = onboardingMethodFilter.split(",");
217         for (String value : values) {
218             OnboardingMethod.valueOf(value);
219         }
220     }
221
222     private void validatePermissionValue(String permissionsFilter) {
223         String[] values = permissionsFilter.split(",");
224         for (String value : values) {
225             PermissionTypes.valueOf(value);
226         }
227     }
228
229     @VisibleForTesting
230     Map<ItemAction, ActionSideAffects> getActionSideAffectsMap() {
231         return actionSideAffectsMap;
232     }
233
234     private ManagersProvider getManagersProvider() {
235         if (managersProvider == null) {
236             managersProvider = new ManagersProvider();
237         }
238         return managersProvider;
239     }
240
241     @VisibleForTesting
242     void setManagersProvider(ManagersProvider managersProvider) {
243         this.managersProvider = managersProvider;
244     }
245
246     //Do not delete - is in use, duplicates code to prevent dependency on openecomp-sdc-vendor-software-product-api
247     private enum OnboardingMethod {NetworkPackage, Manual}
248
249     private class ActionSideAffects {
250
251         private ActivityType activityType;
252         private NotificationEventTypes notificationType;
253
254         private ActionSideAffects(ActivityType activityType, NotificationEventTypes notificationType) {
255             this.activityType = activityType;
256             this.notificationType = notificationType;
257         }
258
259         private Version getLatestVersion(String itemId) {
260             List<Version> list = getManagersProvider().getVersioningManager().list(itemId);
261             Optional<Version> max = list.stream().max(Version::compareTo);
262             return max.orElse(null);
263         }
264
265         private void execute(Item item, String user) {
266             notifyUsers(item.getId(), item.getName(), user, this.notificationType);
267             getManagersProvider().getActivityLogManager()
268                 .logActivity(new ActivityLogEntity(item.getId(), getLatestVersion(item.getId()), this.activityType, user, true, "", ""));
269         }
270
271         private void notifyUsers(String itemId, String itemName, String userName, NotificationEventTypes eventType) {
272             Map<String, Object> eventProperties = new HashMap<>();
273             eventProperties.put(ITEM_NAME, itemName == null ? getManagersProvider().getItemManager().get(itemId).getName() : itemName);
274             eventProperties.put(ITEM_ID, itemId);
275             eventProperties.put(PERMISSION_USER, userName);
276             Event syncEvent = new SyncEvent(eventType.getEventName(), itemId, eventProperties, itemId);
277             try {
278                 getManagersProvider().getNotificationPropagationManager().notifySubscribers(syncEvent, userName);
279             } catch (Exception e) {
280                 LOGGER.error("Failed to send sync notification to users subscribed to item '{}'", itemId, e);
281             }
282         }
283     }
284 }