public static void buildDeleteNotification(
     OJAnnotatedClass owner, OJAnnotatedOperation delete, PropertyWrapper propertyWrapper) {
   OJIfStatement ifChanged = new OJIfStatement();
   ifChanged.setCondition("true");
   PropertyWrapper otherEnd = PropertyWrapper.from(propertyWrapper.getOtherEnd());
   if (otherEnd.isMany()) {
     OJForStatement forStatement =
         new OJForStatement(
             otherEnd.getName(), otherEnd.javaBaseTypePath(), "this." + otherEnd.getter() + "()");
     forStatement
         .getBody()
         .addToStatements(constructNotifierForOtherEndMany(propertyWrapper, otherEnd));
     delete.getBody().addToStatements(0, forStatement);
   } else {
     ifChanged.addToThenPart(constructNotifier(propertyWrapper));
     delete.getBody().addToStatements(0, ifChanged);
   }
   owner.addToImports(
       UmlgClassOperations.getPathName(propertyWrapper.getOwningType())
           .append(UmlgClassOperations.propertyEnumName(propertyWrapper.getOwningType())));
   owner.addToImports(UmlgGenerationUtil.UmlgNotificationManager);
   owner.addToImports(UmlgGenerationUtil.ChangeHolder);
   owner.addToImports(UmlgGenerationUtil.ChangeHolder);
   owner.addToImports("java.util.Optional");
 }
 private static void buildGetAssociationClassForPropertyInstance(
     OJAnnotatedClass owner, PropertyWrapper propertyWrapper) {
   OJAnnotatedOperation getAC =
       new OJAnnotatedOperation(
           propertyWrapper.associationClassGetterForProperty(),
           propertyWrapper.getAssociationClassPathName());
   getAC.addParam(propertyWrapper.fieldname(), propertyWrapper.javaBaseTypePath());
   OJForStatement forAC =
       new OJForStatement(
           "ac",
           propertyWrapper.getAssociationClassPathName(),
           "this." + propertyWrapper.getAssociationClassFakePropertyName());
   OJIfStatement ifStatement =
       new OJIfStatement(
           "ac." + propertyWrapper.getter() + "().equals(" + propertyWrapper.fieldname() + ")",
           "return ac");
   forAC.getBody().addToStatements(ifStatement);
   getAC.getBody().addToStatements(forAC);
   getAC.getBody().addToStatements("return null");
   owner.addToOperations(getAC);
 }
  private void addPostObjectRepresentation(PropertyWrapper pWrap, OJAnnotatedClass annotatedClass) {

    OJAnnotatedOperation post =
        new OJAnnotatedOperation("post", UmlgRestletGenerationUtil.Representation);
    post.addToParameters(new OJParameter("entity", UmlgRestletGenerationUtil.Representation));
    post.addToThrows(UmlgRestletGenerationUtil.ResourceException);
    annotatedClass.addToImports(UmlgRestletGenerationUtil.ResourceException);
    UmlgGenerationUtil.addOverrideAnnotation(post);
    UmlgGenerationUtil.addSuppressWarning(post);

    PropertyWrapper otherEndPWrap = new PropertyWrapper(pWrap.getOtherEnd());

    OJPathName parentPathName = otherEndPWrap.javaBaseTypePath();
    post.getBody()
        .addToStatements(
            "this."
                + parentPathName.getLast().toLowerCase()
                + "Id = "
                + UmlgRestletGenerationUtil.UmlgURLDecoder.getLast()
                + ".decode((String)getRequestAttributes().get(\""
                + parentPathName.getLast().toLowerCase()
                + "Id\"))");
    annotatedClass.addToImports(UmlgRestletGenerationUtil.UmlgURLDecoder);

    post.getBody()
        .addToStatements(
            parentPathName.getLast()
                + " parentResource = "
                + UmlgGenerationUtil.UMLGAccess
                + "."
                + UmlgGenerationUtil.getEntity
                + "("
                + parentPathName.getLast().toLowerCase()
                + "Id"
                + ")");

    OJTryStatement ojTryStatement = new OJTryStatement();
    OJField mapper = new OJField("mapper", UmlgGenerationUtil.ObjectMapper);
    mapper.setInitExp(
        UmlgGenerationUtil.ObjectMapperFactory.getLast() + ".INSTANCE.getObjectMapper()");
    annotatedClass.addToImports(UmlgGenerationUtil.ObjectMapperFactory);
    ojTryStatement.getTryPart().addToLocals(mapper);

    OJPathName pathName =
        new OJPathName("java.util.Map").addToGenerics("String").addToGenerics("Object");
    OJAnnotatedField entityText = new OJAnnotatedField("entityText", "String");
    entityText.setInitExp("entity.getText()");
    ojTryStatement.getTryPart().addToLocals(entityText);

    OJField resultMap =
        new OJField(
            "resultMap",
            new OJPathName("java.util.Map")
                .addToGenerics(
                    new OJPathName("Class<? extends " + pWrap.javaBaseTypePath().getLast() + ">"))
                .addToGenerics(
                    "List<" + UmlgRestletGenerationUtil.UmlgNodeJsonHolder.getLast() + ">"));
    resultMap.setInitExp(
        "new HashMap<Class<? extends "
            + pWrap.javaBaseTypePath().getLast()
            + ">, List<"
            + UmlgRestletGenerationUtil.UmlgNodeJsonHolder.getLast()
            + ">>()");
    annotatedClass.addToImports("java.util.HashMap");
    annotatedClass.addToImports("java.util.List");
    annotatedClass.addToImports(UmlgRestletGenerationUtil.UmlgNodeJsonHolder);
    ojTryStatement.getTryPart().addToLocals(resultMap);

    ojTryStatement
        .getTryPart()
        .addToStatements(
            pathName.getLast()
                + " overloaded = mapper.readValue("
                + entityText.getName()
                + ", Map.class)");
    ojTryStatement.getTryPart().addToStatements("Object o = overloaded.get(\"insert\")");

    // Insert
    OJIfStatement ifInsert = new OJIfStatement("o != null");
    OJIfStatement ifArrayForInsert = new OJIfStatement("o instanceof ArrayList");
    OJPathName genericsForArray =
        new OJPathName("java.util.Map").addToGenerics("String").addToGenerics("Object");
    OJField array =
        new OJField("array", new OJPathName("java.util.List").addToGenerics(genericsForArray));
    array.setInitExp("(ArrayList<Map<String, Object>>)o");
    ifArrayForInsert.getThenPart().addToLocals(array);
    ifInsert.addToThenPart(ifArrayForInsert);

    ojTryStatement.getTryPart().addToStatements(ifInsert);
    OJForStatement forArray =
        new OJForStatement(
            "overloadedJsonMap",
            new OJPathName("java.util.Map")
                .addToGenerics(new OJPathName("String"))
                .addToGenerics(new OJPathName("Object")),
            "array");
    ifArrayForInsert.addToThenPart(forArray);
    forArray.getBody().addToStatements("add(resultMap, parentResource, overloadedJsonMap)");

    OJField map =
        new OJField(
            "overloadedJsonMap",
            new OJPathName("java.util.Map").addToGenerics("String").addToGenerics("Object"));
    map.setInitExp("(Map<String, Object>) o");
    ifArrayForInsert.setElsePart(new OJBlock());
    ifArrayForInsert.getElsePart().addToLocals(map);
    ifArrayForInsert
        .getElsePart()
        .addToStatements("add(resultMap, parentResource, overloadedJsonMap)");

    addPostResource(pWrap, annotatedClass, parentPathName);

    // Delete
    ojTryStatement.getTryPart().addToStatements("o = overloaded.get(\"delete\")");
    OJIfStatement ifDelete = new OJIfStatement("o != null");
    OJIfStatement ifArrayForDelete = new OJIfStatement("o instanceof ArrayList");
    genericsForArray =
        new OJPathName("java.util.Map").addToGenerics("String").addToGenerics("Object");
    array =
        new OJField("array", new OJPathName("java.util.ArrayList").addToGenerics(genericsForArray));
    array.setInitExp("(ArrayList<Map<String, Object>>)o");
    ifArrayForDelete.getThenPart().addToLocals(array);
    ifDelete.addToThenPart(ifArrayForDelete);
    ojTryStatement.getTryPart().addToStatements(ifDelete);
    forArray =
        new OJForStatement(
            "map",
            new OJPathName("java.util.Map")
                .addToGenerics(new OJPathName("String"))
                .addToGenerics(new OJPathName("Object")),
            "array");
    ifArrayForDelete.addToThenPart(forArray);
    if (pWrap.isComposite()) {
      forArray.getBody().addToStatements("delete(map)");
    } else {
      forArray.getBody().addToStatements("delete(parentResource, map)");
    }

    map =
        new OJField(
            "map", new OJPathName("java.util.Map").addToGenerics("String").addToGenerics("Object"));
    map.setInitExp("(Map<String, Object>) o");
    ifArrayForDelete.setElsePart(new OJBlock());
    ifArrayForDelete.getElsePart().addToLocals(map);
    if (pWrap.isComposite()) {
      ifArrayForDelete.getElsePart().addToStatements("delete(map)");
    } else {
      ifArrayForDelete.getElsePart().addToStatements("delete(parentResource, map)");
    }
    addDeleteResource(pWrap, annotatedClass, parentPathName);

    // Update
    ojTryStatement.getTryPart().addToStatements("o = overloaded.get(\"update\")");
    OJIfStatement ifUpdate = new OJIfStatement("o != null");
    OJIfStatement ifArrayForUpdate = new OJIfStatement("o instanceof ArrayList");
    genericsForArray =
        new OJPathName("java.util.Map").addToGenerics("String").addToGenerics("Object");
    array =
        new OJField("array", new OJPathName("java.util.ArrayList").addToGenerics(genericsForArray));
    array.setInitExp("(ArrayList<Map<String, Object>>)o");
    ifArrayForUpdate.getThenPart().addToLocals(array);
    ifUpdate.addToThenPart(ifArrayForUpdate);
    ojTryStatement.getTryPart().addToStatements(ifUpdate);

    forArray =
        new OJForStatement(
            "overloadedJsonMap",
            new OJPathName("java.util.Map")
                .addToGenerics(new OJPathName("String"))
                .addToGenerics(new OJPathName("Object")),
            "array");
    ifArrayForUpdate.addToThenPart(forArray);
    if (pWrap.isOrdered()) {
      forArray.getBody().addToStatements("put(resultMap, parentResource, overloadedJsonMap)");
    } else {
      forArray.getBody().addToStatements("put(resultMap, overloadedJsonMap)");
    }
    map =
        new OJField(
            "overloadedJsonMap",
            new OJPathName("java.util.Map").addToGenerics("String").addToGenerics("Object"));
    map.setInitExp("(Map<String, Object>) o");
    ifArrayForUpdate.setElsePart(new OJBlock());
    ifArrayForUpdate.getElsePart().addToLocals(map);

    if (pWrap.isOrdered()) {
      // Include the parent as it will be needed to add the child at a particular index
      ifArrayForUpdate
          .getElsePart()
          .addToStatements("put(resultMap, parentResource, overloadedJsonMap)");
    } else {
      ifArrayForUpdate.getElsePart().addToStatements("put(resultMap, overloadedJsonMap)");
    }

    addPutResource(pWrap, annotatedClass, parentPathName);

    // Check if transaction needs commiting
    commitOrRollback(ojTryStatement);

    OJBlock jsonResultBlock = new OJBlock();
    ojTryStatement.getTryPart().addToStatements(jsonResultBlock);

    OJField result = new OJField("result", "java.lang.StringBuilder");
    result.setInitExp("new StringBuilder(\"[\")");
    jsonResultBlock.addToLocals(result);
    OJField count = new OJField("count", "int");
    count.setInitExp("1");
    jsonResultBlock.addToLocals(count);

    OJForStatement forConcreteClassifiers =
        new OJForStatement(
            "baseClass",
            new OJPathName("Class")
                .addToGenerics("? extends " + pWrap.javaBaseTypePath().getLast()),
            "resultMap.keySet()");
    jsonResultBlock.addToStatements(forConcreteClassifiers);
    if (pWrap.isOne()) {
      forConcreteClassifiers.getBody().addToStatements("result.append(\"{\\\"data\\\": \")");
    } else {
      forConcreteClassifiers.getBody().addToStatements("result.append(\"{\\\"data\\\": [\")");
    }
    OJField objectList =
        new OJField(
            "objectList",
            new OJPathName("java.util.List")
                .addToGenerics(UmlgRestletGenerationUtil.UmlgNodeJsonHolder));
    objectList.setInitExp("resultMap.get(baseClass)");
    forConcreteClassifiers.getBody().addToLocals(objectList);

    OJField objectListCount = new OJField("objectListCount", new OJPathName("int"));
    objectListCount.setInitExp("1");
    forConcreteClassifiers.getBody().addToLocals(objectListCount);

    OJForStatement forObjectList =
        new OJForStatement("object", UmlgRestletGenerationUtil.UmlgNodeJsonHolder, "objectList");
    forObjectList.getBody().addToStatements("result.append(object.toJson())");
    OJIfStatement ifObjectListCountSmallerThanSize =
        new OJIfStatement("objectListCount++ < objectList.size()", "result.append(\",\")");
    forObjectList.getBody().addToStatements(ifObjectListCountSmallerThanSize);
    forConcreteClassifiers.getBody().addToStatements(forObjectList);

    if (pWrap.isOne()) {
      forConcreteClassifiers.getBody().addToStatements("result.append(\",\")");
    } else {
      forConcreteClassifiers.getBody().addToStatements("result.append(\"],\")");
    }
    forConcreteClassifiers.getBody().addToStatements("result.append(\" \\\"meta\\\" : {\")");
    forConcreteClassifiers
        .getBody()
        .addToStatements(
            "result.append(\"\\\"qualifiedName\\\": \\\"" + pWrap.getQualifiedName() + "\\\"\")");
    forConcreteClassifiers.getBody().addToStatements("result.append(\", \\\"to\\\": \")");

    OJIfStatement ifClassInstanceOf = null;
    Set<Classifier> concreteImplementations =
        UmlgClassOperations.getConcreteImplementations((Classifier) pWrap.getType());
    if (!concreteImplementations.isEmpty()) {
      ifClassInstanceOf = new OJIfStatement();
      forConcreteClassifiers.getBody().addToStatements(ifClassInstanceOf);
    }
    boolean first = true;
    for (Classifier concreteImplementation : concreteImplementations) {
      OJBlock ojIfBlock;
      if (first) {
        first = false;
        ifClassInstanceOf.setCondition(
            "baseClass.equals("
                + UmlgClassOperations.getPathName(concreteImplementation).getLast()
                + ".class)");
        ojIfBlock = ifClassInstanceOf.getThenPart();
      } else {
        ojIfBlock =
            ifClassInstanceOf.addToElseIfCondition(
                "baseClass.equals("
                    + UmlgClassOperations.getPathName(concreteImplementation).getLast()
                    + ".class)",
                "");
      }
      ojIfBlock.addToStatements(
          "result.append("
              + UmlgClassOperations.propertyEnumName(concreteImplementation)
              + ".asJson())");
      annotatedClass.addToImports(
          UmlgClassOperations.getPathName(concreteImplementation)
              .append(UmlgClassOperations.propertyEnumName(concreteImplementation)));

      ojIfBlock.addToStatements("result.append(\", \\\"from\\\": \")");
      Classifier owningType = (Classifier) pWrap.getOwningType();
      ojIfBlock.addToStatements(
          "result.append(" + UmlgClassOperations.propertyEnumName(owningType) + ".asJson())");
      annotatedClass.addToImports(
          UmlgClassOperations.getPathName(owningType)
              .append(UmlgClassOperations.propertyEnumName(owningType)));
      ojIfBlock.addToStatements("result.append(\"}\")");
    }

    OJIfStatement ifLast = new OJIfStatement("count++ == resultMap.size()");
    ifLast.addToThenPart("result.append(\"}\")");
    ifLast.addToElsePart("result.append(\"},\")");
    forConcreteClassifiers.getBody().addToStatements(ifLast);

    if (!concreteImplementations.isEmpty()) {
      ifClassInstanceOf.addToElsePart(
          "throw new IllegalStateException(\"Unknown type \" + baseClass.getName())");
    }
    jsonResultBlock.addToStatements("result.append(\"]\")");
    jsonResultBlock.addToStatements(
        "return new "
            + UmlgRestletGenerationUtil.JsonRepresentation.getLast()
            + "(result.toString())");

    ojTryStatement.setCatchParam(new OJParameter("e", new OJPathName("java.lang.Exception")));
    ojTryStatement.getCatchPart().addToStatements(UmlgGenerationUtil.UMLGAccess + ".rollback()");

    ojTryStatement
        .getCatchPart()
        .addToStatements(
            "throw "
                + UmlgRestletGenerationUtil.UmlgExceptionUtilFactory.getLast()
                + ".getTumlExceptionUtil().handle(e)");
    annotatedClass.addToImports(UmlgRestletGenerationUtil.UmlgExceptionUtilFactory);

    post.getBody().addToStatements(ojTryStatement);

    annotatedClass.addToImports(parentPathName);

    annotatedClass.addToImports(UmlgGenerationUtil.UMLGPathName);
    annotatedClass.addToImports(UmlgRestletGenerationUtil.JsonRepresentation);
    annotatedClass.addToOperations(post);
  }
  public static void buildManyAdder(
      OJAnnotatedClass owner,
      PropertyWrapper propertyWrapper,
      boolean indexed,
      boolean ignoreInverse) {
    OJAnnotatedOperation adder = new OJAnnotatedOperation(propertyWrapper.adder());
    if (!propertyWrapper.isMemberOfAssociationClass()) {
      if (indexed) {
        adder.addParam("index", "int");
      }
      adder.addParam(propertyWrapper.fieldname(), propertyWrapper.javaTypePath());
    } else {
      if (indexed) {
        adder.addParam("index", "int");
      }
      adder.addParam(
          propertyWrapper.getAssociationClassFakePropertyName(),
          propertyWrapper.javaTypePathWithAssociationClass());
    }

    if (!(owner instanceof OJAnnotatedInterface)) {
      if (!propertyWrapper.hasQualifiers()) {
        if (!propertyWrapper.isMemberOfAssociationClass()) {
          OJIfStatement ifNotNull =
              new OJIfStatement("!" + propertyWrapper.fieldname() + ".isEmpty()");
          ifNotNull.addToThenPart(
              "this."
                  + propertyWrapper.fieldname()
                  + ".addAll("
                  + propertyWrapper.fieldname()
                  + ")");
          adder.getBody().addToStatements(ifNotNull);
        } else {
          // iterate the association class set as it contains a Pair
          OJForStatement associationClassPairs =
              new OJForStatement(
                  "pair",
                  propertyWrapper.getAssociationClassPair(),
                  propertyWrapper.getAssociationClassFakePropertyName());
          associationClassPairs
              .getBody()
              .addToStatements(propertyWrapper.adder() + "(pair.getFirst(), pair.getSecond())");
          adder.getBody().addToStatements(associationClassPairs);
        }
      } else {
        String elementName = "_" + propertyWrapper.fieldname().substring(0, 1);
        OJForStatement forAll =
            new OJForStatement(
                elementName, propertyWrapper.javaBaseTypePath(), propertyWrapper.fieldname());
        forAll
            .getBody()
            .addToStatements("this." + propertyWrapper.adder() + "(" + elementName + ")");
        adder.getBody().addToStatements(forAll);
      }
    }
    owner.addToOperations(adder);

    OJAnnotatedOperation singleAdder =
        new OJAnnotatedOperation(
            !ignoreInverse ? propertyWrapper.adder() : propertyWrapper.adderIgnoreInverse());
    if (indexed) {
      singleAdder.addParam("index", "int");
    }
    singleAdder.addParam(propertyWrapper.fieldname(), propertyWrapper.javaBaseTypePath());
    if (propertyWrapper.isMemberOfAssociationClass()) {
      singleAdder.addParam(
          StringUtils.uncapitalize(propertyWrapper.getAssociationClass().getName()),
          UmlgClassOperations.getPathName(propertyWrapper.getAssociationClass()));
    }
    if (!(owner instanceof OJAnnotatedInterface)) {

      PropertyWrapper otherEnd = new PropertyWrapper(propertyWrapper.getOtherEnd());
      if (
      /*For bags the one side can have many edges to the same element*/ propertyWrapper.isUnique()
          && propertyWrapper.hasOtherEnd()
          && !propertyWrapper.isEnumeration()
          && otherEnd.isOne()) {
        OJIfStatement ifNotNull2 = new OJIfStatement(propertyWrapper.fieldname() + " != null");
        ifNotNull2.addToThenPart(propertyWrapper.fieldname() + "." + otherEnd.clearer() + "()");
        ifNotNull2.addToThenPart(
            propertyWrapper.fieldname()
                + ".initialiseProperty("
                + UmlgClassOperations.propertyEnumName(otherEnd.getOwningType())
                + "."
                + otherEnd.fieldname()
                + ", false)");
        ifNotNull2.addToThenPart(
            propertyWrapper.remover() + "(" + propertyWrapper.fieldname() + ")");
        owner.addToImports(
            UmlgClassOperations.getPathName(otherEnd.getOwningType())
                .append(UmlgClassOperations.propertyEnumName(otherEnd.getOwningType())));
        singleAdder.getBody().addToStatements(ifNotNull2);
      }
      OJIfStatement ifNotNull = new OJIfStatement(propertyWrapper.fieldname() + " != null");

      // Add in validations

      OJBlock block;
      if (propertyWrapper.isDataType()) {
        OJField failedConstraints =
            new OJField(
                "violations",
                new OJPathName("java.util.List")
                    .addToGenerics(UmlgGenerationUtil.UmlgConstraintViolation));
        failedConstraints.setInitExp(
            propertyWrapper.validator() + "(" + propertyWrapper.fieldname() + ")");
        ifNotNull.getThenPart().addToLocals(failedConstraints);
        OJIfStatement ifValidated = new OJIfStatement("violations.isEmpty()");
        ifValidated.addToElsePart(
            "throw new "
                + UmlgGenerationUtil.UmlgConstraintViolationException.getLast()
                + "(violations)");
        owner.addToImports(UmlgGenerationUtil.UmlgConstraintViolationException);
        ifNotNull.addToThenPart(ifValidated);
        block = ifValidated.getThenPart();
      } else {
        block = ifNotNull.getThenPart();
      }

      if (!propertyWrapper.isMemberOfAssociationClass()) {
        if (!indexed) {
          if (!ignoreInverse) {
            block.addToStatements(
                "this."
                    + propertyWrapper.fieldname()
                    + ".add("
                    + propertyWrapper.fieldname()
                    + ")");
          } else {
            block.addToStatements(
                "this."
                    + propertyWrapper.fieldname()
                    + ".addIgnoreInverse("
                    + propertyWrapper.fieldname()
                    + ")");
          }
        } else {
          block.addToStatements(
              "this."
                  + propertyWrapper.fieldname()
                  + ".add(index, "
                  + propertyWrapper.fieldname()
                  + ")");
        }
      } else {
        if (!indexed) {
          block.addToStatements(
              "this."
                  + propertyWrapper.fieldname()
                  + ".add("
                  + propertyWrapper.fieldname()
                  + ", "
                  + StringUtils.uncapitalize(propertyWrapper.getAssociationClass().getName())
                  + ")");
        } else {
          block.addToStatements(
              "this."
                  + propertyWrapper.fieldname()
                  + ".add(index, "
                  + propertyWrapper.fieldname()
                  + ", "
                  + StringUtils.uncapitalize(propertyWrapper.getAssociationClass().getName())
                  + ")");
        }
      }
      singleAdder.getBody().addToStatements(ifNotNull);
    }
    owner.addToOperations(singleAdder);

    //        //Add change listener
    //        if (propertyWrapper.isChangedListener()) {
    //            PropertyChangeNotificationBuilder.buildChangeNotification(owner, singleAdder,
    // propertyWrapper, PropertyChangeNotificationBuilder.CHANGE_TYPE.ADD);
    //        }

  }