Search in sources :

Example 1 with SystemTimer

use of org.hisp.dhis.commons.timer.SystemTimer in project dhis2-core by dhis2.

the class DefaultPreheatService method preheat.

@Override
@SuppressWarnings("unchecked")
public Preheat preheat(PreheatParams params) {
    Timer timer = new SystemTimer().start();
    Preheat preheat = new Preheat();
    preheat.setUser(params.getUser());
    preheat.setDefaults(manager.getDefaults());
    if (preheat.getUser() == null) {
        preheat.setUser(currentUserService.getCurrentUser());
    }
    preheat.put(PreheatIdentifier.UID, preheat.getUser());
    preheat.put(PreheatIdentifier.CODE, preheat.getUser());
    for (Class<? extends IdentifiableObject> klass : params.getObjects().keySet()) {
        params.getObjects().get(klass).stream().filter(identifiableObject -> StringUtils.isEmpty(identifiableObject.getUid())).forEach(identifiableObject -> ((BaseIdentifiableObject) identifiableObject).setUid(CodeGenerator.generateUid()));
    }
    Map<Class<? extends IdentifiableObject>, List<IdentifiableObject>> uniqueCollectionMap = new HashMap<>();
    Set<Class<? extends IdentifiableObject>> klasses = new HashSet<>(params.getObjects().keySet());
    if (PreheatMode.ALL == params.getPreheatMode()) {
        if (params.getClasses().isEmpty()) {
            schemaService.getMetadataSchemas().stream().filter(Schema::isIdentifiableObject).forEach(schema -> params.getClasses().add((Class<? extends IdentifiableObject>) schema.getKlass()));
        }
        for (Class<? extends IdentifiableObject> klass : params.getClasses()) {
            Query query = Query.from(schemaService.getDynamicSchema(klass));
            query.setUser(preheat.getUser());
            List<? extends IdentifiableObject> objects = queryService.query(query);
            if (PreheatIdentifier.UID == params.getPreheatIdentifier() || PreheatIdentifier.AUTO == params.getPreheatIdentifier()) {
                preheat.put(PreheatIdentifier.UID, objects);
            }
            if (PreheatIdentifier.CODE == params.getPreheatIdentifier() || PreheatIdentifier.AUTO == params.getPreheatIdentifier()) {
                preheat.put(PreheatIdentifier.CODE, objects);
            }
            if (klasses.contains(klass) && !objects.isEmpty()) {
                uniqueCollectionMap.put(klass, new ArrayList<>(objects));
            }
        }
    } else if (PreheatMode.REFERENCE == params.getPreheatMode()) {
        Map<PreheatIdentifier, Map<Class<? extends IdentifiableObject>, Set<String>>> references = collectReferences(params.getObjects());
        Map<Class<? extends IdentifiableObject>, Set<String>> uidMap = references.get(PreheatIdentifier.UID);
        Map<Class<? extends IdentifiableObject>, Set<String>> codeMap = references.get(PreheatIdentifier.CODE);
        if (uidMap != null && (PreheatIdentifier.UID == params.getPreheatIdentifier() || PreheatIdentifier.AUTO == params.getPreheatIdentifier())) {
            for (Class<? extends IdentifiableObject> klass : uidMap.keySet()) {
                List<List<String>> identifiers = Lists.partition(Lists.newArrayList(uidMap.get(klass)), 20000);
                if (!identifiers.isEmpty()) {
                    for (List<String> ids : identifiers) {
                        Query query = Query.from(schemaService.getDynamicSchema(klass));
                        query.setUser(preheat.getUser());
                        query.add(Restrictions.in("id", ids));
                        List<? extends IdentifiableObject> objects = queryService.query(query);
                        preheat.put(PreheatIdentifier.UID, objects);
                    }
                }
            }
        }
        if (codeMap != null && (PreheatIdentifier.CODE == params.getPreheatIdentifier() || PreheatIdentifier.AUTO == params.getPreheatIdentifier())) {
            for (Class<? extends IdentifiableObject> klass : codeMap.keySet()) {
                List<List<String>> identifiers = Lists.partition(Lists.newArrayList(codeMap.get(klass)), 20000);
                if (!identifiers.isEmpty()) {
                    for (List<String> ids : identifiers) {
                        Query query = Query.from(schemaService.getDynamicSchema(klass));
                        query.setUser(preheat.getUser());
                        query.add(Restrictions.in("code", ids));
                        List<? extends IdentifiableObject> objects = queryService.query(query);
                        preheat.put(PreheatIdentifier.CODE, objects);
                    }
                }
            }
        }
        for (Class<? extends IdentifiableObject> klass : klasses) {
            Query query = Query.from(schemaService.getDynamicSchema(klass));
            query.setUser(preheat.getUser());
            List<? extends IdentifiableObject> objects = queryService.query(query);
            if (!objects.isEmpty()) {
                uniqueCollectionMap.put(klass, new ArrayList<>(objects));
            }
        }
    }
    if (uniqueCollectionMap.containsKey(User.class)) {
        List<IdentifiableObject> userCredentials = new ArrayList<>();
        for (IdentifiableObject identifiableObject : uniqueCollectionMap.get(User.class)) {
            User user = (User) identifiableObject;
            if (user.getUserCredentials() != null) {
                userCredentials.add(user.getUserCredentials());
            }
        }
        uniqueCollectionMap.put(UserCredentials.class, userCredentials);
    }
    preheat.setUniquenessMap(collectUniqueness(uniqueCollectionMap));
    // add preheat placeholders for objects that will be created and set mandatory/unique attributes
    for (Class<? extends IdentifiableObject> klass : params.getObjects().keySet()) {
        List<IdentifiableObject> objects = params.getObjects().get(klass);
        preheat.put(params.getPreheatIdentifier(), objects);
    }
    handleAttributes(params.getObjects(), preheat);
    handleSecurity(params.getObjects(), params.getPreheatIdentifier(), preheat);
    periodStore.getAll().forEach(period -> preheat.getPeriodMap().put(period.getName(), period));
    periodStore.getAllPeriodTypes().forEach(periodType -> preheat.getPeriodTypeMap().put(periodType.getName(), periodType));
    log.info("(" + preheat.getUsername() + ") Import:Preheat[" + params.getPreheatMode() + "] took " + timer.toString());
    return preheat;
}
Also used : ReflectionUtils(org.hisp.dhis.system.util.ReflectionUtils) BaseAnalyticalObject(org.hisp.dhis.common.BaseAnalyticalObject) Restrictions(org.hisp.dhis.query.Restrictions) PeriodService(org.hisp.dhis.period.PeriodService) MergeService(org.hisp.dhis.schema.MergeService) Autowired(org.springframework.beans.factory.annotation.Autowired) TrackedEntityAttributeDimension(org.hisp.dhis.trackedentity.TrackedEntityAttributeDimension) StringUtils(org.apache.commons.lang3.StringUtils) MergeParams(org.hisp.dhis.schema.MergeParams) EmbeddedObject(org.hisp.dhis.common.EmbeddedObject) CategoryDimension(org.hisp.dhis.dataelement.CategoryDimension) UserCredentials(org.hisp.dhis.user.UserCredentials) Map(java.util.Map) Period(org.hisp.dhis.period.Period) Query(org.hisp.dhis.query.Query) BaseIdentifiableObject(org.hisp.dhis.common.BaseIdentifiableObject) UserGroup(org.hisp.dhis.user.UserGroup) Collection(java.util.Collection) Set(java.util.Set) SchemaService(org.hisp.dhis.schema.SchemaService) QueryService(org.hisp.dhis.query.QueryService) Property(org.hisp.dhis.schema.Property) Collectors(java.util.stream.Collectors) DataDimensionItem(org.hisp.dhis.common.DataDimensionItem) List(java.util.List) AttributeService(org.hisp.dhis.attribute.AttributeService) Schema(org.hisp.dhis.schema.Schema) LogFactory(org.apache.commons.logging.LogFactory) AnalyticalObject(org.hisp.dhis.common.AnalyticalObject) PropertyType(org.hisp.dhis.schema.PropertyType) DataSetElement(org.hisp.dhis.dataset.DataSetElement) HashMap(java.util.HashMap) Attribute(org.hisp.dhis.attribute.Attribute) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Lists(com.google.common.collect.Lists) IdentifiableObjectManager(org.hisp.dhis.common.IdentifiableObjectManager) User(org.hisp.dhis.user.User) IdentifiableObject(org.hisp.dhis.common.IdentifiableObject) SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) DataElementOperand(org.hisp.dhis.dataelement.DataElementOperand) TrackedEntityProgramIndicatorDimension(org.hisp.dhis.trackedentity.TrackedEntityProgramIndicatorDimension) Timer(org.hisp.dhis.commons.timer.Timer) CollectionUtils(org.hisp.dhis.commons.collection.CollectionUtils) CurrentUserService(org.hisp.dhis.user.CurrentUserService) PeriodStore(org.hisp.dhis.period.PeriodStore) TrackedEntityDataElementDimension(org.hisp.dhis.trackedentity.TrackedEntityDataElementDimension) Log(org.apache.commons.logging.Log) CodeGenerator(org.hisp.dhis.common.CodeGenerator) Transactional(org.springframework.transaction.annotation.Transactional) Set(java.util.Set) HashSet(java.util.HashSet) User(org.hisp.dhis.user.User) Query(org.hisp.dhis.query.Query) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) BaseIdentifiableObject(org.hisp.dhis.common.BaseIdentifiableObject) IdentifiableObject(org.hisp.dhis.common.IdentifiableObject) SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) Timer(org.hisp.dhis.commons.timer.Timer) List(java.util.List) ArrayList(java.util.ArrayList) Map(java.util.Map) HashMap(java.util.HashMap) SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) HashSet(java.util.HashSet)

