All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.polygenesis.abstraction.thing.dsl.PurposeFunctionBuilder Maven / Gradle / Ivy

The newest version!
/*-
 * ==========================LICENSE_START=================================
 * PolyGenesis Platform
 * ========================================================================
 * Copyright (C) 2015 - 2019 Christos Tsakostas, OREGOR LTD
 * ========================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ===========================LICENSE_END==================================
 */

package io.polygenesis.abstraction.thing.dsl;

import io.polygenesis.abstraction.data.Data;
import io.polygenesis.abstraction.data.DataArray;
import io.polygenesis.abstraction.data.DataObject;
import io.polygenesis.abstraction.data.DataPrimitive;
import io.polygenesis.abstraction.data.DataPurpose;
import io.polygenesis.abstraction.data.PrimitiveType;
import io.polygenesis.abstraction.thing.Function;
import io.polygenesis.abstraction.thing.Purpose;
import io.polygenesis.abstraction.thing.Thing;
import io.polygenesis.commons.text.TextConverter;
import io.polygenesis.commons.valueobjects.ObjectName;
import io.polygenesis.commons.valueobjects.PackageName;
import io.polygenesis.commons.valueobjects.VariableName;
import io.polygenesis.core.AbstractionScope;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * The type Purpose function builder.
 *
 * @author Christos Tsakostas
 */
public class PurposeFunctionBuilder {

  private final PackageName rootPackageNameVo;
  private final Thing thing;
  private final Set functions;

  // ===============================================================================================
  // CONSTRUCTOR(S)
  // ===============================================================================================

  private PurposeFunctionBuilder(Thing thing, PackageName rootPackageName) {
    this.rootPackageNameVo = rootPackageName;
    this.thing = thing;
    functions = new LinkedHashSet<>();
  }

  // ===============================================================================================
  // START
  // ===============================================================================================

  /**
   * For thing function builder.
   *
   * @param thing the thing
   * @param rootPackageName the root package name
   * @return the function builder
   */
  public static PurposeFunctionBuilder forThing(Thing thing, String rootPackageName) {
    return new PurposeFunctionBuilder(thing, new PackageName(rootPackageName));
  }

  /**
   * For thing purpose function builder.
   *
   * @param thing the thing
   * @param rootPackageName the root package name
   * @return the purpose function builder
   */
  public static PurposeFunctionBuilder forThing(Thing thing, PackageName rootPackageName) {
    return new PurposeFunctionBuilder(thing, rootPackageName);
  }

  // ===============================================================================================
  // WITH
  // ===============================================================================================

  /**
   * With crud function function builder.
   *
   * @param models the models
   * @return the function builder
   */
  public final PurposeFunctionBuilder withCrudFunction(Set models) {
    withFunctionCreate(models);
    withFunctionModify("modify", models);
    withFunctionFetchOne(models);
    withFunctionFetchPagedCollection(models);
    return this;
  }

  /**
   * With function create no return value purpose function builder.
   *
   * @param functionName the function name
   * @param models the models
   * @return the purpose function builder
   */
  public final PurposeFunctionBuilder withFunctionCreateNoReturnValue(
      String functionName, Set models) {
    return withFunctionCreate(functionName, models, new LinkedHashSet<>(), false);
  }

  /**
   * With function create purpose function builder.
   *
   * @param arguments the arguments
   * @return the purpose function builder
   */
  public final PurposeFunctionBuilder withFunctionCreate(Set arguments) {
    return withFunctionCreate("create", arguments, new LinkedHashSet<>(), true);
  }

  /**
   * With function create purpose function builder.
   *
   * @param arguments the arguments
   * @param outputs the outputs
   * @return the purpose function builder
   */
  public final PurposeFunctionBuilder withFunctionCreate(Set arguments, Set outputs) {
    return withFunctionCreate("create", arguments, outputs, true);
  }

  /**
   * With function create purpose function builder.
   *
   * @param functionName the function name
   * @param models the models
   * @return the purpose function builder
   */
  public final PurposeFunctionBuilder withFunctionCreate(String functionName, Set models) {
    return withFunctionCreate(functionName, models, new LinkedHashSet<>(), true);
  }

  /**
   * With function create thing builder.
   *
   * @param functionName the function name
   * @param arguments the arguments
   * @param outputs the outputs
   * @param returnValue the return value
   * @return the thing builder
   */
  @SuppressWarnings("CPD-START")
  private PurposeFunctionBuilder withFunctionCreate(
      String functionName, Set arguments, Set outputs, Boolean returnValue) {

    // ---------------------------------------------------------------------------------------------
    // RETURN VALUE
    if (returnValue) {
      DataObject returnValueDataObject =
          new DataObject(
              new ObjectName(
                  String.format(
                      "%s%sResponse",
                      functionName, TextConverter.toUpperCamel(thing.getThingName().getText()))),
              thing.makePackageName(rootPackageNameVo, thing));

      // -------------------------------------------------------------------------------------------

      returnValueDataObject.addData(
          DataPrimitive.ofDataBusinessType(
              DataPurpose.thingIdentity(),
              PrimitiveType.STRING,
              new VariableName(
                  String.format(
                      "%sId", TextConverter.toLowerCamel(thing.getThingName().getText())))));

      // -------------------------------------------------------------------------------------------
      outputs.forEach(returnValueDataObject::addData);
      // -------------------------------------------------------------------------------------------

      // -------------------------------------------------------------------------------------------
      // FUNCTION
      Function function =
          FunctionBuilder.of(thing, functionName, Purpose.create())
              .setReturnValue(returnValueDataObject)
              .addArguments(generateArgumentsData(thing, arguments))
              .build();

      this.functions.add(function);
    } else {
      Function function =
          FunctionBuilder.of(thing, functionName, Purpose.create())
              .addArguments(generateArgumentsData(thing, arguments))
              .build();

      this.functions.add(function);
    }
    return this;
  }

  /**
   * With function ensure existence purpose function builder.
   *
   * @return the purpose function builder
   */
  public PurposeFunctionBuilder withFunctionEnsureExistence() {
    String functionName = "ensureExistence";

    Function function =
        FunctionBuilder.of(thing, functionName, Purpose.ensureExistence())
            .addArguments(generateArgumentsData(thing))
            .build();

    this.functions.add(function);

    return this;
  }

  /**
   * With function modify no return value purpose function builder.
   *
   * @param functionName the function name
   * @param models the models
   * @return the purpose function builder
   */
  public final PurposeFunctionBuilder withFunctionModifyNoReturnValue(
      String functionName, Set models) {
    return withFunctionModify(functionName, models, false, thing.getAbstractionsScopes());
  }

  /**
   * With function modify no return value purpose function builder.
   *
   * @param functionName the function name
   * @param models the models
   * @param abstractionScopes the abstraction scopes
   * @return the purpose function builder
   */
  public final PurposeFunctionBuilder withFunctionModifyNoReturnValue(
      String functionName, Set models, Set abstractionScopes) {
    return withFunctionModify(functionName, models, false, abstractionScopes);
  }

  /**
   * With function modify purpose function builder.
   *
   * @param functionName the function name
   * @param models the models
   * @return the purpose function builder
   */
  public final PurposeFunctionBuilder withFunctionModify(String functionName, Set models) {
    return withFunctionModify(functionName, models, true, thing.getAbstractionsScopes());
  }

  /**
   * With function modify purpose function builder.
   *
   * @param functionName the function name
   * @param arguments the arguments
   * @param returnValue the return value
   * @param abstractionScopes the abstraction scopes
   * @return the purpose function builder
   */
  private PurposeFunctionBuilder withFunctionModify(
      String functionName,
      Set arguments,
      Boolean returnValue,
      Set abstractionScopes) {

    // ---------------------------------------------------------------------------------------------
    // RETURN VALUE
    // ---------------------------------------------------------------------------------------------
    if (returnValue) {
      DataObject returnValueDataObject =
          new DataObject(
              new ObjectName(
                  String.format(
                      "%s%sResponse",
                      functionName, TextConverter.toUpperCamel(thing.getThingName().getText()))),
              thing.makePackageName(rootPackageNameVo, thing));

      // -------------------------------------------------------------------------------------------

      returnValueDataObject.addData(
          DataPrimitive.ofDataBusinessType(
              DataPurpose.thingIdentity(),
              PrimitiveType.STRING,
              new VariableName(
                  String.format(
                      "%sId", TextConverter.toLowerCamel(thing.getThingName().getText())))));

      // -------------------------------------------------------------------------------------------
      // FUNCTION
      // -------------------------------------------------------------------------------------------

      Function function =
          FunctionBuilder.of(thing, functionName, Purpose.modify())
              .setReturnValue(returnValueDataObject)
              .addArguments(generateArgumentsData(thing, arguments))
              .setAbstractionScopes(abstractionScopes)
              .build();

      this.functions.add(function);
    } else {
      // -------------------------------------------------------------------------------------------
      // FUNCTION
      // -------------------------------------------------------------------------------------------

      Function function =
          FunctionBuilder.of(thing, functionName, Purpose.modify())
              .addArguments(generateArgumentsData(thing, arguments))
              .setAbstractionScopes(abstractionScopes)
              .build();

      this.functions.add(function);
    }

    return this;
  }

