2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 package org.onap.aai.spike.schema;
23 import java.util.HashMap;
26 import com.google.common.base.CaseFormat;
27 import com.google.gson.JsonElement;
28 import com.google.gson.JsonObject;
29 import org.eclipse.persistence.dynamic.DynamicType;
30 import org.eclipse.persistence.internal.helper.DatabaseField;
31 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
32 import org.eclipse.persistence.mappings.DatabaseMapping;
33 import org.eclipse.persistence.oxm.XMLField;
34 import org.onap.aai.cl.eelf.LoggerFactory;
35 import org.onap.aai.spike.event.incoming.GizmoEdge;
36 import org.onap.aai.spike.event.incoming.GizmoGraphEvent;
37 import org.onap.aai.spike.event.incoming.GizmoVertex;
38 import org.onap.aai.spike.exception.SpikeException;
41 * This class is responsible for transforming raw graph entities (such as vertices and edges) into
42 * representations which correspond to the OXM models.
44 public class GraphEventTransformer {
46 private static org.onap.aai.cl.api.Logger logger =
47 LoggerFactory.getInstance().getLogger(GraphEventTransformer.class.getName());
48 private static final String AAI_UUID = "aai-uuid";
53 * @throws SpikeException
55 public static void validateVertexModel(GizmoVertex rawVertex) throws SpikeException {
57 validateVertexModel(OXMModelLoader.getLatestVersion(), rawVertex);
60 public static void populateUUID(GizmoGraphEvent event) throws SpikeException {
62 if (event.getVertex() != null) {
63 if (event.getVertex().getProperties().getAsJsonObject().has(AAI_UUID)) {
65 .setId(event.getVertex().getProperties().getAsJsonObject().get(AAI_UUID).getAsString());
67 } else if (event.getRelationship() != null) {
68 if (event.getRelationship().getProperties().getAsJsonObject().has(AAI_UUID)) {
69 event.getRelationship().setId(
70 event.getRelationship().getProperties().getAsJsonObject().get(AAI_UUID).getAsString());
73 if (event.getRelationship().getSource().getProperties().getAsJsonObject().has(AAI_UUID)) {
74 event.getRelationship().getSource().setId(event.getRelationship().getSource().getProperties()
75 .getAsJsonObject().get(AAI_UUID).getAsString());
77 if (event.getRelationship().getTarget().getProperties().getAsJsonObject().has(AAI_UUID)) {
78 event.getRelationship().getTarget().setId(event.getRelationship().getTarget().getProperties()
79 .getAsJsonObject().get(AAI_UUID).getAsString());
82 } catch (Exception ex) {
83 throw new SpikeException("Unable to parse uuid in incoming event");
91 * @throws SpikeException
93 public static void validateVertexModel(String version, GizmoVertex rawVertex) throws SpikeException {
97 DynamicJAXBContext jaxbContext = OXMModelLoader.getContextForVersion(version);
98 String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,
99 CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, rawVertex.getType()));
100 final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass);
101 final DynamicType reservedType = jaxbContext.getDynamicType("ReservedPropNames");
103 Set<Map.Entry<String, JsonElement>> vertexEntriesSet =
104 rawVertex.getProperties().getAsJsonObject().entrySet();
105 Map<String, JsonElement> vertexEntriesMap = new HashMap<String, JsonElement>();
106 for (Map.Entry<String, JsonElement> entry : vertexEntriesSet) {
107 vertexEntriesMap.put(entry.getKey(), entry.getValue());
110 JsonObject modelJsonElement = new JsonObject();
111 // Iterate over all of the attributes specified in the model schema,
113 // our dynamic instance with the corresponding values supplied in
115 for (DatabaseMapping mapping : modelObjectType.getDescriptor().getMappings()) {
116 if (mapping.isAbstractDirectMapping()) {
117 DatabaseField f = mapping.getField();
118 String keyName = f.getName().substring(0, f.getName().indexOf("/"));
120 String defaultValue = mapping.getProperties().get("defaultValue") == null ? ""
121 : mapping.getProperties().get("defaultValue").toString();
123 if (((XMLField) f).isRequired() && !vertexEntriesMap.containsKey(keyName)
124 && !defaultValue.isEmpty()) {
125 modelJsonElement.addProperty(keyName, defaultValue);
128 // If this is a required field, but is not present in the
129 // raw vertex, reject this
130 // as an invalid input since we can't build a valid object
131 // from what we were provided.
132 if (((XMLField) f).isRequired() && !vertexEntriesMap.containsKey(keyName)
133 && defaultValue.isEmpty()) {
134 throw new SpikeException("Missing required field: " + keyName);
137 // If this is a non-required field, then set it if a value
138 // was provided in the
140 if (vertexEntriesMap.containsKey(keyName)) {
141 validateFieldType(vertexEntriesMap.get(keyName), f.getType());
142 modelJsonElement.add(keyName, vertexEntriesMap.get(keyName));
147 // Ensure any of the reserved properties are added to the payload
148 for (DatabaseMapping mapping : reservedType.getDescriptor().getMappings()) {
149 if (mapping.isAbstractDirectMapping()) {
150 DatabaseField field = mapping.getField();
151 String keyName = field.getName().substring(0, field.getName().indexOf("/"));
153 if (vertexEntriesMap.containsKey(keyName)) {
154 validateFieldType(vertexEntriesMap.get(keyName), field.getType());
155 modelJsonElement.add(keyName, vertexEntriesMap.get(keyName));
160 rawVertex.setProperties(modelJsonElement);
161 } catch (Exception e) {
162 throw new SpikeException(e.getMessage());
169 * @throws SpikeException
171 public static void validateEdgeModel(GizmoEdge rawEdge) throws SpikeException {
173 validateEdgeModel(EdgeRulesLoader.getLatestSchemaVersion(), rawEdge);
180 * @throws SpikeException
182 public static void validateEdgeModel(String version, GizmoEdge rawEdge) throws SpikeException {
184 if (logger.isDebugEnabled()) {
185 logger.debug("Convert edge: " + rawEdge.toString() + " to model version: " + version);
188 // Get the relationship schema for the supplied version.
189 RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
193 // Validate that our edge does have the necessary endpoints.
194 if (rawEdge.getSource() == null || rawEdge.getTarget() == null) {
195 throw new SpikeException("Source or target endpoint not specified");
198 // Create a key based on source:target:relationshipType
199 String sourceNodeType = rawEdge.getSource().getType();
200 String targetNodeType = rawEdge.getTarget().getType();
201 String key = sourceNodeType + ":" + targetNodeType + ":" + rawEdge.getType();
203 // Now, look up the specific schema model based on the key we just
205 Map<String, Class<?>> relationshipModel = schema.lookupRelation(key);
206 if (relationshipModel == null || relationshipModel.isEmpty()) {
207 throw new SpikeException("Invalid source/target/relationship type: " + key);
210 Set<Map.Entry<String, JsonElement>> edgeEntriesSet = rawEdge.getProperties().getAsJsonObject().entrySet();
211 Map<String, JsonElement> edgeEntriesMap = new HashMap<String, JsonElement>();
212 for (Map.Entry<String, JsonElement> entry : edgeEntriesSet) {
213 edgeEntriesMap.put(entry.getKey(), entry.getValue());
216 JsonObject modelJsonElement = new JsonObject();
218 for (String property : relationshipModel.keySet()) {
220 if (!edgeEntriesMap.containsKey(property)) {
221 throw new SpikeException("Missing required field: " + property);
224 validateFieldType(edgeEntriesMap.get(property), relationshipModel.get(property));
225 modelJsonElement.add(property, edgeEntriesMap.get(property));
229 rawEdge.setProperties(modelJsonElement);
232 } catch (Exception ex) {
233 throw new SpikeException(ex.getMessage());
237 @SuppressWarnings("unchecked")
238 public static Object validateFieldType(JsonElement value, Class clazz) throws SpikeException {
240 if (clazz.isAssignableFrom(Integer.class)) {
241 return value.getAsInt();
242 } else if (clazz.isAssignableFrom(Long.class)) {
243 return value.getAsLong();
244 } else if (clazz.isAssignableFrom(Float.class)) {
245 return value.getAsFloat();
246 } else if (clazz.isAssignableFrom(Double.class)) {
247 return value.getAsDouble();
248 } else if (clazz.isAssignableFrom(Boolean.class)) {
249 return value.getAsBoolean();
254 } catch (Exception e) {
255 throw new SpikeException("Invalid property value: " + value);
259 public static Object validateFieldType(String value, Class clazz) throws SpikeException {
261 if (clazz.isAssignableFrom(Integer.class)) {
262 return Integer.parseInt(value);
263 } else if (clazz.isAssignableFrom(Long.class)) {
264 return Long.parseLong(value);
265 } else if (clazz.isAssignableFrom(Float.class)) {
266 return Float.parseFloat(value);
267 } else if (clazz.isAssignableFrom(Double.class)) {
268 return Double.parseDouble(value);
269 } else if (clazz.isAssignableFrom(Boolean.class)) {
270 if (!value.equals("true") && !value.equals("false")) {
271 throw new SpikeException("Invalid property value: " + value);
273 return Boolean.parseBoolean(value);
277 } catch (Exception e) {
278 throw new SpikeException("Invalid property value: " + value);