Example 2 with SystemTimer

use of org.hisp.dhis.commons.timer.SystemTimer in project dhis2-core by dhis2.

the class DefaultMetadataImportService method importMetadata.

@Override
public ImportReport importMetadata(MetadataImportParams params) {
    Timer timer = new SystemTimer().start();
    ImportReport importReport = new ImportReport();
    importReport.setImportParams(params);
    importReport.setStatus(Status.OK);
    if (params.getUser() == null) {
        params.setUser(currentUserService.getCurrentUser());
    }
    String message = "(" + params.getUsername() + ") Import:Start";
    log.info(message);
    if (params.hasTaskId()) {
        notifier.notify(params.getTaskId(), message);
    }
    ObjectBundleParams bundleParams = params.toObjectBundleParams();
    ObjectBundle bundle = objectBundleService.create(bundleParams);
    prepareBundle(bundle);
    ObjectBundleValidationReport validationReport = objectBundleValidationService.validate(bundle);
    importReport.addTypeReports(validationReport.getTypeReportMap());
    if (!(!validationReport.getErrorReports().isEmpty() && AtomicMode.ALL == bundle.getAtomicMode())) {
        Timer commitTimer = new SystemTimer().start();
        ObjectBundleCommitReport commitReport = objectBundleService.commit(bundle);
        importReport.addTypeReports(commitReport.getTypeReportMap());
        if (!importReport.getErrorReports().isEmpty()) {
            importReport.setStatus(Status.WARNING);
        }
        log.info("(" + bundle.getUsername() + ") Import:Commit took " + commitTimer.toString());
    } else {
        importReport.getStats().ignored();
        importReport.getTypeReports().forEach(tr -> tr.getStats().ignored());
        importReport.setStatus(Status.ERROR);
    }
    message = "(" + bundle.getUsername() + ") Import:Done took " + timer.toString();
    log.info(message);
    if (bundle.hasTaskId()) {
        notifier.notify(bundle.getTaskId(), NotificationLevel.INFO, message, true).addTaskSummary(bundle.getTaskId(), importReport);
    }
    if (ObjectBundleMode.VALIDATE == params.getImportMode()) {
        return importReport;
    }
    Lists.newArrayList(importReport.getTypeReportMap().keySet()).forEach(typeReportKey -> {
        if (importReport.getTypeReportMap().get(typeReportKey).getStats().getTotal() == 0) {
            importReport.getTypeReportMap().remove(typeReportKey);
            return;
        }
        TypeReport typeReport = importReport.getTypeReportMap().get(typeReportKey);
        if (ImportReportMode.ERRORS == params.getImportReportMode()) {
            Lists.newArrayList(typeReport.getObjectReportMap().keySet()).forEach(objectReportKey -> {
                if (typeReport.getObjectReportMap().get(objectReportKey).getErrorReportsByCode().isEmpty()) {
                    typeReport.getObjectReportMap().remove(objectReportKey);
                }
            });
        }
        if (ImportReportMode.DEBUG != params.getImportReportMode()) {
            typeReport.getObjectReports().forEach(objectReport -> objectReport.setDisplayName(null));
        }
    });
    return importReport;
}
Also used : ObjectBundleParams(org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleParams) ObjectBundleCommitReport(org.hisp.dhis.dxf2.metadata.objectbundle.feedback.ObjectBundleCommitReport) ObjectBundle(org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundle) SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) Timer(org.hisp.dhis.commons.timer.Timer) ObjectBundleValidationReport(org.hisp.dhis.dxf2.metadata.objectbundle.feedback.ObjectBundleValidationReport) TypeReport(org.hisp.dhis.feedback.TypeReport) ImportReport(org.hisp.dhis.dxf2.metadata.feedback.ImportReport) SystemTimer(org.hisp.dhis.commons.timer.SystemTimer)

