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

io.polygenesis.abstraction.thing.Thing Maven / Gradle / Ivy

/*-
 * ==========================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;

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.DataReferenceToThingByValue;
import io.polygenesis.abstraction.data.DataRepository;
import io.polygenesis.commons.assertion.Assertion;
import io.polygenesis.commons.keyvalue.KeyValue;
import io.polygenesis.commons.text.TextConverter;
import io.polygenesis.commons.valueobjects.ContextName;
import io.polygenesis.commons.valueobjects.ObjectName;
import io.polygenesis.commons.valueobjects.PackageName;
import io.polygenesis.commons.valueobjects.VariableName;
import io.polygenesis.core.Abstraction;
import io.polygenesis.core.AbstractionScope;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * {@link Thing} is defined as a concept or an entity on or for which a {@link Purpose} is defined.
 * Most commonly, the names of the domain business concepts will be defined as things, being
 * concrete entities or more abstract concepts.
 *
 * 

Therefore, a {@link Thing} can be anything that makes sense to code generation. * *

Example of concrete business concepts: Customer, User, LoginContext etc. * *

Example of more abstract concepts: Sum calculation etc. * * @author Christos Tsakostas */ public class Thing implements Abstraction { // =============================================================================================== // STATE // =============================================================================================== private Set abstractionScopes = new LinkedHashSet<>(); private ContextName contextName; private ThingName thingName; private DataRepository thingProperties; private Set functions; private Boolean multiTenant; private Set children; private Thing optionalParent; private Set metadata; // =============================================================================================== // STATIC // =============================================================================================== private static Map childToParentPurposeMap; static { childToParentPurposeMap = new LinkedHashMap<>(); childToParentPurposeMap.put(Purpose.create(), Purpose.entityCreate()); childToParentPurposeMap.put(Purpose.modify(), Purpose.entityModify()); childToParentPurposeMap.put(Purpose.delete(), Purpose.entityRemove()); childToParentPurposeMap.put(Purpose.fetchOne(), Purpose.entityFetch()); childToParentPurposeMap.put(Purpose.fetchPagedCollection(), Purpose.entityFetchAll()); } // =============================================================================================== // CONSTRUCTOR(S) // =============================================================================================== /** * Instantiates a new Thing. * * @param abstractionScopes the abstraction scopes * @param contextName the context name * @param thingName the name * @param thingProperties the thing properties * @param multiTenant the multi tenant * @param optionalParent the optional parent * @param metadata the metadata */ public Thing( Set abstractionScopes, ContextName contextName, ThingName thingName, DataRepository thingProperties, Boolean multiTenant, Thing optionalParent, Set metadata) { setAbstractionScopes(abstractionScopes); setContextName(contextName); setThingName(thingName); setThingProperties(thingProperties); setFunctions(new LinkedHashSet<>()); setMultiTenant(multiTenant); setChildren(new LinkedHashSet<>()); if (optionalParent != null) { setOptionalParent(optionalParent); } setMetadata(metadata); } // =============================================================================================== // STATE MUTATION // =============================================================================================== /** * Add data. * * @param data the data */ public void addData(Set data) { Assertion.isNotNull(data, "data is required"); thingProperties.addSetOfData( data.stream().collect(Collectors.toCollection(LinkedHashSet::new))); } /** * Assign context name. * * @param contextName the context name */ public void assignContextName(ContextName contextName) { setContextName(contextName); } /** * Assign thing properties. * * @param thingProperties the thing properties */ public void assignThingProperties(DataRepository thingProperties) { setThingProperties(thingProperties); } /** * Add function. * * @param function the function */ public void addFunction(Function function) { this.functions.add(function); addThingPropertiesFromFunction(function); } /** * Add functions. * * @param functions the functions */ public void addFunctions(Set functions) { this.functions.addAll(functions); functions.forEach(function -> addThingPropertiesFromFunction(function)); } /** * Add child. * * @param childThing the child thing */ public void addChild(Thing childThing) { Assertion.isNotNull(childThing, "childThing is required"); childThing.setOptionalParent(this); getChildren().add(childThing); addChildThingIntoProperties(childThing); addChildThingManagementFunctions(childThing); } /** * Add metadata. * * @param metadata the metadata */ public void addMetadata(KeyValue metadata) { Assertion.isNotNull(metadata, "metadata is required"); getMetadata().add(metadata); } // =============================================================================================== // TRANSFORMATIONS // =============================================================================================== /** * Gets as data object. * * @param rootPackageName the root package name * @return the as data object */ public DataObject getAsDataObject(PackageName rootPackageName) { return new DataObject( new ObjectName(TextConverter.toUpperCamel(getThingName().getText())), makePackageName(rootPackageName, this)); } // =============================================================================================== // FACTORY // =============================================================================================== /** * Make package name package name. * * @param rootPackageName the root package name * @param thing the thing * @return the package name */ public PackageName makePackageName(PackageName rootPackageName, Thing thing) { if (thing.getMetadataValueIfExists(ThingMetadataKey.PREFERRED_PACKAGE) != null) { return PackageName.class.cast(thing.getMetadataValue(ThingMetadataKey.PREFERRED_PACKAGE)); } if (thing.getOptionalParent() != null) { return makePackageName(rootPackageName, thing.getOptionalParent()); } return new PackageName( String.format( "%s.%s", rootPackageName.getText(), thing.getThingName().getText().toLowerCase())); } // =============================================================================================== // IMPLEMENTATIONS // =============================================================================================== @Override public ObjectName getObjectName() { return new ObjectName(getThingName().getText()); } @Override public Set getAbstractionsScopes() { return abstractionScopes; } // =============================================================================================== // GETTERS // =============================================================================================== /** * Gets context name. * * @return the context name */ public ContextName getContextName() { return contextName; } /** * Gets thing name. * * @return the thing name */ public ThingName getThingName() { return thingName; } /** * Gets thing properties. * * @return the thing properties */ public DataRepository getThingProperties() { return thingProperties; } /** * Gets functions. * * @return the functions */ public Set getFunctions() { return functions; } /** * Gets multi tenant. * * @return the multi tenant */ public Boolean getMultiTenant() { return multiTenant; } /** * Gets children. * * @return the children */ public Set getChildren() { return children; } /** * Gets optional parent. * * @return the optional parent */ public Thing getOptionalParent() { return optionalParent; } // =============================================================================================== // QUERIES // =============================================================================================== /** * Supports abstraction scope boolean. * * @param abstractionScope the abstraction scope * @return the boolean */ public Boolean supportsAbstractionScope(AbstractionScope abstractionScope) { return getAbstractionsScopes() .stream() .anyMatch(abstractionScope1 -> abstractionScope1.equals(abstractionScope)); } /** * Has parent boolean. * * @return the boolean */ public Boolean hasParent() { return getOptionalParent() != null; } /** * Gets function by name. * * @param functionName the function name * @return the function by name */ public Function getFunctionByName(String functionName) { return getFunctions() .stream() .filter(function -> function.getName().getText().equals(functionName)) .findFirst() .orElseThrow(IllegalArgumentException::new); } /** * Gets metadata. * * @return the metadata */ public Set getMetadata() { return metadata; } /** * Gets metadata value. * * @param key the key * @return the metadata value */ public Object getMetadataValue(Object key) { Assertion.isNotNull(key, "key is required"); return metadata .stream() .filter(keyValue -> keyValue.getKey().equals(key)) .map(keyValue -> keyValue.getValue()) .findFirst() .orElseThrow( () -> new IllegalArgumentException( String.format("Cannot find thing metadata for key=%s", key))); } /** * Gets metadata value if exists. * * @param key the key * @return the metadata value if exists */ public Object getMetadataValueIfExists(Object key) { Assertion.isNotNull(key, "key is required"); return metadata .stream() .filter(keyValue -> keyValue.getKey().equals(key)) .map(keyValue -> keyValue.getValue()) .findFirst() .orElse(null); } /** * Gets thing identity. * * @return the thing identity */ public Data getThingIdentity() { return getThingProperties() .getData() .stream() .filter(data -> data.isThingIdentity()) .findFirst() .orElseThrow( () -> new IllegalStateException( String.format("Thing %s does not have identity", getThingName().getText()))); } /** * Gets thing identity as data object from data primitive. * * @param rootPackageName the root package name * @param variableName the variable name * @param dataPrimitive the data primitive * @return the thing identity as data object from data primitive */ public DataObject getThingIdentityAsDataObjectFromDataPrimitive( PackageName rootPackageName, VariableName variableName, DataPrimitive dataPrimitive) { Data data = getThingIdentity(); if (data.isDataGroup()) { return data.getAsDataObject(); } else { DataObject dataObject = new DataObject( new ObjectName(data.getVariableName().getText()), makePackageName(rootPackageName, this), variableName); dataObject.addData(dataPrimitive); return dataObject; } } /** * Extends thing boolean. * * @return the boolean */ public boolean extendsThing() { return getMetadataValueIfExists(ThingMetadataKey.SUPER_CLASS) != null; } /** * Does not extend thing boolean. * * @return the boolean */ public boolean doesNotExtendThing() { return getMetadataValueIfExists(ThingMetadataKey.SUPER_CLASS) == null; } /** * Gets all nested children. * * @return the all nested children */ public Set getAllNestedChildren() { Set allNestedChildren = new LinkedHashSet<>(); fillAllNestedChildren(allNestedChildren, this); return allNestedChildren; } private void fillAllNestedChildren(Set allNestedChildren, Thing thing) { allNestedChildren.add(thing); thing.getChildren().forEach(child -> fillAllNestedChildren(allNestedChildren, child)); } // =============================================================================================== // GUARDS // =============================================================================================== /** * Sets abstraction scopes. * * @param abstractionScopes the abstraction scopes */ public void setAbstractionScopes(Set abstractionScopes) { Assertion.isNotNull(abstractionScopes, "abstractionScopes is required"); this.abstractionScopes = abstractionScopes; } /** * Sets context name. * * @param contextName the context name */ private void setContextName(ContextName contextName) { this.contextName = contextName; } /** * Sets name. * * @param thingName the name */ private void setThingName(ThingName thingName) { Assertion.isNotNull(thingName, "thingName is required"); this.thingName = thingName; } /** * Sets thing properties. * * @param thingProperties the thing properties */ private void setThingProperties(DataRepository thingProperties) { Assertion.isNotNull(thingProperties, "thingProperties is required"); this.thingProperties = thingProperties; } /** * Sets functions. * * @param functions the functions */ private void setFunctions(Set functions) { Assertion.isNotNull(functions, "functions is required"); this.functions = functions; } /** * Sets multi tenant. * * @param multiTenant the multi tenant */ private void setMultiTenant(Boolean multiTenant) { Assertion.isNotNull(multiTenant, "multiTenant is required"); this.multiTenant = multiTenant; } /** * Sets children. * * @param children the children */ private void setChildren(Set children) { Assertion.isNotNull(children, "children is required"); this.children = children; } /** * Sets optional parent. * * @param optionalParent the optional parent */ private void setOptionalParent(Thing optionalParent) { Assertion.isNotNull(optionalParent, "optionalParent is required"); this.optionalParent = optionalParent; } /** * Sets metadata. * * @param metadata the metadata */ private void setMetadata(Set metadata) { Assertion.isNotNull(metadata, "metadata is required"); this.metadata = metadata; } // =============================================================================================== // PRIVATE // =============================================================================================== private void addThingPropertiesFromFunction(Function function) { if (!function.getPurpose().isCommand() && !function.getPurpose().isModify()) { return; } if (function.getThing() != this) { throw new IllegalStateException(); } Set newThingProperties = new LinkedHashSet<>(); function.getArguments().getData().stream().forEach(data -> newThingProperties.add(data)); thingProperties.addSetOfData(newThingProperties); } private void addChildThingIntoProperties(Thing childThing) { String variableName = TextConverter.toUpperCamel(childThing.getThingName().getText()); DataReferenceToThingByValue dataReferenceToThingByValue = DataReferenceToThingByValue.of( childThing, TextConverter.toPlural(childThing.getThingName().getText())); DataArray dataArray = DataArray.of(dataReferenceToThingByValue, variableName); getThingProperties().addData(dataArray); } private void addChildThingManagementFunctions(Thing childThing) { childThing .getFunctions() .forEach( childFunction -> { if (!childToParentPurposeMap.containsKey(childFunction.getPurpose())) { throw new IllegalStateException( String.format( "Purpose %s not found in " + "childToParentPurposeMap", childFunction.getPurpose().getText())); } Function function = new Function( this, childToParentPurposeMap.get(childFunction.getPurpose()), new FunctionName( String.format( "%s%s", TextConverter.toUpperCamel( childFunction.getThing().getThingName().getText()), TextConverter.toUpperCamel(childFunction.getName().getText()))), childFunction.getReturnValue(), childFunction.getArguments(), childFunction.getActivity(), getAbstractionsScopes(), childFunction); // addFunction(function); getFunctions().add(function); }); } // =============================================================================================== // OVERRIDES // =============================================================================================== @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Thing thing = (Thing) o; return Objects.equals(abstractionScopes, thing.abstractionScopes) && Objects.equals(contextName, thing.contextName) && Objects.equals(thingName, thing.thingName) && Objects.equals(thingProperties, thing.thingProperties) && Objects.equals(functions, thing.functions) && Objects.equals(multiTenant, thing.multiTenant) && Objects.equals(children, thing.children) && Objects.equals(metadata, thing.metadata); } @Override public int hashCode() { return Objects.hash( abstractionScopes, contextName, thingName, thingProperties, functions, multiTenant, children, metadata); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy