Jörg Rade created CAUSEWAY-3687: ----------------------------------- Summary: Using @Transactional within a @DomainService Leads to a Missing Menu Entry Key: CAUSEWAY-3687 URL: https://issues.apache.org/jira/browse/CAUSEWAY-3687 Project: Causeway Issue Type: Bug Components: Viewer Wicket Affects Versions: 2.0.0-RC4 Reporter: Jörg Rade
{code:java} package com.kn.lx.domain; import com.kn.lx.util.Constants; import com.kn.lx.config.Properties; import com.kn.lx.input.elastic.QueryResultItemTO; import com.kn.lx.input.elastic.QueryService; import com.kn.lx.input.elastic.pr.PrQuery; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.apache.causeway.applib.annotation.Action; import org.apache.causeway.applib.annotation.ActionLayout; import org.apache.causeway.applib.annotation.DomainService; import org.apache.causeway.applib.annotation.NatureOfService; import org.apache.causeway.applib.annotation.Programmatic; import org.apache.causeway.applib.annotation.SemanticsOf; import org.springframework.transaction.annotation.Transactional; import javax.inject.Inject; import javax.inject.Named; import java.lang.reflect.InvocationTargetException; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @Named("lx.Tasks") @DomainService(nature = NatureOfService.VIEW) @RequiredArgsConstructor(onConstructor_ = {@Inject}) public class Tasks { private final TaskRepository taskRepository; private final QueryService queryService; private final Executions executions; private final Properties properties; @Programmatic public Task create(String className) { final Task obj = new Task(); obj.setQueryClassName(className); obj.setCronExpression(Constants.INSTANCE.getEVERY_FIVE_MINUTES()); obj.setActive(true); taskRepository.saveAndFlush(obj); return obj; } @ActionLayout(sequence = "1") public List<Task> listAll() { return taskRepository.findAll(); } public void init() { createIfAbsent(PrQuery.class.getCanonicalName()); } @ActionLayout(sequence = "2") public void createIfAbsent(final String name) { final Task obj = taskRepository.findByQueryClassName(name); if (null == obj) { create(name); } } @Action(semantics = SemanticsOf.SAFE) @ActionLayout(sequence = "3", cssClassFa = "trash") public void delete(Task task) { taskRepository.delete(task); } List<QueryResultItemTO> executeQuery(PrQuery query) { final Integer chunkSize = properties.getInteger(Constants.INSTANCE.getELASTIC_QUERY_CHUNK_SIZE()); query.setMaxNumberOfHits(chunkSize); String latestTimeStamp = properties.getString(Constants.INSTANCE.getEND_TIME_STAMP()); if (latestTimeStamp.isEmpty()) { latestTimeStamp = properties.getString(Constants.INSTANCE.getSTART_TIME_STAMP()); } return queryService.searchBy(query, latestTimeStamp); } @NonNull PrQuery createForClass(String queryClassName) { try { return (PrQuery) Class.forName(queryClassName).getDeclaredConstructor().newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | InvocationTargetException | NoSuchMethodException e) { throw new RuntimeException(e); } } @Transactional public Task execute(Task argTask) { final Task task = update(argTask); if (task.isActive()) { final PrQuery query = createForClass(task.getQueryClassName()); final List<QueryResultItemTO> queryResultList = executeQuery(query); final Execution e = executions.create(task, queryResultList); e.setEndedAt(LocalDateTime.now()); e.setHits((long) queryResultList.size()); task.getExecutionList().add(e); taskRepository.saveAndFlush(task); executions.sendMessagesFor(e); return task; } return null; } /** * It seems argTask is out of sync when it reaches this point. * Read it again. * * @param argTask Task to be synced * @return Task, synced with DB */ private Task update(Task argTask) { final Optional<? extends Task> optionalTask = taskRepository.findById(argTask.getId()); if (optionalTask.isPresent()) { return optionalTask.get(); } else { throw new RuntimeException("Task not found"); } } } {code} -- This message was sent by Atlassian Jira (v8.20.10#820010)