package com.constellio.model.services.schemas.builders; import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.from; import java.util.ArrayList; 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.ImpossibleRuntimeException; import com.constellio.model.entities.Language; import com.constellio.model.entities.schemas.MetadataSchema; import com.constellio.model.entities.schemas.MetadataSchemaType; import com.constellio.model.entities.schemas.MetadataSchemasRuntimeException.CannotGetMetadatasOfAnotherSchemaType; import com.constellio.model.services.factories.ModelLayerFactory; import com.constellio.model.services.schemas.SchemaComparators; import com.constellio.model.services.schemas.builders.MetadataSchemaBuilderRuntimeException.CannotDeleteSchema; import com.constellio.model.services.schemas.builders.MetadataSchemaTypesBuilderRuntimeException.CannotDeleteSchemaSinceItHasRecords; import com.constellio.model.services.search.SearchServices; import com.constellio.model.utils.ClassProvider; public class MetadataSchemaTypeBuilder { private static final String DEFAULT = "default"; private static final String UNDERSCORE = "_"; private final Set<MetadataSchemaBuilder> allSchemas = new HashSet<MetadataSchemaBuilder>(); private String code; private String collection; private Map<Language, String> labels; private boolean security = true; private boolean inTransactionLog = true; private MetadataSchemaBuilder defaultSchema; private Set<MetadataSchemaBuilder> customSchemas = new HashSet<MetadataSchemaBuilder>(); private Boolean undeletable = false; private boolean readOnlyLocked; private ClassProvider classProvider; private Set<String> flags = new HashSet<>(); MetadataSchemaTypeBuilder() { } static MetadataSchemaTypeBuilder createNewSchemaType(String collection, String code, MetadataSchemaTypesBuilder typesBuilder) { return createNewSchemaType(collection, code, typesBuilder, true); } static MetadataSchemaTypeBuilder createNewSchemaType(String collection, String code, MetadataSchemaTypesBuilder typesBuilder, boolean initialize) { MetadataSchemaTypeBuilder builder = new MetadataSchemaTypeBuilder(); builder.classProvider = typesBuilder.getClassProvider(); builder.code = code; builder.collection = collection; builder.setLabels(configureLabels(code, typesBuilder)); builder.customSchemas = new HashSet<>(); builder.defaultSchema = MetadataSchemaBuilder.createDefaultSchema(builder, typesBuilder, initialize); return builder; } private static Map<Language, String> configureLabels(String code, MetadataSchemaTypesBuilder typesBuilder) { Map<Language, String> label = new HashMap<>(); for (Language language : typesBuilder.getLanguages()) { label.put(language, code); } return label; } public static MetadataSchemaTypeBuilder modifySchemaType(MetadataSchemaType schemaType, ClassProvider classProvider) { MetadataSchemaTypeBuilder builder = new MetadataSchemaTypeBuilder(); builder.readOnlyLocked = schemaType.isReadOnlyLocked(); builder.classProvider = classProvider; builder.code = schemaType.getCode(); builder.collection = schemaType.getCollection(); builder.setLabels(schemaType.getLabels()); builder.undeletable = schemaType.isUndeletable(); builder.defaultSchema = MetadataSchemaBuilder.modifyDefaultSchema(schemaType.getDefaultSchema(), builder); builder.security = schemaType.hasSecurity(); builder.inTransactionLog = schemaType.isInTransactionLog(); builder.customSchemas = new HashSet<>(); for (MetadataSchema schema : schemaType.getSchemas()) { builder.customSchemas.add(MetadataSchemaBuilder.modifySchema(schema, builder)); } return builder; } public String getCode() { return code; } public String getCollection() { return collection; } public Map<Language, String> getLabels() { return labels; } public String getLabel(Language language) { return labels.get(language); } public MetadataSchemaTypeBuilder setLabels(Map<Language, String> labels) { if (labels != null) { this.labels = new HashMap<>(labels); } else { this.labels = new HashMap<>(); } return this; } public MetadataSchemaTypeBuilder addLabel(Language language, String label) { this.labels.put(language, label); return this; } public MetadataSchemaBuilder getDefaultSchema() { return defaultSchema; } public Set<MetadataSchemaBuilder> getCustomSchemas() { return customSchemas; } public Boolean isUndeletable() { return undeletable; } public void setUndeletable(Boolean undeletable) { this.undeletable = undeletable; } public Set<MetadataSchemaBuilder> getAllSchemas() { allSchemas.addAll(customSchemas); allSchemas.add(defaultSchema); return allSchemas; } public MetadataSchemaBuilder getCustomSchema(String localCode) { for (MetadataSchemaBuilder customSchema : customSchemas) { if (localCode.equals(customSchema.getLocalCode())) { return customSchema; } } throw new MetadataSchemaTypeBuilderRuntimeException.NoSuchSchema(localCode); } public static Map<Language, String> configureLabels(Map<String, String> labels) { Map<Language, String> newLabels = new HashMap<>(); for (Entry<String, String> entry : labels.entrySet()) { newLabels.put(Language.withCode(entry.getKey()), entry.getValue()); } return newLabels; } public MetadataSchemaBuilder createCustomSchema(String localCode) { for (MetadataSchemaBuilder customSchema : customSchemas) { if (localCode.equals(customSchema.getLocalCode())) { throw new MetadataSchemaTypeBuilderRuntimeException.SchemaAlreadyDefined(localCode); } } MetadataSchemaBuilder customSchema = MetadataSchemaBuilder.createSchema(defaultSchema, localCode, true); customSchema.setLocalCode(localCode); customSchema.setCollection(collection); customSchema.setCode(code + UNDERSCORE + localCode); customSchemas.add(customSchema); return customSchema; } public MetadataSchemaBuilder createCustomSchema(String localCode, Map<String, String> labels) { for (MetadataSchemaBuilder customSchema : customSchemas) { if (localCode.equals(customSchema.getLocalCode())) { throw new MetadataSchemaTypeBuilderRuntimeException.SchemaAlreadyDefined(localCode); } } MetadataSchemaBuilder customSchema = MetadataSchemaBuilder.createSchema(defaultSchema, localCode, true); customSchema.setLocalCode(localCode); customSchema.setCollection(collection); customSchema.setCode(code + UNDERSCORE + localCode); Map<Language, String> newLabels = configureLabels(labels); customSchema.setLabels(newLabels); customSchemas.add(customSchema); return customSchema; } public MetadataSchemaType build(DataStoreTypesFactory typesFactory, ModelLayerFactory modelLayerFactory) { MetadataSchema defaultSchema = this.defaultSchema.buildDefault(typesFactory, modelLayerFactory); List<MetadataSchema> schemas = new ArrayList<MetadataSchema>(); for (MetadataSchemaBuilder metadataSchemaBuilder : this.customSchemas) { schemas.add(metadataSchemaBuilder.buildCustom(defaultSchema, typesFactory, modelLayerFactory)); } if (labels == null || labels.isEmpty()) { throw new MetadataSchemaTypeBuilderRuntimeException.LabelNotDefined(code); } else { for (Entry<Language, String> entry : labels.entrySet()) { if (StringUtils.isBlank(entry.getValue())) { throw new MetadataSchemaTypeBuilderRuntimeException.LabelNotDefinedForLanguage(entry.getKey(), code); } } } Collections.sort(schemas, SchemaComparators.SCHEMA_COMPARATOR_BY_ASC_LOCAL_CODE); return new MetadataSchemaType(code, collection, labels, schemas, defaultSchema, undeletable, security, inTransactionLog, readOnlyLocked); } public MetadataBuilder getMetadata(String metadataCode) { String[] parsedCode = metadataCode.split(UNDERSCORE); String typeCode = parsedCode[0]; String schemaCode = parsedCode[1]; String metadataLocalCode = parsedCode[2]; if (!typeCode.equals(code)) { throw new CannotGetMetadatasOfAnotherSchemaType(typeCode, code); } MetadataBuilder metadata = null; if (schemaCode.equals(DEFAULT)) { metadata = getDefaultSchema().getMetadata(metadataLocalCode); } else { metadata = getCustomSchema(schemaCode).getMetadata(metadataLocalCode); } if (metadata == null) { throw new MetadataSchemaTypesBuilderRuntimeException.NoSuchMetadata(metadataLocalCode); } else { return metadata; } } public MetadataSchemaBuilder getSchema(String codeOrCode) { MetadataSchemaBuilder schema = null; if (codeOrCode.contains(UNDERSCORE)) { schema = getSchemaWithCompleteCode(codeOrCode); } else { schema = getSchemaWithCode(codeOrCode); } if (schema == null) { throw new MetadataSchemaTypeBuilderRuntimeException.NoSuchSchema(codeOrCode); } else { return schema; } } private MetadataSchemaBuilder getSchemaWithCode(String code) { return code.equals(DEFAULT) ? getDefaultSchema() : getCustomSchema(code); } private MetadataSchemaBuilder getSchemaWithCompleteCode(String schemaCode) { String[] parsedCode = schemaCode.split(UNDERSCORE); String type = parsedCode[0]; if (!type.equals(code)) { throw new ImpossibleRuntimeException("Cannot obtain schema from other type"); } String schemaLocalCode = parsedCode[1]; return getSchemaWithCode(schemaLocalCode); } @Override public String toString() { return "MetadataSchemaTypeBuilder [code=" + code + ", label=" + labels + ", defaultSchema=" + defaultSchema + ", customSchemas=" + customSchemas + ", undeletable=" + undeletable + "]"; } public Set<MetadataBuilder> getAllMetadatas() { Set<MetadataBuilder> metadatas = new HashSet<>(); metadatas.addAll(defaultSchema.getMetadatas()); for (MetadataSchemaBuilder customSchema : customSchemas) { metadatas.addAll(customSchema.getMetadatasWithoutInheritance()); } return metadatas; } public MetadataSchemaTypeBuilder setSecurity(boolean security) { this.security = security; return this; } public boolean isReadOnlyLocked() { return readOnlyLocked; } public MetadataSchemaTypeBuilder setReadOnlyLocked(boolean readOnlyLocked) { this.readOnlyLocked = readOnlyLocked; return this; } public boolean isSecurity() { return security; } public MetadataSchemaTypeBuilder setInTransactionLog(boolean inTransactionLog) { this.inTransactionLog = inTransactionLog; return this; } public boolean isInTransactionLog() { return inTransactionLog; } public boolean hasSchema(String schema) { try { getSchema(schema); return true; } catch (MetadataSchemaTypeBuilderRuntimeException.NoSuchSchema e) { return false; } } public void deleteSchema(MetadataSchema schema, SearchServices searchServices) { if (searchServices.hasResults(from(schema).returnAll())) { throw new CannotDeleteSchemaSinceItHasRecords(schema.getCode()); } else if (DEFAULT.equals(schema.getLocalCode())) { throw new CannotDeleteSchema(schema.getCode()); } else { customSchemas.remove(getSchema(schema.getLocalCode())); } } public ClassProvider getClassProvider() { return classProvider; } public MetadataSchemaBuilder createCustomSchemaCopying(String localCode, String copyingSchemaWithLocalCode) { MetadataSchemaBuilder copiedSchemaBuilder = getCustomSchema(copyingSchemaWithLocalCode); for (MetadataSchemaBuilder customSchema : customSchemas) { if (localCode.equals(customSchema.getLocalCode())) { throw new MetadataSchemaTypeBuilderRuntimeException.SchemaAlreadyDefined(localCode); } } MetadataSchemaBuilder customSchema = MetadataSchemaBuilder.createSchema(defaultSchema, localCode, false); customSchema.setLocalCode(localCode); customSchema.setCollection(collection); customSchema.setCode(code + UNDERSCORE + localCode); customSchema.setLabels(new HashMap<Language, String>(copiedSchemaBuilder.getLabels())); customSchemas.add(customSchema); for (MetadataBuilder metadataBuilder : copiedSchemaBuilder.getMetadatas()) { customSchema.createMetadataCopying(metadataBuilder); } return customSchema; } }