Beispiel #1
0
 private void addLookupEndpoints(SwaggerModel swaggerModel, Entity entity, Locale locale) {
   for (Lookup lookup : entity.getLookupsExposedByRest()) {
     String lookupUrl =
         ClassName.restLookupUrl(
             entity.getName(), entity.getModule(), entity.getNamespace(), lookup.getMethodName());
     swaggerModel.addPathEntry(lookupUrl, HttpMethod.GET, lookupPathEntry(entity, lookup, locale));
   }
 }
Beispiel #2
0
  private static void assertRelationshipIsHistoryCompatible(
      Field field, RelationshipHolder holder, List<Entity> allEntities) {
    Entity relatedEntity = findEntityByName(holder.getRelatedClass(), allEntities);

    if (!hasCorrectTrackingSettings(field, relatedEntity, holder)) {
      String relatedClassName = relatedEntity == null ? "null" : relatedEntity.getClassName();
      throw new InvalidEntitySettingsException(field.getEntity().getClassName(), relatedClassName);
    }
  }
Beispiel #3
0
  private static Entity findEntityByName(String name, List<Entity> allEntities) {
    for (Entity entity : allEntities) {
      if (entity.getClassName().equals(name)) {
        return entity;
      }
    }

    return null;
  }
Beispiel #4
0
 private Response lookupResponse(Entity entity, Lookup lookup, Locale locale) {
   if (lookup.isSingleObjectReturn()) {
     return new ResponseWithSchema(
         msg(locale, RESPONSE_SINGLE_DESC_KEY, entity.getName()),
         definitionWithMetadataPath(entity.getClassName()));
   } else {
     return new ResponseWithSchema(
         msg(locale, RESPONSE_LIST_DESC_KEY, entity.getName()),
         definitionWithMetadataPath(entity.getClassName()));
   }
 }
 private ImportExportBlueprint sortBlueprintRecords(ImportExportBlueprint blueprint) {
   List<Entity> entities = new ArrayList<>(blueprint.size());
   for (ImportExportBlueprint.Record record : blueprint) {
     entities.add(allEntities.retrieveByClassName(record.getEntityName()));
   }
   RelationshipSorter relationshipSorter = new RelationshipSorter();
   relationshipSorter.sort(entities);
   ImportExportBlueprint sortedBlueprint = new ImportExportBlueprint();
   for (Entity entity : entities) {
     String entityName = entity.getClassName();
     sortedBlueprint.includeEntitySchema(entityName, blueprint.isIncludeEntitySchema(entityName));
     sortedBlueprint.includeEntityData(entityName, blueprint.isIncludeEntityData(entityName));
   }
   return sortedBlueprint;
 }
Beispiel #6
0
  private List<Parameter> lookupParameters(Entity entity, Lookup lookup, Locale locale) {
    List<Parameter> parameters = new ArrayList<>();

    for (String lookupFieldName : lookup.getFieldsOrder()) {
      LookupFieldType lookupFieldType = lookup.getLookupFieldType(lookupFieldName);
      Field lookupField;
      if (lookupFieldName.contains(".")) {
        lookupField =
            getRelatedField(
                lookup
                    .getLookupFieldByName(LookupName.getFieldName(lookupFieldName))
                    .getMetadata(Constants.MetadataKeys.RELATED_CLASS)
                    .getValue(),
                LookupName.getRelatedFieldName(lookupFieldName));
      } else {
        lookupField = lookup.getLookupFieldByName(lookupFieldName);
      }
      String paramDesc = lookupParamDescription(lookupField, lookupFieldType, locale);

      Parameter parameter =
          SwaggerFieldConverter.lookupParameter(
              lookupFieldName, lookupField, lookupFieldType, paramDesc);
      parameters.add(parameter);
    }

    parameters.addAll(queryParamsParameters(entity.getFieldsExposedByRest(), locale));

    return parameters;
  }
Beispiel #7
0
  private PathEntry deletePathEntry(Entity entity, Locale locale) {
    final PathEntry pathEntry = new PathEntry();

    final String entityName = entity.getName();

    pathEntry.setDescription(msg(locale, DELETE_DESC_KEY, entityName));
    pathEntry.setOperationId(msg(locale, DELETE_ID_KEY, entityName));
    pathEntry.setProduces(json());
    pathEntry.addTag(entity.getClassName());

    pathEntry.addParameter(deleteIdPathParameter(locale));

    addCommonResponses(pathEntry, locale);
    pathEntry.addResponse(HttpStatus.OK, deleteResponse(entity, locale));

    return pathEntry;
  }
Beispiel #8
0
 private RestOptions restOptionsOrDefault(Entity entity) {
   RestOptions restOptions = entity.getRestOptions();
   if (restOptions == null) {
     // everything off
     restOptions = new RestOptions();
   }
   return restOptions;
 }
Beispiel #9
0
  private PathEntry readPathEntry(Entity entity, Locale locale) {
    final PathEntry pathEntry = new PathEntry();

    final String entityName = entity.getName();

    pathEntry.setDescription(msg(locale, READ_DESC_KEY, entityName));
    pathEntry.setOperationId(msg(locale, READ_ID_KEY, entityName));
    pathEntry.setProduces(json());
    pathEntry.addTag(entity.getClassName());

    pathEntry.setParameters(queryParamsParameters(entity.getFieldsExposedByRest(), locale));
    pathEntry.addParameter(idQueryParameter(locale));

    pathEntry.addResponse(HttpStatus.OK, readResponse(entity, locale));
    addCommonResponses(pathEntry, locale);

    return pathEntry;
  }
Beispiel #10
0
  private PathEntry putPathEntry(Entity entity, Locale locale) {
    final PathEntry pathEntry = new PathEntry();

    final String entityName = entity.getName();

    pathEntry.setDescription(msg(locale, UPDATE_DESC_KEY, entityName));
    pathEntry.setOperationId(msg(locale, UPDATE_ID_KEY, entityName));
    pathEntry.setProduces(json());
    pathEntry.addTag(entity.getClassName());

    pathEntry.addParameter(updateEntityParameter(entity, locale));

    addCommonResponses(pathEntry, locale);
    pathEntry.addResponse(HttpStatus.OK, updatedItemResponse(entity, locale));
    pathEntry.addResponse(HttpStatus.NOT_FOUND, notFoundResponse(entity, locale));

    return pathEntry;
  }
Beispiel #11
0
  private void addDefinitions(SwaggerModel swaggerModel, Entity entity) {
    RestOptions restOptions = restOptionsOrDefault(entity);

    if (restOptions.supportsAnyOperation() || !entity.getLookupsExposedByRest().isEmpty()) {
      // all fields, including generated ones
      swaggerModel.addDefinition(entity.getClassName(), definition(entity, true, true));
      swaggerModel.addDefinition(
          entity.getClassName() + "-WithMetadata", definitionWithMetadata(entity));
    }
    if (restOptions.isAllowCreate()) {
      // no auto-generated fields
      swaggerModel.addDefinition(
          definitionNewName(entity.getClassName()), definition(entity, false, false));
    }
    if (restOptions.isAllowUpdate()) {
      // no auto-generated fields, except ID
      swaggerModel.addDefinition(
          definitionUpdateName(entity.getClassName()), definition(entity, false, true));
    }
  }
Beispiel #12
0
  /**
   * Takes a list of entities and sorts them by the inheritance tree. The entities that extend the
   * Object class or MdsEntity class will be moved to the beggining of the list. After that, the
   * entites that are already present on the list will be added, up the inheritance tree.
   *
   * @param list Initial list of entities to sort
   * @return List of entities, sorted by inheritance tree
   */
  public static List<Entity> sortByInheritance(List<Entity> list) {
    List<Entity> sorted = new ArrayList<>(list.size());

    // firstly we add entities with base class equal to Object class or MdsEntity class
    for (Iterator<Entity> iterator = list.iterator(); iterator.hasNext(); ) {
      Entity entity = iterator.next();

      if (entity.isBaseEntity()) {
        sorted.add(entity);
        iterator.remove();
      }
    }

    // then we add entities which base classes are in sorted list
    // we do that after all entities will be added to sorted list
    while (!list.isEmpty()) {
      for (Iterator<Entity> iterator = list.iterator(); iterator.hasNext(); ) {
        final Entity entity = iterator.next();
        Entity superClass =
            (Entity)
                CollectionUtils.find(
                    sorted,
                    new Predicate() {
                      @Override
                      public boolean evaluate(Object object) {
                        return object instanceof Entity
                            && ((Entity) object).getClassName().equals(entity.getSuperClass());
                      }
                    });

        if (null != superClass) {
          sorted.add(entity);
          iterator.remove();
        }
      }
    }

    return sorted;
  }