Example 3 with SystemTimer

use of org.hisp.dhis.commons.timer.SystemTimer in project dhis2-core by dhis2.

the class DefaultMetadataExportService method getMetadata.

@Override
@SuppressWarnings("unchecked")
public Map<Class<? extends IdentifiableObject>, List<? extends IdentifiableObject>> getMetadata(MetadataExportParams params) {
    Timer timer = new SystemTimer().start();
    Map<Class<? extends IdentifiableObject>, List<? extends IdentifiableObject>> metadata = new HashMap<>();
    if (params.getUser() == null) {
        params.setUser(currentUserService.getCurrentUser());
    }
    if (params.getClasses().isEmpty()) {
        schemaService.getMetadataSchemas().stream().filter(Schema::isIdentifiableObject).forEach(schema -> params.getClasses().add((Class<? extends IdentifiableObject>) schema.getKlass()));
    }
    log.info("(" + params.getUsername() + ") Export:Start");
    for (Class<? extends IdentifiableObject> klass : params.getClasses()) {
        Query query;
        if (params.getQuery(klass) != null) {
            query = params.getQuery(klass);
        } else {
            OrderParams orderParams = new OrderParams(Sets.newHashSet(params.getDefaultOrder()));
            query = queryService.getQueryFromUrl(klass, params.getDefaultFilter(), orderParams.getOrders(schemaService.getDynamicSchema(klass)));
        }
        if (query.getUser() == null) {
            query.setUser(params.getUser());
        }
        query.setDefaultOrder();
        List<? extends IdentifiableObject> objects = queryService.query(query);
        if (!objects.isEmpty()) {
            log.info("(" + params.getUsername() + ") Exported " + objects.size() + " objects of type " + klass.getSimpleName());
            metadata.put(klass, objects);
        }
    }
    log.info("(" + params.getUsername() + ") Export:Done took " + timer.toString());
    return metadata;
}
Also used : SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) Timer(org.hisp.dhis.commons.timer.Timer) Query(org.hisp.dhis.query.Query) HashMap(java.util.HashMap) List(java.util.List) ArrayList(java.util.ArrayList) OrderParams(org.hisp.dhis.dxf2.common.OrderParams) SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) IdentifiableObject(org.hisp.dhis.common.IdentifiableObject)

