package com.constellio.model.services.schemas.builders; import static com.constellio.model.entities.schemas.MetadataValueType.STRING; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.constellio.data.dao.services.DataStoreTypesFactory; import com.constellio.model.entities.Language; import com.constellio.model.entities.calculators.InitializedMetadataValueCalculator; import com.constellio.model.entities.calculators.MetadataValueCalculator; import com.constellio.model.entities.schemas.Metadata; import com.constellio.model.entities.schemas.MetadataSchema; import com.constellio.model.entities.schemas.MetadataSchemaCalculatedInfos; import com.constellio.model.entities.schemas.MetadataSchemaType; import com.constellio.model.entities.schemas.MetadataSchemasRuntimeException; import com.constellio.model.entities.schemas.MetadataSchemasRuntimeException.CannotGetMetadatasOfAnotherSchema; import com.constellio.model.entities.schemas.MetadataSchemasRuntimeException.CannotGetMetadatasOfAnotherSchemaType; import com.constellio.model.entities.schemas.MetadataSchemasRuntimeException.InvalidCode; import com.constellio.model.entities.schemas.MetadataValueType; import com.constellio.model.entities.schemas.MetadataTransiency; import com.constellio.model.entities.schemas.entries.CalculatedDataEntry; import com.constellio.model.entities.schemas.entries.DataEntryType; import com.constellio.model.entities.schemas.preparationSteps.CalculateMetadatasRecordPreparationStep; import com.constellio.model.entities.schemas.preparationSteps.RecordPreparationStep; import com.constellio.model.entities.schemas.preparationSteps.SequenceRecordPreparationStep; import com.constellio.model.entities.schemas.preparationSteps.UpdateCreationModificationUsersAndDateRecordPreparationStep; import com.constellio.model.entities.schemas.preparationSteps.ValidateCyclicReferencesRecordPreparationStep; import com.constellio.model.entities.schemas.preparationSteps.ValidateMetadatasRecordPreparationStep; import com.constellio.model.entities.schemas.preparationSteps.ValidateUsingSchemaValidatorsRecordPreparationStep; import com.constellio.model.entities.schemas.validation.RecordValidator; import com.constellio.model.services.factories.ModelLayerFactory; import com.constellio.model.services.schemas.MetadataList; import com.constellio.model.services.schemas.SchemaComparators; import com.constellio.model.services.schemas.SchemaUtils; import com.constellio.model.services.schemas.builders.MetadataSchemaBuilderRuntimeException.NoSuchMetadata; import com.constellio.model.utils.ClassProvider; import com.constellio.model.utils.DependencyUtils; import com.constellio.model.utils.DependencyUtilsRuntimeException; import com.constellio.model.utils.Lazy; public class MetadataSchemaBuilder { private static final Logger LOGGER = LoggerFactory.getLogger(MetadataSchemaBuilder.class); private static final String UNDERSCORE = "_"; private static final String DEFAULT = "default"; private String localCode; private String collection; private String code; private Map<Language, String> labels; private MetadataSchemaBuilder defaultSchema; private MetadataSchemaTypeBuilder schemaTypeBuilder; private List<MetadataBuilder> metadatas; private boolean undeletable = false; private ClassProvider classProvider; private ClassListBuilder<RecordValidator> schemaValidators; MetadataSchemaBuilder() { } static MetadataSchemaBuilder modifySchema(MetadataSchema schema, MetadataSchemaTypeBuilder schemaType) { MetadataSchemaBuilder builder = new MetadataSchemaBuilder(); builder.classProvider = schemaType.getClassProvider(); builder.setDefaultSchema(schemaType.getDefaultSchema()); builder.setSchemaTypeBuilder(schemaType); builder.setLocalCode(schema.getLocalCode()); builder.setCollection(schema.getCollection()); builder.setCode(schema.getCode()); builder.setUndeletable(schema.isUndeletable()); builder.setLabels(schema.getLabels()); builder.metadatas = new ArrayList<>(); for (Metadata metadata : schema.getMetadatas()) { if (metadata.inheritDefaultSchema()) { MetadataBuilder inheritance = builder.defaultSchema.getMetadata(metadata.getLocalCode()); builder.metadatas.add(MetadataBuilder.modifyMetadataWithInheritance(metadata, inheritance)); } else { builder.metadatas.add(MetadataBuilder.modifyMetadataWithoutInheritance(metadata, builder.classProvider)); } } Set<RecordValidator> customValidators = new HashSet<>(); for (RecordValidator validator : schema.getValidators()) { boolean contains = false; for (String defaultValidatorClassName : schemaType.getDefaultSchema().schemaValidators.implementationsClassname) { contains |= defaultValidatorClassName.equals(validator.getClass().getName()); } if (!contains) { customValidators.add(validator); } } builder.schemaValidators = new ClassListBuilder<>(builder.classProvider, RecordValidator.class, customValidators); return builder; } static MetadataSchemaBuilder modifyDefaultSchema(MetadataSchema defaultSchema, MetadataSchemaTypeBuilder typeBuilder) { MetadataSchemaBuilder builder = new MetadataSchemaBuilder(); builder.classProvider = typeBuilder.getClassProvider(); builder.setLabels(defaultSchema.getLabels()); builder.setLocalCode(defaultSchema.getLocalCode()); builder.setCode(defaultSchema.getCode()); builder.setCollection(defaultSchema.getCollection()); builder.setUndeletable(defaultSchema.isUndeletable()); builder.setSchemaTypeBuilder(typeBuilder); builder.metadatas = new ArrayList<>(); for (Metadata metadata : defaultSchema.getMetadatas()) { builder.metadatas.add(MetadataBuilder.modifyMetadataWithoutInheritance(metadata, builder.classProvider)); } builder.schemaValidators = new ClassListBuilder<>(builder.classProvider, RecordValidator.class, defaultSchema.getValidators()); return builder; } static MetadataSchemaBuilder createSchema(MetadataSchemaBuilder defaultSchema, String localCode, boolean commonMetadatas) { MetadataSchemaBuilder builder = new MetadataSchemaBuilder(); builder.classProvider = defaultSchema.classProvider; builder.setDefaultSchema(defaultSchema); builder.metadatas = new ArrayList<>(); builder.setCollection(defaultSchema.getCollection()); builder.setLocalCode(localCode); builder.setLabels(configureLabels(localCode, defaultSchema)); builder.setCode(defaultSchema.getSchemaTypeBuilder().getCode() + UNDERSCORE + localCode); for (MetadataBuilder metadata : defaultSchema.metadatas) { builder.metadatas.add(MetadataBuilder.createCustomMetadataFromDefault(metadata, localCode)); } builder.schemaValidators = new ClassListBuilder<>(builder.classProvider, RecordValidator.class); return builder; } private static Map<Language, String> configureLabels(String code, MetadataSchemaBuilder typesBuilder) { return configureLabels(code, typesBuilder, new HashMap<Language, String>()); } private static Map<Language, String> configureLabels(String code, MetadataSchemaBuilder typesBuilder, Map<Language, String> labels) { for (Language language : typesBuilder.getLabels().keySet()) { if (StringUtils.isBlank(labels.get(language))) labels.put(language, code); } return labels; } static MetadataSchemaBuilder createDefaultSchema(MetadataSchemaTypeBuilder schemaTypeBuilder, MetadataSchemaTypesBuilder schemaTypesBuilder, boolean initialize) { MetadataSchemaBuilder builder = new MetadataSchemaBuilder(); builder.classProvider = schemaTypeBuilder.getClassProvider(); builder.setSchemaTypeBuilder(schemaTypeBuilder); builder.setLocalCode(DEFAULT); builder.setCollection(schemaTypeBuilder.getCollection()); builder.setLabels(schemaTypeBuilder.getLabels()); builder.setCode(schemaTypeBuilder.getCode() + UNDERSCORE + DEFAULT); builder.setUndeletable(true); builder.metadatas = new ArrayList<>(); builder.schemaValidators = new ClassListBuilder<>(builder.classProvider, RecordValidator.class); if (initialize) { new CommonMetadataBuilder().addCommonMetadataToNewSchema(builder, schemaTypesBuilder); } return builder; } public String getCollection() { return collection; } MetadataSchemaBuilder setCollection(String collection) { this.collection = collection; return this; } public String getCode() { return code; } MetadataSchemaBuilder setCode(String code) { this.code = code; return this; } public String getLocalCode() { return localCode; } MetadataSchemaBuilder setLocalCode(String localCode) { this.localCode = localCode; return this; } public Map<Language, String> getLabels() { return labels; } public String getLabel(Language language) { return labels.get(language); } public MetadataSchemaBuilder setLabels(Map<Language, String> labels) { this.labels = new HashMap<>(labels); return this; } public MetadataSchemaBuilder addLabel(Language language, String label) { this.labels.put(language, label); return this; } public MetadataSchemaBuilder getDefaultSchema() { return defaultSchema; } public MetadataSchemaBuilder setDefaultSchema(MetadataSchemaBuilder defaultSchema) { this.defaultSchema = defaultSchema; this.setSchemaTypeBuilder(defaultSchema.getSchemaTypeBuilder()); return this; } public List<MetadataBuilder> getMetadatas() { return metadatas; } public MetadataSchemaTypeBuilder getSchemaTypeBuilder() { return schemaTypeBuilder; } private MetadataSchemaBuilder setSchemaTypeBuilder(MetadataSchemaTypeBuilder schemaTypeBuilder) { this.schemaTypeBuilder = schemaTypeBuilder; return this; } public boolean isUndeletable() { return undeletable; } public MetadataSchemaBuilder setUndeletable(Boolean undeletable) { this.undeletable = undeletable; return this; } public boolean hasMetadata(String codeOrLocalCode) { return getMetadataOrNull(codeOrLocalCode) != null; } public MetadataBuilder getUserMetadata(String localCode) { for (MetadataBuilder metadataBuilder : getMetadatas()) { if (metadataBuilder.getLocalCode().equals("USR" + localCode)) { return metadataBuilder; } } throw new MetadataSchemaBuilderRuntimeException.NoSuchMetadata("USR" + localCode); } private MetadataBuilder getMetadataOrNull(String codeOrLocalCode) { String partialCode; String[] codeSplitted = SchemaUtils.underscoreSplitWithCache(codeOrLocalCode); if (codeSplitted.length == 3) { partialCode = getPartialCode(codeOrLocalCode); } else if (codeSplitted.length == 1) { partialCode = codeOrLocalCode; } else { throw new MetadataSchemaBuilderRuntimeException.InvalidAttribute("codeOrLocalCode", codeOrLocalCode); } for (MetadataBuilder metadataBuilder : getMetadatas()) { if (metadataBuilder.getLocalCode().equals(partialCode)) { return metadataBuilder; } } return null; } public MetadataBuilder getMetadata(String codeOrLocalCode) { MetadataBuilder metadataBuilder = getMetadataOrNull(codeOrLocalCode); if (metadataBuilder == null) { throw new MetadataSchemaBuilderRuntimeException.NoSuchMetadata(codeOrLocalCode); } else { return metadataBuilder; } } public MetadataBuilder get(Metadata metadata) { return get(metadata.getLocalCode()); } public MetadataBuilder get(String code) { String metadataCode = new SchemaUtils().toLocalMetadataCode(code); validateLocalCode(metadataCode); return getMetadata(metadataCode); } public MetadataBuilder createSystemReserved(String code) { return this.create(code).setUndeletable(true).setSystemReserved(true); } public MetadataBuilder createUndeletable(String code) { return this.create(code).setUndeletable(true); } public MetadataBuilder create(String metadataLocaleCode) { String metadataLocalCode = new SchemaUtils().toLocalMetadataCode(metadataLocaleCode); validateLocalCode(metadataLocalCode); if (hasMetadata(metadataLocalCode)) { throw new MetadataSchemaBuilderRuntimeException.MetadataAlreadyExists(metadataLocaleCode); } if (this.getLocalCode().equals(DEFAULT)) { return createDefaultMetadata(metadataLocaleCode); } else { return createCustomMetadata(metadataLocaleCode); } } MetadataSchema buildDefault(DataStoreTypesFactory typesFactory, ModelLayerFactory modelLayerFactory) { MetadataList newMetadatas = buildMetadatas(typesFactory, modelLayerFactory); validateDefault(this); Map<Language, String> newLabels = this.getLabels(); if (newLabels == null || newLabels.isEmpty()) { newLabels = schemaTypeBuilder.getLabels(); } else { for (Language language : schemaTypeBuilder.getLabels().keySet()) { if (StringUtils.isBlank(newLabels.get(language))) { newLabels.put(language, schemaTypeBuilder.getLabel(language)); } } } Collections.sort(newMetadatas, SchemaComparators.METADATA_COMPARATOR_BY_ASC_LOCAL_CODE); boolean inTransactionLog = schemaTypeBuilder.isInTransactionLog(); Set<RecordValidator> recordValidators = this.schemaValidators.build(); return new MetadataSchema(this.getLocalCode(), this.getCode(), collection, newLabels, newMetadatas, this.isUndeletable(), inTransactionLog, recordValidators, calculateSchemaInfos(newMetadatas, recordValidators)); } private static class SchemaRecordSteps { List<Metadata> automaticMetadatas; List<RecordPreparationStep> steps; } private Lazy<MetadataSchemaCalculatedInfos> lazyCalculateSchemaInfos(final MetadataList newMetadatas, final Set<RecordValidator> recordValidators) { return new Lazy<MetadataSchemaCalculatedInfos>() { @Override protected MetadataSchemaCalculatedInfos load() { return calculateSchemaInfos(newMetadatas, recordValidators); } }; } private MetadataSchemaCalculatedInfos calculateSchemaInfos(MetadataList newMetadatas, Set<RecordValidator> recordValidators) { for (Metadata metadata : newMetadatas.onlyCalculated().onlyWithoutInheritance()) { MetadataValueCalculator<?> calculator = ((CalculatedDataEntry) metadata.getDataEntry()) .getCalculator(); if (calculator instanceof InitializedMetadataValueCalculator) { ((InitializedMetadataValueCalculator) calculator).initialize(newMetadatas, metadata); } } Map<String, Set<String>> allAutoMetadatasDependencies = newSchemaUtils().calculatedMetadataDependencies(newMetadatas); List<String> sequenceMetadatas = newMetadatas.onlySequence().toLocalCodesList(); Set<String> metadatasDependingOnSequence = new HashSet<>(sequenceMetadatas); Map<String, Set<String>> autoMetadatasDependencies = new HashMap<>(); Map<String, Set<String>> autoMetadatasDependenciesBasedOnSequence = new HashMap<>(); boolean hasNewerMetadatasDependingOnSequence = true; while (hasNewerMetadatasDependingOnSequence) { int sizeBefore = metadatasDependingOnSequence.size(); for (Map.Entry<String, Set<String>> entry : allAutoMetadatasDependencies.entrySet()) { for (String dependency : entry.getValue()) { if (metadatasDependingOnSequence.contains(dependency)) { metadatasDependingOnSequence.add(entry.getKey()); } } } hasNewerMetadatasDependingOnSequence = metadatasDependingOnSequence.size() != sizeBefore; } for (Map.Entry<String, Set<String>> entry : allAutoMetadatasDependencies.entrySet()) { if (metadatasDependingOnSequence.contains(entry.getKey())) { autoMetadatasDependenciesBasedOnSequence.put(entry.getKey(), entry.getValue()); } else { autoMetadatasDependencies.put(entry.getKey(), entry.getValue()); } } List<Metadata> autoMetas = orderAutomaticMetadatas(newMetadatas, autoMetadatasDependencies); List<Metadata> autoMetasBasedOnSequence = orderAutomaticMetadatas(newMetadatas, autoMetadatasDependenciesBasedOnSequence); List<Metadata> automaticMetadatas = new ArrayList<>(); automaticMetadatas.addAll(autoMetas); automaticMetadatas.addAll(autoMetasBasedOnSequence); List<Metadata> lazyTransientsMetadatas = new ArrayList<>(); List<Metadata> eagerTransientsMetadatas = new ArrayList<>(); for (Metadata automaticMetadata : automaticMetadatas) { if (automaticMetadata.getTransiency() == MetadataTransiency.TRANSIENT_EAGER) { eagerTransientsMetadatas.add(automaticMetadata); } if (automaticMetadata.getTransiency() == MetadataTransiency.TRANSIENT_LAZY) { lazyTransientsMetadatas.add(automaticMetadata); } } List<RecordPreparationStep> steps = new ArrayList<>(); steps.add(new UpdateCreationModificationUsersAndDateRecordPreparationStep()); steps.add(new ValidateMetadatasRecordPreparationStep(newMetadatas.onlyManuals().onlyNonSystemReserved())); steps.add(new CalculateMetadatasRecordPreparationStep(autoMetas)); steps.add(new ValidateCyclicReferencesRecordPreparationStep()); steps.add(new ValidateMetadatasRecordPreparationStep(autoMetas)); steps.add(new ValidateUsingSchemaValidatorsRecordPreparationStep(new ArrayList<>(recordValidators))); if (!sequenceMetadatas.isEmpty()) { steps.add(new SequenceRecordPreparationStep(newMetadatas.onlySequence())); } if (!autoMetasBasedOnSequence.isEmpty()) { steps.add(new CalculateMetadatasRecordPreparationStep(autoMetasBasedOnSequence)); steps.add(new ValidateMetadatasRecordPreparationStep(autoMetasBasedOnSequence)); if (!recordValidators.isEmpty()) { steps.add(new ValidateUsingSchemaValidatorsRecordPreparationStep(new ArrayList<>(recordValidators))); } } List<Metadata> contentMetadatas = newMetadatas.onlyWithType(MetadataValueType.CONTENT) .sortedUsing(new ContentsComparator()); return new MetadataSchemaCalculatedInfos(steps, automaticMetadatas, contentMetadatas, lazyTransientsMetadatas, eagerTransientsMetadatas); } public static class ContentsComparator implements Comparator<Metadata> { @Override public int compare(Metadata m1, Metadata m2) { if (m1.isDefaultRequirement() && !m2.isDefaultRequirement()) { return -1; } else if (!m1.isDefaultRequirement() && m2.isDefaultRequirement()) { return 1; } else if (m1.isMultivalue() && !m2.isMultivalue()) { return 1; } else if (!m1.isMultivalue() && m2.isMultivalue()) { return -1; } else { String code1 = m1.getLocalCode(); String code2 = m2.getLocalCode(); return code1.compareTo(code2); } } } MetadataList buildMetadatas(DataStoreTypesFactory typesFactory, ModelLayerFactory modelLayerFactory) { MetadataList newMetadatas = new MetadataList(); for (MetadataBuilder metadataBuilder : this.metadatas) { newMetadatas.add(metadataBuilder.buildWithoutInheritance(typesFactory, modelLayerFactory)); } return newMetadatas; } private List<Metadata> orderAutomaticMetadatas(List<Metadata> metadatas, Map<String, Set<String>> automaticMetadatasDependencies) { List<String> sortedMetadataCodes; try { sortedMetadataCodes = newDependencyUtils() .sortByDependency(automaticMetadatasDependencies); } catch (DependencyUtilsRuntimeException.CyclicDependency e) { throw new MetadataSchemaBuilderRuntimeException.CyclicDependenciesInMetadata(e); } List<Metadata> sortedMetadatas = new ArrayList<>(); for (Metadata metadata : metadatas) { if (metadata.getDataEntry().getType() == DataEntryType.AGGREGATED) { sortedMetadatas.add(metadata); } } for (String sortedMetadataCode : sortedMetadataCodes) { for (Metadata metadata : metadatas) { if (sortedMetadataCode.equals(metadata.getLocalCode())) { sortedMetadatas.add(metadata); } } } return Collections.unmodifiableList(sortedMetadatas); } DependencyUtils<String> newDependencyUtils() { return new DependencyUtils<>(); } SchemaUtils newSchemaUtils() { return new SchemaUtils(); } MetadataSchema buildCustom(MetadataSchema defaultSchema, DataStoreTypesFactory typesFactory, ModelLayerFactory modelLayerFactory) { final MetadataList newMetadatas = new MetadataList(); for (MetadataBuilder metadataBuilder : this.metadatas) { try { Metadata inheritance = defaultSchema.getMetadata(metadataBuilder.getLocalCode()); newMetadatas.add(metadataBuilder.buildWithInheritance(inheritance)); } catch (MetadataSchemasRuntimeException.NoSuchMetadata e) { LOGGER.debug("No inheritance found for metadata {}", code, e); newMetadatas.add(metadataBuilder.buildWithoutInheritance(typesFactory, modelLayerFactory)); } } Map<Language, String> newLabels = configureLabels(localCode, getDefaultSchema(), this.getLabels()); Collections.sort(newMetadatas, SchemaComparators.METADATA_COMPARATOR_BY_ASC_LOCAL_CODE); final Set<RecordValidator> recordValidators = this.schemaValidators.build(defaultSchema.getValidators()); boolean inTransactionLog = schemaTypeBuilder.isInTransactionLog(); return new MetadataSchema(this.getLocalCode(), this.getCode(), collection, newLabels, newMetadatas, this.isUndeletable(), inTransactionLog, recordValidators, calculateSchemaInfos(newMetadatas, recordValidators)); } public boolean isInheriting() { return defaultSchema != null; } @Override public String toString() { return "MetadataSchemaBuilder [localCode=" + localCode + ", code=" + code + ", label=" + labels + ", metadatas=" + metadatas + ", undeletable=" + undeletable + "]"; } public ClassListBuilder<RecordValidator> defineValidators() { return schemaValidators; } void validateLocalCode(String localCode) { if (!SchemaUtils.isValidSchemaCodeWithCache(localCode)) { throw new MetadataSchemaBuilderRuntimeException.InvalidAttribute("localCode", localCode); } } private String getPartialCode(String codeOrLocalCode) { String partialCode; String[] parts = codeOrLocalCode.split(UNDERSCORE); if (parts.length != 3) { throw new InvalidCode(code); } partialCode = parts[2]; String requestedType = parts[0]; String requestedSchema = parts[1]; if (!code.startsWith(requestedType)) { throw new CannotGetMetadatasOfAnotherSchemaType(requestedType, code); } if (!requestedSchema.equals(localCode) && !requestedSchema.equals(MetadataSchemaType.DEFAULT)) { throw new CannotGetMetadatasOfAnotherSchema(requestedSchema, localCode); } return partialCode; } private MetadataBuilder createDefaultMetadata(String localCode) { MetadataBuilder metadata = MetadataBuilder.createMetadataWithoutInheritance(localCode, this); this.metadatas.add(metadata); for (MetadataSchemaBuilder customSchemaBuilder : schemaTypeBuilder.getCustomSchemas()) { customSchemaBuilder.metadatas.add(MetadataBuilder.createCustomMetadataFromDefault(metadata, customSchemaBuilder.localCode)); } return metadata; } private MetadataBuilder createCustomMetadata(String code) { MetadataBuilder builder = MetadataBuilder.createMetadataWithoutInheritance(code, this); this.metadatas.add(builder); return builder; } private void validateDefault(MetadataSchemaBuilder builder) { validateLocalCode(localCode); } public Set<MetadataBuilder> getMetadatasWithoutInheritance() { Set<MetadataBuilder> metadatasWithoutInheritance = new HashSet<>(); for (MetadataBuilder metadata : metadatas) { if (metadata.getInheritance() == null) { metadatasWithoutInheritance.add(metadata); } } return metadatasWithoutInheritance; } public void createUniqueCodeMetadata() { createUndeletable("code").setEssential(true).setDefaultRequirement(true).setType(STRING).setUniqueValue(true); } public void deleteMetadataWithoutValidation(MetadataBuilder metadataToDelete) { try { MetadataBuilder metadataBuilder = getMetadata(metadataToDelete.getLocalCode()); metadatas.remove(metadataBuilder); if (metadataBuilder.getCode().contains("_default_")) { deleteInheritedMetadatas(metadataToDelete.getLocalCode()); } } catch (MetadataSchemaTypesBuilderRuntimeException.NoSuchMetadata e) { //OK } catch (NoSuchMetadata e1) { //OK } } private void deleteInheritedMetadatas(String metadataLocalCode) { for (MetadataSchemaBuilder customSchemaBuilder : schemaTypeBuilder.getCustomSchemas()) { MetadataBuilder metadataToDelete = customSchemaBuilder.getMetadata(metadataLocalCode); customSchemaBuilder.deleteInheritedMetadata(metadataToDelete.getLocalCode()); } } void deleteInheritedMetadata(String localCode) { try { MetadataBuilder metadataToDelete = getMetadata(localCode); metadatas.remove(metadataToDelete); } catch (MetadataSchemaTypesBuilderRuntimeException.NoSuchMetadata e) { //OK } catch (NoSuchMetadata e1) { //OK } } public ClassProvider getClassProvider() { return classProvider; } public MetadataBuilder createMetadataCopying(MetadataBuilder metadataBuilder) { MetadataBuilder metadata = MetadataBuilder.createCustomMetadataFromOriginalCustomMetadata(metadataBuilder, this.code); metadatas.add(metadata); return metadata; } }