io.vertigo.studio.notebook.domain.DtSketchBuilder Maven / Gradle / Ivy
The newest version!
/*
* vertigo - application development platform
*
* Copyright (C) 2013-2024, Vertigo.io, [email protected]
*
* 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.
*/
package io.vertigo.studio.notebook.domain;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import io.vertigo.core.lang.Assertion;
import io.vertigo.core.lang.Builder;
import io.vertigo.core.lang.Cardinality;
import io.vertigo.core.locale.LocaleMessageKey;
import io.vertigo.core.locale.LocaleMessageText;
import io.vertigo.core.util.StringUtil;
import io.vertigo.studio.tools.SketchUtil;
/**
* This class must be used to build a DtSketch.
*
* Each dtSketch must have a name following this pattern DT_XXX_YYYY
*
* @author pchretien, mlaroche
*/
public final class DtSketchBuilder implements Builder {
private static class MessageKeyImpl implements LocaleMessageKey {
private static final long serialVersionUID = 6959551752755175151L;
private final String name;
MessageKeyImpl(final String name) {
this.name = name;
}
/** {@inheritDoc} */
@Override
public String name() {
return name;
}
}
private DtSketch dtSketch;
private final String myName;
private DtSketch myFragment;
private String myPackageName;
private StudioStereotype myStereotype;
private DtSketchField myIdField;
private final List myFields = new ArrayList<>();
private String myDataSpace;
private String mySortFieldName;
private String myDisplayFieldName;
private String myHandleFieldName;
private String myKeyFieldName;
/**
* Constructor.
* @param name the name of the dtSketch
*/
DtSketchBuilder(final String name) {
Assertion.check().isNotBlank(name);
//-----
myName = name;
}
/**
* Sets packageName
* @param packageName the name of the package (nullable)
* @return this builder
*/
public DtSketchBuilder withPackageName(final String packageName) {
//the packageName can be null
//-----
myPackageName = packageName;
return this;
}
/**
* Sets fragment
* @param fragment Persistent root DtSketch for this fragment
* @return this builder
*/
public DtSketchBuilder withFragment(final DtSketch fragment) {
Assertion.check().isNotNull(fragment);
//---
myStereotype = StudioStereotype.Fragment;
myFragment = fragment;
return this;
}
/**
* Sets the stereotype of the dtSketch.
*
* @param stereotype the stereotype of the dtSketch
* @return this builder
*/
public DtSketchBuilder withStereoType(final StudioStereotype stereotype) {
Assertion.check().isNotNull(stereotype);
//-----
myStereotype = stereotype;
return this;
}
/**
* Adds a field linked to another dtSketch (aka foreign key).
*
* @param fieldName the name of the field
* @param fkDtSketchName the name of the linked definition
* @param label the label of the field
* @param domainSketch the domain of the field
* @return this builder
*/
public DtSketchBuilder addForeignKey(
final String fieldName,
final String label,
final DomainSketch domainSketch,
final Cardinality cardinality,
final String fkDtSketchName) {
//Pour l'instant on ne gère pas les chamsp computed dynamiques
final boolean persistent = true;
final DtSketchField dtField = createField(
fieldName,
DtSketchField.FieldType.FOREIGN_KEY,
domainSketch,
label,
cardinality,
persistent,
fkDtSketchName,
null);
//On suppose que le build est déjà effectué. TODO: WTF
dtSketch.registerDtField(dtField);
return this;
}
/**
* Adds a computed field.
*
* @param fieldName the name of the field
* @param label the label of the field
* @param domainSketch the domain of the field
* @param computedExpression the expression use to compute the field
* @return this builder
*/
public DtSketchBuilder addComputedField(
final String fieldName,
final String label,
final DomainSketch domainSketch,
final Cardinality cardinality,
final ComputedExpression computedExpression) {
final boolean persistent = false;
final DtSketchField dtField = createField(
fieldName,
DtSketchField.FieldType.COMPUTED,
domainSketch,
label,
cardinality,
persistent,
null,
computedExpression);
myFields.add(dtField);
return this;
}
/**
* Adds a common data field.
*
* @param fieldName the name of the field
* @param domainSketch the domain of the field
* @param label the label of the field
* @param persistent if the fiels is persistent
* @return this builder
*/
public DtSketchBuilder addDataField(
final String fieldName,
final String label,
final DomainSketch domainSketch,
final Cardinality cardinality,
final boolean persistent) {
//the field is dynamic if and only if the dtSketch is dynamic
final DtSketchField dtField = createField(
fieldName,
DtSketchField.FieldType.DATA,
domainSketch,
label,
cardinality,
persistent,
null,
null);
myFields.add(dtField);
return this;
}
/**
* Adds an ID field.
* This field is required.
*
* @param fieldName the name of the field
* @param domainSketch the domain of the field
* @param label the label of the field
* @return this builder
*/
public DtSketchBuilder addIdField(
final String fieldName,
final String label,
final DomainSketch domainSketch) {
Assertion.check().isNull(myIdField, "only one ID per Entity is permitted, error on {0}", myPackageName);
//---
//le champ ID est tjrs required
final Cardinality cardinality = Cardinality.ONE;
//le champ ID est persistant SSI la définition est persitante.
final boolean persistent = true;
//le champ est dynamic SSI la définition est dynamique
final DtSketchField dtField = createField(
fieldName,
DtSketchField.FieldType.ID,
domainSketch,
label,
cardinality,
persistent,
null,
null);
myIdField = dtField;
myFields.add(dtField);
return this;
}
private DtSketchField createField(
final String fieldName,
final DtSketchField.FieldType type,
final DomainSketch domainSketch,
final String strLabel,
final Cardinality cardinality,
final boolean persistent,
final String fkDtSketchName,
final ComputedExpression computedExpression) {
final String shortName = SketchUtil.getLocalName(myName, DtSketch.PREFIX);
//-----
// Le DtField vérifie ses propres règles et gère ses propres optimisations
final String id = "fld" + shortName + '$' + fieldName;
//2. Sinon Indication de longueur portée par le champ du DT.
//-----
final LocaleMessageText labelMsg = LocaleMessageText.ofDefaultMsg(strLabel, new MessageKeyImpl(id));
// Champ CODE_COMMUNE >> getCodeCommune()
//Un champ est persisanty s'il est marqué comme tel et si la définition l'est aussi.
return new DtSketchField(
id,
fieldName,
type,
domainSketch,
labelMsg,
cardinality,
persistent,
fkDtSketchName,
computedExpression);
}
/**
* Sets the dataSpace to which the dtSketch belongs.
* @param dataSpace the dataSpace to which the DtSketch is mapped.
* @return this builder
*/
public DtSketchBuilder withDataSpace(final String dataSpace) {
//the dataSpace can be null, in this case the default dataSpace will be chosen.
//-----
myDataSpace = dataSpace;
return this;
}
/**
* Specifies which field to be used for sorting
* @param sortFieldName fieldName to use
* @return this builder
*/
public DtSketchBuilder withSortField(final String sortFieldName) {
mySortFieldName = sortFieldName;
return this;
}
/**
* Specifies which field to be used for display
* @param displayFieldName fieldName to use
* @return this builder
*/
public DtSketchBuilder withDisplayField(final String displayFieldName) {
myDisplayFieldName = displayFieldName;
return this;
}
/**
* Specifies which field to be used for handle
* @param handleFieldName fieldName to use
* @return this builder
*/
public DtSketchBuilder withHandleField(final String handleFieldName) {
myHandleFieldName = handleFieldName;
return this;
}
/**
* Specifies which field to be used for key to distinguish elements in a collection
* @param keyFieldName fieldName to use
* @return this builder
*/
public DtSketchBuilder withKeyField(final String keyFieldName) {
myKeyFieldName = keyFieldName;
return this;
}
/** {@inheritDoc} */
@Override
public DtSketch build() {
Assertion.check().isNull(dtSketch, "build() already executed");
//-----
if (myStereotype == null) {
myStereotype = myIdField == null ? StudioStereotype.ValueObject : StudioStereotype.Entity;
}
final DtSketchField sortField;
if (mySortFieldName != null) {
sortField = findFieldByName(mySortFieldName)
.orElseThrow(() -> new IllegalStateException(StringUtil.format("Sort field '{0}' not found on '{1}'", mySortFieldName, dtSketch)));
} else if (myStereotype == StudioStereotype.Fragment) {
sortField = myFragment.getSortField().orElse(null);
} else {
sortField = null;
}
final DtSketchField displayField;
if (myDisplayFieldName != null) {
displayField = findFieldByName(myDisplayFieldName)
.orElseThrow(() -> new IllegalStateException(StringUtil.format("Display field '{0}' not found on '{1}'", myDisplayFieldName, dtSketch)));
} else if (myStereotype == StudioStereotype.Fragment) {
displayField = myFragment.getDisplayField().orElse(null);
} else {
displayField = null;
}
final DtSketchField handleField;
if (myHandleFieldName != null) {
handleField = findFieldByName(myHandleFieldName)
.orElseThrow(() -> new IllegalStateException(StringUtil.format("Handle field '{0}' not found on '{1}'", myHandleFieldName, dtSketch)));
} else if (myStereotype == StudioStereotype.Fragment) {
handleField = myFragment.getHandleField().orElse(null);
} else {
handleField = null;
}
final DtSketchField keyField;
if (myKeyFieldName != null) {
keyField = findFieldByName(myKeyFieldName)
.orElseThrow(() -> new IllegalStateException(StringUtil.format("Key field '{0}' not found on '{1}'", myKeyFieldName, dtSketch)));
} else {
keyField = null;
}
dtSketch = new DtSketch(
myName,
Optional.ofNullable(myFragment),
myPackageName,
myStereotype,
myFields,
myDataSpace == null ? "main" : myDataSpace,
Optional.ofNullable(sortField),
Optional.ofNullable(displayField),
Optional.ofNullable(handleField),
Optional.ofNullable(keyField));
return dtSketch;
}
private Optional findFieldByName(final String fieldName) {
Assertion.check().isNotBlank(fieldName);
return myFields
.stream()
.filter(dtField -> fieldName.equals(dtField.getName()))
.findFirst();
}
}