Example 4 with SystemTimer

use of org.hisp.dhis.commons.timer.SystemTimer in project dhis2-core by dhis2.

the class DefaultObjectBundleValidationService method validate.

@Override
public ObjectBundleValidationReport validate(ObjectBundle bundle) {
    Timer timer = new SystemTimer().start();
    ObjectBundleValidationReport validation = new ObjectBundleValidationReport();
    if ((bundle.getUser() == null || bundle.getUser().isSuper()) && bundle.isSkipValidation()) {
        log.warn("Skipping validation for metadata import by user '" + bundle.getUsername() + "'. Not recommended.");
        return validation;
    }
    List<Class<? extends IdentifiableObject>> klasses = getSortedClasses(bundle);
    for (Class<? extends IdentifiableObject> klass : klasses) {
        TypeReport typeReport = new TypeReport(klass);
        List<IdentifiableObject> nonPersistedObjects = bundle.getObjects(klass, false);
        List<IdentifiableObject> persistedObjects = bundle.getObjects(klass, true);
        List<IdentifiableObject> allObjects = bundle.getObjectMap().get(klass);
        handleDefaults(nonPersistedObjects);
        handleDefaults(persistedObjects);
        typeReport.merge(checkDuplicateIds(klass, persistedObjects, nonPersistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
        if (bundle.getImportMode().isCreateAndUpdate()) {
            typeReport.merge(runValidationHooks(klass, nonPersistedObjects, bundle));
            typeReport.merge(runValidationHooks(klass, persistedObjects, bundle));
            typeReport.merge(validateSecurity(klass, nonPersistedObjects, bundle, ImportStrategy.CREATE));
            typeReport.merge(validateSecurity(klass, persistedObjects, bundle, ImportStrategy.UPDATE));
            typeReport.merge(validateBySchemas(klass, nonPersistedObjects, bundle));
            typeReport.merge(validateBySchemas(klass, persistedObjects, bundle));
            typeReport.merge(checkUniqueness(klass, nonPersistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkUniqueness(klass, persistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkMandatoryAttributes(klass, nonPersistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkMandatoryAttributes(klass, persistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkUniqueAttributes(klass, nonPersistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkUniqueAttributes(klass, persistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            TypeReport checkReferences = checkReferences(klass, allObjects, bundle.getPreheat(), bundle.getPreheatIdentifier(), bundle.isSkipSharing());
            if (!checkReferences.getErrorReports().isEmpty() && AtomicMode.ALL == bundle.getAtomicMode()) {
                typeReport.getStats().incIgnored();
            }
            typeReport.getStats().incCreated(nonPersistedObjects.size());
            typeReport.getStats().incUpdated(persistedObjects.size());
            typeReport.merge(checkReferences);
        } else if (bundle.getImportMode().isCreate()) {
            typeReport.merge(runValidationHooks(klass, nonPersistedObjects, bundle));
            typeReport.merge(validateSecurity(klass, nonPersistedObjects, bundle, ImportStrategy.CREATE));
            typeReport.merge(validateForCreate(klass, persistedObjects, bundle));
            typeReport.merge(validateBySchemas(klass, nonPersistedObjects, bundle));
            typeReport.merge(checkUniqueness(klass, nonPersistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkMandatoryAttributes(klass, nonPersistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkUniqueAttributes(klass, nonPersistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            TypeReport checkReferences = checkReferences(klass, allObjects, bundle.getPreheat(), bundle.getPreheatIdentifier(), bundle.isSkipSharing());
            if (!checkReferences.getErrorReports().isEmpty() && AtomicMode.ALL == bundle.getAtomicMode()) {
                typeReport.getStats().incIgnored();
            }
            typeReport.getStats().incCreated(nonPersistedObjects.size());
            typeReport.merge(checkReferences);
        } else if (bundle.getImportMode().isUpdate()) {
            typeReport.merge(runValidationHooks(klass, persistedObjects, bundle));
            typeReport.merge(validateSecurity(klass, persistedObjects, bundle, ImportStrategy.UPDATE));
            typeReport.merge(validateForUpdate(klass, nonPersistedObjects, bundle));
            typeReport.merge(validateBySchemas(klass, persistedObjects, bundle));
            typeReport.merge(checkUniqueness(klass, persistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkMandatoryAttributes(klass, persistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            typeReport.merge(checkUniqueAttributes(klass, persistedObjects, bundle.getPreheat(), bundle.getPreheatIdentifier()));
            TypeReport checkReferences = checkReferences(klass, allObjects, bundle.getPreheat(), bundle.getPreheatIdentifier(), bundle.isSkipSharing());
            if (!checkReferences.getErrorReports().isEmpty() && AtomicMode.ALL == bundle.getAtomicMode()) {
                typeReport.getStats().incIgnored();
            }
            typeReport.getStats().incUpdated(persistedObjects.size());
            typeReport.merge(checkReferences);
        } else if (bundle.getImportMode().isDelete()) {
            typeReport.merge(validateSecurity(klass, persistedObjects, bundle, ImportStrategy.DELETE));
            typeReport.merge(validateForDelete(klass, nonPersistedObjects, bundle));
            typeReport.getStats().incDeleted(persistedObjects.size());
        }
        validation.addTypeReport(typeReport);
    }
    validateAtomicity(bundle, validation);
    bundle.setObjectBundleStatus(ObjectBundleStatus.VALIDATED);
    log.info("(" + bundle.getUsername() + ") Import:Validation took " + timer.toString());
    return validation;
}
Also used : SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) Timer(org.hisp.dhis.commons.timer.Timer) ObjectBundleValidationReport(org.hisp.dhis.dxf2.metadata.objectbundle.feedback.ObjectBundleValidationReport) TypeReport(org.hisp.dhis.feedback.TypeReport) SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) IdentifiableObject(org.hisp.dhis.common.IdentifiableObject)

Example 5 with SystemTimer

use of org.hisp.dhis.commons.timer.SystemTimer in project dhis2-core by dhis2.

the class AbstractJdbcTableManager method populateAndLog.

/**
     * Executes the given table population SQL statement, log and times the operation.
     */
protected void populateAndLog(String sql, String tableName) {
    log.debug(String.format("Populate table: %s with SQL: ", tableName, sql));
    Timer timer = new SystemTimer().start();
    jdbcTemplate.execute(sql);
    log.info(String.format("Populated table in %s: %s", timer.stop().toString(), tableName));
}
Also used : SystemTimer(org.hisp.dhis.commons.timer.SystemTimer) Timer(org.hisp.dhis.commons.timer.Timer) SystemTimer(org.hisp.dhis.commons.timer.SystemTimer)

Aggregations

SystemTimer (org.hisp.dhis.commons.timer.SystemTimer)6 Timer (org.hisp.dhis.commons.timer.Timer)6 IdentifiableObject (org.hisp.dhis.common.IdentifiableObject)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 List (java.util.List)2 ObjectBundleValidationReport (org.hisp.dhis.dxf2.metadata.objectbundle.feedback.ObjectBundleValidationReport)2 TypeReport (org.hisp.dhis.feedback.TypeReport)2 Query (org.hisp.dhis.query.Query)2 Lists (com.google.common.collect.Lists)1 Collection (java.util.Collection)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 Set (java.util.Set)1 Collectors (java.util.stream.Collectors)1 StringUtils (org.apache.commons.lang3.StringUtils)1 Log (org.apache.commons.logging.Log)1 LogFactory (org.apache.commons.logging.LogFactory)1 Attribute (org.hisp.dhis.attribute.Attribute)1 AttributeService (org.hisp.dhis.attribute.AttributeService)1