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