Commit 3e1bd44c authored by Marco Descher's avatar Marco Descher 🏔

[11238] JPA Task#getTaskDescriptor use direct JPA resolvement

parent f5d31cc8
Pipeline #12163 passed with stages
in 4 minutes and 36 seconds
......@@ -8,7 +8,9 @@ import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import ch.elexis.core.jpa.entities.converter.BooleanCharacterConverterSafe;
......@@ -38,8 +40,9 @@ public class Task extends AbstractEntityWithId implements EntityWithId, EntityWi
@Column
protected int triggerEvent = 0;
@Column(length = 32)
protected String descriptorId;
@JoinColumn(name="descriptor")
@ManyToOne
protected TaskDescriptor taskDescriptor;
@Column
@Lob
......@@ -98,12 +101,12 @@ public class Task extends AbstractEntityWithId implements EntityWithId, EntityWi
this.triggerEvent = triggerEvent;
}
public String getDescriptorId(){
return descriptorId;
public TaskDescriptor getTaskDescriptor(){
return taskDescriptor;
}
public void setDescriptorId(String descriptorId){
this.descriptorId = descriptorId;
public void setTaskDescriptor(TaskDescriptor taskDescriptor){
this.taskDescriptor = taskDescriptor;
}
public String getRunContext(){
......
......@@ -1889,5 +1889,23 @@ DROP TABLE TEMP_ETIKETTEN_OBJCLASS_LINK;
<column name="DATA" type="VARCHAR(256)" />
</addColumn>
</changeSet>
<changeSet author="marco" id="manual_TASK_FK_DESCRIPTOR">
<preConditions onFail="MARK_RAN">
<not>
<foreignKeyConstraintExists
foreignKeyName="TASKDESCRIPTOR_FK_ID" />
</not>
</preConditions>
<renameColumn tableName="TASK"
oldColumnName="DESCRIPTORID" newColumnName="DESCRIPTOR" />
<modifyDataType tableName="TASK"
columnName="DESCRIPTOR" newDataType="VARCHAR(25)" />
<addNotNullConstraint tableName="TASK"
columnName="DESCRIPTOR" />
<addForeignKeyConstraint constraintName="TASKDESCRIPTOR_FK_ID"
referencedTableName="TASKDESCRIPTOR" baseColumnNames="DESCRIPTOR" baseTableName="TASK"
referencedColumnNames="ID" />
</changeSet>
</databaseChangeLog>
......@@ -132,8 +132,8 @@
<details key="documentation" value="The task has finished its execution."/>
</eAnnotations>
</eStructuralFeatures>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="descriptorId" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" changeable="false"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="taskDescriptor" lowerBound="1"
eType="#//ITaskDescriptor" changeable="false"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="ITaskService" abstract="true" interface="true">
<eOperations name="createTaskDescriptor" eType="#//ITaskDescriptor" eExceptions="#//TaskException">
......
......@@ -68,7 +68,7 @@
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute model.ecore#//ITask/progressMonitor"/>
<genFeatures property="Readonly" createChild="false" ecoreFeature="ecore:EAttribute model.ecore#//ITask/runContext"/>
<genFeatures property="Readonly" createChild="false" ecoreFeature="ecore:EAttribute model.ecore#//ITask/finished"/>
<genFeatures property="Readonly" createChild="false" ecoreFeature="ecore:EAttribute model.ecore#//ITask/descriptorId"/>
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference model.ecore#//ITask/taskDescriptor"/>
<genOperations ecoreOperation="model.ecore#//ITask/getResultEntryAsTypedList">
<genParameters ecoreParameter="model.ecore#//ITask/getResultEntryAsTypedList/key"/>
<genParameters ecoreParameter="model.ecore#//ITask/getResultEntryAsTypedList/clazz"/>
......
......@@ -42,7 +42,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
* <li>{@link ch.elexis.core.tasks.model.ITask#getProgressMonitor <em>Progress Monitor</em>}</li>
* <li>{@link ch.elexis.core.tasks.model.ITask#getRunContext <em>Run Context</em>}</li>
* <li>{@link ch.elexis.core.tasks.model.ITask#isFinished <em>Finished</em>}</li>
* <li>{@link ch.elexis.core.tasks.model.ITask#getDescriptorId <em>Descriptor Id</em>}</li>
* <li>{@link ch.elexis.core.tasks.model.ITask#getTaskDescriptor <em>Task Descriptor</em>}</li>
* </ul>
*
* @see ch.elexis.core.tasks.model.ModelPackage#getITask()
......@@ -185,19 +185,15 @@ public interface ITask extends Identifiable, Deleteable {
boolean isFinished();
/**
* Returns the value of the '<em><b>Descriptor Id</b></em>' attribute.
* Returns the value of the '<em><b>Task Descriptor</b></em>' reference.
* <!-- begin-user-doc -->
* <p>
* If the meaning of the '<em>Descriptor Id</em>' attribute isn't clear,
* there really should be more of a description here...
* </p>
* <!-- end-user-doc -->
* @return the value of the '<em>Descriptor Id</em>' attribute.
* @see ch.elexis.core.tasks.model.ModelPackage#getITask_DescriptorId()
* @return the value of the '<em>Task Descriptor</em>' reference.
* @see ch.elexis.core.tasks.model.ModelPackage#getITask_TaskDescriptor()
* @model required="true" changeable="false"
* @generated
*/
String getDescriptorId();
ITaskDescriptor getTaskDescriptor();
/**
* <!-- begin-user-doc -->
......
......@@ -40,6 +40,7 @@ public interface ITaskService {
/**
* <!-- begin-user-doc -->
* Removing a task descriptor also removes all ITask entries that reference to it.
* <!-- end-user-doc -->
* @model exceptions="ch.elexis.core.tasks.model.TaskException"
* @generated
......
......@@ -294,13 +294,13 @@ public interface ModelPackage extends EPackage {
int ITASK__FINISHED = ch.elexis.core.model.ModelPackage.IDENTIFIABLE_FEATURE_COUNT + 9;
/**
* The feature id for the '<em><b>Descriptor Id</b></em>' attribute.
* The feature id for the '<em><b>Task Descriptor</b></em>' reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
* @ordered
*/
int ITASK__DESCRIPTOR_ID = ch.elexis.core.model.ModelPackage.IDENTIFIABLE_FEATURE_COUNT + 10;
int ITASK__TASK_DESCRIPTOR = ch.elexis.core.model.ModelPackage.IDENTIFIABLE_FEATURE_COUNT + 10;
/**
* The number of structural features of the '<em>ITask</em>' class.
......@@ -663,15 +663,15 @@ public interface ModelPackage extends EPackage {
EAttribute getITask_Finished();
/**
* Returns the meta object for the attribute '{@link ch.elexis.core.tasks.model.ITask#getDescriptorId <em>Descriptor Id</em>}'.
* Returns the meta object for the reference '{@link ch.elexis.core.tasks.model.ITask#getTaskDescriptor <em>Task Descriptor</em>}'.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @return the meta object for the attribute '<em>Descriptor Id</em>'.
* @see ch.elexis.core.tasks.model.ITask#getDescriptorId()
* @return the meta object for the reference '<em>Task Descriptor</em>'.
* @see ch.elexis.core.tasks.model.ITask#getTaskDescriptor()
* @see #getITask()
* @generated
*/
EAttribute getITask_DescriptorId();
EReference getITask_TaskDescriptor();
/**
* Returns the meta object for class '{@link ch.elexis.core.tasks.model.ITaskService <em>ITask Service</em>}'.
......@@ -983,12 +983,12 @@ public interface ModelPackage extends EPackage {
EAttribute ITASK__FINISHED = eINSTANCE.getITask_Finished();
/**
* The meta object literal for the '<em><b>Descriptor Id</b></em>' attribute feature.
* The meta object literal for the '<em><b>Task Descriptor</b></em>' reference feature.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
EAttribute ITASK__DESCRIPTOR_ID = eINSTANCE.getITask_DescriptorId();
EReference ITASK__TASK_DESCRIPTOR = eINSTANCE.getITask_TaskDescriptor();
/**
* The meta object literal for the '{@link ch.elexis.core.tasks.model.ITaskService <em>ITask Service</em>}' class.
......
......@@ -425,8 +425,8 @@ public class ModelPackageImpl extends EPackageImpl implements ModelPackage {
* @generated
*/
@Override
public EAttribute getITask_DescriptorId() {
return (EAttribute)iTaskEClass.getEStructuralFeatures().get(9);
public EReference getITask_TaskDescriptor() {
return (EReference)iTaskEClass.getEStructuralFeatures().get(9);
}
/**
......@@ -581,7 +581,7 @@ public class ModelPackageImpl extends EPackageImpl implements ModelPackage {
createEAttribute(iTaskEClass, ITASK__PROGRESS_MONITOR);
createEAttribute(iTaskEClass, ITASK__RUN_CONTEXT);
createEAttribute(iTaskEClass, ITASK__FINISHED);
createEAttribute(iTaskEClass, ITASK__DESCRIPTOR_ID);
createEReference(iTaskEClass, ITASK__TASK_DESCRIPTOR);
iTaskServiceEClass = createEClass(ITASK_SERVICE);
......@@ -690,7 +690,7 @@ public class ModelPackageImpl extends EPackageImpl implements ModelPackage {
g1.getETypeArguments().add(g2);
initEAttribute(getITask_RunContext(), g1, "runContext", null, 0, 1, ITask.class, IS_TRANSIENT, !IS_VOLATILE, !IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
initEAttribute(getITask_Finished(), ecorePackage.getEBoolean(), "finished", "false", 1, 1, ITask.class, !IS_TRANSIENT, !IS_VOLATILE, !IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
initEAttribute(getITask_DescriptorId(), ecorePackage.getEString(), "descriptorId", null, 1, 1, ITask.class, !IS_TRANSIENT, !IS_VOLATILE, !IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
initEReference(getITask_TaskDescriptor(), this.getITaskDescriptor(), null, "taskDescriptor", null, 1, 1, ITask.class, !IS_TRANSIENT, !IS_VOLATILE, !IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
op = addEOperation(iTaskEClass, null, "getResultEntryAsTypedList", 0, 1, IS_UNIQUE, IS_ORDERED);
ETypeParameter t1 = addETypeParameter(op, "T");
......
......@@ -19,12 +19,14 @@ import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import ch.elexis.core.jpa.model.adapter.AbstractIdDeleteModelAdapter;
import ch.elexis.core.jpa.model.adapter.AbstractIdModelAdapter;
import ch.elexis.core.model.IXid;
import ch.elexis.core.model.Identifiable;
import ch.elexis.core.model.tasks.IIdentifiedRunnable;
import ch.elexis.core.model.tasks.IIdentifiedRunnable.ReturnParameter;
import ch.elexis.core.tasks.internal.model.service.ContextServiceHolder;
import ch.elexis.core.tasks.internal.model.service.CoreModelServiceHolder;
import ch.elexis.core.tasks.internal.model.service.TaskModelAdapterFactory;
import ch.elexis.core.tasks.model.ITask;
import ch.elexis.core.tasks.model.ITaskDescriptor;
import ch.elexis.core.tasks.model.TaskState;
......@@ -57,6 +59,7 @@ public class Task extends AbstractIdDeleteModelAdapter<ch.elexis.core.jpa.entiti
* {@link ITaskDescriptor#getRunContext()} 3. overlay with runContext value as
* provided
*/
@SuppressWarnings("unchecked")
public Task(ITaskDescriptor taskDescriptor, TaskTriggerType triggerType,
IProgressMonitor progressMonitor, Map<String, String> runContext){
this(new ch.elexis.core.jpa.entities.Task());
......@@ -65,7 +68,9 @@ public class Task extends AbstractIdDeleteModelAdapter<ch.elexis.core.jpa.entiti
getEntity().setState(TaskState.DRAFT.getValue());
getEntity().setTriggerEvent(triggerType.getValue());
getEntity().setDescriptorId(taskDescriptor.getId());
getEntity().setTaskDescriptor(
((AbstractIdModelAdapter<ch.elexis.core.jpa.entities.TaskDescriptor>) taskDescriptor)
.getEntityMarkDirty());
if (runContext != null) {
getEntity().setRunContext(gson.toJson(runContext));
}
......@@ -127,8 +132,10 @@ public class Task extends AbstractIdDeleteModelAdapter<ch.elexis.core.jpa.entiti
}
@Override
public String getDescriptorId(){
return getEntity().getDescriptorId();
public ITaskDescriptor getTaskDescriptor(){
Optional<Identifiable> adapter = TaskModelAdapterFactory.getInstance()
.getModelAdapter(getEntity().getTaskDescriptor(), ITaskDescriptor.class, true, false);
return (ITaskDescriptor) adapter.orElse(null);
}
@Override
......@@ -175,69 +182,58 @@ public class Task extends AbstractIdDeleteModelAdapter<ch.elexis.core.jpa.entiti
Thread.currentThread().setName(taskId);
getEntity().setRunAt(LocalDateTime.now());
Optional<ITaskDescriptor> originTaskDescriptor = TaskServiceHolder.get()
.findTaskDescriptorByIdOrReferenceId(getEntity().getDescriptorId());
if (originTaskDescriptor.isPresent()) {
setState(TaskState.READY);
ITaskDescriptor originTaskDescriptor = getTaskDescriptor();
String runnableWithContextId = originTaskDescriptor.getIdentifiedRunnableId();
try {
IIdentifiedRunnable runnableWithContext =
TaskServiceHolder.get().instantiateRunnableById(runnableWithContextId);
setState(TaskState.READY);
String runnableWithContextId = originTaskDescriptor.get().getIdentifiedRunnableId();
Map<String, Serializable> effectiveRunContext = new HashMap<>();
effectiveRunContext.putAll(runnableWithContext.getDefaultRunContext());
effectiveRunContext.putAll(originTaskDescriptor.getRunContext());
effectiveRunContext.putAll(getRunContext());
// TODO persist executing station
getEntity().setRunContext(gson.toJson(effectiveRunContext));
// TODO validate all required parameters are set, validate url
try {
IIdentifiedRunnable runnableWithContext =
TaskServiceHolder.get().instantiateRunnableById(runnableWithContextId);
Map<String, Serializable> effectiveRunContext = new HashMap<>();
effectiveRunContext.putAll(runnableWithContext.getDefaultRunContext());
effectiveRunContext.putAll(originTaskDescriptor.get().getRunContext());
effectiveRunContext.putAll(getRunContext());
getEntity().setRunContext(gson.toJson(effectiveRunContext));
// TODO validate all required parameters are set, validate url
setState(TaskState.IN_PROGRESS);
long beginTimeMillis = System.currentTimeMillis();
// TODO what if it runs forever?
Map<String, Serializable> result =
runnableWithContext.run(effectiveRunContext, progressMonitor, logger);
long endTimeMillis = System.currentTimeMillis();
if (result == null || !result.containsKey("runnableExecDuration")) {
// returned map may be unmodifiable
result = new HashMap<>(result);
result.put("runnableExecDuration",
Long.toString(endTimeMillis - beginTimeMillis));
}
setResult(result);
TaskState exitState =
(result.containsKey(ReturnParameter.MARKER_WARN)) ? TaskState.COMPLETED_WARN
: TaskState.COMPLETED;
setState(exitState);
if (effectiveRunContext.containsKey(ReturnParameter.MARKER_DO_NOT_PERSIST)
|| getResult().containsKey(ReturnParameter.MARKER_DO_NOT_PERSIST)) {
// only if completion was successful
removeTaskRecord();
}
} catch (Exception e) {
setResult(Collections.singletonMap(
IIdentifiedRunnable.ReturnParameter.FAILED_TASK_EXCEPTION_MESSAGE,
e.getMessage()));
logger.warn(e.getMessage(), e);
setState(TaskState.FAILED);
setState(TaskState.IN_PROGRESS);
long beginTimeMillis = System.currentTimeMillis();
// TODO what if it runs forever?
Map<String, Serializable> result =
runnableWithContext.run(effectiveRunContext, progressMonitor, logger);
long endTimeMillis = System.currentTimeMillis();
if (result == null || !result.containsKey("runnableExecDuration")) {
// returned map may be unmodifiable
result = new HashMap<>(result);
result.put("runnableExecDuration", Long.toString(endTimeMillis - beginTimeMillis));
}
if (progressMonitor != null) {
progressMonitor.done();
setResult(result);
TaskState exitState =
(result.containsKey(ReturnParameter.MARKER_WARN)) ? TaskState.COMPLETED_WARN
: TaskState.COMPLETED;
setState(exitState);
if (effectiveRunContext.containsKey(ReturnParameter.MARKER_DO_NOT_PERSIST)
|| getResult().containsKey(ReturnParameter.MARKER_DO_NOT_PERSIST)) {
// only if completion was successful
removeTaskRecord();
}
} else {
logger.warn("Could not resolve task descriptor [{}]", getEntity().getDescriptorId());
} catch (Exception e) {
setResult(Collections.singletonMap(
IIdentifiedRunnable.ReturnParameter.FAILED_TASK_EXCEPTION_MESSAGE, e.getMessage()));
logger.warn(e.getMessage(), e);
setState(TaskState.FAILED);
}
if (progressMonitor != null) {
progressMonitor.done();
}
}
@Override
......
......@@ -250,6 +250,13 @@ public class TaskServiceImpl implements ITaskService {
}
setActive(taskDescriptor, false);
IQuery<ITask> taskQuery = taskModelService.getQuery(ITask.class, true);
taskQuery.and(ModelPackage.Literals.ITASK__TASK_DESCRIPTOR, COMPARATOR.EQUALS,
taskDescriptor);
List<ITask> execute = taskQuery.execute();
execute.stream().forEach(task -> taskModelService.remove(task));
return taskModelService.remove(taskDescriptor);
}
......@@ -259,27 +266,22 @@ public class TaskServiceImpl implements ITaskService {
triggeredTasks.remove(task);
ITaskDescriptor taskDescriptor =
findTaskDescriptorByIdOrReferenceId(task.getDescriptorId()).orElse(null);
if (taskDescriptor != null) {
OwnerTaskNotification ownerNotification = taskDescriptor.getOwnerNotification();
IUser owner = taskDescriptor.getOwner();
ITaskDescriptor taskDescriptor = task.getTaskDescriptor();
OwnerTaskNotification ownerNotification = taskDescriptor.getOwnerNotification();
IUser owner = taskDescriptor.getOwner();
TaskState state = task.getState();
if (OwnerTaskNotification.WHEN_FINISHED == ownerNotification
|| (OwnerTaskNotification.WHEN_FINISHED_FAILED == ownerNotification
&& TaskState.FAILED == state)) {
TaskState state = task.getState();
if (OwnerTaskNotification.WHEN_FINISHED == ownerNotification
|| (OwnerTaskNotification.WHEN_FINISHED_FAILED == ownerNotification
&& TaskState.FAILED == state)) {
if (owner != null) {
sendMessageToOwner(task, owner, state);
} else {
logger.warn("[{}] requested owner notification, but owner is null",
task.getDescriptorId());
}
if (owner != null) {
sendMessageToOwner(task, owner, state);
} else {
logger.warn("[{}] requested owner notification, but owner is null",
task.getTaskDescriptor().getId());
}
} else {
logger.error("could not load taskdescriptor by id [{}]", task.getDescriptorId());
}
}
......@@ -467,8 +469,7 @@ public class TaskServiceImpl implements ITaskService {
@Override
public Optional<ITask> findLatestExecution(ITaskDescriptor taskDescriptor){
IQuery<ITask> query = taskModelService.getQuery(ITask.class);
query.and(ModelPackage.Literals.ITASK__DESCRIPTOR_ID, COMPARATOR.EQUALS,
taskDescriptor.getId());
query.and(ModelPackage.Literals.ITASK__TASK_DESCRIPTOR, COMPARATOR.EQUALS, taskDescriptor);
query.orderBy("lastupdate", ORDER.DESC);
query.limit(1);
List<ITask> result = query.execute();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment