Removed below sonar issues:
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / parsers / relationship / RelationshipToURI.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 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
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  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  */
22 package org.onap.aai.parsers.relationship;
23
24 import com.att.eelf.configuration.EELFLogger;
25 import com.att.eelf.configuration.EELFManager;
26 import org.apache.tinkerpop.gremlin.structure.Direction;
27 import org.onap.aai.exceptions.AAIException;
28 import org.onap.aai.introspection.*;
29 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
30 import org.onap.aai.parsers.exceptions.AAIIdentityMapParseException;
31 import org.onap.aai.parsers.exceptions.AmbiguousMapAAIException;
32 import org.onap.aai.parsers.uri.URIParser;
33 import org.onap.aai.schema.enums.ObjectMetadata;
34 import org.onap.aai.serialization.db.AAIDirection;
35 import org.onap.aai.serialization.db.EdgeRule;
36 import org.onap.aai.serialization.db.EdgeRules;
37 import org.onap.aai.serialization.db.EdgeType;
38 import org.onap.aai.workarounds.LegacyURITransformer;
39
40 import javax.ws.rs.core.UriBuilder;
41 import java.io.UnsupportedEncodingException;
42 import java.net.URI;
43 import java.net.URISyntaxException;
44 import java.util.ArrayList;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Optional;
48
49 /**
50  * The Class RelationshipToURI.
51  */
52 public class RelationshipToURI {
53
54         private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RelationshipToURI.class);
55                 
56         private Introspector relationship = null;
57         
58         private Loader loader = null;
59         
60         private ModelType modelType = null;
61         
62         private EdgeRules edgeRules = null;
63         
64         private URI uri = null;
65         
66         private LegacyURITransformer urlTransform = null;
67         
68         /**
69          * Instantiates a new relationship to URI.
70          *
71          * @param loader the loader
72          * @param relationship the relationship
73          * @throws UnsupportedEncodingException the unsupported encoding exception
74          * @throws AAIException the AAI exception
75          */
76         public RelationshipToURI(Loader loader, Introspector relationship) throws UnsupportedEncodingException, AAIException {
77                 this.relationship = relationship;
78                 this.modelType = relationship.getModelType();
79                 this.edgeRules = EdgeRules.getInstance();
80                 this.loader = loader;
81                 this.urlTransform   = LegacyURITransformer.getInstance();
82
83                 this.parse();
84                 
85         }
86         
87         /**
88          * Parses the.
89          * @throws  
90          *
91          * @throws UnsupportedEncodingException the unsupported encoding exception
92          * @throws AAIException the AAI exception
93          */
94         protected void parse() throws AAIException {
95                 String relatedLink = (String)relationship.getValue("related-link");
96                 Optional<URI> result;
97                 try {
98                         if (loader.getVersion().compareTo(Version.v10) >= 0) {
99                                 result = processRelatedLink(relatedLink);
100                                 if (!result.isPresent()) {
101                                         result = processRelationshipData();
102                                 }
103                         } else {
104                                 result = processRelationshipData();
105                                 if (!result.isPresent()) {
106                                         result = processRelatedLink(relatedLink);
107                                 }
108                         }
109                         if (result.isPresent()) {
110                                 this.uri = result.get();
111                         } else {
112                                 throw new AAIIdentityMapParseException("nothing to parse");
113                         }
114                 } catch (AAIException e) { 
115                         throw e;
116                 } catch (Exception e) {
117                         throw new AAIIdentityMapParseException("Could not parse relationship-list object: " + e.getMessage(), e);
118                 }
119
120         }
121
122         private Optional<URI> processRelationshipData() throws AAIException, UnsupportedEncodingException {
123                 Optional<URI> result = Optional.empty();
124                 StringBuilder uriBuilder = new StringBuilder();
125                 List<Object> data = (List<Object>)relationship.getValue("relationship-data");
126                 Introspector wrapper;
127                 String key;
128                 String value;
129                 String objectType;
130                 String propertyName;
131                 String topLevelType = null;
132                 String[] split;
133                 HashMap<String, Introspector> map = new HashMap<>();
134                 for (Object datum : data) {
135                         wrapper = IntrospectorFactory.newInstance(modelType, datum);
136                         key = (String)wrapper.getValue("relationship-key");
137                         value = (String)wrapper.getValue("relationship-value");
138                         split = key.split("\\.");
139                         if (split == null || split.length != 2) {
140                                 throw new AAIIdentityMapParseException("incorrect format for key must be of the form {node-type}.{property-name}");
141                         }
142                         //check node name ok
143                         //check prop name ok
144                         objectType = split[0];
145                         propertyName = split[1];
146
147                         try {
148                                 Introspector wrappedObj = loader.introspectorFromName(objectType);
149
150                                 if (!wrappedObj.hasProperty(propertyName)) {
151                                         throw new AAIIdentityMapParseException("invalid property name in map: " + propertyName);
152                                 }
153                                 if (map.containsKey(objectType)) {
154                                         wrappedObj = map.get(objectType);
155                                 } else {
156                                         map.put(objectType, wrappedObj);
157                                 }
158                                 if (wrappedObj.getValue(propertyName) == null) {
159                                         wrappedObj.setValue(propertyName, value);
160                                 } else {
161                                         throw new AmbiguousMapAAIException("cannot determine where key/value goes: " + propertyName + "/" + value);
162                                 }
163                                 
164                                 if (wrappedObj.getMetadata(ObjectMetadata.NAMESPACE) != null) {
165                                         if (topLevelType == null) {
166                                                 topLevelType = objectType;
167                                         } else if (!topLevelType.equals(objectType)){
168                                                 throw new AmbiguousMapAAIException("found two top level nodes of different types: " + topLevelType + " and " + objectType);
169                                         }
170                                 }
171                         } catch (AAIUnknownObjectException e) {
172                                 throw new AAIIdentityMapParseException("invalid object name in map: " + objectType, e);
173                         }
174                         
175                 }
176                 if (!map.isEmpty()) {
177                         String startType = (String)relationship.getValue("related-to");
178                         List<String> nodeTypes = new ArrayList<>();
179                         nodeTypes.addAll(map.keySet());
180                         
181                         String displacedType;
182                         for (int i = 0; i < nodeTypes.size(); i++) {
183                                 if (nodeTypes.get(i).equals(startType)) {
184                                         displacedType = nodeTypes.set(nodeTypes.size() - 1, startType);
185                                         nodeTypes.set(i, displacedType);
186                                         break;
187                                 }
188                         }
189                         sortRelationships(nodeTypes, startType, 1);
190                         int startTypeIndex = nodeTypes.indexOf(startType);
191                         int topLevelIndex = 0;
192                         if (topLevelType != null) {
193                                 topLevelIndex = nodeTypes.indexOf(topLevelType);
194                         }
195                         //remove additional types not needed if they are there
196                         List<String> nodeTypesSubList = nodeTypes;
197                         if (topLevelIndex != 0) {
198                                 nodeTypesSubList = nodeTypes.subList(topLevelIndex, startTypeIndex+1);
199                         }
200                         for (String type : nodeTypesSubList) {
201                                 uriBuilder.append(map.get(type).getURI());
202                         }
203                         if (!nodeTypesSubList.isEmpty()) {
204                                 result = Optional.of(UriBuilder.fromPath(uriBuilder.toString()).build());
205                         }
206                 }
207                 return result;
208         }
209
210         private Optional<URI> processRelatedLink(String relatedLink) throws URISyntaxException, UnsupportedEncodingException, AAIIdentityMapParseException  {
211                 Optional<URI> result = Optional.empty();
212                 if (relatedLink != null) {
213                         URI resultUri = new URI(relatedLink);
214                         String path = resultUri.toString();
215                         resultUri = UriBuilder.fromPath(resultUri.getRawPath()).build();
216                         URIParser uriParser = new URIParser(this.loader, resultUri);
217                         try {
218                                 uriParser.validate();
219                         } catch (AAIException e) {
220                                 throw new AAIIdentityMapParseException("related link is invalid: " + relatedLink, e);
221                         }
222                         result = Optional.of(resultUri);
223                 }
224                 
225                 return result;
226         }
227         
228         /**
229          * Sort relationships.
230          *
231          * @param data the data
232          * @param startType the start type
233          * @param i the i
234          * @return true, if successful
235          * @throws AAIException 
236          */
237         private boolean sortRelationships(List<String> data, String startType, int i) throws AAIException {
238         
239                 if (i == data.size()) {
240                         return true;
241                 }
242                 int j;
243                 String objectType;
244                 String displacedObject;
245                 EdgeRule rule;
246                 Direction direction;
247                 for (j = (data.size() - i) - 1; j >= 0; j--) {
248                         objectType = data.get(j);
249                         try {
250                                 rule = edgeRules.getEdgeRule(EdgeType.TREE, startType, objectType);
251                                 direction = rule.getDirection();
252                                 if (direction != null) {
253                                         if ((rule.getContains().equals(AAIDirection.OUT.toString()) && direction.equals(Direction.IN)) || (rule.getContains().equals(AAIDirection.IN.toString()) && direction.equals(Direction.OUT))) {
254                                                 displacedObject = data.set((data.size() - i) - 1, data.get(j));
255                                                 data.set(j, displacedObject);
256                                                 if (sortRelationships(data, objectType, i+1)) {
257                                                         return true;
258                                                 } else {
259                                                         //continue to process
260                                                 }
261                                         }
262                                 }
263                         } catch (AAIException e) {
264                                 //ignore exceptions generated
265                                 continue;
266                         }
267                 }
268                 
269
270                 return false;
271         }
272         
273         /**
274          * Gets the uri.
275          *
276          * @return the uri
277          */
278         public URI getUri() {
279                 return uri;
280         }
281         
282 }