package org.molgenis.data.platform.decorators; import org.molgenis.auth.User; import org.molgenis.auth.UserAuthorityFactory; import org.molgenis.auth.UserRepositoryDecorator; import org.molgenis.data.*; import org.molgenis.data.aggregation.AggregateAnonymizer; import org.molgenis.data.aggregation.AggregateAnonymizerRepositoryDecorator; import org.molgenis.data.cache.l1.L1Cache; import org.molgenis.data.cache.l1.L1CacheRepositoryDecorator; import org.molgenis.data.cache.l2.L2Cache; import org.molgenis.data.cache.l2.L2CacheRepositoryDecorator; import org.molgenis.data.cache.l3.L3Cache; import org.molgenis.data.cache.l3.L3CacheRepositoryDecorator; import org.molgenis.data.elasticsearch.IndexedRepositoryDecorator; import org.molgenis.data.elasticsearch.SearchService; import org.molgenis.data.i18n.I18nStringDecorator; import org.molgenis.data.i18n.LanguageRepositoryDecorator; import org.molgenis.data.i18n.LanguageService; import org.molgenis.data.i18n.model.Language; import org.molgenis.data.index.IndexActionRegisterService; import org.molgenis.data.index.IndexActionRepositoryDecorator; import org.molgenis.data.listeners.EntityListenerRepositoryDecorator; import org.molgenis.data.listeners.EntityListenersService; import org.molgenis.data.meta.AttributeRepositoryDecorator; import org.molgenis.data.meta.EntityTypeDependencyResolver; import org.molgenis.data.meta.EntityTypeRepositoryDecorator; import org.molgenis.data.meta.PackageRepositoryDecorator; import org.molgenis.data.meta.model.Attribute; import org.molgenis.data.meta.model.EntityType; import org.molgenis.data.meta.model.Package; import org.molgenis.data.meta.model.Tag; import org.molgenis.data.meta.system.SystemEntityTypeRegistry; import org.molgenis.data.settings.AppSettings; import org.molgenis.data.transaction.TransactionInformation; import org.molgenis.data.transaction.TransactionalRepositoryDecorator; import org.molgenis.data.validation.*; import org.molgenis.data.validation.meta.*; import org.molgenis.security.core.MolgenisPermissionService; import org.molgenis.security.owned.OwnedEntityRepositoryDecorator; import org.molgenis.util.EntityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; import static java.util.Objects.requireNonNull; import static org.molgenis.auth.UserMetaData.USER; import static org.molgenis.data.i18n.model.I18nStringMetaData.I18N_STRING; import static org.molgenis.data.i18n.model.LanguageMetadata.LANGUAGE; import static org.molgenis.data.meta.model.AttributeMetadata.ATTRIBUTE_META_DATA; import static org.molgenis.data.meta.model.EntityTypeMetadata.ENTITY_TYPE_META_DATA; import static org.molgenis.data.meta.model.PackageMetadata.PACKAGE; import static org.molgenis.data.meta.model.TagMetadata.TAG; import static org.molgenis.security.owned.OwnedEntityType.OWNED; @Component public class MolgenisRepositoryDecoratorFactory implements RepositoryDecoratorFactory { private final EntityManager entityManager; private final EntityAttributesValidator entityAttributesValidator; private final AggregateAnonymizer aggregateAnonymizer; private final AppSettings appSettings; private final DataService dataService; private final ExpressionValidator expressionValidator; private final RepositoryDecoratorRegistry repositoryDecoratorRegistry; private final SystemEntityTypeRegistry systemEntityTypeRegistry; private final UserAuthorityFactory userAuthorityFactory; private final IndexActionRegisterService indexActionRegisterService; private final SearchService searchService; private final PasswordEncoder passwordEncoder; private final L1Cache l1Cache; private final EntityListenersService entityListenersService; private final L2Cache l2Cache; private final TransactionInformation transactionInformation; private final MolgenisPermissionService permissionService; private final EntityTypeValidator entityTypeValidator; private final PackageValidator packageValidator; private final TagValidator tagValidator; private final L3Cache l3Cache; private final LanguageService languageService; private final EntityTypeDependencyResolver entityTypeDependencyResolver; private final AttributeValidator attributeValidator; private final PlatformTransactionManager transactionManager; private final QueryValidator queryValidator; @Autowired public MolgenisRepositoryDecoratorFactory(EntityManager entityManager, EntityAttributesValidator entityAttributesValidator, AggregateAnonymizer aggregateAnonymizer, AppSettings appSettings, DataService dataService, ExpressionValidator expressionValidator, RepositoryDecoratorRegistry repositoryDecoratorRegistry, SystemEntityTypeRegistry systemEntityTypeRegistry, UserAuthorityFactory userAuthorityFactory, IndexActionRegisterService indexActionRegisterService, SearchService searchService, PasswordEncoder passwordEncoder, L1Cache l1Cache, L2Cache l2Cache, TransactionInformation transactionInformation, EntityListenersService entityListenersService, MolgenisPermissionService permissionService, EntityTypeValidator entityTypeValidator, PackageValidator packageValidator, TagValidator tagValidator, L3Cache l3Cache, LanguageService languageService, EntityTypeDependencyResolver entityTypeDependencyResolver, AttributeValidator attributeValidator, PlatformTransactionManager transactionManager, QueryValidator queryValidator) { this.entityManager = requireNonNull(entityManager); this.entityAttributesValidator = requireNonNull(entityAttributesValidator); this.aggregateAnonymizer = requireNonNull(aggregateAnonymizer); this.appSettings = requireNonNull(appSettings); this.dataService = requireNonNull(dataService); this.expressionValidator = requireNonNull(expressionValidator); this.repositoryDecoratorRegistry = requireNonNull(repositoryDecoratorRegistry); this.systemEntityTypeRegistry = requireNonNull(systemEntityTypeRegistry); this.userAuthorityFactory = requireNonNull(userAuthorityFactory); this.indexActionRegisterService = requireNonNull(indexActionRegisterService); this.searchService = requireNonNull(searchService); this.passwordEncoder = requireNonNull(passwordEncoder); this.l1Cache = requireNonNull(l1Cache); this.entityListenersService = requireNonNull(entityListenersService); this.l2Cache = requireNonNull(l2Cache); this.transactionInformation = requireNonNull(transactionInformation); this.permissionService = requireNonNull(permissionService); this.entityTypeValidator = requireNonNull(entityTypeValidator); this.packageValidator = requireNonNull(packageValidator); this.tagValidator = requireNonNull(tagValidator); this.l3Cache = requireNonNull(l3Cache); this.languageService = requireNonNull(languageService); this.entityTypeDependencyResolver = requireNonNull(entityTypeDependencyResolver); this.attributeValidator = requireNonNull(attributeValidator); this.transactionManager = requireNonNull(transactionManager); this.queryValidator = requireNonNull(queryValidator); } @Override public Repository<Entity> createDecoratedRepository(Repository<Entity> repository) { Repository<Entity> decoratedRepository = repositoryDecoratorRegistry.decorate(repository); // 12. Query the L2 cache before querying the database decoratedRepository = new L2CacheRepositoryDecorator(decoratedRepository, l2Cache, transactionInformation); // 11. Query the L1 cache before querying the database decoratedRepository = new L1CacheRepositoryDecorator(decoratedRepository, l1Cache); // 10. Route specific queries to the index decoratedRepository = new IndexedRepositoryDecorator(decoratedRepository, searchService); // 9. Query the L3 cache before querying the index decoratedRepository = new L3CacheRepositoryDecorator(decoratedRepository, l3Cache, transactionInformation); // 8. Register the cud action needed to index indexed repositories decoratedRepository = new IndexActionRepositoryDecorator(decoratedRepository, indexActionRegisterService); // 7. Custom decorators decoratedRepository = applyCustomRepositoryDecorators(decoratedRepository); // 6. Owned decorator if (EntityUtils.doesExtend(decoratedRepository.getEntityType(), OWNED)) { decoratedRepository = new OwnedEntityRepositoryDecorator(decoratedRepository); } // 5. Entity reference resolver decorator decoratedRepository = new EntityReferenceResolverDecorator(decoratedRepository, entityManager); // 4. Entity listener decoratedRepository = new EntityListenerRepositoryDecorator(decoratedRepository, entityListenersService); // 3. validation decorator decoratedRepository = new RepositoryValidationDecorator(dataService, decoratedRepository, entityAttributesValidator, expressionValidator); // 2. aggregate anonymization decorator decoratedRepository = new AggregateAnonymizerRepositoryDecorator<>(decoratedRepository, aggregateAnonymizer, appSettings); // 1. security decorator decoratedRepository = new RepositorySecurityDecorator(decoratedRepository); // 0. transaction decorator decoratedRepository = new TransactionalRepositoryDecorator<>(decoratedRepository, transactionManager); // -1. query validation decorator decoratedRepository = new QueryValidationRepositoryDecorator<>(decoratedRepository, queryValidator); return decoratedRepository; } /** * Apply custom repository decorators based on entity meta data * * @param repo entity repository * @return decorated entity repository */ private Repository<Entity> applyCustomRepositoryDecorators(Repository<Entity> repo) { if (repo.getName().equals(USER)) { repo = (Repository<Entity>) (Repository<? extends Entity>) new UserRepositoryDecorator( (Repository<User>) (Repository<? extends Entity>) repo, userAuthorityFactory, dataService, passwordEncoder); } else if (repo.getName().equals(ATTRIBUTE_META_DATA)) { repo = (Repository<Entity>) (Repository<? extends Entity>) new AttributeRepositoryDecorator( (Repository<Attribute>) (Repository<? extends Entity>) repo, systemEntityTypeRegistry, dataService, permissionService); repo = (Repository<Entity>) (Repository<? extends Entity>) new AttributeRepositoryValidationDecorator( (Repository<Attribute>) (Repository<? extends Entity>) repo, attributeValidator); } else if (repo.getName().equals(ENTITY_TYPE_META_DATA)) { repo = (Repository<Entity>) (Repository<? extends Entity>) new EntityTypeRepositoryDecorator( (Repository<EntityType>) (Repository<? extends Entity>) repo, dataService, systemEntityTypeRegistry, permissionService); repo = (Repository<Entity>) (Repository<? extends Entity>) new EntityTypeRepositoryValidationDecorator( (Repository<EntityType>) (Repository<? extends Entity>) repo, entityTypeValidator); } else if (repo.getName().equals(PACKAGE)) { repo = (Repository<Entity>) (Repository<? extends Entity>) new PackageRepositoryDecorator( (Repository<Package>) (Repository<? extends Entity>) repo, dataService, entityTypeDependencyResolver); repo = (Repository<Entity>) (Repository<? extends Entity>) new PackageRepositoryValidationDecorator( (Repository<Package>) (Repository<? extends Entity>) repo, packageValidator); } else if (repo.getName().equals(TAG)) { repo = (Repository<Entity>) (Repository<? extends Entity>) new TagRepositoryValidationDecorator( (Repository<Tag>) (Repository<? extends Entity>) repo, tagValidator); } else if (repo.getName().equals(LANGUAGE)) { repo = (Repository<Entity>) (Repository<? extends Entity>) new LanguageRepositoryDecorator( (Repository<Language>) (Repository<? extends Entity>) repo, languageService); } else if (repo.getName().equals(I18N_STRING)) { repo = new I18nStringDecorator(repo); } return repo; } }