  /**
   * With function batch process purpose function builder.
   *
   * @return the purpose function builder
   */
  public PurposeFunctionBuilder withFunctionBatchProcess() {
    return withFunctionModifyNoReturnValue("batchProcess", new LinkedHashSet<>());
  }

  /**
   * With function fetch one thing builder.
   *
   * @param models the models
   * @return the thing builder
   */
  @SuppressWarnings("CPD-END")
  public final PurposeFunctionBuilder withFunctionFetchOne(Set models) {

    // ---------------------------------------------------------------------------------------------
    // ARGUMENTS
    // ---------------------------------------------------------------------------------------------
    DataObject argumentDataObject =
        new DataObject(
            new ObjectName(
                String.format(
                    "Fetch%sRequest", TextConverter.toUpperCamel(thing.getThingName().getText()))),
            thing.makePackageName(rootPackageNameVo, thing),
            new VariableName("request"));

    // ---------------------------------------------------------------------------------------------
    // Add Parent Thing Identity if Any
    if (thing.getOptionalParent() != null) {
      argumentDataObject.addData(getParentThingIdentity(thing));
    }

    // ---------------------------------------------------------------------------------------------
    // Add Thing Identity
    argumentDataObject.addData(getThingIdentity(thing));

    // ---------------------------------------------------------------------------------------------
    // RETURN VALUE
    // ---------------------------------------------------------------------------------------------
    DataObject returnValueDataObject =
        new DataObject(
            new ObjectName(
                String.format(
                    "Fetch%sResponse", TextConverter.toUpperCamel(thing.getThingName().getText()))),
            thing.makePackageName(rootPackageNameVo, thing));

    // ---------------------------------------------------------------------------------------------
    models.forEach(returnValueDataObject::addData);
    // ---------------------------------------------------------------------------------------------

    // ---------------------------------------------------------------------------------------------
    // FUNCTION
    // ---------------------------------------------------------------------------------------------

    Function function =
        FunctionBuilder.of(thing, "fetch", Purpose.fetchOne())
            .setReturnValue(returnValueDataObject)
            .addArguments(argumentDataObject.getModels())
            .build();

    this.functions.add(function);
    return this;
  }