Beispiel #13
0
  private static boolean hasCorrectTrackingSettings(
      Field field, Entity relatedEntity, RelationshipHolder holder) {
    boolean recordsHistory = field.getEntity().isRecordHistory();
    boolean relatedRecordsHistory = relatedEntity.isRecordHistory();

    if (holder.isBiDirectional()) {
      // Both sides of bi-directional relationship must have the same history tracking settings
      return !(recordsHistory ^ relatedRecordsHistory);
    } else {
      // For uni-directional relationship, the related side must not have more strict options than
      // the entity that defines the relationship
      return recordsHistory ? relatedRecordsHistory : true;
    }
  }
Beispiel #14
0
  private void addCrudEndpoints(SwaggerModel swaggerModel, Entity entity, Locale locale) {
    final String entityPath =
        ClassName.restUrl(entity.getName(), entity.getModule(), entity.getNamespace());

    RestOptions restOptions = restOptionsOrDefault(entity);

    if (restOptions.isAllowRead()) {
      // retrieveAll and retrieveById
      swaggerModel.addPathEntry(entityPath, HttpMethod.GET, readPathEntry(entity, locale));
    }
    if (restOptions.isAllowCreate()) {
      // post new item
      swaggerModel.addPathEntry(entityPath, HttpMethod.POST, postPathEntry(entity, locale));
    }
    if (restOptions.isAllowUpdate()) {
      // update an existing item
      swaggerModel.addPathEntry(entityPath, HttpMethod.PUT, putPathEntry(entity, locale));
    }
    if (restOptions.isAllowDelete()) {
      // delete an item
      swaggerModel.addPathEntry(
          entityPath + ID_PATHVAR, HttpMethod.DELETE, deletePathEntry(entity, locale));
    }
  }
Beispiel #15
0
  private PathEntry lookupPathEntry(Entity entity, Lookup lookup, Locale locale) {
    final PathEntry pathEntry = new PathEntry();

    pathEntry.setDescription(msg(locale, LOOKUP_DESC_KEY, lookup.getLookupName()));
    pathEntry.setOperationId(lookup.getMethodName());
    pathEntry.setProduces(json());
    pathEntry.addTag(entity.getClassName());

    pathEntry.setParameters(lookupParameters(entity, lookup, locale));

    pathEntry.addResponse(HttpStatus.OK, lookupResponse(entity, lookup, locale));
    addCommonResponses(pathEntry, locale);

    if (lookup.isSingleObjectReturn()) {
      pathEntry.addResponse(HttpStatus.NOT_FOUND, lookup404Response(entity, locale));
    }

    return pathEntry;
  }
Beispiel #16
0
  private Definition definitionWithMetadata(Entity entity) {
    final Definition definition = new Definition();

    Property metadata = new Property();
    metadata.setRef(definitionPath("Metadata"));
    Property data = new Property(ARRAY_TYPE);
    data.setRef(definitionPath(entity.getClassName()));

    final Map<String, Property> properties = new LinkedHashMap<>();
    properties.put("metadata", metadata);
    properties.put("data", data);

    final List<String> required = new ArrayList<>();
    required.add("metadata");
    required.add("data");

    definition.setProperties(properties);
    definition.setRequired(required);

    return definition;
  }
Beispiel #17
0
  private void buildDefinitionProperties(
      Map<String, Property> properties,
      List<String> required,
      Entity entity,
      boolean includeAuto,
      boolean includeId) {
    if (includeId) {
      properties.put(Constants.Util.ID_FIELD_NAME, new Property(INTEGER_TYPE, INT64_FORMAT));
    }

    for (Field field : entity.getFields()) {
      final String fieldName = field.getName();
      if (field.isExposedViaRest()) {
        // auto generated fields included only in responses
        if (!field.isAutoGenerated() || includeAuto) {
          Property property = SwaggerFieldConverter.fieldToProperty(field);
          properties.put(fieldName, property);
          if (field.isRequired()) {
            required.add(fieldName);
          }
        }
      }
    }
  }
