2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 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
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.onap.aai.parsers.relationship;
23 import java.io.UnsupportedEncodingException;
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;
31 import jakarta.ws.rs.core.UriBuilder;
33 import org.apache.tinkerpop.gremlin.structure.Direction;
34 import org.onap.aai.config.SpringContextAware;
35 import org.onap.aai.edges.EdgeIngestor;
36 import org.onap.aai.edges.EdgeRule;
37 import org.onap.aai.edges.EdgeRuleQuery;
38 import org.onap.aai.edges.enums.AAIDirection;
39 import org.onap.aai.edges.enums.EdgeType;
40 import org.onap.aai.edges.exceptions.AmbiguousRuleChoiceException;
41 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
42 import org.onap.aai.exceptions.AAIException;
43 import org.onap.aai.introspection.Introspector;
44 import org.onap.aai.introspection.IntrospectorFactory;
45 import org.onap.aai.introspection.Loader;
46 import org.onap.aai.introspection.ModelType;
47 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
48 import org.onap.aai.parsers.exceptions.AAIIdentityMapParseException;
49 import org.onap.aai.parsers.exceptions.AmbiguousMapAAIException;
50 import org.onap.aai.parsers.uri.URIParser;
51 import org.onap.aai.schema.enums.ObjectMetadata;
52 import org.onap.aai.setup.SchemaVersions;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.context.ApplicationContext;
58 * The Class RelationshipToURI.
60 public class RelationshipToURI {
62 private static final Logger LOGGER = LoggerFactory.getLogger(RelationshipToURI.class);
64 private Introspector relationship = null;
66 private Loader loader = null;
68 private ModelType modelType = null;
70 private EdgeIngestor edgeRules = null;
72 private URI uri = null;
74 private SchemaVersions schemaVersions;
77 * Instantiates a new relationship to URI.
79 * @param loader the loader
80 * @param relationship the relationship
81 * @throws UnsupportedEncodingException the unsupported encoding exception
82 * @throws AAIException the AAI exception
84 public RelationshipToURI(Loader loader, Introspector relationship)
85 throws UnsupportedEncodingException, AAIException {
86 this.relationship = relationship;
87 this.modelType = relationship.getModelType();
89 this.initEdgeIngestor();
94 protected void initEdgeIngestor() {
95 // TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
96 ApplicationContext ctx = SpringContextAware.getApplicationContext();
97 edgeRules = ctx.getBean(EdgeIngestor.class);
98 schemaVersions = (SchemaVersions) ctx.getBean("schemaVersions");
106 * @throws UnsupportedEncodingException the unsupported encoding exception
107 * @throws AAIException the AAI exception
109 protected void parse() throws AAIException {
110 String relatedLink = (String) relationship.getValue("related-link");
111 Optional<URI> result;
113 if (loader.getVersion().compareTo(schemaVersions.getRelatedLinkVersion()) >= 0) {
114 result = processRelatedLink(relatedLink);
115 if (result.isEmpty()) {
116 result = processRelationshipData();
119 result = processRelationshipData();
120 if (result.isEmpty()) {
121 result = processRelatedLink(relatedLink);
124 if (result.isPresent()) {
125 this.uri = result.get();
127 throw new AAIIdentityMapParseException("nothing to parse");
129 } catch (AAIException e) {
131 } catch (Exception e) {
132 throw new AAIIdentityMapParseException("Could not parse relationship-list object: " + e.getMessage(), e);
137 private Optional<URI> processRelationshipData() throws AAIException, UnsupportedEncodingException {
138 Optional<URI> result = Optional.empty();
139 StringBuilder uriBuilder = new StringBuilder();
140 List<Object> data = (List<Object>) relationship.getValue("relationship-data");
141 Introspector wrapper;
146 String topLevelType = null;
148 HashMap<String, Introspector> map = new HashMap<>();
149 for (Object datum : data) {
150 wrapper = IntrospectorFactory.newInstance(modelType, datum);
151 key = (String) wrapper.getValue("relationship-key");
152 value = (String) wrapper.getValue("relationship-value");
153 split = key.split("\\.");
154 if (split == null || split.length != 2) {
155 throw new AAIIdentityMapParseException(
156 "incorrect format for key must be of the form {node-type}.{property-name}");
158 // check node name ok
159 // check prop name ok
160 objectType = split[0];
161 propertyName = split[1];
164 Introspector wrappedObj = loader.introspectorFromName(objectType);
166 if (!wrappedObj.hasProperty(propertyName)) {
167 throw new AAIIdentityMapParseException("invalid property name in map: " + propertyName);
169 if (map.containsKey(objectType)) {
170 wrappedObj = map.get(objectType);
172 map.put(objectType, wrappedObj);
174 if (wrappedObj.getValue(propertyName) == null) {
175 wrappedObj.setValue(propertyName, value);
177 throw new AmbiguousMapAAIException(
178 "cannot determine where key/value goes: " + propertyName + "/" + value);
181 if (wrappedObj.getMetadata(ObjectMetadata.NAMESPACE) != null) {
182 if (topLevelType == null) {
183 topLevelType = objectType;
184 } else if (!topLevelType.equals(objectType)) {
185 throw new AmbiguousMapAAIException(
186 "found two top level nodes of different types: " + topLevelType + " and " + objectType);
189 } catch (AAIUnknownObjectException e) {
190 throw new AAIIdentityMapParseException("invalid object name in map: " + objectType, e);
194 if (!map.isEmpty()) {
195 String startType = (String) relationship.getValue("related-to");
196 List<String> nodeTypes = new ArrayList<>();
197 nodeTypes.addAll(map.keySet());
199 String displacedType;
200 for (int i = 0; i < nodeTypes.size(); i++) {
201 if (nodeTypes.get(i).equals(startType)) {
202 displacedType = nodeTypes.set(nodeTypes.size() - 1, startType);
203 nodeTypes.set(i, displacedType);
207 sortRelationships(nodeTypes, startType, 1);
208 int startTypeIndex = nodeTypes.indexOf(startType);
209 int topLevelIndex = 0;
210 if (topLevelType != null) {
211 topLevelIndex = nodeTypes.indexOf(topLevelType);
213 // remove additional types not needed if they are there
214 List<String> nodeTypesSubList = nodeTypes;
215 if (topLevelIndex != 0) {
216 nodeTypesSubList = nodeTypes.subList(topLevelIndex, startTypeIndex + 1);
218 for (String type : nodeTypesSubList) {
219 uriBuilder.append(map.get(type).getURI());
221 if (!nodeTypesSubList.isEmpty()) {
222 result = Optional.of(UriBuilder.fromPath(uriBuilder.toString()).build());
228 private Optional<URI> processRelatedLink(String relatedLink)
229 throws URISyntaxException, UnsupportedEncodingException, AAIIdentityMapParseException {
230 Optional<URI> result = Optional.empty();
231 if (relatedLink != null) {
232 URI resultUri = new URI(relatedLink);
233 String path = resultUri.toString();
234 resultUri = UriBuilder.fromPath(resultUri.getRawPath()).build();
235 URIParser uriParser = new URIParser(this.loader, resultUri);
237 uriParser.validate();
238 } catch (AAIException e) {
239 throw new AAIIdentityMapParseException("related link is invalid: " + relatedLink, e);
241 result = Optional.of(resultUri);
248 * Sort relationships.
250 * @param data the data
251 * @param startType the start type
253 * @return true, if successful
254 * @throws AAIException
256 private boolean sortRelationships(List<String> data, String startType, int i) throws AAIException {
258 if (i == data.size()) {
263 String displacedObject;
266 for (j = (data.size() - i) - 1; j >= 0; j--) {
267 objectType = data.get(j);
270 .getRule(new EdgeRuleQuery.Builder(startType, objectType).edgeType(EdgeType.TREE).build());
271 direction = rule.getDirection();
272 if (direction != null) {
273 if ((rule.getContains().equals(AAIDirection.OUT.toString()) && direction.equals(Direction.IN))
274 || (rule.getContains().equals(AAIDirection.IN.toString())
275 && direction.equals(Direction.OUT))) {
276 displacedObject = data.set((data.size() - i) - 1, data.get(j));
277 data.set(j, displacedObject);
278 if (sortRelationships(data, objectType, i + 1)) {
281 // continue to process
285 } catch (AAIException | EdgeRuleNotFoundException | AmbiguousRuleChoiceException e) {
286 // ignore exceptions generated
299 public URI getUri() {