package com.constellio.model.services.schemas.builders;
import static com.constellio.model.entities.schemas.MetadataTransiency.PERSISTED;
import static com.constellio.model.entities.schemas.entries.DataEntryType.MANUAL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import com.constellio.data.dao.services.DataStoreTypesFactory;
import com.constellio.data.utils.Factory;
import com.constellio.data.utils.ImpossibleRuntimeException;
import com.constellio.model.entities.EnumWithSmallCode;
import com.constellio.model.entities.Language;
import com.constellio.model.entities.Taxonomy;
import com.constellio.model.entities.schemas.AllowedReferences;
import com.constellio.model.entities.schemas.InheritedMetadataBehaviors;
import com.constellio.model.entities.schemas.Metadata;
import com.constellio.model.entities.schemas.MetadataAccessRestriction;
import com.constellio.model.entities.schemas.MetadataPopulateConfigs;
import com.constellio.model.entities.schemas.MetadataTransiency;
import com.constellio.model.entities.schemas.MetadataValueType;
import com.constellio.model.entities.schemas.StructureFactory;
import com.constellio.model.entities.schemas.entries.DataEntry;
import com.constellio.model.entities.schemas.entries.ManualDataEntry;
import com.constellio.model.entities.schemas.validation.RecordMetadataValidator;
import com.constellio.model.services.contents.ContentFactory;
import com.constellio.model.services.encrypt.EncryptionServices;
import com.constellio.model.services.factories.ModelLayerFactory;
import com.constellio.model.services.schemas.SchemaUtils;
import com.constellio.model.services.schemas.builders.MetadataBuilderRuntimeException.CannotCreateMultivalueReferenceToPrincipalTaxonomy;
import com.constellio.model.services.schemas.builders.MetadataBuilderRuntimeException.EssentialMetadataCannotBeDisabled;
import com.constellio.model.services.schemas.builders.MetadataBuilderRuntimeException.EssentialMetadataInSummaryCannotBeDisabled;
import com.constellio.model.services.schemas.builders.MetadataBuilderRuntimeException.InvalidAttribute;
import com.constellio.model.services.schemas.builders.MetadataBuilderRuntimeException.MetadataCannotBeUniqueAndMultivalue;
import com.constellio.model.services.taxonomies.TaxonomiesManager;
import com.constellio.model.utils.ClassProvider;
import com.constellio.model.utils.InstanciationUtils;
public class MetadataBuilder {
private static final String UNDERSCORE = "_";
AllowedReferencesBuilder allowedReferencesBuilder;
DataEntry dataEntry;
private MetadataBuilder inheritance;
private String localCode;
private String collection;
private String code;
private Map<Language, String> labels = new HashMap<>();
private Boolean enabled;
private MetadataValueType type;
private boolean undeletable = false;
private boolean multivalue = false;
private boolean systemReserved = false;
private boolean unmodifiable = false;
private boolean uniqueValue = false;
private boolean childOfRelationship = false;
private boolean taxonomyRelationship = false;
private boolean searchable = false;
private MetadataTransiency transiency = PERSISTED;
private boolean schemaAutocomplete = false;
private boolean sortable = false;
private boolean encrypted = false;
private boolean essentialInSummary = false;
private boolean multiLingual;
private boolean markedForDeletion = false;
private boolean increasedDependencyLevel = false;
private Boolean defaultRequirement;
private Boolean essential = false;
private ClassListBuilder<RecordMetadataValidator<?>> recordMetadataValidators;
private MetadataAccessRestrictionBuilder accessRestrictionBuilder;
private Class<? extends StructureFactory> structureFactoryClass;
private Class<? extends Enum<?>> enumClass;
private Metadata originalMetadata;
private Object defaultValue = null;
private MetadataPopulateConfigsBuilder populateConfigsBuilder;
private ClassProvider classProvider;
private String inputMask;
private Boolean duplicable;
private Set<String> customAttributes;
MetadataBuilder() {
}
static MetadataBuilder createCustomMetadataFromOriginalCustomMetadata(MetadataBuilder customMetadata, String codeSchema) {
MetadataBuilder copy;
if (customMetadata.getInheritance() == null) {
copy = modifyMetadataWithoutInheritance(customMetadata.getOriginalMetadata(), customMetadata.getClassProvider());
} else {
MetadataBuilder inheritanceCopy = MetadataBuilder.modifyMetadataWithoutInheritance(
customMetadata.getInheritance().getOriginalMetadata(), customMetadata.getClassProvider());
copy = modifyMetadataWithInheritance(customMetadata.getOriginalMetadata(), inheritanceCopy);
}
copy.setCode(codeSchema + "_" + copy.getLocalCode());
return copy;
}
static MetadataBuilder createCustomMetadataFromDefault(MetadataBuilder defaultMetadata, String codeSchema) {
MetadataBuilder builder = new MetadataBuilder();
builder.classProvider = defaultMetadata.classProvider;
builder.setLocalCode(defaultMetadata.localCode);
builder.setCollection(defaultMetadata.collection);
builder.setCode(defaultMetadata.getCode().replace(UNDERSCORE + "default" + UNDERSCORE,
UNDERSCORE + codeSchema + UNDERSCORE));
builder.setDefaultRequirement(null);
builder.setEnabled(null);
builder.inheritance = defaultMetadata;
builder.type = defaultMetadata.getType();
builder.dataEntry = defaultMetadata.dataEntry;
builder.defaultValue = copy(defaultMetadata.defaultValue);
builder.recordMetadataValidators = new ClassListBuilder<>(builder.classProvider, RecordMetadataValidator.class);
builder.populateConfigsBuilder = MetadataPopulateConfigsBuilder.modify(defaultMetadata.getPopulateConfigsBuilder());
builder.multiLingual = defaultMetadata.multiLingual;
builder.customAttributes = defaultMetadata.customAttributes;
return builder;
}
private static Object copy(Object value) {
if (value instanceof List) {
return new ArrayList<Object>((List) value);
}
return value;
}
static MetadataBuilder createMetadataWithoutInheritance(String localCode, MetadataSchemaBuilder schemaBuilder) {
MetadataBuilder builder = new MetadataBuilder();
builder.classProvider = schemaBuilder.getClassProvider();
builder.setCollection(schemaBuilder.getCollection());
builder.setLocalCode(localCode);
for (Language language : schemaBuilder.getLabels().keySet()) {
builder.addLabel(language, localCode);
}
builder.setEnabled(true);
builder.setDefaultRequirement(false);
builder.setCode(schemaBuilder.getCode() + UNDERSCORE + localCode);
builder.recordMetadataValidators = new ClassListBuilder<>(builder.classProvider, RecordMetadataValidator.class);
builder.accessRestrictionBuilder = MetadataAccessRestrictionBuilder.create();
builder.populateConfigsBuilder = MetadataPopulateConfigsBuilder.create();
builder.setDuplicable(false);
builder.customAttributes = new HashSet<>();
return builder;
}
static MetadataBuilder modifyMetadataWithoutInheritance(Metadata defaultMetadata, ClassProvider classProvider) {
MetadataBuilder builder = new MetadataBuilder();
builder.classProvider = classProvider;
setBuilderPropertiesOfMetadataWithoutInheritance(defaultMetadata, builder);
return builder;
}
static MetadataBuilder modifyMetadataWithInheritance(Metadata metadata, MetadataBuilder defaultMetadata) {
MetadataBuilder builder = new MetadataBuilder();
builder.inheritance = defaultMetadata;
setBuilderPropertiesOfMetadataWithInheritance(metadata, defaultMetadata, builder);
return builder;
}
@SuppressWarnings("unchecked")
private static void setBuilderPropertiesOfMetadataWithoutInheritance(Metadata metadata, MetadataBuilder builder) {
builder.setLocalCode(metadata.getLocalCode());
builder.setCollection(metadata.getCollection());
builder.setCode(metadata.getCode());
builder.originalMetadata = metadata;
builder.setLabels(metadata.getLabels());
builder.enabled = metadata.isEnabled();
builder.type = metadata.getType();
builder.undeletable = metadata.isUndeletable();
builder.defaultRequirement = metadata.isDefaultRequirement();
builder.multivalue = metadata.isMultivalue();
builder.searchable = metadata.isSearchable();
builder.transiency = metadata.getTransiency();
builder.sortable = metadata.isSortable();
builder.schemaAutocomplete = metadata.isSchemaAutocomplete();
builder.unmodifiable = metadata.isUnmodifiable();
builder.uniqueValue = metadata.isUniqueValue();
builder.systemReserved = metadata.isSystemReserved();
builder.encrypted = metadata.isEncrypted();
builder.essential = metadata.isEssential();
builder.essentialInSummary = metadata.isEssentialInSummary();
builder.childOfRelationship = metadata.isChildOfRelationship();
builder.taxonomyRelationship = metadata.isTaxonomyRelationship();
builder.defaultValue = metadata.getDefaultValue();
builder.inputMask = metadata.getInputMask();
builder.markedForDeletion = metadata.isMarkedForDeletion();
builder.dataEntry = metadata.getDataEntry();
builder.recordMetadataValidators = new ClassListBuilder<RecordMetadataValidator<?>>(builder.classProvider,
RecordMetadataValidator.class, metadata.getValidators());
builder.accessRestrictionBuilder = MetadataAccessRestrictionBuilder.modify(metadata.getAccessRestrictions());
builder.multiLingual = metadata.isMultiLingual();
if (metadata.getStructureFactory() != null) {
builder.structureFactoryClass = (Class) metadata.getStructureFactory().getClass();
}
builder.enumClass = metadata.getEnumClass();
if (metadata.getAllowedReferences() != null) {
builder.allowedReferencesBuilder = new AllowedReferencesBuilder(metadata.getAllowedReferences());
}
builder.populateConfigsBuilder = MetadataPopulateConfigsBuilder.modify(metadata.getPopulateConfigs());
builder.duplicable = metadata.isDuplicable();
builder.increasedDependencyLevel = metadata.isIncreasedDependencyLevel();
builder.customAttributes = new HashSet<>(metadata.getCustomAttributes());
}
@SuppressWarnings("unchecked")
private static void setBuilderPropertiesOfMetadataWithInheritance(Metadata metadata, MetadataBuilder inheritanceMetadata,
MetadataBuilder builder) {
builder.classProvider = inheritanceMetadata.classProvider;
builder.originalMetadata = metadata;
builder.localCode = metadata.getLocalCode();
builder.code = metadata.getCode();
builder.collection = metadata.getCollection();
builder.type = metadata.getType();
builder.defaultRequirement = metadata.isDefaultRequirement();
builder.undeletable = metadata.isUndeletable();
builder.multivalue = metadata.isMultivalue();
builder.searchable = metadata.isSearchable();
builder.transiency = metadata.getTransiency();
builder.sortable = metadata.isSortable();
builder.schemaAutocomplete = metadata.isSchemaAutocomplete();
builder.unmodifiable = metadata.isUnmodifiable();
builder.encrypted = metadata.isEncrypted();
builder.uniqueValue = metadata.isUniqueValue();
builder.systemReserved = metadata.isSystemReserved();
builder.essential = metadata.isEssential();
builder.essentialInSummary = metadata.isEssentialInSummary();
builder.childOfRelationship = metadata.isChildOfRelationship();
builder.taxonomyRelationship = metadata.isTaxonomyRelationship();
builder.markedForDeletion = metadata.isMarkedForDeletion();
builder.recordMetadataValidators = new ClassListBuilder<RecordMetadataValidator<?>>(
builder.classProvider, RecordMetadataValidator.class, metadata.getValidators());
builder.accessRestrictionBuilder = null;
builder.multiLingual = metadata.isMultiLingual();
builder.customAttributes = inheritanceMetadata.customAttributes;
builder.increasedDependencyLevel = metadata.isIncreasedDependencyLevel();
for (String validatorClassName : inheritanceMetadata.recordMetadataValidators.implementationsClassname) {
builder.recordMetadataValidators.remove(validatorClassName);
}
if (inheritanceMetadata.getLabels() != null && !inheritanceMetadata.getLabels().isEmpty()) {
for (Language language : inheritanceMetadata.getLabels().keySet()) {
if (!inheritanceMetadata.getLabel(language).equals(metadata.getLabel(language))) {
builder.addLabel(language, metadata.getLabel(language));
}
}
}
if (metadata.getInputMask() != null && !metadata.getInputMask().equals(inheritanceMetadata.getInputMask())) {
builder.inputMask = metadata.getInputMask();
}
if (metadata.getDefaultValue() != null && !metadata.getDefaultValue().equals(inheritanceMetadata.getDefaultValue())) {
builder.defaultValue = metadata.getDefaultValue();
}
if (inheritanceMetadata.getEnabled() != null && !inheritanceMetadata.getEnabled().equals(metadata.isEnabled())) {
builder.enabled = metadata.isEnabled();
}
if (metadata.getStructureFactory() != null) {
builder.structureFactoryClass = (Class) metadata.getStructureFactory().getClass();
}
builder.enumClass = metadata.getEnumClass();
if (inheritanceMetadata.getDefaultRequirement() != null
&& inheritanceMetadata.getDefaultRequirement().equals(metadata.isDefaultRequirement())) {
builder.setDefaultRequirement(null);
}
builder.populateConfigsBuilder = MetadataPopulateConfigsBuilder.modify(metadata.getPopulateConfigs());
if (inheritanceMetadata.isDuplicable() != null && !inheritanceMetadata.isDuplicable().equals(metadata.isDuplicable())) {
builder.duplicable = metadata.isDuplicable();
}
}
public MetadataBuilder getInheritance() {
return inheritance;
}
public String getLocalCode() {
return localCode;
}
private MetadataBuilder setLocalCode(String localCode) {
ensureCanModify("localCode");
this.localCode = localCode;
return this;
}
public String getCollection() {
return collection;
}
private MetadataBuilder setCollection(String collection) {
ensureCanModify("collection");
this.collection = collection;
return this;
}
public String getCode() {
return code;
}
private MetadataBuilder setCode(String code) {
this.code = code;
return this;
}
public String getLabel(Language language) {
return labels.get(language);
}
public Map<Language, String> getLabels() {
return labels;
}
public MetadataBuilder setLabels(Map<Language, String> labels) {
if (labels == null) {
this.labels = new HashMap<>();
} else {
this.labels = new HashMap<>(labels);
}
return this;
}
public MetadataBuilder addLabel(Language language, String label) {
this.labels.put(language, label);
return this;
}
public Boolean getEnabled() {
return enabled;
}
public MetadataBuilder setEnabled(Boolean enabled) {
this.enabled = enabled;
return this;
}
public Boolean isUndeletable() {
return inheritance == null ? undeletable : inheritance.isUndeletable();
}
public MetadataBuilder setUndeletable(boolean undeletable) {
ensureCanModify("undeletable");
this.undeletable = undeletable;
return this;
}
public boolean isMultivalue() {
return inheritance == null ? multivalue : inheritance.isMultivalue();
}
public MetadataBuilder setMultivalue(boolean multivalue) {
ensureCanModify("multivalue");
if (multivalue && isUniqueValue()) {
throw new MetadataCannotBeUniqueAndMultivalue(localCode);
}
this.multivalue = multivalue;
return this;
}
public boolean isMultiLingual() {
return inheritance == null ? multiLingual : inheritance.isMultiLingual();
}
public MetadataBuilder setMultiLingual(boolean multiLingual) {
ensureCanModify("multiLingual");
this.multiLingual = multiLingual;
return this;
}
public boolean isSortable() {
return inheritance == null ? sortable : inheritance.isSortable();
}
public MetadataBuilder setSortable(boolean sortable) {
ensureCanModify("sortable");
this.sortable = sortable;
return this;
}
public boolean isIncreasedDependencyLevel() {
return inheritance == null ? increasedDependencyLevel : inheritance.isIncreasedDependencyLevel();
}
public MetadataBuilder setIncreasedDependencyLevel(boolean increasedDependencyLevel) {
ensureCanModify("increasedDependencyLevel");
this.increasedDependencyLevel = increasedDependencyLevel;
return this;
}
public boolean isSearchable() {
return inheritance == null ? searchable : inheritance.isSearchable();
}
public MetadataBuilder setSearchable(boolean searchable) {
ensureCanModify("searchable");
this.searchable = searchable;
return this;
}
public MetadataTransiency getTransiency() {
return inheritance == null ? transiency : inheritance.getTransiency();
}
public MetadataBuilder setTransiency(MetadataTransiency transiency) {
ensureCanModify("transiency");
this.transiency = transiency;
return this;
}
public boolean isSchemaAutocomplete() {
return inheritance == null ? schemaAutocomplete : inheritance.isSchemaAutocomplete();
}
public MetadataBuilder setSchemaAutocomplete(boolean schemaAutocomplete) {
ensureCanModify("autocomplete");
this.schemaAutocomplete = schemaAutocomplete;
return this;
}
public boolean isUniqueValue() {
return inheritance == null ? uniqueValue : inheritance.uniqueValue;
}
public MetadataBuilder setUniqueValue(boolean uniqueValue) {
ensureCanModify("uniqueValue");
if (uniqueValue && isMultivalue()) {
throw new MetadataCannotBeUniqueAndMultivalue(localCode);
}
this.uniqueValue = uniqueValue;
return this;
}
public boolean isUnmodifiable() {
return inheritance == null ? unmodifiable : inheritance.unmodifiable;
}
public MetadataBuilder setUnmodifiable(boolean unmodifiable) {
ensureCanModify("unmodifiable");
this.unmodifiable = unmodifiable;
return this;
}
public boolean isSystemReserved() {
return inheritance == null ? systemReserved : inheritance.systemReserved;
}
public MetadataBuilder setSystemReserved(boolean systemReserved) {
ensureCanModify("systemReserved");
this.systemReserved = systemReserved;
if (systemReserved) {
this.undeletable = true;
}
return this;
}
public boolean isEssential() {
return inheritance == null ? essential : inheritance.essential;
}
public boolean isEssentialInSummary() {
return inheritance == null ? essentialInSummary : inheritance.essentialInSummary;
}
public MetadataBuilder setEssential(boolean essential) {
ensureCanModify("essential");
this.essential = essential;
if (essential) {
this.undeletable = true;
}
return this;
}
public MetadataBuilder setEssentialInSummary(boolean essentialInSummary) {
ensureCanModify("essentialInSummary");
this.essentialInSummary = essentialInSummary;
return this;
}
public boolean isEncrypted() {
return inheritance == null ? encrypted : inheritance.encrypted;
}
public MetadataBuilder setEncrypted(boolean encrypted) {
ensureCanModify("encrypted");
this.encrypted = encrypted;
return this;
}
public boolean isMarkedForDeletion() {
return inheritance == null ? markedForDeletion : inheritance.markedForDeletion;
}
public MetadataBuilder setMarkedForDeletion(boolean markedForDeletion) {
ensureCanModify("markedForDeletion");
if (markedForDeletion) {
setEssentialInSummary(false);
setEssential(false);
setDefaultRequirement(false);
setEnabled(false);
}
this.markedForDeletion = markedForDeletion;
return this;
}
public Object getDefaultValue() {
return defaultValue;
}
public MetadataBuilder setDefaultValue(Object defaultValue) {
this.defaultValue = defaultValue;
return this;
}
public String getInputMask() {
return inputMask;
}
public MetadataBuilder setInputMask(String inputMask) {
this.inputMask = inputMask;
return this;
}
public MetadataPopulateConfigsBuilder getPopulateConfigsBuilder() {
return populateConfigsBuilder;
}
public MetadataPopulateConfigsBuilder definePopulateConfigsBuilder(MetadataPopulateConfigsBuilder populateConfigsBuilder) {
this.populateConfigsBuilder = populateConfigsBuilder;
return this.populateConfigsBuilder;
}
AllowedReferencesBuilder getAllowedReferencesBuider() {
return inheritance == null ? allowedReferencesBuilder : inheritance.allowedReferencesBuilder;
}
public Boolean getDefaultRequirement() {
return defaultRequirement;
}
public MetadataBuilder required() {
return setDefaultRequirement(true);
}
public MetadataBuilder setDefaultRequirement(Boolean defaultRequirement) {
this.defaultRequirement = defaultRequirement;
return this;
}
public MetadataValueType getType() {
return inheritance == null ? type : inheritance.type;
}
public MetadataBuilder setTypeWithoutValidation(MetadataValueType newType) {
//Warning : Dangerous!
this.type = newType;
return this;
}
public MetadataBuilder setType(MetadataValueType newType) {
ensureCanModify("type");
if (this.type != null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(code, "type");
}
if (newType == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(code, "type");
}
this.type = newType;
if (this.type == MetadataValueType.CONTENT) {
this.structureFactoryClass = ContentFactory.class;
}
return this;
}
public Boolean isDuplicable() {
return duplicable;
}
public MetadataBuilder setDuplicable(Boolean duplicable) {
this.duplicable = duplicable;
return this;
}
public AllowedReferencesBuilder defineReferences() {
ensureCanModify("defineReferences");
if (type == null) {
type = MetadataValueType.REFERENCE;
}
if (type != MetadataValueType.REFERENCE) {
throw new MetadataBuilderRuntimeException.AllowedReferencesOnlyUsableOnReferenceTypeMetadata(code);
}
if (allowedReferencesBuilder == null) {
allowedReferencesBuilder = new AllowedReferencesBuilder();
}
return allowedReferencesBuilder;
}
public MetadataBuilder defineChildOfRelationshipToType(MetadataSchemaTypeBuilder schemaType) {
setChildOfRelationship(true);
return defineReferencesTo(schemaType);
}
public MetadataBuilder defineChildOfRelationshipToSchemas(MetadataSchemaBuilder... schemas) {
return defineChildOfRelationshipToSchemas(Arrays.asList(schemas));
}
public MetadataBuilder defineChildOfRelationshipToSchemas(List<MetadataSchemaBuilder> schemas) {
setChildOfRelationship(true);
return defineReferencesTo(schemas);
}
public MetadataBuilder defineTaxonomyRelationshipToType(MetadataSchemaTypeBuilder schemaType) {
setTaxonomyRelationship(true);
return defineReferencesTo(schemaType);
}
public MetadataBuilder defineTaxonomyRelationshipToSchemas(MetadataSchemaBuilder... schemas) {
return defineTaxonomyRelationshipToSchemas(Arrays.asList(schemas));
}
public MetadataBuilder defineTaxonomyRelationshipToSchemas(List<MetadataSchemaBuilder> schemas) {
setTaxonomyRelationship(true);
return defineReferencesTo(schemas);
}
public MetadataBuilder defineReferencesTo(MetadataSchemaTypeBuilder schemaType) {
defineReferences().setCompleteSchemaTypeCode(schemaType.getCode());
return this;
}
public MetadataBuilder defineReferencesTo(MetadataSchemaBuilder... schemas) {
return defineReferencesTo(Arrays.asList(schemas));
}
public MetadataBuilder defineReferencesTo(List<MetadataSchemaBuilder> schemas) {
for (MetadataSchemaBuilder schema : schemas) {
defineReferences().getSchemas().add(schema.getCode());
}
return this;
}
public DataEntry getDataEntry() {
return inheritance == null ? dataEntry : inheritance.dataEntry;
}
Metadata buildWithInheritance(Metadata inheritance) {
if (this.getLabels() == null || this.getLabels().isEmpty()) {
this.setLabels(inheritance.getLabels());
} else {
for (Language language : inheritance.getLabels().keySet()) {
if ((this.getLabel(language) == null || this.getLabel(language).equals(localCode))) {
addLabel(language, inheritance.getLabel(language));
}
}
}
if (this.getEnabled() == null) {
this.enabled = inheritance.isEnabled();
}
if (this.getDefaultRequirement() == null) {
this.defaultRequirement = inheritance.isDefaultRequirement();
}
if (!this.getPopulateConfigsBuilder().isEmpty()) {
this.populateConfigsBuilder = MetadataPopulateConfigsBuilder.modify(this.getPopulateConfigsBuilder());
} else {
this.populateConfigsBuilder = MetadataPopulateConfigsBuilder.modify(inheritance.getPopulateConfigs());
}
if (inputMask == null) {
this.inputMask = inheritance.getInputMask();
}
if (this.defaultValue == null) {
this.defaultValue = inheritance.getDefaultValue();
}
validateWithInheritance(inheritance, this);
MetadataPopulateConfigs populateConfigs = this.populateConfigsBuilder.build();
if (originalMetadata != null && this.inheritance != null && this.inheritance.originalMetadata != null && populateConfigs
.equals(originalMetadata.getPopulateConfigs())) {
if (originalMetadata.getPopulateConfigs().equals(this.inheritance.originalMetadata.getPopulateConfigs())) {
populateConfigs = inheritance.getPopulateConfigs();
}
}
if (duplicable == null) {
duplicable = inheritance.isDuplicable();
}
return new Metadata(inheritance, this.getLabels(), this.getEnabled(), this.getDefaultRequirement(), this.code,
this.recordMetadataValidators.build(), this.defaultValue, this.inputMask, populateConfigs, duplicable);
}
Metadata buildWithoutInheritance(DataStoreTypesFactory typesFactory, final ModelLayerFactory modelLayerFactory) {
AllowedReferences references = allowedReferencesBuilder == null ? null : allowedReferencesBuilder.build();
Set<RecordMetadataValidator<?>> validators = this.recordMetadataValidators.build();
if (enabled == null) {
enabled = true;
}
if (defaultRequirement == null) {
defaultRequirement = false;
}
if (this.dataEntry == null) {
this.dataEntry = new ManualDataEntry();
}
if (references != null && taxonomyRelationship && multivalue) {
TaxonomiesManager taxonomiesManager = modelLayerFactory.getTaxonomiesManager();
validateNotReferencingTaxonomy(references.getTypeWithAllowedSchemas(), taxonomiesManager);
}
validateWithoutInheritance(this);
String dataStoreType = getDataStoreType(this.getLocalCode(), typesFactory, this.type, this.multivalue);
StructureFactory structureFactory = new InstanciationUtils()
.instanciateWithoutExpectableExceptions(structureFactoryClass);
InheritedMetadataBehaviors behaviors = new InheritedMetadataBehaviors(this.isUndeletable(), multivalue, systemReserved,
unmodifiable, uniqueValue, childOfRelationship, taxonomyRelationship, sortable, searchable, schemaAutocomplete,
essential, encrypted, essentialInSummary, multiLingual, markedForDeletion, customAttributes,
increasedDependencyLevel, transiency);
MetadataAccessRestriction accessRestriction = accessRestrictionBuilder.build();
final Factory<ModelLayerFactory> modelLayerFactoryFactory = modelLayerFactory.getModelLayerFactoryFactory();
Factory<EncryptionServices> encryptionServicesFactory = new Factory<EncryptionServices>() {
@Override
public EncryptionServices get() {
return modelLayerFactoryFactory.get().newEncryptionServices();
}
};
if (duplicable == null) {
duplicable = false;
}
return new Metadata(localCode, this.getCode(), collection, this.getLabels(), this.getEnabled(), behaviors,
this.type, references, this.getDefaultRequirement(), this.dataEntry, validators, dataStoreType,
accessRestriction, structureFactory, enumClass, defaultValue, inputMask, populateConfigsBuilder.build(),
encryptionServicesFactory, duplicable);
}
private void validateNotReferencingTaxonomy(String typeWithAllowedSchemas, TaxonomiesManager taxonomiesManager) {
Taxonomy principalTaxonomy = taxonomiesManager.getPrincipalTaxonomy(collection);
if (principalTaxonomy != null && principalTaxonomy.getSchemaTypes().contains(typeWithAllowedSchemas)) {
throw new CannotCreateMultivalueReferenceToPrincipalTaxonomy(code);
}
}
private String getDataStoreType(String metadataCode, DataStoreTypesFactory typesFactory, MetadataValueType type,
boolean multivalue) {
if (metadataCode.equals("id")) {
return null;
}
String dataStoreType;
switch (type) {
case BOOLEAN:
dataStoreType = typesFactory.forBoolean(multivalue);
break;
case ENUM:
dataStoreType = typesFactory.forString(multivalue);
break;
case CONTENT:
dataStoreType = typesFactory.forString(multivalue);
break;
case STRUCTURE:
dataStoreType = typesFactory.forString(multivalue);
break;
case DATE:
dataStoreType = typesFactory.forDate(multivalue);
break;
case DATE_TIME:
dataStoreType = typesFactory.forDateTime(multivalue);
break;
case NUMBER:
dataStoreType = typesFactory.forDouble(multivalue);
break;
case REFERENCE:
dataStoreType = typesFactory.forString(multivalue);
break;
case STRING:
dataStoreType = typesFactory.forString(multivalue);
break;
case TEXT:
dataStoreType = typesFactory.forText(multivalue);
break;
default:
throw new ImpossibleRuntimeException("Unsupported type : " + type);
}
return dataStoreType;
}
@Override
public String toString() {
return "MetadataBuilder [inheritance=" + inheritance + ", localCode=" + localCode + ", code=" + code + ", enabled="
+ enabled + ", type=" + type + ", allowedReferencesBuilder=" + allowedReferencesBuilder
+ ", undeletable=" + undeletable + ", defaultRequirement=" + defaultRequirement + ", dataEntry=" + dataEntry
+ ", duplicable=" + duplicable + "]";
}
public MetadataBuilder addValidator(Class<? extends RecordMetadataValidator> clazz) {
defineValidators().add(clazz);
return this;
}
public ClassListBuilder<RecordMetadataValidator<?>> defineValidators() {
return recordMetadataValidators;
}
public DataEntryBuilder defineDataEntry() {
ensureCanModify("data entry");
// if (dataEntry != null) {
// throw new MetadataBuilderRuntimeException.InvalidAttribute(this.localCode, "data entry already defined");
// }
return new DataEntryBuilder(this);
}
private void ensureCanModify(String attribute) {
if (this.inheritance != null) {
throw new MetadataSchemaBuilderRuntimeException.CannotModifyAttributeOfInheritingMetadata(this.getLocalCode(),
attribute);
}
}
private void validateWithInheritance(Metadata inheritance, MetadataBuilder builder) {
if (inheritance == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "inheritance");
}
validateCode(inheritance.getLocalCode());
if (builder.getLabels() == null || builder.getLabels().isEmpty()) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "label");
} else {
for (Entry<Language, String> entry : builder.getLabels().entrySet()) {
if (StringUtils.isBlank(entry.getValue())) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "label");
}
}
}
if (builder.getEnabled() == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "enabled");
}
if (builder.getDefaultRequirement() == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "defaultRequirement");
}
if (Boolean.FALSE == builder.getEnabled() && inheritance.isEssential()) {
throw new EssentialMetadataCannotBeDisabled(code);
}
if (Boolean.FALSE == builder.getEnabled() && inheritance.isEssentialInSummary()) {
throw new EssentialMetadataInSummaryCannotBeDisabled(code);
}
}
private void validateWithoutInheritance(MetadataBuilder builder) {
validateCode(builder.localCode);
if (builder.code == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "code");
}
if (builder.getLabels() == null || builder.getLabels().isEmpty()) {
//FIXME
builder.addLabel(Language.French, builder.getCode());
// throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "label");
}
if (builder.getEnabled() == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "enabled");
}
if (builder.type == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "type");
}
if (!isReferenceMetadataValid(builder)) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "allowedReferences");
}
if (builder.dataEntry == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "dataEntry");
}
if (builder.defaultRequirement == null) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(builder.getCode(), "defaultRequirement");
}
if (builder.getType().equals(MetadataValueType.REFERENCE)) {
builder.defineReferences().getSchemaType();
}
if (Boolean.FALSE == builder.getEnabled() && builder.isEssential()) {
throw new EssentialMetadataCannotBeDisabled(code);
}
if (Boolean.FALSE == builder.getEnabled() && builder.isEssentialInSummary()) {
throw new EssentialMetadataInSummaryCannotBeDisabled(code);
}
if ((transiency != null && transiency != PERSISTED) && builder.getDataEntry().getType() == MANUAL) {
throw new MetadataBuilderRuntimeException.MetadataEnteredManuallyCannotBeTransient(code);
}
if ((transiency != null && transiency != PERSISTED) && builder.getType() == MetadataValueType.REFERENCE) {
throw new MetadataBuilderRuntimeException.ReferenceCannotBeTransient(code);
}
}
private boolean isReferenceMetadataValid(MetadataBuilder builder) {
if (builder.type == MetadataValueType.REFERENCE) {
AllowedReferencesBuilder allowedReferencesBuilder = builder.allowedReferencesBuilder;
if (allowedReferencesBuilder == null) {
return false;
} else
return !((allowedReferencesBuilder.getSchemas() == null || allowedReferencesBuilder.getSchemas().isEmpty())
&& builder.allowedReferencesBuilder.getSchemaType() == null);
}
return true;
}
void validateCode(String localCode) {
if (SchemaUtils.isValidMetadataCodeWithCache(localCode)) {
throw new MetadataBuilderRuntimeException.InvalidAttribute(this.getCode(), "code");
}
}
public boolean isChildOfRelationship() {
return inheritance == null ? childOfRelationship : inheritance.childOfRelationship;
}
public boolean isTaxonomyRelationship() {
return inheritance == null ? taxonomyRelationship : inheritance.taxonomyRelationship;
}
public MetadataBuilder setChildOfRelationship(boolean childOfRelationship) {
ensureCanModify("childOfRelationship");
this.childOfRelationship = childOfRelationship;
return this;
}
public MetadataBuilder setTaxonomyRelationship(boolean taxonomyRelationship) {
ensureCanModify("taxonomyRelationship");
this.taxonomyRelationship = taxonomyRelationship;
return this;
}
public MetadataAccessRestrictionBuilder defineAccessRestrictions() {
return accessRestrictionBuilder;
}
public MetadataBuilder defineStructureFactory(Class<? extends StructureFactory> structureFactory) {
this.structureFactoryClass = structureFactory;
if (this.type == null) {
this.type = MetadataValueType.STRUCTURE;
}
return this;
}
public Class<? extends StructureFactory> getStructureFactory() {
return structureFactoryClass;
}
public boolean hasDefinedReferences() {
return allowedReferencesBuilder != null;
}
public MetadataBuilder defineAsEnum(Class<? extends Enum<?>> enumClass) {
if (enumClass == null) {
throw new InvalidAttribute(code, "enumClass");
}
if (!EnumWithSmallCode.class.isAssignableFrom(enumClass)) {
throw new MetadataBuilderRuntimeException.EnumClassMustImplementEnumWithSmallCode(enumClass);
}
this.enumClass = enumClass;
this.type = MetadataValueType.ENUM;
return this;
}
public Class<? extends Enum<?>> getEnumClass() {
return enumClass;
}
public AllowedReferencesBuilder getAllowedReferencesBuilder() {
return allowedReferencesBuilder;
}
public Metadata getOriginalMetadata() {
return originalMetadata;
}
public void setAllowedReferenceBuilder(AllowedReferencesBuilder allowedReferencesBuilder) {
this.allowedReferencesBuilder = allowedReferencesBuilder;
}
public boolean hasFlag(String flag) {
return customAttributes.contains(flag);
}
public MetadataBuilder setCustomAttributes(Set<String> customAttributes) {
this.customAttributes = customAttributes;
return this;
}
public MetadataBuilder addCustomAttribute(String customAttribute) {
if (customAttribute.contains(",")) {
throw new MetadataBuilderRuntimeException.InvalidAttribute("Custom Attribute", customAttribute);
}
customAttributes.add(customAttribute);
return this;
}
public MetadataBuilder removeCustomAttribute(String customAttribute) {
customAttributes.remove(customAttribute);
return this;
}
public ClassProvider getClassProvider() {
return classProvider;
}
public Set<String> getCustomAttributes() {
return Collections.unmodifiableSet(customAttributes);
}
}