2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.be.components.impl;
23 import fj.data.Either;
24 import org.apache.commons.lang3.tuple.ImmutablePair;
25 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
26 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
27 import org.openecomp.sdc.be.model.ComponentInstance;
28 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
29 import org.openecomp.sdc.be.model.Resource;
30 import org.openecomp.sdc.exception.ResponseFormat;
31 import org.springframework.beans.factory.annotation.Autowired;
32 import org.springframework.stereotype.Component;
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.List;
38 import java.util.Map.Entry;
39 import java.util.Optional;
41 import java.util.stream.Collectors;
44 * This class holds the logic of arranging resource instance on the canvas for imported VF
49 @Component("compositionBusinessLogic")
50 public class CompositionBusinessLogic {
52 private ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
54 private static final int VFC_CANVAS_ELEMENT_SIZE = 50;
55 private static final int CP_CANVAS_ELEMENT_SIZE = 21;
56 private static final int CANVAS_WIDTH = 1000;
57 private static final int CANVAS_HEIGHT = 700;
58 private static final int SPACE_BETWEEN_ELEMENTS = VFC_CANVAS_ELEMENT_SIZE * 4;
59 private static final double CP_RADIUS_FACTOR = 0.4;
61 enum RelativePosition {
65 protected Either<List<ComponentInstance>, ResponseFormat> setPositionsForComponentInstances(Resource resource, String userId) {
66 Either<List<ComponentInstance>, ResponseFormat> result = Either.left(resource.getComponentInstances());
68 boolean isNotAllPositionsCalculated = resource.getComponentInstances() == null
69 || resource.getComponentInstances().stream().filter(p -> (p.getPosX() == null || p.getPosX().isEmpty()) || (p.getPosY() == null || p.getPosY().isEmpty())).findAny().isPresent();
71 if (isNotAllPositionsCalculated && resource.getComponentInstances() != null) {
72 // Arrange Icons In Spiral Pattern
73 Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstanceLocations = buildSpiralPatternPositioningForComponentInstances(resource);
75 // Set Relative Locations According to Canvas Size
76 componentInstanceLocations.entrySet().stream().forEach(e -> setRelativePosition(e));
79 result = componentInstanceBusinessLogic.updateComponentInstance(ComponentTypeEnum.RESOURCE_PARAM_NAME, resource.getUniqueId(), userId, resource.getComponentInstances(), false, false);
86 private void setRelativePosition(Entry<ImmutablePair<Double, Double>, ComponentInstance> entry) {
87 int xCenter = CANVAS_WIDTH / 2;
88 int yCenter = CANVAS_HEIGHT / 2;
90 ImmutablePair<Double, Double> matrixPosition = entry.getKey();
91 ComponentInstance componentInstance = entry.getValue();
92 componentInstance.setPosX(calculateCompositionPosition(xCenter, matrixPosition.getLeft(), componentInstance));
93 componentInstance.setPosY(calculateCompositionPosition(yCenter, matrixPosition.getRight(), componentInstance));
96 private String calculateCompositionPosition(int center, double relativePosition, ComponentInstance componentInstance) {
97 final double topLeftCanvasPosition = center + relativePosition * CompositionBusinessLogic.SPACE_BETWEEN_ELEMENTS;
98 double offsetedCanvasPosition;
99 switch (componentInstance.getOriginType()) {
101 offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.CP_CANVAS_ELEMENT_SIZE / 2;
104 offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.CP_CANVAS_ELEMENT_SIZE / 2;
107 offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.VFC_CANVAS_ELEMENT_SIZE / 2;
110 offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.VFC_CANVAS_ELEMENT_SIZE / 2;
113 offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.VFC_CANVAS_ELEMENT_SIZE / 2;
116 offsetedCanvasPosition = topLeftCanvasPosition - CompositionBusinessLogic.VFC_CANVAS_ELEMENT_SIZE / 2;
119 return String.valueOf(offsetedCanvasPosition);
122 protected Map<ImmutablePair<Double, Double>, ComponentInstance> buildSpiralPatternPositioningForComponentInstances(Resource resource) {
124 Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstanceLocations = new HashMap<>();
126 List<ComponentInstance> componentInstances = new ArrayList<>();
127 componentInstances.addAll(resource.getComponentInstances());
128 Map<ComponentInstance, List<ComponentInstance>> connectededCps = getCpsConnectedToVFC(componentInstances, resource);
129 // Remove all cp that are connected from the list
130 componentInstances.removeAll(connectededCps.values().stream().flatMap(e -> e.stream()).collect(Collectors.toList()));
132 buildSpiralPatternForMajorComponents(componentInstanceLocations, componentInstances);
133 buildCirclePatternForCps(componentInstanceLocations, connectededCps);
135 return componentInstanceLocations;
138 protected void buildCirclePatternForCps(Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstLocations, Map<ComponentInstance, List<ComponentInstance>> connectedCps) {
140 for (Entry<ComponentInstance, List<ComponentInstance>> vfcCpList : connectedCps.entrySet()) {
141 Entry<ImmutablePair<Double, Double>, ComponentInstance> vfcOfTheCps = componentInstLocations.entrySet().stream().filter(p -> p.getValue().getUniqueId().equals(vfcCpList.getKey().getUniqueId())).findAny().get();
142 buildCirclePatternForOneGroupOfCps(vfcOfTheCps.getKey(), vfcCpList.getValue(), componentInstLocations);
147 private void buildCirclePatternForOneGroupOfCps(ImmutablePair<Double, Double> vfcLocation, List<ComponentInstance> cpsGroup, Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstLocations) {
148 final int numberOfCps = cpsGroup.size();
149 double angleBetweenCps = (!cpsGroup.isEmpty()) ? Math.toRadians(360) / numberOfCps : 0;
150 double currentAngle = 0;
151 Double xCenter = vfcLocation.getLeft();
152 Double yCenter = vfcLocation.getRight();
153 for (ComponentInstance currCp : cpsGroup) {
154 double cpXposition = xCenter + CompositionBusinessLogic.CP_RADIUS_FACTOR * Math.cos(currentAngle);
155 double cpYposition = yCenter + CompositionBusinessLogic.CP_RADIUS_FACTOR * Math.sin(currentAngle);
156 componentInstLocations.put(new ImmutablePair<Double, Double>(cpXposition, cpYposition), currCp);
157 currentAngle += angleBetweenCps;
162 private void buildSpiralPatternForMajorComponents(Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstanceLocations, List<ComponentInstance> componentInstances) {
163 int elementsCounter = 0;
164 ImmutablePair<Double, Double> currPlacement;
165 ImmutablePair<Double, Double> prevPlacement = null;
166 RelativePosition relationToPrevElement = null;
167 for (ComponentInstance curr : componentInstances) {
169 if (elementsCounter == 1) {
170 currPlacement = new ImmutablePair<Double, Double>(0D, 0D);
171 } else if (elementsCounter == 2) {
172 currPlacement = new ImmutablePair<Double, Double>(-1D, 0D);
173 relationToPrevElement = RelativePosition.LEFT;
175 relationToPrevElement = getRelativePositionForCurrentElement(componentInstanceLocations, relationToPrevElement, prevPlacement);
176 currPlacement = getRelativeElementLocation(prevPlacement, relationToPrevElement);
180 componentInstanceLocations.put(currPlacement, curr);
181 prevPlacement = currPlacement;
185 protected Map<ComponentInstance, List<ComponentInstance>> getCpsConnectedToVFC(List<ComponentInstance> allComponentInstances, Resource vf) {
186 Map<ComponentInstance, List<ComponentInstance>> vfcWithItsCps = new HashMap<>();
187 List<RequirementCapabilityRelDef> allRelations = vf.getComponentInstancesRelations();
188 for (ComponentInstance curr : allComponentInstances) {
190 if (curr.getOriginType() == OriginTypeEnum.CP) {
191 // List Of elements the CP is connected to
192 List<RequirementCapabilityRelDef> connectedToList = allRelations.stream().filter(p -> p.getFromNode().equals(curr.getUniqueId()) || p.getToNode().equals(curr.getUniqueId())).collect(Collectors.toList());
193 // Adds Only CPs Which are connected to VFC
194 filterCpConnectedToVFC(allComponentInstances, vfcWithItsCps, curr, connectedToList);
197 return vfcWithItsCps;
200 private void filterCpConnectedToVFC(List<ComponentInstance> allComponentInstances, Map<ComponentInstance, List<ComponentInstance>> vfcWithItsCps, ComponentInstance currCP, List<RequirementCapabilityRelDef> connectedToTheCPList) {
201 if (!connectedToTheCPList.isEmpty()) {
202 // Set Of Ids Of components Instances which are connected certain CP
203 Set<String> mateIds = connectedToTheCPList.stream().map(cpRelation -> cpRelation.getFromNode().equals(currCP.getUniqueId()) ? cpRelation.getToNode() : cpRelation.getFromNode()).collect(Collectors.toSet());
205 // Vfc Component instance Connected to the CP
206 Optional<ComponentInstance> optionalVfcConnectedToCP = allComponentInstances.stream().
207 // All instances connected to CP
208 filter(p -> mateIds.contains(p.getUniqueId())).
209 // Filter in only VFC connected to the CP
210 filter(p -> p.getOriginType() == OriginTypeEnum.VFC).findAny();
212 if (optionalVfcConnectedToCP.isPresent()) {
213 final ComponentInstance vfcWithCps = optionalVfcConnectedToCP.get();
214 if (vfcWithItsCps.containsKey(vfcWithCps)) {
215 vfcWithItsCps.get(vfcWithCps).add(currCP);
217 List<ComponentInstance> cpsList = new ArrayList<>();
219 vfcWithItsCps.put(vfcWithCps, cpsList);
225 private RelativePosition getRelativePositionForCurrentElement(Map<ImmutablePair<Double, Double>, ComponentInstance> componentInstanceLocations, RelativePosition relationToPrevElement, ImmutablePair<Double, Double> prevPlacement) {
226 switch (relationToPrevElement) {
228 boolean isOccupied = isAdjacentElementOccupied(prevPlacement, RelativePosition.UP, componentInstanceLocations);
229 relationToPrevElement = isOccupied ? RelativePosition.LEFT : RelativePosition.UP;
233 boolean isOccupied = isAdjacentElementOccupied(prevPlacement, RelativePosition.DOWN, componentInstanceLocations);
234 relationToPrevElement = isOccupied ? RelativePosition.RIGHT : RelativePosition.DOWN;
238 boolean isOccupied = isAdjacentElementOccupied(prevPlacement, RelativePosition.RIGHT, componentInstanceLocations);
239 relationToPrevElement = isOccupied ? RelativePosition.UP : RelativePosition.RIGHT;
243 boolean isOccupied = isAdjacentElementOccupied(prevPlacement, RelativePosition.LEFT, componentInstanceLocations);
244 relationToPrevElement = isOccupied ? RelativePosition.DOWN : RelativePosition.LEFT;
248 throw new UnsupportedOperationException();
251 return relationToPrevElement;
254 private boolean isAdjacentElementOccupied(ImmutablePair<Double, Double> currElement, RelativePosition adjacentElementRelationToCurrElement, Map<ImmutablePair<Double, Double>, ComponentInstance> allElements) {
256 ImmutablePair<Double, Double> adjacentElementPosition = getRelativeElementLocation(currElement, adjacentElementRelationToCurrElement);
257 return allElements.containsKey(adjacentElementPosition);
260 private ImmutablePair<Double, Double> getRelativeElementLocation(ImmutablePair<Double, Double> currElement, RelativePosition relativeLocation) {
261 ImmutablePair<Double, Double> relativeElementPosition;
262 switch (relativeLocation) {
265 relativeElementPosition = new ImmutablePair<Double, Double>(currElement.getLeft() - 1, currElement.getRight());
269 relativeElementPosition = new ImmutablePair<Double, Double>(currElement.getLeft() + 1, currElement.getRight());
273 relativeElementPosition = new ImmutablePair<Double, Double>(currElement.getLeft(), currElement.getRight() + 1);
277 relativeElementPosition = new ImmutablePair<Double, Double>(currElement.getLeft(), currElement.getRight() - 1);
281 throw new UnsupportedOperationException();
284 return relativeElementPosition;