  /**
   * Fetch paged collection thing builder.
   *
   * @param models the models
   * @return the thing builder
   */
  public final PurposeFunctionBuilder withFunctionFetchPagedCollection(Set models) {

    // ---------------------------------------------------------------------------------------------
    // ARGUMENTS
    // ---------------------------------------------------------------------------------------------
    DataObject argumentDataObject =
        new DataObject(
            new ObjectName(
                String.format(
                    "Fetch%sCollectionRequest",
                    TextConverter.toUpperCamel(thing.getThingName().getText()))),
            thing.makePackageName(rootPackageNameVo, thing),
            new VariableName("request"));

    // ---------------------------------------------------------------------------------------------
    // Add Parent Thing Identity if Any
    if (thing.getOptionalParent() != null) {
      argumentDataObject.addData(getParentThingIdentity(thing));
    }

    // ---------------------------------------------------------------------------------------------
    argumentDataObject.addData(
        DataPrimitive.ofDataBusinessType(
            DataPurpose.pageNumber(), PrimitiveType.INTEGER, new VariableName("pageNumber")));

    argumentDataObject.addData(
        DataPrimitive.ofDataBusinessType(
            DataPurpose.pageSize(), PrimitiveType.INTEGER, new VariableName("pageSize")));

    // ---------------------------------------------------------------------------------------------
    // RETURN VALUE
    // ---------------------------------------------------------------------------------------------
    String arrayElementDataTypeAndVariableName =
        String.format(
            "%sCollectionRecord", TextConverter.toUpperCamel(thing.getThingName().getText()));

    DataObject arrayElement =
        new DataObject(
            new ObjectName(arrayElementDataTypeAndVariableName),
            thing.makePackageName(rootPackageNameVo, thing));

    // ---------------------------------------------------------------------------------------------
    arrayElement.addData(
        DataPrimitive.ofDataBusinessType(
            DataPurpose.thingIdentity(), PrimitiveType.STRING, new VariableName("rootId")));

    models.forEach(arrayElement::addData);
    // ---------------------------------------------------------------------------------------------

    String arrayDataTypeAndVariableName =
        String.format(
            "Fetch%sCollectionResponse",
            TextConverter.toUpperCamel(thing.getThingName().getText()));

    DataArray dataArray = new DataArray(new VariableName("someArray"), arrayElement);

    DataObject dataObjectReturnValue =
        new DataObject(
            new ObjectName(arrayDataTypeAndVariableName),
            thing.makePackageName(rootPackageNameVo, thing));

    dataObjectReturnValue.addData(dataArray);

    // ---------------------------------------------------------------------------------------------
    // FUNCTION
    // ---------------------------------------------------------------------------------------------

    Function function =
        FunctionBuilder.of(thing, "fetchPagedCollection", Purpose.fetchPagedCollection())
            .setReturnValue(dataObjectReturnValue)
            .addArguments(argumentDataObject.getModels())
            .build();

    this.functions.add(function);
    return this;
  }

  // ===============================================================================================
  // END
  // ===============================================================================================

  /**
   * Build set.
   *
   * @return the set
   */
  public final Set build() {
    return functions;
  }

  // ===============================================================================================
  // PRIVATE
  // ===============================================================================================

  private Set generateArgumentsData(Thing thing) {
    return generateArgumentsData(thing, new LinkedHashSet<>());
  }

  private Set generateArgumentsData(Thing thing, Set data) {
    Set argumentsData = new LinkedHashSet<>();

    if (!thing.supportsAbstractionScope(AbstractionScope.externallyProvided())) {
      // -------------------------------------------------------------------------------------------
      // Add Parent Thing Identity if Any
      if (thing.getOptionalParent() != null) {
        argumentsData.add(getParentThingIdentity(thing));
      }

      // -------------------------------------------------------------------------------------------
      // Add Thing Identity
      argumentsData.add(getThingIdentity(thing));

      // -------------------------------------------------------------------------------------------
      // Add Tenant Identity
      if (thing.getMultiTenant()) {
        argumentsData.add(getTenantIdentity(thing));
      }
    }

    // ---------------------------------------------------------------------------------------------
    // Add the provided data
    argumentsData.addAll(data);

    return argumentsData;
  }

  private Data getThingIdentity(Thing thing) {
    return thing
        .getThingProperties()
        .getData()
        .stream()
        .filter(this::isDataThingIdentity)
        .findFirst()
        .orElseThrow(
            () ->
                new IllegalStateException(
                    String.format(
                        "Thing with name='%s' is not uniquely identified",
                        thing.getThingName().getText())));
  }

  private Data getParentThingIdentity(Thing thing) {
    return thing
        .getThingProperties()
        .getData()
        .stream()
        .filter(this::isDataParentThingIdentity)
        .findFirst()
        .orElseThrow();
  }

  private Data getTenantIdentity(Thing thing) {
    return thing
        .getThingProperties()
        .getData()
        .stream()
        .filter(this::isDataTenantIdentity)
        .findFirst()
        .orElseThrow(
            () ->
                new IllegalStateException(
                    String.format(
                        "Thing with name='%s' is not uniquely identified",
                        thing.getThingName().getText())));
  }

  private boolean isDataThingIdentity(Data data) {
    return data.getDataPurpose().equals(DataPurpose.thingIdentity());
  }

  private boolean isDataParentThingIdentity(Data data) {
    return data.getDataPurpose().equals(DataPurpose.parentThingIdentity());
  }

  private boolean isDataTenantIdentity(Data data) {
    return data.getDataPurpose().equals(DataPurpose.tenantIdentity());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy