Apply multiplicity Rule upon Edge creation
[aai/gizmo.git] / src / main / java / org / onap / schema / validation / RelationshipSchemaValidator.java
  * limitations under the License.
  * ============LICENSE_END=========================================================
  */
-package org.onap.schema;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonNull;
+package org.onap.schema.validation;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.ws.rs.core.Response.Status;
 import org.onap.crud.entity.Edge;
 import org.onap.crud.entity.Vertex;
 import org.onap.crud.exception.CrudException;
-import org.onap.crud.service.EdgePayload;
+import org.onap.crud.parser.EdgePayload;
+import org.onap.crud.parser.util.EdgePayloadUtil;
 import org.onap.crud.util.CrudServiceUtil;
-import org.onap.schema.OxmModelValidator.Metadata;
+import org.onap.schema.EdgeRulesLoader;
+import org.onap.schema.RelationshipSchema;
+import org.onap.schema.validation.OxmModelValidator.Metadata;
 import org.radeox.util.logging.Logger;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.ws.rs.core.Response.Status;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
 
 public class RelationshipSchemaValidator {
 
-  public static final String SOURCE_NODE = "source";
-  public static final String TARGET_NODE = "target";
-
-  final static Pattern urlPattern = Pattern.compile("services/inventory/(.*)/(.*)/(.*)");
-
-  public static Map<String, Object> resolveCollectionfilter(String version, String type,
-                                                            Map<String, String> filter)
-      throws CrudException {
+  private static final String SOURCE_LABEL = "Source";
+  private static final String TARGET_LABEL = "Target";
 
+  public static Map<String, Object> resolveCollectionfilter(String version, String type, Map<String, String> filter) throws CrudException {
     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
     if (schema == null) {
       throw new CrudException("", Status.NOT_FOUND);
@@ -64,19 +59,15 @@ public class RelationshipSchemaValidator {
           Object value = CrudServiceUtil.validateFieldType(filter.get(key), props.get(key));
           result.put(key, value);
         } catch (Exception ex) {
-          // Skip any exceptions thrown while validating the filter
-          // key value
+          // Skip any exceptions thrown while validating the filter key value
           continue;
         }
       }
     }
-
     return result;
-
   }
 
   public static void validateType(String version, String type) throws CrudException {
-
     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
     if (!schema.isValidType(type)) {
       throw new CrudException("Invalid " + RelationshipSchema.SCHEMA_RELATIONSHIP_TYPE
@@ -86,17 +77,16 @@ public class RelationshipSchemaValidator {
 
   }
 
-  public static Edge validateIncomingAddPayload(String version, String type, Vertex sourceNode,
-                                                Vertex targetNode, JsonElement properties)
-      throws CrudException {
-    EdgePayload payload = new EdgePayload();
-    payload.setSource("services/inventory/" + version + "/" + sourceNode.getType()
-        + "/" + sourceNode.getId().get());
-    payload.setTarget("services/inventory/" + version + "/" + targetNode.getType()
-        + "/" + targetNode.getId().get());
-    payload.setType(type);
-    payload.setProperties(properties);
-    return validateIncomingAddPayload(version, type, payload);
+  public static Edge validateIncomingAddPayload(String version, String type, EdgePayload payload,
+    List<Edge> sourceVertexEdges, List<Edge> targetVertexEdges) throws CrudException {
+
+    //perform standard validation
+    Edge edge = validateIncomingAddPayload(version, type, payload);
+
+    // validate payload using multiplicity edge rules
+    MultiplicityValidator.validatePayloadMultiplicity(payload, sourceVertexEdges, targetVertexEdges, type, version);
+
+    return edge;
   }
 
   public static Edge validateIncomingAddPayload(String version, String type, EdgePayload payload)
@@ -104,49 +94,28 @@ public class RelationshipSchemaValidator {
     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
 
     try {
-
       if (payload.getSource() == null || payload.getTarget() == null) {
         throw new CrudException("Source/Target not specified", Status.BAD_REQUEST);
       }
 
-      Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
-      Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
-
-      if (!sourceMatcher.matches() || !targetMatcher.matches()) {
-        throw new CrudException("Invalid Source/Target Urls", Status.BAD_REQUEST);
-      }
-
-      // create key based on source:target:relationshipType
-      String sourceNodeType = sourceMatcher.group(2);
-      String targetNodeType = targetMatcher.group(2);
-
-      String sourceNodeId = sourceMatcher.group(3);
-      String targetNodeId = targetMatcher.group(3);
-
-      String key = sourceNodeType + ":" + targetNodeType + ":" + type;
+      String key = EdgePayloadUtil.generateEdgeKey(payload.getSource(), payload.getTarget(), type);
 
       // find the validate the key from the schema
       Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
 
       if (schemaObject == null) {
-        throw new CrudException("Invalid source/target/relationship type: " + key,
-            Status.BAD_REQUEST);
+        throw new CrudException("Invalid source/target/relationship type: " + key, Status.BAD_REQUEST);
       }
 
-      Edge.Builder modelEdgeBuilder = new Edge.Builder(type);
-
-      modelEdgeBuilder.source(new Vertex.Builder(sourceNodeType).id(sourceNodeId).build());
-      modelEdgeBuilder.target(new Vertex.Builder(targetNodeType).id(targetNodeId).build());
+      Edge.Builder modelEdgeBuilder = EdgePayloadUtil.getBuilderFromEdgePayload(payload.getSource(), payload.getTarget(), type);
 
       // validate it properties
       validateEdgeProps(modelEdgeBuilder, payload.getProperties(), schemaObject);
 
       return modelEdgeBuilder.build();
     } catch (Exception ex) {
-
       throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
     }
-
   }
 
   public static Edge validateIncomingPatchPayload(Edge edge, String version, EdgePayload payload)
@@ -154,42 +123,20 @@ public class RelationshipSchemaValidator {
     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
 
     try {
-      if (payload.getSource() != null) {
-        Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
-
-        if (!sourceMatcher.matches()) {
-          throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
-        }
-        String sourceNodeId = sourceMatcher.group(3);
-        if (!sourceNodeId.equals(edge.getSource().getId().get())) {
-          throw new CrudException("Source can't be updated", Status.BAD_REQUEST);
-        }
-      }
-
-      if (payload.getTarget() != null) {
-        Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
+      validateEdgeVertexMatchesPayload(edge.getSource(), payload.getSource(), SOURCE_LABEL);
+      validateEdgeVertexMatchesPayload(edge.getTarget(), payload.getTarget(), TARGET_LABEL);
 
-        if (!targetMatcher.matches()) {
-          throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
-        }
-        String sourceNodeId = targetMatcher.group(3);
-        if (!sourceNodeId.equals(edge.getTarget().getId().get())) {
-          throw new CrudException("Target can't be updated", Status.BAD_REQUEST);
-        }
-      }
-      
       // Remove the timestamp properties from the existing edge, as these should be managed by Champ.
       Map<String,Object> existingProps = edge.getProperties();
-      
+
       if (existingProps.containsKey(Metadata.CREATED_TS.propertyName())) {
         existingProps.remove(Metadata.CREATED_TS.propertyName());
       }
       if (existingProps.containsKey(Metadata.UPDATED_TS.propertyName())) {
         existingProps.remove(Metadata.UPDATED_TS.propertyName());
       }
-      
-      // create key based on source:target:relationshipType
 
+      // create key based on source:target:relationshipType
       String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
           + ":" + edge.getType();
 
@@ -202,43 +149,40 @@ public class RelationshipSchemaValidator {
         return edge;
       }
 
-      Set<Map.Entry<String, JsonElement>> entries = payload.getProperties()
-          .getAsJsonObject().entrySet();
+      validateEdgePropertiesFromPayload(edge, payload, schemaObject);
 
-      for (Map.Entry<String, JsonElement> entry : entries) {
+      return edge;
+    } catch (Exception ex) {
+      throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
+    }
+  }
 
-        if (!schemaObject.containsKey(entry.getKey())) {
-          throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
-        } else if (entry.getValue() instanceof JsonNull && edge.getProperties()
-            .containsKey(entry.getKey())) {
-          edge.getProperties().remove(entry.getKey());
-        } else if (!(entry.getValue() instanceof JsonNull)) {
-          Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(),
-              schemaObject.get(entry.getKey()));
-          edge.getProperties().put(entry.getKey(), value);
-        }
+  private static void validateEdgePropertiesFromPayload(Edge edge, EdgePayload payload, Map<String, Class<?>> schemaObject) throws CrudException {
+    Set<Map.Entry<String, JsonElement>> entries = payload.getProperties().getAsJsonObject().entrySet();
+    for (Map.Entry<String, JsonElement> entry : entries) {
 
+      if (!schemaObject.containsKey(entry.getKey())) {
+        throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
+      } else if (entry.getValue() instanceof JsonNull && edge.getProperties().containsKey(entry.getKey())) {
+        edge.getProperties().remove(entry.getKey());
+      } else if (!(entry.getValue() instanceof JsonNull)) {
+        Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(), schemaObject.get(entry.getKey()));
+        edge.getProperties().put(entry.getKey(), value);
       }
+    }
+  }
 
-      return edge;
 
-    } catch (Exception ex) {
+  public static Edge validateIncomingUpdatePayload(Edge edge, String version, EdgePayload payload, String type,
+            List<Edge> sourceVertexEdges, List<Edge> targetVertexEdges) throws CrudException {
 
-      throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
-    }
-  }
+    //perform standard validation
+    Edge validatedEdge = validateIncomingUpdatePayload(edge, version, payload);
 
-  public static Edge validateIncomingUpdatePayload(Edge edge, String version, Vertex sourceNode,
-                                                   Vertex targetNode, JsonElement properties)
-      throws CrudException {
-    EdgePayload payload = new EdgePayload();
-    payload.setSource("services/inventory/" + version + "/" + sourceNode.getType()
-        + "/" + sourceNode.getId().get());
-    payload.setTarget("services/inventory/" + version + "/" + targetNode.getType()
-        + "/" + targetNode.getId().get());
-    payload.setType(edge.getType());
-    payload.setProperties(properties);
-    return validateIncomingUpdatePayload(edge, version, payload);
+    // validate payload using multiplicity edge rules
+    MultiplicityValidator.validatePayloadMultiplicity(payload, sourceVertexEdges, targetVertexEdges, type, version);
+
+    return validatedEdge;
   }
 
   public static Edge validateIncomingUpdatePayload(Edge edge, String version, EdgePayload payload)
@@ -246,32 +190,10 @@ public class RelationshipSchemaValidator {
     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
 
     try {
+      validateEdgeVertexMatchesPayload(edge.getSource(), payload.getSource(), SOURCE_LABEL);
+      validateEdgeVertexMatchesPayload(edge.getTarget(), payload.getTarget(), TARGET_LABEL);
 
-      if (payload.getSource() != null) {
-        Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
-
-        if (!sourceMatcher.matches()) {
-          throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
-        }
-        String sourceNodeId = sourceMatcher.group(3);
-        if (!sourceNodeId.equals(edge.getSource().getId().get())) {
-          throw new CrudException("Source can't be updated", Status.BAD_REQUEST);
-        }
-      }
-
-      if (payload.getTarget() != null) {
-        Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
-
-        if (!targetMatcher.matches()) {
-          throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
-        }
-        String sourceNodeId = targetMatcher.group(3);
-        if (!sourceNodeId.equals(edge.getTarget().getId().get())) {
-          throw new CrudException("Target can't be updated", Status.BAD_REQUEST);
-        }
-      }
       // create key based on source:target:relationshipType
-
       String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
           + ":" + edge.getType();
 
@@ -284,32 +206,29 @@ public class RelationshipSchemaValidator {
         return edge;
       }
 
-      Edge.Builder updatedEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId().get());
-
-      updatedEdgeBuilder
-          .source(new Vertex.Builder(edge.getSource().getType()).id(edge.getSource().getId()
-              .get()).build());
-      updatedEdgeBuilder
-          .target(new Vertex.Builder(edge.getTarget().getType()).id(edge.getTarget().getId()
-              .get()).build());
+      Edge.Builder updatedEdgeBuilder = EdgePayloadUtil.getBuilderFromEdge(edge);
 
       validateEdgeProps(updatedEdgeBuilder, payload.getProperties(), schemaObject);
 
       return updatedEdgeBuilder.build();
     } catch (Exception ex) {
-
       throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
     }
   }
 
+  private static void validateEdgeVertexMatchesPayload(Vertex edgeVertex, String payloadVertex, String vertexTypeLabel) throws CrudException {
+    if (payloadVertex != null) {
+      String sourceNodeId = EdgePayloadUtil.getVertexNodeId(payloadVertex);
+      if (!sourceNodeId.equals(edgeVertex.getId().get())) {
+        throw new CrudException(vertexTypeLabel + " can't be updated", Status.BAD_REQUEST);
+      }
+    }
+  }
 
-  private static void validateEdgeProps(Edge.Builder builder, JsonElement props,
-                                        Map<String, Class<?>> schemaObject)
-      throws CrudException {
+  private static void validateEdgeProps(Edge.Builder builder, JsonElement props, Map<String, Class<?>> schemaObject) throws CrudException {
     Set<Map.Entry<String, JsonElement>> entries = props.getAsJsonObject().entrySet();
 
     for (Map.Entry<String, JsonElement> entry : entries) {
-
       if (!schemaObject.containsKey(entry.getKey())) {
         throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
       } else {
@@ -317,13 +236,10 @@ public class RelationshipSchemaValidator {
             schemaObject.get(entry.getKey()));
         builder.property(entry.getKey(), value);
       }
-
     }
-
   }
 
   public static Edge validateOutgoingPayload(String version, Edge edge) throws CrudException {
-
     Edge.Builder modelEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId()
         .get()).source(edge.getSource())
         .target(edge.getTarget());
@@ -346,16 +262,4 @@ public class RelationshipSchemaValidator {
     }
     return modelEdgeBuilder.build();
   }
-
-    
-  public static String vertexTypeFromUri(String uri) throws CrudException {
-      
-    Matcher matcher = urlPattern.matcher(uri);
-
-    if (!matcher.matches()) {
-      throw new CrudException("Invalid Source/Target Urls", Status.BAD_REQUEST);
-    }
-
-    return matcher.group(2);
-  }
 }