package com.constellio.model.entities.schemas;
import static com.constellio.model.entities.Language.French;
import static com.constellio.model.entities.schemas.MetadataValueType.STRING;
import static com.constellio.model.entities.schemas.MetadataTransiency.PERSISTED;
import static com.constellio.model.entities.schemas.Schemas.CODE;
import static com.constellio.model.entities.schemas.Schemas.IDENTIFIER;
import static com.constellio.model.entities.schemas.Schemas.TITLE;
import static com.constellio.model.services.schemas.builders.ClassListBuilder.combine;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import com.constellio.data.utils.Factory;
import com.constellio.model.entities.Language;
import com.constellio.model.entities.schemas.entries.DataEntry;
import com.constellio.model.entities.schemas.sort.DefaultStringSortFieldNormalizer;
import com.constellio.model.entities.schemas.sort.StringSortFieldNormalizer;
import com.constellio.model.entities.schemas.validation.RecordMetadataValidator;
import com.constellio.model.services.encrypt.EncryptionServices;
import com.constellio.model.services.schemas.SchemaUtils;
public class Metadata implements DataStoreField {
final Metadata inheritance;
final String collection;
final String localCode;
final String code;
final Map<Language, String> labels;
final String dataStoreType;
final boolean enabled;
final MetadataValueType type;
final AllowedReferences allowedReferences;
final boolean defaultRequirement;
final DataEntry dataEntry;
final InheritedMetadataBehaviors inheritedMetadataBehaviors;
final Set<RecordMetadataValidator<?>> recordMetadataValidators;
final MetadataAccessRestriction accessRestriction;
final StructureFactory structureFactory;
final Class<? extends Enum<?>> enumClass;
final Object defaultValue;
final MetadataPopulateConfigs populateConfigs;
final Factory<EncryptionServices> encryptionServicesFactory;
final String inputMask;
final boolean duplicable;
final String dataStoreCode;
final String inheritanceCode;
final boolean global;
Metadata(String localCode, MetadataValueType type, boolean multivalue) {
this("global_default", localCode, type, multivalue, false);
}
Metadata(String localCode, MetadataValueType type, boolean multivalue, boolean multiLingual) {
this("global_default", localCode, type, multivalue, multiLingual);
}
Metadata(String schemaCode, String datastoreCode, MetadataValueType type, boolean multivalue, boolean multiLingual) {
this.inheritance = null;
this.enabled = false;
this.collection = null;
this.type = type;
this.allowedReferences = null;
this.inheritedMetadataBehaviors = new InheritedMetadataBehaviors(false, multivalue, false, false, false, false, false,
false, false, false, false, false, false, multiLingual, false, new HashSet<String>(), false, PERSISTED);
this.defaultRequirement = false;
this.dataEntry = null;
this.encryptionServicesFactory = null;
this.accessRestriction = new MetadataAccessRestriction();
this.inputMask = null;
if (datastoreCode.contains("_") && !datastoreCode.equals("_version_")) {
int firstUnderscoreIndex = datastoreCode.indexOf("_");
String codeWithoutId = datastoreCode.substring(0, firstUnderscoreIndex);
this.dataStoreType = datastoreCode.substring(firstUnderscoreIndex + 1);
if (codeWithoutId.endsWith("PId")) {
codeWithoutId = codeWithoutId.substring(0, codeWithoutId.length() - 3);
}
if (codeWithoutId.endsWith("Id")) {
codeWithoutId = codeWithoutId.substring(0, codeWithoutId.length() - 2);
}
this.localCode = codeWithoutId;
this.code = schemaCode + "_" + this.localCode;
} else {
this.localCode = datastoreCode;
this.dataStoreType = null;
this.code = schemaCode + "_" + localCode;
}
this.labels = Collections.emptyMap();
this.recordMetadataValidators = null;
this.structureFactory = null;
this.enumClass = null;
this.defaultValue = multivalue ? Collections.emptyList() : null;
this.populateConfigs = new MetadataPopulateConfigs();
this.duplicable = false;
this.dataStoreCode = computeDataStoreCode();
this.inheritanceCode = computeInheritanceCode();
this.global = computeIsGlobal();
}
public final String computeInheritanceCode() {
if (getInheritance() == null) {
return getCode();
} else {
String[] parts = SchemaUtils.underscoreSplitWithCache(getCode());
return parts[0] + "_default_" + parts[2];
}
}
private String computeDataStoreCode() {
if (type == MetadataValueType.REFERENCE) {
if (isChildOfRelationship()) {
return dataStoreType == null ? localCode : (localCode + "PId_" + dataStoreType);
} else {
return dataStoreType == null ? localCode : (localCode + "Id_" + dataStoreType);
}
} else {
return dataStoreType == null ? localCode : (localCode + "_" + dataStoreType);
}
}
public final boolean computeIsGlobal() {
return Schemas.isGlobalMetadata(getLocalCode());
}
public Metadata(String localCode, String code, String collection, Map<Language, String> labels, Boolean enabled,
InheritedMetadataBehaviors inheritedMetadataBehaviors, MetadataValueType type,
AllowedReferences allowedReferences, Boolean defaultRequirement, DataEntry dataEntry,
Set<RecordMetadataValidator<?>> recordMetadataValidators, String dataStoreType,
MetadataAccessRestriction accessRestriction, StructureFactory structureFactory, Class<? extends Enum<?>> enumClass,
Object defaultValue, String inputMask, MetadataPopulateConfigs populateConfigs,
Factory<EncryptionServices> encryptionServices, Boolean duplicatbale) {
super();
this.inheritance = null;
this.localCode = localCode;
this.code = code;
this.collection = collection;
this.labels = Collections.unmodifiableMap(labels);
this.enabled = enabled;
this.type = type;
this.allowedReferences = allowedReferences;
this.inheritedMetadataBehaviors = inheritedMetadataBehaviors;
this.defaultRequirement = defaultRequirement;
this.dataEntry = dataEntry;
this.dataStoreType = dataStoreType;
this.recordMetadataValidators = recordMetadataValidators;
this.accessRestriction = accessRestriction;
this.structureFactory = structureFactory;
this.enumClass = enumClass;
this.defaultValue = defaultValue;
this.inputMask = inputMask;
this.populateConfigs = populateConfigs;
this.encryptionServicesFactory = encryptionServices;
this.duplicable = duplicatbale;
this.dataStoreCode = computeDataStoreCode();
this.inheritanceCode = computeInheritanceCode();
this.global = computeIsGlobal();
}
public Metadata(Metadata inheritance, Map<Language, String> labels, boolean enabled, boolean defaultRequirement, String code,
Set<RecordMetadataValidator<?>> recordMetadataValidators, Object defaultValue, String inputMask,
MetadataPopulateConfigs populateConfigs, boolean duplicable) {
super();
this.localCode = inheritance.getLocalCode();
this.code = code;
this.collection = inheritance.collection;
this.inheritance = inheritance;
this.labels = Collections.unmodifiableMap(labels);
this.enabled = enabled;
this.type = inheritance.getType();
this.allowedReferences = inheritance.getAllowedReferences();
this.inheritedMetadataBehaviors = inheritance.getInheritedMetadataBehaviors();
this.defaultRequirement = defaultRequirement;
this.dataEntry = inheritance.getDataEntry();
this.dataStoreType = inheritance.getDataStoreType();
this.accessRestriction = inheritance.getAccessRestrictions();
this.recordMetadataValidators = combine(inheritance.recordMetadataValidators, recordMetadataValidators);
this.populateConfigs = populateConfigs;
this.structureFactory = inheritance.structureFactory;
this.enumClass = inheritance.enumClass;
this.defaultValue = defaultValue;
this.inputMask = inputMask;
this.encryptionServicesFactory = inheritance.encryptionServicesFactory;
this.duplicable = duplicable;
this.dataStoreCode = computeDataStoreCode();
this.inheritanceCode = computeInheritanceCode();
this.global = computeIsGlobal();
}
public String getCode() {
return code;
}
public String getLocalCode() {
return localCode;
}
public String getDataStoreCode() {
return dataStoreCode;
}
public String getFrenchLabel() {
return getLabel(French);
}
public String getLabel(Language language) {
return labels.get(language);
}
public Map<Language, String> getLabels() {
return labels;
}
public Map<String, String> getLabelsByLanguageCodes() {
Map<String, String> labelsMap = new HashMap<>();
for (Language language : getLabels().keySet()) {
labelsMap.put(language.getCode(), getLabels().get(language));
}
return labelsMap;
}
public boolean isEnabled() {
return enabled;
}
public boolean inheritDefaultSchema() {
return inheritance != null;
}
public MetadataValueType getType() {
return type;
}
public String getReferencedSchemaType() {
return getAllowedReferences().getTypeWithAllowedSchemas();
}
public AllowedReferences getAllowedReferences() {
return allowedReferences;
}
public InheritedMetadataBehaviors getInheritedMetadataBehaviors() {
return inheritedMetadataBehaviors;
}
public Metadata getInheritance() {
return inheritance;
}
public boolean isDefaultRequirement() {
return defaultRequirement;
}
public DataEntry getDataEntry() {
return dataEntry;
}
public String getDataStoreType() {
return dataStoreType;
}
public boolean isMultivalue() {
return getInheritedMetadataBehaviors().isMultivalue();
}
public boolean isMultiLingual() {
return getInheritedMetadataBehaviors().isMultiLingual();
}
public boolean isUndeletable() {
return getInheritedMetadataBehaviors().isUndeletable();
}
public boolean isSystemReserved() {
return getInheritedMetadataBehaviors().isSystemReserved();
}
public boolean isUnmodifiable() {
return getInheritedMetadataBehaviors().isUnmodifiable();
}
public boolean isUniqueValue() {
return getInheritedMetadataBehaviors().isUniqueValue();
}
public boolean isChildOfRelationship() {
return getInheritedMetadataBehaviors().isChildOfRelationship();
}
public boolean isTaxonomyRelationship() {
return getInheritedMetadataBehaviors().isTaxonomyRelationship();
}
public boolean isSearchable() {
return getInheritedMetadataBehaviors().isSearchable();
}
public MetadataTransiency getTransiency() {
return getInheritedMetadataBehaviors().getTransiency();
}
public boolean isSortable() {
return getInheritedMetadataBehaviors().isSortable();
}
public boolean isEssential() {
return getInheritedMetadataBehaviors().isEssential();
}
public boolean isEssentialInSummary() {
return getInheritedMetadataBehaviors().isEssentialInSummary();
}
public boolean isEncrypted() {
return getInheritedMetadataBehaviors().isEncrypted();
}
public boolean isSchemaAutocomplete() {
return getInheritedMetadataBehaviors().isSchemaAutocomplete();
}
public Set<String> getCustomAttributes() {
return getInheritedMetadataBehaviors().getCustomAttributes();
}
public boolean isIncreasedDependencyLevel() {
return getInheritedMetadataBehaviors().isReverseDependency();
}
public StringSortFieldNormalizer getSortFieldNormalizer() {
return hasNormalizedSortField() ? new DefaultStringSortFieldNormalizer() : null;
}
public Object getDefaultValue() {
return defaultValue;
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "dataEntry", "structureFactory", "encryptionServicesFactory");
}
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj, "dataEntry", "recordMetadataValidators", "structureFactory",
"encryptionServicesFactory");
}
@Override
public String toString() {
return localCode;
}
public Set<RecordMetadataValidator<?>> getValidators() {
return recordMetadataValidators;
}
public String getCollection() {
return collection;
}
public final boolean isLocalCode(String code) {
return getLocalCode().equals(code);
}
public MetadataAccessRestriction getAccessRestrictions() {
return accessRestriction;
}
public StructureFactory getStructureFactory() {
return structureFactory;
}
public Class<? extends Enum<?>> getEnumClass() {
return enumClass;
}
public static Metadata newDummyMetadata(String schemaCode, String localCode, MetadataValueType type, boolean multivalue,
boolean multiLingual) {
return new Metadata(schemaCode, localCode, type, multivalue, multiLingual);
}
public static Metadata newGlobalMetadata(String dataStoreCode, MetadataValueType type, boolean multivalue,
boolean multiLingual) {
return new Metadata("global_default", dataStoreCode, type, multivalue, multiLingual);
}
public Metadata getSearchableMetadataWithLanguage(String language) {
String schemaCode = code.replace("_" + localCode, "");
return new Metadata(schemaCode, getDataStoreCode().replace("_s", "_t") + "_" + language, type, isMultivalue(),
isMultiLingual());
}
public boolean isSameLocalCode(Metadata metadata) {
return localCode.equals(metadata.getLocalCode());
}
public boolean isSameLocalCodeThanAny(Metadata... metadatas) {
for (Metadata metadata : metadatas) {
if (localCode.equals(metadata.getLocalCode())) {
return true;
}
}
return false;
}
public boolean isSameLocalCodeIn(String... metadatasLocalCodes) {
for (String metadataLocalCode : metadatasLocalCodes) {
if (localCode.equals(metadataLocalCode)) {
return true;
}
}
return false;
}
public String getSchemaCode() {
return new SchemaUtils().getSchemaCode(this);
}
public MetadataPopulateConfigs getPopulateConfigs() {
return populateConfigs;
}
public boolean hasCode(String otherCode) {
return new SchemaUtils().hasSameTypeAndLocalCode(code, otherCode);
}
public Factory<EncryptionServices> getEncryptionServicesFactory() {
return encryptionServicesFactory;
}
public Metadata getAnalyzedField(String languageCode) {
return Schemas.getSearchableMetadata(this, languageCode);
}
public boolean hasNormalizedSortField() {
boolean globalMetadataWithNormalizedSortField =
CODE.getLocalCode().equals(getLocalCode()) || TITLE.getLocalCode().equals(getLocalCode());
boolean isIdentifier = IDENTIFIER.getDataStoreCode().equals(getDataStoreCode());
return (isSortable() || globalMetadataWithNormalizedSortField) && type == STRING && !isMultivalue() && !isIdentifier;
}
public Metadata getSortField() {
return hasNormalizedSortField() ? Schemas.getSortMetadata(this) : null;
}
public boolean isSameValueThan(Metadata otherMetadata) {
boolean sameValue = type == otherMetadata.type &&
isMultivalue() == otherMetadata.isMultivalue();
if (sameValue && otherMetadata.type == MetadataValueType.REFERENCE) {
sameValue = allowedReferences.equals(otherMetadata.getAllowedReferences());
}
if (sameValue && otherMetadata.type == MetadataValueType.ENUM) {
sameValue = enumClass.equals(otherMetadata.getEnumClass());
}
if (sameValue && otherMetadata.type == MetadataValueType.STRUCTURE) {
sameValue = structureFactory.getClass().equals(otherMetadata.getStructureFactory().getClass());
}
return sameValue;
}
public String getInputMask() {
return inputMask;
}
public boolean hasSameCode(Metadata metadata) {
return localCode.equals(metadata.getLocalCode());
}
public boolean isDuplicable() {
return duplicable;
}
public boolean isMarkedForDeletion() {
return inheritedMetadataBehaviors.isMarkedForDeletion();
}
public String getInheritanceCode() {
return inheritanceCode;
}
public boolean isGlobal() {
return global;
}
}