Beispiel #18
0
 private Response readResponse(Entity entity, Locale locale) {
   return new ResponseWithSchema(
       msg(locale, RESPONSE_LIST_DESC_KEY, entity.getName()),
       definitionWithMetadataPath(entity.getClassName()));
 }
Beispiel #19
0
 private Field getRelatedField(String entityClassName, String fieldName) {
   Entity entity = allEntities.retrieveByClassName(entityClassName);
   return entity.getField(fieldName);
 }
Beispiel #20
0
 private Parameter newEntityParameter(Entity entity, Locale locale) {
   return bodyParameter(
       entity.getName(),
       msg(locale, CREATE_BODY_DESC_KEY, entity.getName()),
       definitionNewPath(entity.getClassName()));
 }
Beispiel #21
0
 private Response notFoundResponse(Entity entity, Locale locale) {
   return new Response(msg(locale, RESPONSE_NOT_FOUND_KEY, entity.getName()));
 }
Beispiel #22
0
 private Response deleteResponse(Entity entity, Locale locale) {
   return new Response(msg(locale, RESPONSE_DELETE_DESC_KEY, entity.getName()));
 }
Beispiel #23
0
 private Response updatedItemResponse(Entity entity, Locale locale) {
   return new ResponseWithSchema(
       msg(locale, RESPONSE_UPDATED_DESC_KEY, entity.getName()),
       definitionPath(entity.getClassName()));
 }
Beispiel #24
0
 private Parameter updateEntityParameter(Entity entity, Locale locale) {
   return bodyParameter(
       entity.getName(),
       msg(locale, UPDATE_BODY_DESC_KEY, entity.getName()),
       definitionUpdatePath(entity.getClassName()));
 }
Beispiel #25
0
  /**
   * Takes a list of entities and sorts them, according to relationships they have. The entities
   * that have uni-directional relationship with another entity, will be moved to the position
   * behind the entity they are related with. The bi-directional relationships are not sorted,
   * moreover if invalid bi-directional relationship is found, an exception is thrown.
   *
   * @param list Initial list of entities to sort
   * @return List of entities, sorted by relationship
   */
  public static List<Entity> sortByHasARelation(List<Entity> list) {
    List<Entity> sorted = new ArrayList<>(list);
    MultiValueMap<String, String> unresolvedRelations = new LinkedMultiValueMap<>();

    // we need to check if classes have 'has-a' relation
    // these classes should be later in list
    // we do that after all entities will be added to sorted list
    for (int i = 0; i < sorted.size(); ++i) {
      Entity entity = sorted.get(i);
      List<Field> fields =
          (List<Field>)
              CollectionUtils.select(
                  entity.getFields(),
                  new Predicate() {
                    @Override
                    public boolean evaluate(Object object) {
                      return object instanceof Field && ((Field) object).getType().isRelationship();
                    }
                  });

      if (CollectionUtils.isNotEmpty(fields)) {
        int max = i;

        for (Field field : fields) {
          final RelationshipHolder holder = new RelationshipHolder(field);

          // For each field we perform a validation to spot circular, unresolvable relations,
          // which means the data model is incorrect
          unresolvedRelations = validateRelationship(unresolvedRelations, field, holder);
          assertRelationshipIsHistoryCompatible(field, holder, list);

          Entity relation =
              (Entity)
                  CollectionUtils.find(
                      sorted,
                      new Predicate() {
                        @Override
                        public boolean evaluate(Object object) {
                          return object instanceof Entity
                              && ((Entity) object)
                                  .getClassName()
                                  .equalsIgnoreCase(holder.getRelatedClass());
                        }
                      });

          // In case the relation is bidirectional, we shouldn't move the class,
          // in order to avoid infinite loop
          boolean biDirectional = field.getMetadata(RELATED_FIELD) != null;
          max = Math.max(max, biDirectional ? -1 : sorted.indexOf(relation));
        }

        if (max != i) {
          sorted.remove(i);
          --i;

          if (max < sorted.size()) {
            sorted.add(max, entity);
          } else {
            sorted.add(entity);
          }
        }
      }
    }

    return sorted;
  }
Beispiel #26
0
 private Response lookup404Response(Entity entity, Locale locale) {
   return new Response(msg(locale, RESPONSE_LOOKUP_NOT_FOUND_KEY, entity.getName()));
 }