diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml
index 930153a320..1fc9454e3a 100644
--- a/config/alfresco/public-rest-context.xml
+++ b/config/alfresco/public-rest-context.xml
@@ -915,6 +915,22 @@
+
+
+
+
+
+ org.alfresco.rest.workflow.api.Activities
+
+
+
+
+
+
+
+
+
+
@@ -925,18 +941,24 @@
-
+
+
+
+
+
+
+
-
+
-
+
@@ -956,6 +978,6 @@
-
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/audit/control_nb_NO.properties b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/control_nb_NO.properties
index d3d8761efc..d20f87a372 100755
--- a/config/alfresco/templates/webscripts/org/alfresco/repository/audit/control_nb_NO.properties
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/audit/control_nb_NO.properties
@@ -2,6 +2,6 @@
audit.err.app.notProvided=Programnavn ikke gitt.
audit.err.app.notFound=Program ikke funnet: {0}
audit.err.path.notProvided=Ingen sti har blitt gitt etter programnavnet.
-audit.err.action.invalid=Parameteren 'handling' m\u00e5 enten v\u00e6re 'aktiver' eller 'deaktiver'
-audit.err.value.classNotFound='valueType' ikke gjenkjent: {0}
+audit.err.action.invalid=Parameteren ''handling'' m\u00e5 enten v\u00e6re ''aktiver'' eller ''deaktiver''
+audit.err.value.classNotFound=''valueType'' ikke gjenkjent: {0}
audit.err.value.convertFailed=Kan ikke konvertere ''{0}'' til type ''{1}''
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/links/links-delete.post_nb_NO.properties b/config/alfresco/templates/webscripts/org/alfresco/repository/links/links-delete.post_nb_NO.properties
index c7049dc2d2..8b15ed9623 100755
--- a/config/alfresco/templates/webscripts/org/alfresco/repository/links/links-delete.post_nb_NO.properties
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/links/links-delete.post_nb_NO.properties
@@ -1,3 +1,3 @@
links-delete.err.not.found=Ingen gyldige koblingsnavn ble angitt
-links-delete.access.denied=Du har ikke tillatelse til \u00e5 slette koblingen med navnet '{0}'
+links-delete.access.denied=Du har ikke tillatelse til \u00e5 slette koblingen med navnet ''{0}''
links-delete.msg.deleted=Slettet node {0}
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_it.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_it.properties
new file mode 100644
index 0000000000..6a6deed140
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_it.properties
@@ -0,0 +1,7 @@
+page.create.error.nameAlreadyUsed=Il nome ''{0}'' \u00e8 stato gi\u00e0 utilizzato
+page.create.error.noNameProvided=Non \u00e8 stato fornito alcun nome per la pagina
+page.create.error.noDefProvided=Non \u00e8 stata fornita alcuna definizione di pagina per la pagina
+page.create.error.invalidJson=La definizione di pagina non era valida JSON: {0}
+page.create.error.noTargetLocation=La posizione di destinazione per le pagine "Condividi risorse/pagine" non \u00e8 stata creata nel dizionario dei dati
+page.create.error.couldNotCreate=Non \u00e8 stato possibile creare la pagina.
+page.create.error.unexpected=Si \u00e8 verificato un errore imprevisto.
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_ja.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_ja.properties
new file mode 100644
index 0000000000..6204ba537a
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_ja.properties
@@ -0,0 +1,7 @@
+page.create.error.nameAlreadyUsed=\u540d\u524d''{0}''\u306f\u65e2\u306b\u4f7f\u308f\u308c\u3066\u3044\u307e\u3059\u3002
+page.create.error.noNameProvided=\u30da\u30fc\u30b8\u306e\u540d\u524d\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+page.create.error.noDefProvided=\u30da\u30fc\u30b8\u306e\u30da\u30fc\u30b8\u5b9a\u7fa9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+page.create.error.invalidJson=\u30da\u30fc\u30b8\u5b9a\u7fa9\u306eJSON\u304c\u7121\u52b9\u3067\u3059: {0}
+page.create.error.noTargetLocation=\u30da\u30fc\u30b8"ShareResources/pages"\u306e\u30bf\u30fc\u30b2\u30c3\u30c8\u306e\u5834\u6240\u304c\u30c7\u30fc\u30bf\u30c7\u30a3\u30af\u30b7\u30e7\u30ca\u30ea\u5185\u306b\u4f5c\u6210\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+page.create.error.couldNotCreate=\u30da\u30fc\u30b8\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
+page.create.error.unexpected=\u4e0d\u660e\u306a\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_nb_NO.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_nb_NO.properties
new file mode 100644
index 0000000000..aa047e2f4d
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_nb_NO.properties
@@ -0,0 +1,7 @@
+page.create.error.nameAlreadyUsed=Navnet ''{0}'' er allerede brukt
+page.create.error.noNameProvided=Intet navn oppgitt for siden
+page.create.error.noDefProvided=Ingen sidedefinisjon oppgitt for siden
+page.create.error.invalidJson=Sidedefinisjonen ikke gyldig JSON: {0}
+page.create.error.noTargetLocation=M\u00e5lstedet for sidene "ShareResources/sider" ikke opprettet i datamappen
+page.create.error.couldNotCreate=Det var ikke mulig \u00e5 opprette siden.
+page.create.error.unexpected=Det oppstod en uventet feil.
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_nl.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_nl.properties
new file mode 100644
index 0000000000..74a8b02383
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_nl.properties
@@ -0,0 +1,7 @@
+page.create.error.nameAlreadyUsed=De naam ''{0}'' is al gebruikt
+page.create.error.noNameProvided=Er is geen naam opgegeven voor de pagina
+page.create.error.noDefProvided=Er is geen paginadefinitie opgegeven voor de pagina
+page.create.error.invalidJson=De paginadefinitie is niet geldig (JSON): {0}
+page.create.error.noTargetLocation=De doellocatie voor de pagina's "Resources/pagina's delen" is niet gemaakt in de data dictionary
+page.create.error.couldNotCreate=De pagina kon niet worden gemaakt.
+page.create.error.unexpected=Er is een onverwachte fout opgetreden.
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_ru.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_ru.properties
new file mode 100644
index 0000000000..f38aea007c
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_ru.properties
@@ -0,0 +1,7 @@
+page.create.error.nameAlreadyUsed=\u0418\u043c\u044f ''{0}'' \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043e
+page.create.error.noNameProvided=\u0414\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0438\u043c\u044f
+page.create.error.noDefProvided=\u0414\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435
+page.create.error.invalidJson=\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u044f\u0432\u043b\u044f\u043b\u043e\u0441\u044c \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u043c JSON: {0}
+page.create.error.noTargetLocation=\u0412 \u0441\u043b\u043e\u0432\u0430\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043e \u0446\u0435\u043b\u0435\u0432\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446 "ShareResources/pages"
+page.create.error.couldNotCreate=\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.
+page.create.error.unexpected=\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_zh_CN.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_zh_CN.properties
new file mode 100644
index 0000000000..3b20136a9c
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.post_zh_CN.properties
@@ -0,0 +1,7 @@
+page.create.error.nameAlreadyUsed=\u540d\u79f0''{0}''\u5df2\u4f7f\u7528
+page.create.error.noNameProvided=\u6ca1\u6709\u4e3a\u9875\u9762\u6307\u5b9a\u540d\u79f0
+page.create.error.noDefProvided=\u6ca1\u6709\u63d0\u4f9b\u9875\u9762\u5b9a\u4e49
+page.create.error.invalidJson=\u9875\u9762\u5b9a\u4e49\u65e0\u6548 JSON\uff1a{0}
+page.create.error.noTargetLocation=\u672a\u5728\u6570\u636e\u5b57\u5178\u4e2d\u521b\u5efa\u9875\u9762"ShareResources/pages"\u7684\u76ee\u6807\u4f4d\u7f6e
+page.create.error.couldNotCreate=\u65e0\u6cd5\u521b\u5efa\u9875\u9762\u3002
+page.create.error.unexpected=\u51fa\u73b0\u610f\u5916\u9519\u8bef\u3002
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_it.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_it.properties
new file mode 100644
index 0000000000..4b12ddb749
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_it.properties
@@ -0,0 +1,8 @@
+page.update.error.nameAlreadyUsed=Il nome ''{0}'' \u00e8 stato gi\u00e0 utilizzato
+page.update.error.noNameProvided=Non \u00e8 stato fornito alcun nome per la pagina
+page.update.error.noDefProvided=Non \u00e8 stata fornita alcuna definizione di pagina per la pagina
+page.update.error.invalidJson=La definizione di pagina non era valida JSON: {0}
+page.update.error.noTargetLocation=La posizione di destinazione per le pagine "Condividi risorse/pagine" non \u00e8 stata creata nel dizionario dei dati
+page.update.error.couldNotCreate=Non \u00e8 stato possibile creare la pagina.
+page.update.error.doesNotExist=La pagina richiesta da aggiornare non esiste
+page.update.error.unexpected=Si \u00e8 verificato un errore imprevisto.
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_ja.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_ja.properties
new file mode 100644
index 0000000000..80e23ced96
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_ja.properties
@@ -0,0 +1,8 @@
+page.update.error.nameAlreadyUsed=\u540d\u524d''{0}''\u306f\u65e2\u306b\u4f7f\u308f\u308c\u3066\u3044\u307e\u3059\u3002
+page.update.error.noNameProvided=\u30da\u30fc\u30b8\u306e\u540d\u524d\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+page.update.error.noDefProvided=\u30da\u30fc\u30b8\u306e\u30da\u30fc\u30b8\u5b9a\u7fa9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+page.update.error.invalidJson=\u30da\u30fc\u30b8\u5b9a\u7fa9\u306eJSON\u304c\u7121\u52b9\u3067\u3059: {0}
+page.update.error.noTargetLocation=\u30da\u30fc\u30b8"ShareResources/pages"\u306e\u30bf\u30fc\u30b2\u30c3\u30c8\u306e\u5834\u6240\u304c\u30c7\u30fc\u30bf\u30c7\u30a3\u30af\u30b7\u30e7\u30ca\u30ea\u5185\u306b\u4f5c\u6210\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+page.update.error.couldNotCreate=\u30da\u30fc\u30b8\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
+page.update.error.doesNotExist=\u66f4\u65b0\u3059\u308b\u3053\u3068\u3092\u8981\u6c42\u3055\u308c\u305f\u30da\u30fc\u30b8\u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
+page.update.error.unexpected=\u4e0d\u660e\u306a\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_nb_NO.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_nb_NO.properties
new file mode 100644
index 0000000000..adb2dd1277
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_nb_NO.properties
@@ -0,0 +1,8 @@
+page.update.error.nameAlreadyUsed=Navnet ''{0}'' er allerede brukt
+page.update.error.noNameProvided=Intet navn oppgitt for siden
+page.update.error.noDefProvided=Ingen sidedefinisjon oppgitt for siden
+page.update.error.invalidJson=Sidedefinisjonen ikke gyldig JSON: {0}
+page.update.error.noTargetLocation=M\u00e5lstedet for sidene "ShareResources/sider" ikke opprettet i datamappen
+page.update.error.couldNotCreate=Det var ikke mulig \u00e5 opprette siden.
+page.update.error.doesNotExist=Forespurt side som skal oppdateres eksisterer ikke
+page.update.error.unexpected=Det oppstod en uventet feil.
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_nl.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_nl.properties
new file mode 100644
index 0000000000..8aafc38bd4
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_nl.properties
@@ -0,0 +1,8 @@
+page.update.error.nameAlreadyUsed=De naam ''{0}'' is al gebruikt
+page.update.error.noNameProvided=Er is geen naam opgegeven voor de pagina
+page.update.error.noDefProvided=Er is geen paginadefinitie opgegeven voor de pagina
+page.update.error.invalidJson=De paginadefinitie is niet geldig (JSON): {0}
+page.update.error.noTargetLocation=De doellocatie voor de pagina's "Resources/pagina's delen" is niet gemaakt in de data dictionary
+page.update.error.couldNotCreate=De pagina kon niet worden gemaakt.
+page.update.error.doesNotExist=De opgevraagde pagina die moet worden bijgewerkt bestaat niet
+page.update.error.unexpected=Er is een onverwachte fout opgetreden.
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_ru.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_ru.properties
new file mode 100644
index 0000000000..37c7f97cb3
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_ru.properties
@@ -0,0 +1,8 @@
+page.update.error.nameAlreadyUsed=\u0418\u043c\u044f ''{0}'' \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043e
+page.update.error.noNameProvided=\u0414\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0438\u043c\u044f
+page.update.error.noDefProvided=\u0414\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435
+page.update.error.invalidJson=\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u044f\u0432\u043b\u044f\u043b\u043e\u0441\u044c \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u043c JSON: {0}
+page.update.error.noTargetLocation=\u0412 \u0441\u043b\u043e\u0432\u0430\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043e \u0446\u0435\u043b\u0435\u0432\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446 "ShareResources/pages"
+page.update.error.couldNotCreate=\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.
+page.update.error.doesNotExist=\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435, \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
+page.update.error.unexpected=\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_zh_CN.properties b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_zh_CN.properties
new file mode 100644
index 0000000000..617d728e18
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/remote-content/page-definition.put_zh_CN.properties
@@ -0,0 +1,8 @@
+page.update.error.nameAlreadyUsed=\u540d\u79f0''{0}''\u5df2\u4f7f\u7528
+page.update.error.noNameProvided=\u6ca1\u6709\u4e3a\u9875\u9762\u6307\u5b9a\u540d\u79f0
+page.update.error.noDefProvided=\u6ca1\u6709\u63d0\u4f9b\u9875\u9762\u5b9a\u4e49
+page.update.error.invalidJson=\u9875\u9762\u5b9a\u4e49\u65e0\u6548 JSON\uff1a{0}
+page.update.error.noTargetLocation=\u672a\u5728\u6570\u636e\u5b57\u5178\u4e2d\u521b\u5efa\u9875\u9762"ShareResources/pages"\u7684\u76ee\u6807\u4f4d\u7f6e
+page.update.error.couldNotCreate=\u65e0\u6cd5\u521b\u5efa\u9875\u9762\u3002
+page.update.error.doesNotExist=\u8bf7\u6c42\u66f4\u65b0\u7684\u9875\u9762\u4e0d\u5b58\u5728
+page.update.error.unexpected=\u51fa\u73b0\u610f\u5916\u9519\u8bef\u3002
diff --git a/source/java/org/alfresco/rest/workflow/api/Activities.java b/source/java/org/alfresco/rest/workflow/api/Activities.java
new file mode 100644
index 0000000000..403381190a
--- /dev/null
+++ b/source/java/org/alfresco/rest/workflow/api/Activities.java
@@ -0,0 +1,10 @@
+package org.alfresco.rest.workflow.api;
+
+import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
+import org.alfresco.rest.framework.resource.parameters.Parameters;
+import org.alfresco.rest.workflow.api.model.Activity;
+
+public interface Activities
+{
+ CollectionWithPagingInfo getActivities(String processId, Parameters parameters);
+}
diff --git a/source/java/org/alfresco/rest/workflow/api/ProcessDefinitions.java b/source/java/org/alfresco/rest/workflow/api/ProcessDefinitions.java
index dfc93a7563..c8e2b38eae 100644
--- a/source/java/org/alfresco/rest/workflow/api/ProcessDefinitions.java
+++ b/source/java/org/alfresco/rest/workflow/api/ProcessDefinitions.java
@@ -18,11 +18,12 @@
*/
package org.alfresco.rest.workflow.api;
+import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
-import org.alfresco.rest.workflow.api.model.ProcessDefinition;
import org.alfresco.rest.workflow.api.model.FormModelElement;
+import org.alfresco.rest.workflow.api.model.ProcessDefinition;
public interface ProcessDefinitions
{
@@ -30,5 +31,7 @@ public interface ProcessDefinitions
public ProcessDefinition getProcessDefinition(String definitionId);
+ public BinaryResource getProcessDefinitionImage(String definitionId);
+
public CollectionWithPagingInfo getStartFormModel(String definitionId, Paging paging);
}
diff --git a/source/java/org/alfresco/rest/workflow/api/Processes.java b/source/java/org/alfresco/rest/workflow/api/Processes.java
index 3afaf03ceb..d28f93623c 100644
--- a/source/java/org/alfresco/rest/workflow/api/Processes.java
+++ b/source/java/org/alfresco/rest/workflow/api/Processes.java
@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api;
+import java.util.List;
+
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
@@ -47,6 +49,8 @@ public interface Processes
CollectionWithPagingInfo getVariables(String processId, Paging paging);
Variable updateVariable(String processId, Variable entity);
+
+ List updateVariables(String processId, List variables);
void deleteVariable(String processId, String id);
diff --git a/source/java/org/alfresco/rest/workflow/api/Tasks.java b/source/java/org/alfresco/rest/workflow/api/Tasks.java
index 631302b77b..d3d5db51ca 100644
--- a/source/java/org/alfresco/rest/workflow/api/Tasks.java
+++ b/source/java/org/alfresco/rest/workflow/api/Tasks.java
@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api;
+import java.util.List;
+
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
@@ -26,11 +28,14 @@ import org.alfresco.rest.workflow.api.model.Item;
import org.alfresco.rest.workflow.api.model.Task;
import org.alfresco.rest.workflow.api.model.TaskCandidate;
import org.alfresco.rest.workflow.api.model.TaskVariable;
+import org.alfresco.rest.workflow.api.model.Variable;
import org.alfresco.rest.workflow.api.model.VariableScope;
public interface Tasks
{
CollectionWithPagingInfo getTasks(Parameters parameters);
+
+ CollectionWithPagingInfo getTasks(String processId, Parameters parameters);
Task getTask(String taskId);
@@ -44,6 +49,8 @@ public interface Tasks
CollectionWithPagingInfo getTaskVariables(String taskId, Paging paging, VariableScope scope);
TaskVariable updateTaskVariable(String taskId, TaskVariable taskVariable);
+
+ List updateTaskVariables(String taskId, List variables);
void deleteTaskVariable(String taskId, String variableName);
diff --git a/source/java/org/alfresco/rest/workflow/api/deployments/package-info.java b/source/java/org/alfresco/rest/workflow/api/deployments/package-info.java
index fde009568e..1fc1f53e71 100644
--- a/source/java/org/alfresco/rest/workflow/api/deployments/package-info.java
+++ b/source/java/org/alfresco/rest/workflow/api/deployments/package-info.java
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
-@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
+@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api.deployments;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;
\ No newline at end of file
diff --git a/source/java/org/alfresco/rest/workflow/api/impl/ActivitiesImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/ActivitiesImpl.java
new file mode 100644
index 0000000000..a1f52ededc
--- /dev/null
+++ b/source/java/org/alfresco/rest/workflow/api/impl/ActivitiesImpl.java
@@ -0,0 +1,50 @@
+package org.alfresco.rest.workflow.api.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.activiti.engine.history.HistoricActivityInstance;
+import org.activiti.engine.history.HistoricActivityInstanceQuery;
+import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
+import org.alfresco.rest.framework.resource.parameters.Paging;
+import org.alfresco.rest.framework.resource.parameters.Parameters;
+import org.alfresco.rest.workflow.api.Activities;
+import org.alfresco.rest.workflow.api.model.Activity;
+
+public class ActivitiesImpl extends WorkflowRestImpl implements Activities
+{
+ private static final String STATUS_ACTIVE = "active";
+ private static final String STATUS_COMPLETED = "completed";
+
+ @Override
+ public CollectionWithPagingInfo getActivities(String processId, Parameters parameters)
+ {
+ Paging paging = parameters.getPaging();
+ String status = parameters.getParameter("status");
+
+ validateIfUserAllowedToWorkWithProcess(processId);
+
+ HistoricActivityInstanceQuery query = activitiProcessEngine
+ .getHistoryService()
+ .createHistoricActivityInstanceQuery();
+
+ if (STATUS_ACTIVE.equals(status)) query.unfinished();
+ else if (STATUS_COMPLETED.equals(status)) query.finished();
+
+ query.processInstanceId(processId);
+
+ query.orderByExecutionId().asc();
+
+ List activities = query.listPage(paging.getSkipCount(), paging.getMaxItems());
+
+ List page = new ArrayList(activities.size());
+ for (HistoricActivityInstance activityInstance: activities)
+ {
+ Activity activity = new Activity(activityInstance);
+ page.add(activity);
+ }
+
+ return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
+ }
+
+}
diff --git a/source/java/org/alfresco/rest/workflow/api/impl/MapBasedQueryWalker.java b/source/java/org/alfresco/rest/workflow/api/impl/MapBasedQueryWalker.java
index 75c27fbcc3..8112409a1c 100644
--- a/source/java/org/alfresco/rest/workflow/api/impl/MapBasedQueryWalker.java
+++ b/source/java/org/alfresco/rest/workflow/api/impl/MapBasedQueryWalker.java
@@ -170,7 +170,7 @@ public class MapBasedQueryWalker extends WalkerCallbackAdapter
{
String localPropertyName = propertyName.replaceFirst("variables/", "");
Object actualValue = null;
- if (propertyValue.contains("_") && propertyValue.contains(" "))
+ if ((propertyValue.contains("_") || propertyValue.contains(":")) && propertyValue.contains(" "))
{
String typeDef = propertyValue.substring(0, propertyValue.indexOf(' '));
try
diff --git a/source/java/org/alfresco/rest/workflow/api/impl/ProcessDefinitionsImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/ProcessDefinitionsImpl.java
index c3ba7a5242..35a05f3ea3 100644
--- a/source/java/org/alfresco/rest/workflow/api/impl/ProcessDefinitionsImpl.java
+++ b/source/java/org/alfresco/rest/workflow/api/impl/ProcessDefinitionsImpl.java
@@ -18,13 +18,19 @@
*/
package org.alfresco.rest.workflow.api.impl;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.UUID;
import org.activiti.engine.form.StartFormData;
+import org.activiti.engine.impl.form.StartFormHandler;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.alfresco.repo.i18n.MessageService;
@@ -34,7 +40,11 @@ import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.repo.workflow.WorkflowObjectFactory;
import org.alfresco.repo.workflow.WorkflowQNameConverter;
import org.alfresco.rest.antlr.WhereClauseParser;
+import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
+import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
+import org.alfresco.rest.framework.resource.content.BinaryResource;
+import org.alfresco.rest.framework.resource.content.FileBinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
@@ -44,6 +54,8 @@ import org.alfresco.rest.workflow.api.model.FormModelElement;
import org.alfresco.rest.workflow.api.model.ProcessDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.TempFileProvider;
+import org.apache.commons.io.IOUtils;
public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessDefinitions
{
@@ -55,6 +67,9 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
"category", "key", "name"
}));
+ private static final Set PROCESS_DEFINITION_COLLECTION_SORT_PROPERTIES = new HashSet(Arrays.asList(
+ "deploymentId", "key", "category", "id", "version", "name"
+ ));
MessageService messageService;
String engineId;
@@ -79,52 +94,135 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
ProcessDefinitionQuery query = activitiProcessEngine
.getRepositoryService()
.createProcessDefinitionQuery()
- .processDefinitionCategoryNotEquals(WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL)
- .orderByProcessDefinitionName().asc()
- .orderByProcessDefinitionVersion().asc();
-
- // Filter based on tenant, if required
- if (tenantService.isEnabled() && deployWorkflowsInTenant)
- {
- query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
- }
+ .processDefinitionCategoryNotEquals(WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL);
MapBasedQueryWalker propertyWalker = new MapBasedQueryWalker(PROCESS_DEFINITION_COLLECTION_EQUALS_QUERY_PROPERTIES,
PROCESS_DEFINITION_COLLECTION_MATCHES_QUERY_PROPERTIES);
+ boolean keyQueryIncluded = false;
+
if(parameters.getQuery() != null)
{
QueryHelper.walk(parameters.getQuery(), propertyWalker);
// Property equals
- if(propertyWalker.getProperty("category", WhereClauseParser.EQUALS) != null) {
- query.processDefinitionCategory(propertyWalker.getProperty("category", WhereClauseParser.EQUALS));
+ String categoryProperty = propertyWalker.getProperty("category", WhereClauseParser.EQUALS);
+ if (categoryProperty != null)
+ {
+ query.processDefinitionCategory(categoryProperty);
}
- if(propertyWalker.getProperty("key", WhereClauseParser.EQUALS) != null) {
- query.processDefinitionKey(propertyWalker.getProperty("key", WhereClauseParser.EQUALS));
+
+ String keyProperty = propertyWalker.getProperty("key", WhereClauseParser.EQUALS);
+ if (keyProperty != null)
+ {
+ query.processDefinitionKey(getProcessDefinitionKey(keyProperty));
+ keyQueryIncluded = true;
}
- if(propertyWalker.getProperty("name", WhereClauseParser.EQUALS) != null) {
- query.processDefinitionName(propertyWalker.getProperty("name", WhereClauseParser.EQUALS));
+
+ String nameProperty = propertyWalker.getProperty("name", WhereClauseParser.EQUALS);
+ if (nameProperty != null)
+ {
+ query.processDefinitionName(nameProperty);
}
- if(propertyWalker.getProperty("version", WhereClauseParser.EQUALS) != null) {
- query.processDefinitionVersion(propertyWalker.getProperty("version", WhereClauseParser.EQUALS, Integer.class));
+
+ Integer versionProperty = propertyWalker.getProperty("version", WhereClauseParser.EQUALS, Integer.class);
+ if (versionProperty != null)
+ {
+ query.processDefinitionVersion(versionProperty);
}
- if(propertyWalker.getProperty("deploymentId", WhereClauseParser.EQUALS) != null) {
- query.deploymentId(propertyWalker.getProperty("deploymentId", WhereClauseParser.EQUALS));
+
+ String deploymentProperty = propertyWalker.getProperty("deploymentId", WhereClauseParser.EQUALS);
+ if (deploymentProperty != null)
+ {
+ query.deploymentId(deploymentProperty);
}
// Property matches
- if(propertyWalker.getProperty("category", WhereClauseParser.MATCHES) != null) {
- query.processDefinitionCategoryLike(propertyWalker.getProperty("category", WhereClauseParser.MATCHES));
+ String categoryMatchesProperty = propertyWalker.getProperty("category", WhereClauseParser.MATCHES);
+ if (categoryMatchesProperty != null)
+ {
+ query.processDefinitionCategoryLike(categoryMatchesProperty);
}
- if(propertyWalker.getProperty("key", WhereClauseParser.MATCHES) != null) {
- query.processDefinitionKeyLike(propertyWalker.getProperty("key", WhereClauseParser.MATCHES));
+
+ String keyMatchesProperty = propertyWalker.getProperty("key", WhereClauseParser.MATCHES);
+ if (keyMatchesProperty != null)
+ {
+ query.processDefinitionKeyLike(getProcessDefinitionKey(keyMatchesProperty));
+ keyQueryIncluded = true;
}
- if(propertyWalker.getProperty("name", WhereClauseParser.MATCHES) != null) {
- query.processDefinitionNameLike(propertyWalker.getProperty("name", WhereClauseParser.MATCHES));
+
+ String nameLikeProperty = propertyWalker.getProperty("name", WhereClauseParser.MATCHES);
+ if (nameLikeProperty != null)
+ {
+ query.processDefinitionNameLike(nameLikeProperty);
}
}
+ // Filter based on tenant, if required
+ if (keyQueryIncluded == false && tenantService.isEnabled() && deployWorkflowsInTenant)
+ {
+ query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
+ }
+
+ String sortParam = parameters.getParameter("sort");
+ if (sortParam != null)
+ {
+ if (PROCESS_DEFINITION_COLLECTION_SORT_PROPERTIES.contains(sortParam))
+ {
+ if ("id".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessDefinitionId();
+ }
+ else if ("deploymentId".equalsIgnoreCase(sortParam))
+ {
+ query.orderByDeploymentId();
+ }
+ else if ("key".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessDefinitionKey();
+ }
+ else if ("category".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessDefinitionCategory();
+ }
+ else if ("version".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessDefinitionVersion();
+ }
+ else if ("name".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessDefinitionName();
+ }
+ }
+ else
+ {
+ throw new InvalidArgumentException("sort " + sortParam +
+ " is not supported, supported items are " + PROCESS_DEFINITION_COLLECTION_SORT_PROPERTIES.toArray());
+ }
+
+ String sortOrderParam = parameters.getParameter("sortOrder");
+ if (sortOrderParam != null)
+ {
+ if ("asc".equalsIgnoreCase(sortOrderParam))
+ {
+ query.asc();
+ }
+ else if ("desc".equalsIgnoreCase(sortOrderParam))
+ {
+ query.desc();
+ }
+ else
+ {
+ throw new InvalidArgumentException("sort order " + sortOrderParam +
+ " is not supported, supported items are asc and desc");
+ }
+ }
+ }
+ else
+ {
+ query.orderByProcessDefinitionId().asc();
+ }
+
List processDefinitions =
query.listPage(parameters.getPaging().getSkipCount(), parameters.getPaging().getMaxItems());
@@ -160,10 +258,70 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
ProcessDefinition deploymentRest = createProcessDefinitionRest((ProcessDefinitionEntity) processDefinition);
return deploymentRest;
}
+
+ @Override
+ public BinaryResource getProcessDefinitionImage(String definitionId)
+ {
+ ProcessDefinitionQuery query = activitiProcessEngine
+ .getRepositoryService()
+ .createProcessDefinitionQuery()
+ .processDefinitionId(definitionId);
+
+ if (tenantService.isEnabled() && deployWorkflowsInTenant)
+ {
+ query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
+ }
+
+ org.activiti.engine.repository.ProcessDefinition processDefinition = query.singleResult();
+
+ if (processDefinition == null)
+ {
+ throw new EntityNotFoundException(definitionId);
+ }
+
+ try
+ {
+ InputStream processDiagram = activitiProcessEngine.getRepositoryService().getProcessDiagram(definitionId);
+ if (processDiagram != null)
+ {
+ File file = TempFileProvider.createTempFile(definitionId + UUID.randomUUID(), ".png");
+ FileOutputStream fos = new FileOutputStream(file);
+ IOUtils.copy(processDiagram, fos);
+ fos.close();
+
+ return new FileBinaryResource(file);
+ }
+ else
+ {
+ throw new ApiException("No image available for definitionId " + definitionId);
+ }
+ }
+ catch (IOException error)
+ {
+ throw new ApiException("Error while getting process definition image.");
+ }
+ }
@Override
public CollectionWithPagingInfo getStartFormModel(String definitionId, Paging paging)
{
+ // first validate if user is allowed to access the process definition if workflows are deployed per tenant
+ if (tenantService.isEnabled() && deployWorkflowsInTenant)
+ {
+ ProcessDefinitionQuery query = activitiProcessEngine
+ .getRepositoryService()
+ .createProcessDefinitionQuery()
+ .processDefinitionId(definitionId);
+
+ query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
+ org.activiti.engine.repository.ProcessDefinition processDefinition = query.singleResult();
+
+ if (processDefinition == null)
+ {
+ throw new EntityNotFoundException(definitionId);
+ }
+ }
+
StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(definitionId);
if (startFormData == null)
{
@@ -183,23 +341,88 @@ public class ProcessDefinitionsImpl extends WorkflowRestImpl implements ProcessD
TypeDefinition startTaskType = workflowFactory.getTaskFullTypeDefinition(startFormData.getFormKey(), true);
return getFormModelElements(startTaskType, paging);
}
+
+ protected String getProcessDefinitionKey(String key)
+ {
+ String processDefKey = null;
+ if (tenantService.isEnabled() && deployWorkflowsInTenant)
+ {
+ processDefKey = "@" + TenantUtil.getCurrentDomain() + "@" + key;
+ }
+ else
+ {
+ processDefKey = key;
+ }
+ return processDefKey;
+ }
+
+ protected String getLocalProcessDefinitionKey(String key)
+ {
+ String processDefKey = null;
+ if (tenantService.isEnabled() && deployWorkflowsInTenant)
+ {
+ processDefKey = key.substring(key.lastIndexOf("@") + 1);
+ }
+ else
+ {
+ processDefKey = key;
+ }
+ return processDefKey;
+ }
protected ProcessDefinition createProcessDefinitionRest(ProcessDefinitionEntity processDefinition)
{
ProcessDefinition processDefinitionRest = new ProcessDefinition(processDefinition);
+ String localKey = getLocalProcessDefinitionKey(processDefinition.getKey());
+ processDefinitionRest.setKey(localKey);
+
+ String displayId = localKey + ".workflow";
+ processDefinitionRest.setTitle(getLabel(displayId, "title"));
+ processDefinitionRest.setDescription(getLabel(displayId, "description"));
+
processDefinitionRest.setGraphicNotationDefined(processDefinition.isGraphicalNotationDefined());
if (processDefinition.hasStartFormKey())
{
- try {
- StartFormData startFormData = activitiProcessEngine.getFormService().getStartFormData(processDefinition.getId());
+ try
+ {
+ StartFormData startFormData = null;
+ ProcessDefinitionEntity definitionEntity = getCachedProcessDefinition(processDefinition.getId());
+ if (definitionEntity != null)
+ {
+ StartFormHandler startFormHandler = definitionEntity.getStartFormHandler();
+ if (startFormHandler == null) {
+ throw new ApiException("No start form defined for " + processDefinition.getId());
+ }
+
+ startFormData = startFormHandler.createStartFormData(definitionEntity);
+ }
+ else
+ {
+ startFormData = activitiProcessEngine.getFormService().getStartFormData(processDefinition.getId());
+ }
+
if (startFormData != null)
{
processDefinitionRest.setStartFormResourceKey(startFormData.getFormKey());
}
- } catch(Exception e) {
- e.printStackTrace();
+ }
+ catch (ApiException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new ApiException("Error while retrieving start form key");
}
}
return processDefinitionRest;
}
+
+ protected String getLabel(String displayId, String labelKey)
+ {
+ String keyBase = displayId.replace(":", "_");
+ String key = keyBase+ "." + labelKey;
+ String label = messageService.getMessage(key);
+ return label;
+ }
}
diff --git a/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java
index ee567020ac..6871d31661 100644
--- a/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java
+++ b/source/java/org/alfresco/rest/workflow/api/impl/ProcessesImpl.java
@@ -39,13 +39,11 @@ import org.activiti.engine.RuntimeService;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
-import org.activiti.engine.history.HistoricTaskInstance;
-import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator;
import org.activiti.engine.impl.identity.Authentication;
-import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.ProcessDefinition;
+import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.i18n.MessageService;
@@ -71,7 +69,6 @@ import org.alfresco.rest.antlr.WhereClauseParser;
import org.alfresco.rest.framework.core.exceptions.ApiException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
-import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.content.FileBinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
@@ -90,12 +87,15 @@ import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.InvalidQNameException;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.ISO8601DateFormat;
import org.alfresco.util.TempFileProvider;
import org.alfresco.util.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
@@ -142,6 +142,10 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
"startedAt", "endedAt"
));
+ private static final Set PROCESS_COLLECTION_SORT_PROPERTIES = new HashSet(Arrays.asList(
+ "processDefinitionId", "businessKey", "id", "startedAt", "endedAt", "durationInMillis"
+ ));
+
public void setAuthorityDAO(AuthorityDAO authorityDAO)
{
this.authorityDAO = authorityDAO;
@@ -303,8 +307,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
final HistoricProcessInstanceQuery query = activitiProcessEngine
.getHistoryService()
- .createHistoricProcessInstanceQuery()
- .orderByProcessInstanceStartTime().desc();
+ .createHistoricProcessInstanceQuery();
if (processDefinitionId != null) query.processDefinitionId(processDefinitionId);
if (businessKey != null) query.processInstanceBusinessKey(businessKey);
@@ -400,12 +403,71 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
query.involvedUser(AuthenticationUtil.getRunAsUser());
}
+ String sortParam = parameters.getParameter("sort");
+ if (sortParam != null)
+ {
+ if (PROCESS_COLLECTION_SORT_PROPERTIES.contains(sortParam))
+ {
+ if ("processDefinitionId".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessDefinitionId();
+ }
+ else if ("id".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessInstanceId();
+ }
+ else if ("businessKey".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessInstanceBusinessKey();
+ }
+ else if ("startedAt".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessInstanceStartTime();
+ }
+ else if ("endedAt".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessInstanceEndTime();
+ }
+ else if ("durationInMillis".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessInstanceDuration();
+ }
+ }
+ else
+ {
+ throw new InvalidArgumentException("sort " + sortParam +
+ " is not supported, supported items are " + PROCESS_COLLECTION_SORT_PROPERTIES.toArray());
+ }
+
+ String sortOrderParam = parameters.getParameter("sortOrder");
+ if (sortOrderParam != null)
+ {
+ if ("asc".equalsIgnoreCase(sortOrderParam))
+ {
+ query.asc();
+ }
+ else if ("desc".equalsIgnoreCase(sortOrderParam))
+ {
+ query.desc();
+ }
+ else
+ {
+ throw new InvalidArgumentException("sort order " + sortOrderParam +
+ " is not supported, supported items are asc and desc");
+ }
+ }
+ }
+ else
+ {
+ query.orderByProcessInstanceStartTime().desc();
+ }
+
List processInstances = query.listPage(paging.getSkipCount(), paging.getMaxItems());
List page = new ArrayList(processInstances.size());
for (HistoricProcessInstance processInstance: processInstances)
{
- page.add(new ProcessInfo(processInstance));
+ page.add(createProcessInfo(processInstance));
}
return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
@@ -419,8 +481,6 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("processId is required to get the process info");
}
- validateIfUserAllowedToWorkWithProcess(processId);
-
HistoricProcessInstance processInstance = activitiProcessEngine
.getHistoryService()
.createHistoricProcessInstanceQuery()
@@ -429,10 +489,10 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
if (processInstance == null)
{
- throw new EntityNotFoundException("could not find process for id " + processId);
+ throw new EntityNotFoundException(processId);
}
- return new ProcessInfo(processInstance);
+ return createProcessInfo(processInstance);
}
@Override
@@ -455,7 +515,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
ProcessDefinition definition = activitiProcessEngine
.getRepositoryService()
.createProcessDefinitionQuery()
- .processDefinitionKey(createProcessDefinitionKey(process.getProcessDefinitionKey()))
+ .processDefinitionKey(getProcessDefinitionKey(process.getProcessDefinitionKey()))
.latestVersion()
.singleResult();
@@ -475,7 +535,17 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
if(!definitionExistingChecked)
{
// Check if the required definition actually exists
- if(activitiProcessEngine.getRepositoryService().createProcessDefinitionQuery().processDefinitionId(processDefinitionId).count() == 0)
+ ProcessDefinitionQuery query = activitiProcessEngine
+ .getRepositoryService()
+ .createProcessDefinitionQuery()
+ .processDefinitionId(processDefinitionId);
+
+ if (tenantService.isEnabled() && deployWorkflowsInTenant)
+ {
+ query.processDefinitionKeyLike("@" + TenantUtil.getCurrentDomain() + "@%");
+ }
+
+ if(query.count() == 0)
{
throw new InvalidArgumentException("No workflow definition could be found with id '" + processDefinitionId +"'.");
}
@@ -512,10 +582,14 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
if (taskAssociations.containsKey(propNameMap.get(variableName)))
{
AssociationDefinition associationDef = taskAssociations.get(propNameMap.get(variableName));
- if (variableValue != null && "person".equalsIgnoreCase(associationDef.getTargetClass().getTitle(dictionaryService)))
+ if (variableValue != null && ContentModel.TYPE_PERSON.equals(associationDef.getTargetClass().getName()))
{
variableValue = getPersonNodeRef(variableValue.toString());
}
+ else if (variableValue != null && ContentModel.TYPE_AUTHORITY_CONTAINER.equals(associationDef.getTargetClass().getName()))
+ {
+ variableValue = authorityService.getAuthorityNodeRef(variableValue.toString());
+ }
}
if (variableValue instanceof Serializable)
@@ -533,28 +607,29 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
NodeRef workflowPackageNodeRef = null;
try
{
- workflowPackageNodeRef = workflowPackageComponent.createPackage(null);
- startParams.put(WorkflowModel.ASSOC_PACKAGE, workflowPackageNodeRef);
+ workflowPackageNodeRef = workflowPackageComponent.createPackage(null);
+ startParams.put(WorkflowModel.ASSOC_PACKAGE, workflowPackageNodeRef);
}
catch (Exception e)
{
- throw new ApiException("couldn't create workflow package: " + e.getMessage(), e);
+ throw new ApiException("couldn't create workflow package: " + e.getMessage(), e);
}
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(process.getItems()))
{
- try
- {
- for (String item: process.getItems())
+ try
{
- QName workflowPackageItemId = QName.createQName("wpi", item);
- nodeService.addChild(workflowPackageNodeRef, new NodeRef(item), WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId);
+ for (String item: process.getItems())
+ {
+ NodeRef itemNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, item);
+ QName workflowPackageItemId = QName.createQName("wpi", itemNodeRef.toString());
+ nodeService.addChild(workflowPackageNodeRef, itemNodeRef, WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ApiException("Error while adding items to package: " + e.getMessage(), e);
}
- }
- catch (Exception e)
- {
- throw new ApiException("Error while adding items to package: " + e.getMessage(), e);
- }
}
// Set start task properties. This should be done before instance is started, since it's id will be used
@@ -578,7 +653,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
}
}
- if(tenantService.isEnabled())
+ if (tenantService.isEnabled())
{
// Specify which tenant domain the workflow was started in.
variables.put(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
@@ -598,7 +673,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
.processInstanceId(processInstance.getId())
.singleResult();
- return new ProcessInfo(historicProcessInstance);
+ return createProcessInfo(historicProcessInstance);
}
@Override
@@ -673,7 +748,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
List documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef());
for (ChildAssociationRef childAssociationRef : documentList)
{
- if (childAssociationRef.getChildRef().toString().equals(itemId))
+ if (childAssociationRef.getChildRef().getId().equals(itemId))
{
item = createItemForNodeRef(childAssociationRef.getChildRef());
break;
@@ -718,10 +793,22 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("process doesn't contain a workflow package variable");
}
+ // check if noderef exists
try
{
- QName workflowPackageItemId = QName.createQName("wpi", item.getId());
- nodeService.addChild(packageScriptNode.getNodeRef(), new NodeRef(item.getId()), WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId);
+ nodeService.getProperties(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, item.getId()));
+ }
+ catch (Exception e)
+ {
+ throw new EntityNotFoundException("item with id " + item.getId() + " not found");
+ }
+
+ try
+ {
+ NodeRef itemNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, item.getId());
+ QName workflowPackageItemId = QName.createQName("wpi", itemNodeRef.toString());
+ nodeService.addChild(packageScriptNode.getNodeRef(), itemNodeRef,
+ WorkflowModel.ASSOC_PACKAGE_CONTAINS, workflowPackageItemId);
}
catch (Exception e)
{
@@ -761,13 +848,29 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("process doesn't contain a workflow package variable");
}
+ boolean itemIdFoundInPackage = false;
+ List documentList = nodeService.getChildAssocs(packageScriptNode.getNodeRef());
+ for (ChildAssociationRef childAssociationRef : documentList)
+ {
+ if (childAssociationRef.getChildRef().getId().equals(itemId))
+ {
+ itemIdFoundInPackage = true;
+ break;
+ }
+ }
+
+ if (itemIdFoundInPackage == false)
+ {
+ throw new EntityNotFoundException("Item " + itemId + " not found in the process package variable");
+ }
+
try
{
- nodeService.removeChild(packageScriptNode.getNodeRef(), new NodeRef(itemId));
+ nodeService.removeChild(packageScriptNode.getNodeRef(), new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, itemId));
}
- catch (Exception e)
+ catch (InvalidNodeRefException e)
{
- throw new ApiException("could not delete item from process " + e.getMessage(), e);
+ throw new EntityNotFoundException("Item " + itemId + " not found");
}
}
@@ -822,6 +925,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
{
formKey = startFormData.getFormKey();
}
+
TypeDefinition startTaskTypeDefinition = workflowFactory.getTaskFullTypeDefinition(formKey, true);
// Convert raw variables to Variable objects
@@ -838,12 +942,41 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
ProcessInstance processInstance = activitiProcessEngine.getRuntimeService().createProcessInstanceQuery()
.processInstanceId(processId).singleResult();
- if(processInstance == null)
+ if (processInstance == null)
{
throw new EntityNotFoundException(processId);
}
- if(variable.getName() == null)
+ return updateVariableInProcess(processId, variable);
+ }
+
+ @Override
+ public List updateVariables(String processId, List variables)
+ {
+ validateIfUserAllowedToWorkWithProcess(processId);
+
+ ProcessInstance processInstance = activitiProcessEngine.getRuntimeService().createProcessInstanceQuery()
+ .processInstanceId(processId).singleResult();
+
+ if (processInstance == null)
+ {
+ throw new EntityNotFoundException(processId);
+ }
+
+ List updatedVariables = new ArrayList();
+ if (variables != null)
+ {
+ for (Variable variable : variables)
+ {
+ updatedVariables.add(updateVariableInProcess(processId, variable));
+ }
+ }
+ return updatedVariables;
+ }
+
+ protected Variable updateVariableInProcess(String processId,Variable variable)
+ {
+ if (variable.getName() == null)
{
throw new InvalidArgumentException("Variable name is required.");
}
@@ -872,9 +1005,18 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
throw new InvalidArgumentException("Unsupported type of variable: '" + variable.getType() +"'.");
}
+ Object actualValue = null;
+ if ("java.util.Date".equalsIgnoreCase(dataTypeDefinition.getJavaClassName()))
+ {
+ // fix for different ISO 8601 Date format classes in Alfresco (org.alfresco.util and Spring Surf)
+ actualValue = ISO8601DateFormat.parse((String) variable.getValue());
+ }
+ else
+ {
+ actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, variable.getValue());
+ }
+ variable.setValue(actualValue);
- // Get raw variable value and set value
- Object actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, variable.getValue());
activitiProcessEngine.getRuntimeService().setVariable(processId, variable.getName(), actualValue);
// Set actual used type before returning
@@ -921,13 +1063,10 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
try
{
- ProcessDefinition procDef = activitiProcessEngine.getRepositoryService().createProcessDefinitionQuery()
- .processDefinitionId(processInstance.getProcessDefinitionId())
- .singleResult();
+ BpmnModel model = activitiProcessEngine.getRepositoryService().getBpmnModel(processInstance.getProcessDefinitionId());
- if(((ProcessDefinitionEntity) procDef).isGraphicalNotationDefined())
+ if(model != null && model.getLocationMap().size() > 0)
{
- BpmnModel model = activitiProcessEngine.getRepositoryService().getBpmnModel(processInstance.getProcessDefinitionId());
List activeActivities = activitiProcessEngine.getRuntimeService().getActiveActivityIds(processId);
InputStream generateDiagram = ProcessDiagramGenerator.generateDiagram(model, "png", activeActivities);
@@ -949,65 +1088,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
}
}
- protected void validateIfUserAllowedToWorkWithProcess(String processId)
- {
- if (tenantService.isEnabled())
- {
- try
- {
- String tenantDomain = (String) activitiProcessEngine.getRuntimeService().getVariable(processId, ActivitiConstants.VAR_TENANT_DOMAIN);
- if (TenantUtil.getCurrentDomain().equals(tenantDomain) == false)
- {
- throw new PermissionDeniedException("Process is running in another tenant");
- }
- }
- catch (ActivitiObjectNotFoundException e)
- {
- throw new EntityNotFoundException(processId);
- }
- }
-
- try
- {
- ActivitiScriptNode initiator = (ActivitiScriptNode) activitiProcessEngine.getRuntimeService().getVariable(processId, WorkflowConstants.PROP_INITIATOR);
- if (AuthenticationUtil.getRunAsUser().equals(initiator.getNodeRef().getId()))
- {
- // user is allowed
- return;
- }
- }
- catch (ActivitiObjectNotFoundException e)
- {
- throw new EntityNotFoundException(processId);
- }
-
- HistoricTaskInstanceQuery query = activitiProcessEngine.getHistoryService()
- .createHistoricTaskInstanceQuery()
- .processInstanceId(processId);
-
- if (authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser()))
- {
- // Admin is allowed to read all processes in the current tenant
- if (tenantService.isEnabled())
- {
- query.processVariableValueEquals(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
- }
- }
- else
- {
- // If non-admin user, involvement in the task is required (either owner, assignee or externally involved).
- query.taskInvolvedUser(AuthenticationUtil.getRunAsUser());
- }
-
- List taskList = query.list();
-
- if(org.apache.commons.collections.CollectionUtils.isEmpty(taskList))
- {
- throw new PermissionDeniedException("user is not allowed to access information about process " + processId);
- }
- }
-
- protected String createProcessDefinitionKey(String paramProcessDefinitionKey)
+ protected String getProcessDefinitionKey(String paramProcessDefinitionKey)
{
String processDefinitionKey = null;
if (tenantService.isEnabled() && deployWorkflowsInTenant)
@@ -1020,6 +1101,20 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
}
return processDefinitionKey;
}
+
+ protected String getLocalProcessDefinitionKey(String key)
+ {
+ String processDefKey = null;
+ if (tenantService.isEnabled() && deployWorkflowsInTenant)
+ {
+ processDefKey = key.substring(key.lastIndexOf("@") + 1);
+ }
+ else
+ {
+ processDefKey = key;
+ }
+ return processDefKey;
+ }
protected NodeRef getPersonNodeRef(String name)
{
@@ -1034,6 +1129,18 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
return authority;
}
+ protected ProcessInfo createProcessInfo(HistoricProcessInstance processInstance)
+ {
+ ProcessInfo processInfo = new ProcessInfo(processInstance);
+ ProcessDefinition definitionEntity = getCachedProcessDefinition(processInstance.getProcessDefinitionId());
+ if (definitionEntity == null)
+ {
+ definitionEntity = activitiProcessEngine.getRepositoryService().getProcessDefinition(processInstance.getProcessDefinitionId());
+ }
+ processInfo.setProcessDefinitionKey(getLocalProcessDefinitionKey(definitionEntity.getKey()));
+ return processInfo;
+ }
+
protected Item createItemForNodeRef(NodeRef nodeRef) {
Map properties = nodeService.getProperties(nodeRef);
Item item = new Item();
@@ -1047,7 +1154,7 @@ public class ProcessesImpl extends WorkflowRestImpl implements Processes
ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
- item.setId(nodeRef.toString());
+ item.setId(nodeRef.getId());
item.setName(name);
item.setTitle(title);
item.setDescription(description);
diff --git a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java
index ddb6c650f5..7d281a9d35 100644
--- a/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java
+++ b/source/java/org/alfresco/rest/workflow/api/impl/TasksImpl.java
@@ -30,6 +30,8 @@ import org.activiti.engine.ActivitiTaskAlreadyClaimedException;
import org.activiti.engine.form.FormData;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
+import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
+import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.IdentityLinkType;
import org.activiti.engine.task.TaskQuery;
@@ -57,6 +59,7 @@ import org.alfresco.rest.workflow.api.model.FormModelElement;
import org.alfresco.rest.workflow.api.model.Item;
import org.alfresco.rest.workflow.api.model.Task;
import org.alfresco.rest.workflow.api.model.TaskCandidate;
+import org.alfresco.rest.workflow.api.model.TaskStateTransition;
import org.alfresco.rest.workflow.api.model.TaskVariable;
import org.alfresco.rest.workflow.api.model.VariableScope;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
@@ -64,8 +67,10 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
+import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.namespace.InvalidQNameException;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.ISO8601DateFormat;
public class TasksImpl extends WorkflowRestImpl implements Tasks
{
@@ -76,12 +81,12 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
* All properties that are read-only and cannot be updated on a single task-resource.
*/
private static final List TASK_READ_ONLY_PROPERTIES = Arrays.asList(
- "id", "processId", "processDefinitionId", "actibityDefinitionId", "startedAt", "endedAt", "durationInMs", "formResourceKey"
+ "id", "processId", "processDefinitionId", "activityDefinitionId", "startedAt", "endedAt", "durationInMs", "formResourceKey"
);
private static final Set TASK_COLLECTION_EQUALS_QUERY_PROPERTIES = new HashSet(Arrays.asList(
- "status", "assignee", "owner", "candidateUser", "candidateGroup", "name", "description", "priority", "processInstanceId",
- "processInstanceBusinessKey", "activityDefinitionId", "processDefinitionId", "processDefinitionName", "startedAt", "dueAt"
+ "status", "assignee", "owner", "candidateUser", "candidateGroup", "name", "description", "priority", "processId",
+ "processBusinessKey", "activityDefinitionId", "processDefinitionId", "processDefinitionName", "startedAt", "dueAt"
));
private static final Set TASK_COLLECTION_MATCHES_QUERY_PROPERTIES = new HashSet(Arrays.asList(
@@ -104,6 +109,14 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
"priority"
));
+ private static final Set TASK_COLLECTION_RUNNING_SORT_PROPERTIES = new HashSet(Arrays.asList(
+ "id", "name", "description", "priority", "processId", "assignee", "startedAt", "dueAt"
+ ));
+
+ private static final Set TASK_COLLECTION_HISTORY_SORT_PROPERTIES = new HashSet(Arrays.asList(
+ "id", "name", "description", "priority", "processId", "processDefinitionId", "assignee", "owner", "startedAt", "endedAt", "durationInMs", "dueAt"
+ ));
+
private RestVariableHelper restVariableHelper;
private WorkflowObjectFactory workflowFactory;
private WorkflowQNameConverter qNameConverter;
@@ -155,8 +168,8 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
Integer priority = propertyWalker.getProperty("priority", WhereClauseParser.EQUALS, Integer.class);
Integer priorityGreaterThanOrEquals = propertyWalker.getProperty("priority", WhereClauseParser.GREATERTHANOREQUALS, Integer.class);
Integer priorityLessThanOrEquals = propertyWalker.getProperty("priority", WhereClauseParser.LESSTHANOREQUALS, Integer.class);
- String processInstanceId = propertyWalker.getProperty("processInstanceId", WhereClauseParser.EQUALS);
- String processInstanceBusinessKey = propertyWalker.getProperty("processInstanceBusinessKey", WhereClauseParser.EQUALS);
+ String processInstanceId = propertyWalker.getProperty("processId", WhereClauseParser.EQUALS);
+ String processInstanceBusinessKey = propertyWalker.getProperty("processBusinessKey", WhereClauseParser.EQUALS);
String activityDefinitionId = propertyWalker.getProperty("activityDefinitionId", WhereClauseParser.EQUALS);
String activityDefinitionIdLike = propertyWalker.getProperty("activityDefinitionId", WhereClauseParser.MATCHES);
String processDefinitionId = propertyWalker.getProperty("processDefinitionId", WhereClauseParser.EQUALS);
@@ -177,7 +190,30 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
if (assignee != null) query.taskAssignee(assignee);
if (owner != null) query.taskOwner(owner);
- if (candidateUser != null) query.taskCandidateUser(candidateUser);
+ if (candidateUser != null)
+ {
+ Set parents = authorityService.getContainingAuthorities(AuthorityType.GROUP, candidateUser, false);
+ if (parents != null)
+ {
+ List authorities = new ArrayList();
+ authorities.addAll(parents);
+
+ // there's a limitation in at least Oracle for using an IN statement with more than 1000 items
+ if (parents.size() > 1000)
+ {
+ authorities = authorities.subList(0, 1000);
+ }
+
+ if (authorities.size() > 0)
+ {
+ query.taskCandidateGroupIn(authorities);
+ }
+ else
+ {
+ query.taskCandidateUser(candidateUser);
+ }
+ }
+ }
if (candidateGroup != null) query.taskCandidateGroup(candidateGroup);
if (name != null) query.taskName(name);
if (nameLike != null) query.taskNameLike(nameLike);
@@ -208,6 +244,30 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
{
query.taskVariableValueEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHAN)
+ {
+ query.taskVariableValueGreaterThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
+ }
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHANOREQUALS)
+ {
+ query.taskVariableValueGreaterThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
+ }
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHAN)
+ {
+ query.taskVariableValueLessThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
+ }
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHANOREQUALS)
+ {
+ query.taskVariableValueLessThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
+ }
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.MATCHES)
+ {
+ if (queryVariableHolder.getPropertyValue() instanceof String == false)
+ {
+ throw new InvalidArgumentException("the matches operator can only be used with a String value for property " + queryVariableHolder.getPropertyName());
+ }
+ query.taskVariableValueLike(queryVariableHolder.getPropertyName(), (String) queryVariableHolder.getPropertyValue());
+ }
else if (queryVariableHolder.getOperator() == WhereClauseParser.NEGATION)
{
query.taskVariableValueNotEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
@@ -285,6 +345,30 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
{
query.taskVariableValueEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
}
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHAN)
+ {
+ query.taskVariableValueGreaterThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
+ }
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.GREATERTHANOREQUALS)
+ {
+ query.taskVariableValueGreaterThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
+ }
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHAN)
+ {
+ query.taskVariableValueLessThan(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
+ }
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.LESSTHANOREQUALS)
+ {
+ query.taskVariableValueLessThanOrEqual(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
+ }
+ else if (queryVariableHolder.getOperator() == WhereClauseParser.MATCHES)
+ {
+ if (queryVariableHolder.getPropertyValue() instanceof String == false)
+ {
+ throw new InvalidArgumentException("the matches operator can only be used with a String value for property " + queryVariableHolder.getPropertyName());
+ }
+ query.taskVariableValueLike(queryVariableHolder.getPropertyName(), (String) queryVariableHolder.getPropertyValue());
+ }
else if (queryVariableHolder.getOperator() == WhereClauseParser.NEGATION)
{
query.taskVariableValueNotEquals(queryVariableHolder.getPropertyName(), queryVariableHolder.getPropertyValue());
@@ -325,6 +409,220 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
}
+
+ @Override
+ public CollectionWithPagingInfo getTasks(String processId, Parameters parameters)
+ {
+ Paging paging = parameters.getPaging();
+ String status = parameters.getParameter("status");
+
+ validateIfUserAllowedToWorkWithProcess(processId);
+
+ List page = null;
+ if (status == null || STATUS_ACTIVE.equals(status))
+ {
+ TaskQuery query = activitiProcessEngine
+ .getTaskService()
+ .createTaskQuery();
+
+ query.processInstanceId(processId);
+
+ String sortParam = parameters.getParameter("sort");
+ if (sortParam != null)
+ {
+ if (TASK_COLLECTION_RUNNING_SORT_PROPERTIES.contains(sortParam))
+ {
+ if ("id".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskId();
+ }
+ else if ("name".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskName();
+ }
+ else if ("description".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskDescription();
+ }
+ else if ("priority".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskPriority();
+ }
+ else if ("processId".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessInstanceId();
+ }
+ else if ("assignee".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskAssignee();
+ }
+ else if ("startedAt".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskCreateTime();
+ }
+ else if ("dueAt".equalsIgnoreCase(sortParam))
+ {
+ query.orderByDueDate();
+ }
+ }
+ else
+ {
+ throw new InvalidArgumentException("sort " + sortParam +
+ " is not supported, supported items are " + TASK_COLLECTION_RUNNING_SORT_PROPERTIES.toArray());
+ }
+
+ String sortOrderParam = parameters.getParameter("sortOrder");
+ if (sortOrderParam != null)
+ {
+ if ("asc".equalsIgnoreCase(sortOrderParam))
+ {
+ query.asc();
+ }
+ else if ("desc".equalsIgnoreCase(sortOrderParam))
+ {
+ query.desc();
+ }
+ else
+ {
+ throw new InvalidArgumentException("sort order " + sortOrderParam +
+ " is not supported, supported items are asc and desc");
+ }
+ }
+ }
+ else
+ {
+ query.orderByDueDate().asc();
+ }
+
+ List tasks = query.listPage(paging.getSkipCount(), paging.getMaxItems());
+
+ page = new ArrayList(tasks.size());
+ for (org.activiti.engine.task.Task taskInstance: tasks)
+ {
+ Task task = new Task(taskInstance);
+ task.setFormResourceKey(getFormResourceKey(taskInstance));
+ page.add(task);
+ }
+ }
+ else if (STATUS_COMPLETED.equals(status) || STATUS_ANY.equals(status))
+ {
+ HistoricTaskInstanceQuery query = activitiProcessEngine
+ .getHistoryService()
+ .createHistoricTaskInstanceQuery();
+
+ if (STATUS_COMPLETED.equals(status)) query.finished();
+
+ query.processInstanceId(processId);
+
+ // Add tenant filtering
+ if(tenantService.isEnabled()) {
+ query.processVariableValueEquals(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
+ }
+
+ // Add involvment filtering if user is not admin
+ if(!authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser())) {
+ query.taskInvolvedUser(AuthenticationUtil.getRunAsUser());
+ }
+
+ String sortParam = parameters.getParameter("sort");
+ if (sortParam != null)
+ {
+ if (TASK_COLLECTION_HISTORY_SORT_PROPERTIES.contains(sortParam))
+ {
+ if ("id".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskId();
+ }
+ else if ("name".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskName();
+ }
+ else if ("description".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskDescription();
+ }
+ else if ("priority".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskPriority();
+ }
+ else if ("processId".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessInstanceId();
+ }
+ else if ("processDefinitionId".equalsIgnoreCase(sortParam))
+ {
+ query.orderByProcessDefinitionId();
+ }
+ else if ("assignee".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskAssignee();
+ }
+ else if ("owner".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskOwner();
+ }
+ else if ("startedAt".equalsIgnoreCase(sortParam))
+ {
+ query.orderByHistoricTaskInstanceStartTime();
+ }
+ else if ("endedAt".equalsIgnoreCase(sortParam))
+ {
+ query.orderByHistoricTaskInstanceEndTime();
+ }
+ else if ("durationInMs".equalsIgnoreCase(sortParam))
+ {
+ query.orderByHistoricTaskInstanceDuration();
+ }
+ else if ("dueAt".equalsIgnoreCase(sortParam))
+ {
+ query.orderByTaskDueDate();
+ }
+ }
+ else
+ {
+ throw new InvalidArgumentException("sort " + sortParam +
+ " is not supported, supported items are " + TASK_COLLECTION_HISTORY_SORT_PROPERTIES.toArray());
+ }
+
+ String sortOrderParam = parameters.getParameter("sortOrder");
+ if (sortOrderParam != null)
+ {
+ if ("asc".equalsIgnoreCase(sortOrderParam))
+ {
+ query.asc();
+ }
+ else if ("desc".equalsIgnoreCase(sortOrderParam))
+ {
+ query.desc();
+ }
+ else
+ {
+ throw new InvalidArgumentException("sort order " + sortOrderParam +
+ " is not supported, supported items are asc and desc");
+ }
+ }
+ }
+ else
+ {
+ query.orderByTaskDueDate().asc();
+ }
+
+ List tasks = query.listPage(paging.getSkipCount(), paging.getMaxItems());
+
+ page = new ArrayList(tasks.size());
+ for (HistoricTaskInstance taskInstance: tasks)
+ {
+ Task task = new Task(taskInstance);
+ page.add(task);
+ }
+ }
+ else
+ {
+ throw new InvalidArgumentException("Invalid status parameter: " + status);
+ }
+
+ return CollectionWithPagingInfo.asPaged(paging, page, false, page.size());
+ }
@Override
public Task getTask(String taskId)
@@ -509,7 +807,7 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
}
// Lookup type definition for the task
- TypeDefinition taskType = workflowFactory.getTaskFullTypeDefinition(formData.getFormKey(), true);
+ TypeDefinition taskType = getWorkflowFactory().getTaskFullTypeDefinition(formData.getFormKey(), true);
return getFormModelElements(taskType, paging);
}
@@ -543,7 +841,25 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
public TaskVariable updateTaskVariable(String taskId, TaskVariable taskVariable)
{
org.activiti.engine.task.Task taskInstance = getValidTask(taskId, true);
-
+ return updateVariableInTask(taskId, taskInstance, taskVariable);
+ }
+
+ public List updateTaskVariables(String taskId, List variables)
+ {
+ org.activiti.engine.task.Task taskInstance = getValidTask(taskId, true);
+ List updatedVariables = new ArrayList();
+ if (variables != null)
+ {
+ for (TaskVariable variable : variables)
+ {
+ updatedVariables.add(updateVariableInTask(taskId, taskInstance, variable));
+ }
+ }
+ return updatedVariables;
+ }
+
+ protected TaskVariable updateVariableInTask(String taskId, org.activiti.engine.task.Task taskInstance, TaskVariable taskVariable)
+ {
if(taskVariable.getName() == null)
{
throw new InvalidArgumentException("Variable name is required.");
@@ -603,12 +919,22 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
}
}
- if(dataTypeDefinition == null)
+ if (dataTypeDefinition == null)
{
throw new InvalidArgumentException("Unsupported type of variable: '" + taskVariable.getType() +"'.");
}
- Object actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, taskVariable.getValue());
+ Object actualValue = null;
+ if ("java.util.Date".equalsIgnoreCase(dataTypeDefinition.getJavaClassName()))
+ {
+ // fix for different ISO 8601 Date format classes in Alfresco (org.alfresco.util and Spring Surf)
+ actualValue = ISO8601DateFormat.parse((String) taskVariable.getValue());
+ }
+ else
+ {
+ actualValue = DefaultTypeConverter.INSTANCE.convert(dataTypeDefinition, taskVariable.getValue());
+ }
+ taskVariable.setValue(actualValue);
if (VariableScope.LOCAL.equals(taskVariable.getVariableScope()))
{
@@ -716,10 +1042,27 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
return processes.getItems(task.getProcessInstanceId(), paging);
}
- protected String getFormResourceKey(org.activiti.engine.task.Task task) {
+ protected String getFormResourceKey(final org.activiti.engine.task.Task task)
+ {
if (task.getProcessDefinitionId() != null)
{
- return activitiProcessEngine.getFormService().getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+ ProcessDefinitionEntity definitionEntity = getCachedProcessDefinition(task.getProcessDefinitionId());
+
+ String formKey = null;
+ if (definitionEntity != null)
+ {
+ TaskDefinition taskDefinition = definitionEntity.getTaskDefinitions().get(task.getTaskDefinitionKey());
+ if (taskDefinition != null)
+ {
+ formKey = taskDefinition.getTaskFormHandler().getFormKey().getExpressionText();
+ }
+ }
+ else
+ {
+ formKey = activitiProcessEngine.getFormService().getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+ }
+
+ return formKey;
}
else
{
@@ -910,10 +1253,10 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
// Task is not yet finished, so potentially claimable. If user is part of a "candidateGroup", the task is accessible to the
// user regardless of not being involved/owner/assignee
isTaskClaimable = activitiProcessEngine.getTaskService()
- .createTaskQuery()
- .taskCandidateGroupIn(new ArrayList(authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser())))
- .taskId(taskId)
- .count() == 1;
+ .createTaskQuery()
+ .taskCandidateGroupIn(new ArrayList(authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser())))
+ .taskId(taskId)
+ .count() == 1;
}
if(!isTaskClaimable)
@@ -943,26 +1286,4 @@ public class TasksImpl extends WorkflowRestImpl implements Tasks
}
return workflowFactory;
}
-
-
- private enum TaskStateTransition {
-
- COMPLETED, CLAIMED, UNCLAIMED, DELEGATED, RESOLVED;
-
- /**
- * @return the {@link TaskStateTransition} for the given string
- * @throws InvalidArgumentException when no action exists for the given string
- */
- public static TaskStateTransition getTaskActionFromString(String action)
- {
- for(TaskStateTransition taskAction : values())
- {
- if(taskAction.name().toLowerCase().equals(action))
- {
- return taskAction;
- }
- }
- throw new InvalidArgumentException("The task state property has an invalid value: " + action);
- }
- }
}
diff --git a/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java b/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java
index 7308db82c0..aa64e460d1 100644
--- a/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java
+++ b/source/java/org/alfresco/rest/workflow/api/impl/WorkflowRestImpl.java
@@ -1,6 +1,7 @@
package org.alfresco.rest.workflow.api.impl;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
@@ -9,16 +10,36 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import org.activiti.engine.ActivitiObjectNotFoundException;
import org.activiti.engine.ProcessEngine;
+import org.activiti.engine.history.HistoricTaskInstance;
+import org.activiti.engine.history.HistoricTaskInstanceQuery;
+import org.activiti.engine.impl.ProcessEngineImpl;
+import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
+import org.activiti.engine.impl.context.Context;
+import org.activiti.engine.impl.interceptor.Command;
+import org.activiti.engine.impl.interceptor.CommandContext;
+import org.activiti.engine.impl.persistence.deploy.DeploymentCache;
+import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantService;
+import org.alfresco.repo.tenant.TenantUtil;
+import org.alfresco.repo.workflow.WorkflowConstants;
+import org.alfresco.repo.workflow.activiti.ActivitiConstants;
+import org.alfresco.repo.workflow.activiti.ActivitiScriptNode;
+import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
+import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.model.FormModelElement;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
+import org.alfresco.service.cmr.dictionary.Constraint;
+import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
@@ -42,6 +63,7 @@ public class WorkflowRestImpl
protected DictionaryService dictionaryService;
protected ProcessEngine activitiProcessEngine;
protected boolean deployWorkflowsInTenant;
+ protected List excludeModelTypes = new ArrayList(Arrays.asList("bpm_priority", "bpm_description", "bpm_dueDate"));
static
{
@@ -81,6 +103,32 @@ public class WorkflowRestImpl
this.deployWorkflowsInTenant = deployWorkflowsInTenant;
}
+ /**
+ * Get the process definition from the cache if available
+ *
+ * @param processDefinitionId the unique id identifier of the process definition
+ */
+ public ProcessDefinitionEntity getCachedProcessDefinition(final String processDefinitionId)
+ {
+ ProcessEngineConfigurationImpl processConfig = (ProcessEngineConfigurationImpl) ((ProcessEngineImpl) activitiProcessEngine).getProcessEngineConfiguration();
+ ProcessDefinitionEntity definitionEntity = processConfig.getCommandExecutorTxRequired().execute(new Command()
+ {
+
+ @Override
+ public ProcessDefinitionEntity execute(CommandContext commandContext)
+ {
+ DeploymentCache cache = Context
+ .getProcessEngineConfiguration()
+ .getDeploymentManager()
+ .getProcessDefinitionCache();
+
+ return cache.get(processDefinitionId);
+ }
+
+ });
+ return definitionEntity;
+ }
+
/**
* Get the first parameter value, converted to the requested type.
* @param parameters used to extract parameter value from
@@ -131,16 +179,33 @@ public class WorkflowRestImpl
List page = new ArrayList();
for (Entry entry : taskProperties.entrySet())
{
+ String name = entry.getKey().toPrefixString(namespaceService).replace(':', '_');
+
// Only add properties which are not part of an excluded type
- if(!typesToExclude.contains(entry.getValue().getContainerClass().getName()))
+ if(!typesToExclude.contains(entry.getValue().getContainerClass().getName()) && excludeModelTypes.contains(name) == false)
{
FormModelElement element = new FormModelElement();
- element.setName(entry.getKey().toPrefixString(namespaceService).replace(':', '_'));
+ element.setName(name);
element.setQualifiedName(entry.getKey().toString());
element.setTitle(entry.getValue().getTitle(dictionaryService));
element.setRequired(entry.getValue().isMandatory());
element.setDataType(entry.getValue().getDataType().getName().toPrefixString(namespaceService));
element.setDefaultValue(entry.getValue().getDefaultValue());
+ if (entry.getValue().getConstraints() != null)
+ {
+ for (ConstraintDefinition constraintDef : entry.getValue().getConstraints())
+ {
+ Constraint constraint = constraintDef.getConstraint();
+ if (constraint != null && constraint instanceof ListOfValuesConstraint)
+ {
+ ListOfValuesConstraint valuesConstraint = (ListOfValuesConstraint) constraint;
+ if (valuesConstraint.getAllowedValues() != null && valuesConstraint.getAllowedValues().size() > 0)
+ {
+ element.setAllowedValues(valuesConstraint.getAllowedValues());
+ }
+ }
+ }
+ }
page.add(element);
}
}
@@ -174,7 +239,8 @@ public class WorkflowRestImpl
ClassDefinition parentClassDefinition = taskType.getParentClassDefinition();
boolean contentClassFound = false;
- while(parentClassDefinition != null) {
+ while(parentClassDefinition != null)
+ {
if(contentClassFound)
{
typesToExclude.add(parentClassDefinition.getName());
@@ -190,4 +256,72 @@ public class WorkflowRestImpl
}
return typesToExclude;
}
+
+ /**
+ * Validates if the logged in user is allowed to get information about a specific process instance.
+ * If the user is not allowed an exception is thrown.
+ *
+ * @param processId identifier of the process instance
+ */
+ protected void validateIfUserAllowedToWorkWithProcess(String processId)
+ {
+ if (tenantService.isEnabled())
+ {
+ try
+ {
+ String tenantDomain = (String) activitiProcessEngine.getRuntimeService().getVariable(processId, ActivitiConstants.VAR_TENANT_DOMAIN);
+ if (TenantUtil.getCurrentDomain().equals(tenantDomain) == false)
+ {
+ throw new PermissionDeniedException("Process is running in another tenant");
+ }
+ }
+ catch (ActivitiObjectNotFoundException e)
+ {
+ throw new EntityNotFoundException(processId);
+ }
+ }
+
+ try
+ {
+ ActivitiScriptNode initiator = (ActivitiScriptNode) activitiProcessEngine.getRuntimeService().getVariable(processId, WorkflowConstants.PROP_INITIATOR);
+ if (AuthenticationUtil.getRunAsUser().equals(initiator.getNodeRef().getId()))
+ {
+ // user is allowed
+ return;
+ }
+ }
+ catch (ActivitiObjectNotFoundException e)
+ {
+ throw new EntityNotFoundException(processId);
+ }
+
+ HistoricTaskInstanceQuery query = activitiProcessEngine.getHistoryService()
+ .createHistoricTaskInstanceQuery()
+ .processInstanceId(processId);
+
+ if (authorityService.isAdminAuthority(AuthenticationUtil.getRunAsUser()))
+ {
+ // Admin is allowed to read all processes in the current tenant
+ if (tenantService.isEnabled())
+ {
+ query.processVariableValueEquals(ActivitiConstants.VAR_TENANT_DOMAIN, TenantUtil.getCurrentDomain());
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ // If non-admin user, involvement in the task is required (either owner, assignee or externally involved).
+ query.taskInvolvedUser(AuthenticationUtil.getRunAsUser());
+ }
+
+ List taskList = query.list();
+
+ if(org.apache.commons.collections.CollectionUtils.isEmpty(taskList))
+ {
+ throw new PermissionDeniedException("user is not allowed to access information about process " + processId);
+ }
+ }
}
diff --git a/source/java/org/alfresco/rest/workflow/api/model/Activity.java b/source/java/org/alfresco/rest/workflow/api/model/Activity.java
new file mode 100644
index 0000000000..e967c565b6
--- /dev/null
+++ b/source/java/org/alfresco/rest/workflow/api/model/Activity.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.rest.workflow.api.model;
+
+import java.util.Date;
+
+import org.activiti.engine.history.HistoricActivityInstance;
+
+/**
+ * Representation of an activity in the Activiti engine.
+ *
+ * @author Tijs Rademakers
+ */
+public class Activity
+{
+ String id;
+ String activityDefinitionId;
+ String activityDefinitionName;
+ String activityDefinitionType;
+ Date startedAt;
+ Date endedAt;
+ Long durationInMs;
+
+ public Activity(HistoricActivityInstance activity) {
+ this.id = activity.getId();
+ this.activityDefinitionId = activity.getActivityId();
+ this.activityDefinitionName = activity.getActivityName();
+ this.activityDefinitionType = activity.getActivityType();
+ this.startedAt = activity.getStartTime();
+ this.endedAt = activity.getEndTime();
+ this.durationInMs = activity.getDurationInMillis();
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public void setId(String id)
+ {
+ this.id = id;
+ }
+
+ public String getActivityDefinitionId()
+ {
+ return activityDefinitionId;
+ }
+
+ public void setActivityDefinitionId(String activityDefinitionId)
+ {
+ this.activityDefinitionId = activityDefinitionId;
+ }
+
+ public String getActivityDefinitionName()
+ {
+ return activityDefinitionName;
+ }
+
+ public void setActivityDefinitionName(String activityDefinitionName)
+ {
+ this.activityDefinitionName = activityDefinitionName;
+ }
+
+ public String getActivityDefinitionType()
+ {
+ return activityDefinitionType;
+ }
+
+ public void setActivityDefinitionType(String activityDefinitionType)
+ {
+ this.activityDefinitionType = activityDefinitionType;
+ }
+
+ public Date getStartedAt()
+ {
+ return startedAt;
+ }
+
+ public void setStartedAt(Date startedAt)
+ {
+ this.startedAt = startedAt;
+ }
+
+ public Date getEndedAt()
+ {
+ return endedAt;
+ }
+
+ public void setEndedAt(Date endedAt)
+ {
+ this.endedAt = endedAt;
+ }
+
+ public Long getDurationInMs()
+ {
+ return durationInMs;
+ }
+
+ public void setDurationInMs(Long durationInMs)
+ {
+ this.durationInMs = durationInMs;
+ }
+}
diff --git a/source/java/org/alfresco/rest/workflow/api/model/FormModelElement.java b/source/java/org/alfresco/rest/workflow/api/model/FormModelElement.java
index 4d6a2c8386..f285ed1b83 100644
--- a/source/java/org/alfresco/rest/workflow/api/model/FormModelElement.java
+++ b/source/java/org/alfresco/rest/workflow/api/model/FormModelElement.java
@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api.model;
+import java.util.List;
+
public class FormModelElement
{
String name;
@@ -26,6 +28,7 @@ public class FormModelElement
String dataType;
boolean required;
String defaultValue;
+ List allowedValues;
public String getName()
{
@@ -75,4 +78,12 @@ public class FormModelElement
{
this.defaultValue = defaultValue;
}
+ public List getAllowedValues()
+ {
+ return allowedValues;
+ }
+ public void setAllowedValues(List allowedValues)
+ {
+ this.allowedValues = allowedValues;
+ }
}
diff --git a/source/java/org/alfresco/rest/workflow/api/model/ProcessDefinition.java b/source/java/org/alfresco/rest/workflow/api/model/ProcessDefinition.java
index 9db50ef2d3..0a46846017 100644
--- a/source/java/org/alfresco/rest/workflow/api/model/ProcessDefinition.java
+++ b/source/java/org/alfresco/rest/workflow/api/model/ProcessDefinition.java
@@ -27,7 +27,8 @@ public class ProcessDefinition
String category;
int version;
String deploymentId;
-
+ String title;
+ String description;
String startFormResourceKey;
Boolean isGraphicNotationDefined;
@@ -38,7 +39,6 @@ public class ProcessDefinition
public ProcessDefinition(org.activiti.engine.repository.ProcessDefinition processDefinition)
{
this.id = processDefinition.getId();
- this.key = processDefinition.getKey();
this.name = processDefinition.getName();
this.category = processDefinition.getCategory();
this.version = processDefinition.getVersion();
@@ -104,6 +104,26 @@ public class ProcessDefinition
{
this.deploymentId = deploymentId;
}
+
+ public String getTitle()
+ {
+ return title;
+ }
+
+ public void setTitle(String title)
+ {
+ this.title = title;
+ }
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+ public void setDescription(String description)
+ {
+ this.description = description;
+ }
public String getStartFormResourceKey()
{
diff --git a/source/java/org/alfresco/rest/workflow/api/model/ProcessInfo.java b/source/java/org/alfresco/rest/workflow/api/model/ProcessInfo.java
index a5502fb730..6efcb2ca89 100644
--- a/source/java/org/alfresco/rest/workflow/api/model/ProcessInfo.java
+++ b/source/java/org/alfresco/rest/workflow/api/model/ProcessInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -32,10 +32,14 @@ public class ProcessInfo
String processDefinitionKey;
Date startedAt;
Date endedAt;
- Long durationInMillis;
+ Long durationInMs;
String deleteReason;
+ String startUserId;
+ String startActivityId;
+ String endActivityId;
String businessKey;
String superProcessInstanceId;
+ boolean completed;
Map variables;
Set items;
@@ -50,9 +54,14 @@ public class ProcessInfo
this.processDefinitionId = processInstance.getProcessDefinitionId();
this.startedAt = processInstance.getStartTime();
this.endedAt = processInstance.getEndTime();
- this.durationInMillis = processInstance.getDurationInMillis();
+ this.durationInMs = processInstance.getDurationInMillis();
this.deleteReason = processInstance.getDeleteReason();
+ this.startUserId = processInstance.getStartUserId();
+ this.startActivityId = processInstance.getStartActivityId();
+ this.endActivityId = processInstance.getEndActivityId();
this.businessKey = processInstance.getBusinessKey();
+ this.superProcessInstanceId = processInstance.getSuperProcessInstanceId();
+ this.completed = (processInstance.getEndTime() != null);
}
public String getId()
@@ -75,14 +84,14 @@ public class ProcessInfo
this.processDefinitionId = processDefinitionId;
}
- public Long getDurationInMillis()
+ public Long getDurationInMs()
{
- return durationInMillis;
+ return durationInMs;
}
- public void setDurationInMillis(Long durationInMillis)
+ public void setDurationInMs(Long durationInMs)
{
- this.durationInMillis = durationInMillis;
+ this.durationInMs = durationInMs;
}
public String getDeleteReason()
@@ -145,6 +154,46 @@ public class ProcessInfo
this.endedAt = endedAt;
}
+ public String getStartUserId()
+ {
+ return startUserId;
+ }
+
+ public void setStartUserId(String startUserId)
+ {
+ this.startUserId = startUserId;
+ }
+
+ public String getStartActivityId()
+ {
+ return startActivityId;
+ }
+
+ public void setStartActivityId(String startActivityId)
+ {
+ this.startActivityId = startActivityId;
+ }
+
+ public String getEndActivityId()
+ {
+ return endActivityId;
+ }
+
+ public void setEndActivityId(String endActivityId)
+ {
+ this.endActivityId = endActivityId;
+ }
+
+ public boolean isCompleted()
+ {
+ return completed;
+ }
+
+ public void setCompleted(boolean completed)
+ {
+ this.completed = completed;
+ }
+
public Map getVariables()
{
return variables;
diff --git a/source/java/org/alfresco/rest/workflow/api/model/Task.java b/source/java/org/alfresco/rest/workflow/api/model/Task.java
index 1e39f28b93..571e7b72b0 100644
--- a/source/java/org/alfresco/rest/workflow/api/model/Task.java
+++ b/source/java/org/alfresco/rest/workflow/api/model/Task.java
@@ -21,6 +21,7 @@ package org.alfresco.rest.workflow.api.model;
import java.util.Date;
import org.activiti.engine.history.HistoricTaskInstance;
+import org.activiti.engine.task.DelegationState;
public class Task
{
@@ -60,6 +61,18 @@ public class Task
this.owner = taskInstance.getOwner();
this.assignee = taskInstance.getAssignee();
this.formResourceKey = taskInstance.getFormKey();
+ if (taskInstance.getEndTime() != null)
+ {
+ this.state = TaskStateTransition.COMPLETED.name().toLowerCase();
+ }
+ else if (taskInstance.getAssignee() != null)
+ {
+ this.state = TaskStateTransition.CLAIMED.name().toLowerCase();
+ }
+ else
+ {
+ this.state = TaskStateTransition.UNCLAIMED.name().toLowerCase();
+ }
}
public Task(org.activiti.engine.task.Task taskInstance)
@@ -75,6 +88,18 @@ public class Task
this.priority = taskInstance.getPriority();
this.owner = taskInstance.getOwner();
this.assignee = taskInstance.getAssignee();
+ if (taskInstance.getDelegationState() == DelegationState.PENDING)
+ {
+
+ }
+ if (taskInstance.getAssignee() != null)
+ {
+ this.state = TaskStateTransition.CLAIMED.name().toLowerCase();
+ }
+ else
+ {
+ this.state = TaskStateTransition.UNCLAIMED.name().toLowerCase();
+ }
}
public String getId()
diff --git a/source/java/org/alfresco/rest/workflow/api/model/TaskStateTransition.java b/source/java/org/alfresco/rest/workflow/api/model/TaskStateTransition.java
new file mode 100644
index 0000000000..cb7b57a3a0
--- /dev/null
+++ b/source/java/org/alfresco/rest/workflow/api/model/TaskStateTransition.java
@@ -0,0 +1,24 @@
+package org.alfresco.rest.workflow.api.model;
+
+import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
+
+public enum TaskStateTransition {
+
+ COMPLETED, CLAIMED, UNCLAIMED, DELEGATED, RESOLVED;
+
+ /**
+ * @return the {@link TaskStateTransition} for the given string
+ * @throws InvalidArgumentException when no action exists for the given string
+ */
+ public static TaskStateTransition getTaskActionFromString(String action)
+ {
+ for(TaskStateTransition taskAction : values())
+ {
+ if(taskAction.name().toLowerCase().equals(action))
+ {
+ return taskAction;
+ }
+ }
+ throw new InvalidArgumentException("The task state property has an invalid value: " + action);
+ }
+}
diff --git a/source/java/org/alfresco/rest/workflow/api/package-info.java b/source/java/org/alfresco/rest/workflow/api/package-info.java
index 89066ee3e4..0127e16e21 100644
--- a/source/java/org/alfresco/rest/workflow/api/package-info.java
+++ b/source/java/org/alfresco/rest/workflow/api/package-info.java
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
-@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
+@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;
\ No newline at end of file
diff --git a/source/java/org/alfresco/rest/workflow/api/processdefinitions/ProcessDefinitionsRestEntityResource.java b/source/java/org/alfresco/rest/workflow/api/processdefinitions/ProcessDefinitionsRestEntityResource.java
index 9d694a1444..84ae7ace56 100644
--- a/source/java/org/alfresco/rest/workflow/api/processdefinitions/ProcessDefinitionsRestEntityResource.java
+++ b/source/java/org/alfresco/rest/workflow/api/processdefinitions/ProcessDefinitionsRestEntityResource.java
@@ -18,13 +18,16 @@
*/
package org.alfresco.rest.workflow.api.processdefinitions;
+import org.alfresco.rest.framework.BinaryProperties;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.WebApiParameters;
import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.resource.EntityResource;
+import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
+import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.workflow.api.ProcessDefinitions;
@@ -32,7 +35,8 @@ import org.alfresco.rest.workflow.api.model.ProcessDefinition;
@EntityResource(name="process-definitions", title = "Process definitions")
public class ProcessDefinitionsRestEntityResource implements EntityResourceAction.Read,
- EntityResourceAction.ReadById{
+ EntityResourceAction.ReadById,
+ BinaryResourceAction.Read {
ProcessDefinitions processDefinitions;
@@ -59,4 +63,12 @@ public class ProcessDefinitionsRestEntityResource implements EntityResourceActio
{
return processDefinitions.getProcessDefinition(id);
}
+
+ @Override
+ @WebApiDescription(title = "Get a process definition image", description = "Get a process definition image")
+ @BinaryProperties({"image"})
+ public BinaryResource readProperty(String id, Parameters parameters) throws EntityNotFoundException
+ {
+ return processDefinitions.getProcessDefinitionImage(id);
+ }
}
diff --git a/source/java/org/alfresco/rest/workflow/api/processdefinitions/package-info.java b/source/java/org/alfresco/rest/workflow/api/processdefinitions/package-info.java
index e7e3c9bc5a..4e6b2054ae 100644
--- a/source/java/org/alfresco/rest/workflow/api/processdefinitions/package-info.java
+++ b/source/java/org/alfresco/rest/workflow/api/processdefinitions/package-info.java
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
-@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
+@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api.processdefinitions;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;
\ No newline at end of file
diff --git a/source/java/org/alfresco/rest/workflow/api/processes/ProcessActivitiesRelation.java b/source/java/org/alfresco/rest/workflow/api/processes/ProcessActivitiesRelation.java
new file mode 100644
index 0000000000..dd2a847ea6
--- /dev/null
+++ b/source/java/org/alfresco/rest/workflow/api/processes/ProcessActivitiesRelation.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.rest.workflow.api.processes;
+
+import org.alfresco.rest.framework.WebApiDescription;
+import org.alfresco.rest.framework.resource.RelationshipResource;
+import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
+import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
+import org.alfresco.rest.framework.resource.parameters.Parameters;
+import org.alfresco.rest.workflow.api.Activities;
+import org.alfresco.rest.workflow.api.model.Activity;
+
+/**
+ *
+ * @author Tijs Rademakers
+ *
+ */
+@RelationshipResource(name = "activities", entityResource = ProcessesRestEntityResource.class, title = "Activities for the current process")
+public class ProcessActivitiesRelation implements RelationshipResourceAction.Read
+{
+ protected Activities activities;
+
+ public void setActivities(Activities activities)
+ {
+ this.activities = activities;
+ }
+
+ /**
+ * List the activities.
+ */
+ @Override
+ @WebApiDescription(title = "Get Activities", description = "Get a paged list of the activities")
+ public CollectionWithPagingInfo readAll(String processId, Parameters parameters)
+ {
+ return activities.getActivities(processId, parameters);
+ }
+}
diff --git a/source/java/org/alfresco/rest/workflow/api/processes/ProcessTasksRelation.java b/source/java/org/alfresco/rest/workflow/api/processes/ProcessTasksRelation.java
new file mode 100644
index 0000000000..b093758bcf
--- /dev/null
+++ b/source/java/org/alfresco/rest/workflow/api/processes/ProcessTasksRelation.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005-2012 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.rest.workflow.api.processes;
+
+import org.alfresco.rest.framework.WebApiDescription;
+import org.alfresco.rest.framework.resource.RelationshipResource;
+import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
+import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
+import org.alfresco.rest.framework.resource.parameters.Parameters;
+import org.alfresco.rest.workflow.api.Tasks;
+import org.alfresco.rest.workflow.api.model.Task;
+
+/**
+ *
+ * @author Tijs Rademakers
+ *
+ */
+@RelationshipResource(name = "tasks", entityResource = ProcessesRestEntityResource.class, title = "Tasks for the current process")
+public class ProcessTasksRelation implements RelationshipResourceAction.Read
+{
+ protected Tasks tasks;
+
+ public void setTasks(Tasks tasks)
+ {
+ this.tasks = tasks;
+ }
+
+ /**
+ * List the tasks.
+ */
+ @Override
+ @WebApiDescription(title = "Get Tasks", description = "Get a paged list of the tasks")
+ public CollectionWithPagingInfo readAll(String processId, Parameters parameters)
+ {
+ return tasks.getTasks(processId, parameters);
+ }
+}
diff --git a/source/java/org/alfresco/rest/workflow/api/processes/ProcessVariablesRelation.java b/source/java/org/alfresco/rest/workflow/api/processes/ProcessVariablesRelation.java
index 38ca6cff7b..a752c127af 100644
--- a/source/java/org/alfresco/rest/workflow/api/processes/ProcessVariablesRelation.java
+++ b/source/java/org/alfresco/rest/workflow/api/processes/ProcessVariablesRelation.java
@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api.processes;
+import java.util.List;
+
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
@@ -32,7 +34,7 @@ import org.alfresco.rest.workflow.api.model.Variable;
*
*/
@RelationshipResource(name = "variables", entityResource = ProcessesRestEntityResource.class, title = "Variables for the current process")
-public class ProcessVariablesRelation implements RelationshipResourceAction.Read,
+public class ProcessVariablesRelation implements RelationshipResourceAction.Read, RelationshipResourceAction.Create,
RelationshipResourceAction.Update, RelationshipResourceAction.Delete
{
protected Processes processes;
@@ -51,6 +53,16 @@ public class ProcessVariablesRelation implements RelationshipResourceAction.Read
{
return processes.getVariables(processId, parameters.getPaging());
}
+
+ /**
+ * Creates or updates multiple variables. If the variable name doesn't exist yet it will be created
+ */
+ @Override
+ @WebApiDescription(title = "Create or Update Variables", description = "Create or update multiple variable")
+ public List create(String processId, List variables, Parameters parameters)
+ {
+ return processes.updateVariables(processId, variables);
+ }
/**
* Update a variable. If the variable name doesn't exist yet it will be created
diff --git a/source/java/org/alfresco/rest/workflow/api/processes/ProcessesRestEntityResource.java b/source/java/org/alfresco/rest/workflow/api/processes/ProcessesRestEntityResource.java
index c2d7020433..3babbc1552 100644
--- a/source/java/org/alfresco/rest/workflow/api/processes/ProcessesRestEntityResource.java
+++ b/source/java/org/alfresco/rest/workflow/api/processes/ProcessesRestEntityResource.java
@@ -27,7 +27,6 @@ import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.WebApiParameters;
import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
-import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
@@ -79,16 +78,11 @@ public class ProcessesRestEntityResource implements EntityResourceAction.Read.
*/
-@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
+@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api.processes;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;
\ No newline at end of file
diff --git a/source/java/org/alfresco/rest/workflow/api/tasks/TaskVariablesRelation.java b/source/java/org/alfresco/rest/workflow/api/tasks/TaskVariablesRelation.java
index 00d7ca93e2..9a95783711 100644
--- a/source/java/org/alfresco/rest/workflow/api/tasks/TaskVariablesRelation.java
+++ b/source/java/org/alfresco/rest/workflow/api/tasks/TaskVariablesRelation.java
@@ -18,6 +18,8 @@
*/
package org.alfresco.rest.workflow.api.tasks;
+import java.util.List;
+
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
@@ -35,7 +37,7 @@ import org.alfresco.rest.workflow.api.model.VariableScope;
*
*/
@RelationshipResource(name = "variables", entityResource = TasksRestEntityResource.class, title = "Variables for the current task")
-public class TaskVariablesRelation implements RelationshipResourceAction.Read,
+public class TaskVariablesRelation implements RelationshipResourceAction.Read, RelationshipResourceAction.Create,
RelationshipResourceAction.Update, RelationshipResourceAction.Delete
{
private Tasks tasks;
@@ -64,6 +66,16 @@ public class TaskVariablesRelation implements RelationshipResourceAction.Read create(String taskId, List variables, Parameters parameters)
+ {
+ return tasks.updateTaskVariables(taskId, variables);
+ }
/**
* Update a task variable. If the variable name doesn't exist yet it will be created
diff --git a/source/java/org/alfresco/rest/workflow/api/tasks/package-info.java b/source/java/org/alfresco/rest/workflow/api/tasks/package-info.java
index 21e76c7e87..867383a3be 100644
--- a/source/java/org/alfresco/rest/workflow/api/tasks/package-info.java
+++ b/source/java/org/alfresco/rest/workflow/api/tasks/package-info.java
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
-@WebApi(name="alfresco", scope=Api.SCOPE.PUBLIC, version=1)
+@WebApi(name="workflow", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rest.workflow.api.tasks;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;
\ No newline at end of file
diff --git a/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java b/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java
index 545c87bf56..a98a1d9673 100644
--- a/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java
+++ b/source/test-java/org/alfresco/rest/api/tests/client/PublicApiHttpClient.java
@@ -71,7 +71,7 @@ public class PublicApiHttpClient
private static final String OLD_BASE_URL = "http://{0}:{1}{2}/{3}/{4}/api/";
private static final String INDEX_URL = "http://{0}:{1}{2}/{3}";
- private static final String BASE_URL = "http://{0}:{1}{2}/{3}/{4}/{5}/alfresco/versions/1";
+ private static final String BASE_URL = "http://{0}:{1}{2}/{3}/{4}/{5}/{6}/versions/1";
private static final String PUBLICAPI_CMIS_SERVICE_URL = "http://{0}:{1}{2}/{3}/cmis/versions/{4}/{5}";
private static final String PUBLICAPI_CMIS_URL = "http://{0}:{1}{2}/{3}/{4}/{5}/cmis/versions/{6}/{7}";
private static final String ATOM_PUB_URL = "http://{0}:{1}{2}/cmisatom";
@@ -86,6 +86,9 @@ public class PublicApiHttpClient
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
+ // can be overriden by other clients like the workflow client
+ protected String apiName = "alfresco";
+
public PublicApiHttpClient(String host, int port, String contextPath, String servletName, AuthenticatedHttp authenticatedHttp)
{
super();
@@ -500,7 +503,7 @@ public class PublicApiHttpClient
Pair relationshipCollectionInfo = getRelationCollectionInfo(resourceClass);
sb.append(MessageFormat.format(BASE_URL, new Object[] {host, String.valueOf(port), contextPath, servletName,
- tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain, scope.toString()}));
+ tenantDomain == null ? TenantUtil.DEFAULT_TENANT : tenantDomain, scope.toString(), apiName}));
if(relationshipCollectionInfo != null)
{
@@ -578,7 +581,7 @@ public class PublicApiHttpClient
tenantDomain = TenantUtil.DEFAULT_TENANT;
}
sb.append(MessageFormat.format(BASE_URL, new Object[] {host, String.valueOf(port), contextPath, servletName,
- tenantDomain, scope}));
+ tenantDomain, scope, apiName}));
if(collectionName != null)
{
diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/EnterpriseWorkflowTestApi.java b/source/test-java/org/alfresco/rest/workflow/api/tests/EnterpriseWorkflowTestApi.java
index 2c291d226a..d2686c033d 100644
--- a/source/test-java/org/alfresco/rest/workflow/api/tests/EnterpriseWorkflowTestApi.java
+++ b/source/test-java/org/alfresco/rest/workflow/api/tests/EnterpriseWorkflowTestApi.java
@@ -2,9 +2,12 @@ package org.alfresco.rest.workflow.api.tests;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.InputStream;
import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.repository.DeploymentBuilder;
@@ -23,11 +26,11 @@ import org.alfresco.rest.api.tests.client.AuthenticationDetailsProvider;
import org.alfresco.rest.api.tests.client.HttpClientProvider;
import org.alfresco.rest.api.tests.client.HttpResponse;
import org.alfresco.rest.api.tests.client.PublicApiException;
-import org.alfresco.rest.api.tests.client.PublicApiHttpClient;
import org.alfresco.rest.api.tests.client.RequestContext;
import org.alfresco.rest.api.tests.client.UserAuthenticationDetailsProviderImpl;
import org.alfresco.rest.api.tests.client.UserData;
import org.alfresco.rest.api.tests.client.UserDataService;
+import org.alfresco.rest.api.tests.client.data.MemberOfSite;
import org.alfresco.rest.workflow.api.model.ProcessInfo;
import org.alfresco.rest.workflow.api.tests.WorkflowApiClient.ProcessesClient;
import org.alfresco.service.ServiceRegistry;
@@ -85,7 +88,7 @@ public class EnterpriseWorkflowTestApi extends EnterpriseTestApi
};
AuthenticationDetailsProvider authenticationDetailsProvider = new UserAuthenticationDetailsProviderImpl(userDataService, "admin", "admin");
AuthenticatedHttp authenticatedHttp = new AuthenticatedHttp(httpClientProvider, authenticationDetailsProvider);
- this.httpClient = new PublicApiHttpClient("localhost", TestFixture.PORT, TestFixture.CONTEXT_PATH,
+ this.httpClient = new WorkflowApiHttpClient("localhost", TestFixture.PORT, TestFixture.CONTEXT_PATH,
TestFixture.PUBLIC_API_SERVLET_NAME, authenticatedHttp);
this.publicApiClient = new WorkflowApiClient(httpClient, userDataService);
activitiProcessEngine = (ProcessEngine) applicationContext.getBean("activitiProcessEngine");
@@ -116,6 +119,29 @@ public class EnterpriseWorkflowTestApi extends EnterpriseTestApi
return requestContext;
}
+ protected TestNetwork getOtherNetwork(String usedNetworkId) throws Exception {
+ Iterator networkIt = getTestFixture().getNetworksIt();
+ while(networkIt.hasNext()) {
+ TestNetwork network = networkIt.next();
+ if(!usedNetworkId.equals(network.getId())) {
+ return network;
+ }
+ }
+ fail("Need more than one network to test permissions");
+ return null;
+ }
+
+ protected TestPerson getOtherPersonInNetwork(String usedPerson, String networkId) throws Exception {
+ TestNetwork usedNetwork = getTestFixture().getNetwork(networkId);
+ for(TestPerson person : usedNetwork.getPeople()) {
+ if(!person.getId().equals(usedPerson)) {
+ return person;
+ }
+ }
+ fail("Network doesn't have additonal users, cannot perform test");
+ return null;
+ }
+
protected Date parseDate(JSONObject entry, String fieldName) {
String dateText = (String) entry.get(fieldName);
if (dateText!=null) {
@@ -188,10 +214,17 @@ public class EnterpriseWorkflowTestApi extends EnterpriseTestApi
}
/**
- * Start an adhoc-process through the public REST-API.
+ * Start an adhoc-process without business key through the public REST-API.
+ */
+ protected ProcessInfo startAdhocProcess(final RequestContext requestContext, NodeRef[] documentRefs) throws PublicApiException {
+ return startAdhocProcess(requestContext, documentRefs, null);
+ }
+
+ /**
+ * Start an adhoc-process with possible business key through the public REST-API.
*/
@SuppressWarnings("unchecked")
- protected ProcessInfo startAdhocProcess(final RequestContext requestContext, NodeRef[] documentRefs) throws PublicApiException {
+ protected ProcessInfo startAdhocProcess(final RequestContext requestContext, NodeRef[] documentRefs, String businessKey) throws PublicApiException {
org.activiti.engine.repository.ProcessDefinition processDefinition = activitiProcessEngine
.getRepositoryService()
.createProcessDefinitionQuery()
@@ -202,8 +235,13 @@ public class EnterpriseWorkflowTestApi extends EnterpriseTestApi
final JSONObject createProcessObject = new JSONObject();
createProcessObject.put("processDefinitionId", processDefinition.getId());
+ if (businessKey != null)
+ {
+ createProcessObject.put("businessKey", businessKey);
+ }
final JSONObject variablesObject = new JSONObject();
variablesObject.put("bpm_priority", 1);
+ variablesObject.put("wf_notifyMe", Boolean.FALSE);
TenantUtil.runAsUserTenant(new TenantRunAsWork()
{
@@ -220,7 +258,7 @@ public class EnterpriseWorkflowTestApi extends EnterpriseTestApi
final JSONArray itemsObject = new JSONArray();
for (NodeRef nodeRef : documentRefs)
{
- itemsObject.add(nodeRef.toString());
+ itemsObject.add(nodeRef.getId());
}
createProcessObject.put("items", itemsObject);
}
@@ -229,4 +267,43 @@ public class EnterpriseWorkflowTestApi extends EnterpriseTestApi
return processesClient.createProcess(createProcessObject.toJSONString());
}
+
+ /**
+ * Start a review pooled process through the public REST-API.
+ */
+ @SuppressWarnings("unchecked")
+ protected ProcessInfo startReviewPooledProcess(final RequestContext requestContext) throws PublicApiException {
+ org.activiti.engine.repository.ProcessDefinition processDefinition = activitiProcessEngine
+ .getRepositoryService()
+ .createProcessDefinitionQuery()
+ .processDefinitionKey("@" + requestContext.getNetworkId() + "@activitiReviewPooled")
+ .singleResult();
+
+ ProcessesClient processesClient = publicApiClient.processesClient();
+
+ final JSONObject createProcessObject = new JSONObject();
+ createProcessObject.put("processDefinitionId", processDefinition.getId());
+
+ final JSONObject variablesObject = new JSONObject();
+ variablesObject.put("bpm_priority", 1);
+ variablesObject.put("wf_notifyMe", Boolean.FALSE);
+
+ TenantUtil.runAsUserTenant(new TenantRunAsWork()
+ {
+ @Override
+ public Void doWork() throws Exception
+ {
+ List memberships = getTestFixture().getNetwork(requestContext.getNetworkId()).getSiteMemberships(requestContext.getRunAsUser());
+ assertTrue(memberships.size() > 0);
+ MemberOfSite memberOfSite = memberships.get(0);
+ String group = "GROUP_site_" + memberOfSite.getSiteId() + "_" + memberOfSite.getRole().name();
+ variablesObject.put("bpm_groupAssignee", group);
+ return null;
+ }
+ }, requestContext.getRunAsUser(), requestContext.getNetworkId());
+
+ createProcessObject.put("variables", variablesObject);
+
+ return processesClient.createProcess(createProcessObject.toJSONString());
+ }
}
diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionParser.java b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionParser.java
index a925cceea0..faa17ffc90 100644
--- a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionParser.java
+++ b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -34,6 +34,8 @@ public class ProcessDefinitionParser extends ListParser
processDefinition.setVersion(((Number) entry.get("version")).intValue());
processDefinition.setName((String) entry.get("name"));
processDefinition.setDeploymentId((String) entry.get("deploymentId"));
+ processDefinition.setTitle((String) entry.get("title"));
+ processDefinition.setDescription((String) entry.get("description"));
processDefinition.setCategory((String) entry.get("category"));
processDefinition.setStartFormResourceKey((String) entry.get("startFormResourceKey"));
processDefinition.setGraphicNotationDefined((Boolean) entry.get("graphicNotationDefined"));
diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionWorkflowApiTest.java
index 5d00219f1e..79c7dadeed 100644
--- a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionWorkflowApiTest.java
+++ b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessDefinitionWorkflowApiTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2012 Alfresco Software Limited.
+ * Copyright (C) 2005-2013 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -29,6 +29,9 @@ import java.util.List;
import java.util.Map;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.rest.api.tests.RepoService.TestNetwork;
+import org.alfresco.rest.api.tests.client.HttpResponse;
import org.alfresco.rest.api.tests.client.PublicApiClient.ListResponse;
import org.alfresco.rest.api.tests.client.PublicApiException;
import org.alfresco.rest.api.tests.client.RequestContext;
@@ -40,8 +43,7 @@ import org.junit.Test;
import org.springframework.http.HttpStatus;
/**
- *
- *
+ * @author Tijs Rademakers
* @author Frederik Heremans
*/
public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
@@ -57,11 +59,11 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
ListResponse processDefinitionsResponse = processDefinitionsClient.getProcessDefinitions(null);
Map processDefinitionMap = getProcessDefinitionMapByKey(processDefinitionsResponse.getList());
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiReviewPooled", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiParallelGroupReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiParallelReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiAdhoc", requestContext)));
+ assertTrue(processDefinitionMap.containsKey("activitiReviewPooled"));
+ assertTrue(processDefinitionMap.containsKey("activitiReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelGroupReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
assertEquals(5, processDefinitionMap.size());
@@ -74,16 +76,18 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
assertNotNull(activitiDefinition);
- ProcessDefinition adhocDefinition = processDefinitionMap.get(adhocKey);
+ ProcessDefinition adhocDefinitionRest = processDefinitionMap.get("activitiAdhoc");
- assertEquals(activitiDefinition.getId(), adhocDefinition.getId());
- assertEquals(activitiDefinition.getKey(), adhocDefinition.getKey());
- assertEquals(activitiDefinition.getDeploymentId(), adhocDefinition.getDeploymentId());
- assertEquals(activitiDefinition.getCategory(), adhocDefinition.getCategory());
- assertEquals(activitiDefinition.getName(), adhocDefinition.getName());
- assertEquals(activitiDefinition.getVersion(), adhocDefinition.getVersion());
- assertEquals(((ProcessDefinitionEntity) activitiDefinition).isGraphicalNotationDefined(), adhocDefinition.isGraphicNotationDefined());
- assertEquals("wf:submitAdhocTask", adhocDefinition.getStartFormResourceKey());
+ assertEquals(activitiDefinition.getId(), adhocDefinitionRest.getId());
+ assertEquals("activitiAdhoc", adhocDefinitionRest.getKey());
+ assertEquals(activitiDefinition.getDeploymentId(), adhocDefinitionRest.getDeploymentId());
+ assertEquals(activitiDefinition.getCategory(), adhocDefinitionRest.getCategory());
+ assertEquals(activitiDefinition.getName(), adhocDefinitionRest.getName());
+ assertEquals(activitiDefinition.getVersion(), adhocDefinitionRest.getVersion());
+ assertEquals(((ProcessDefinitionEntity) activitiDefinition).isGraphicalNotationDefined(), adhocDefinitionRest.isGraphicNotationDefined());
+ assertEquals("wf:submitAdhocTask", adhocDefinitionRest.getStartFormResourceKey());
+ assertEquals("New Task", adhocDefinitionRest.getTitle());
+ assertEquals("Assign a new task to yourself or a colleague", adhocDefinitionRest.getDescription());
}
@Test
@@ -104,11 +108,11 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
// Filter on category equals
Map processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(category = 'http://alfresco.org')");
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiReviewPooled", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiParallelGroupReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiParallelReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiAdhoc", requestContext)));
+ assertTrue(processDefinitionMap.containsKey("activitiReviewPooled"));
+ assertTrue(processDefinitionMap.containsKey("activitiReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelGroupReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
assertEquals(5, processDefinitionMap.size());
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(category = 'unexisting')");
@@ -116,15 +120,15 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
// Filter on name equals
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(name = 'Adhoc Activiti Process')");
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiAdhoc", requestContext)));
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
assertEquals(1, processDefinitionMap.size());
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(name = 'unexisting')");
assertEquals(0, processDefinitionMap.size());
// Filter on key equals
- processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(key='" + adhocKey +"')");
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiAdhoc", requestContext)));
+ processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(key='activitiAdhoc')");
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
assertEquals(1, processDefinitionMap.size());
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(key='unexisting')");
@@ -139,7 +143,7 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
// Filter on deploymentId equals
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(deploymentId='" + activitiDefinition.getDeploymentId() + "')");
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiAdhoc", requestContext)));
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
assertEquals(1, processDefinitionMap.size());
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(deploymentId='unexisting')");
@@ -148,11 +152,11 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
// Filter on category matches
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(category matches('%alfresco.o%'))");
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiReviewPooled", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiParallelGroupReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiParallelReview", requestContext)));
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiAdhoc", requestContext)));
+ assertTrue(processDefinitionMap.containsKey("activitiReviewPooled"));
+ assertTrue(processDefinitionMap.containsKey("activitiReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelGroupReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
assertEquals(5, processDefinitionMap.size());
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(category matches('unexisting'))");
@@ -160,15 +164,15 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
// Filter on name matches
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(name matches('Adhoc Activiti %'))");
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiAdhoc", requestContext)));
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
assertEquals(1, processDefinitionMap.size());
processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(name matches('unexisting'))");
assertEquals(0, processDefinitionMap.size());
// Filter on key matches
- processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(key matches('" + adhocKey.substring(0, adhocKey.length() - 3) +"%'))");
- assertTrue(processDefinitionMap.containsKey(createProcessDefinitionKey("activitiAdhoc", requestContext)));
+ processDefinitionMap = getProcessDefinitions(processDefinitionsClient, "(key matches('activitiAd%'))");
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
assertEquals(1, processDefinitionMap.size());
}
@@ -193,7 +197,7 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
// Check fields of a resulting process-definition
assertEquals(activitiDefinition.getId(), adhocDefinition.getId());
- assertEquals(activitiDefinition.getKey(), adhocDefinition.getKey());
+ assertEquals("activitiAdhoc", adhocDefinition.getKey());
assertEquals(activitiDefinition.getDeploymentId(), adhocDefinition.getDeploymentId());
assertEquals(activitiDefinition.getCategory(), adhocDefinition.getCategory());
assertEquals(activitiDefinition.getName(), adhocDefinition.getName());
@@ -254,10 +258,10 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
// Check well-known properties and their types
// Validate bpm:description
- JSONObject modelEntry = modelFieldsByName.get("bpm_description");
+ JSONObject modelEntry = modelFieldsByName.get("bpm_workflowDescription");
assertNotNull(modelEntry);
assertEquals("Description", modelEntry.get("title"));
- assertEquals("{http://www.alfresco.org/model/bpm/1.0}description", modelEntry.get("qualifiedName"));
+ assertEquals("{http://www.alfresco.org/model/bpm/1.0}workflowDescription", modelEntry.get("qualifiedName"));
assertEquals("d:text", modelEntry.get("dataType"));
assertFalse((Boolean)modelEntry.get("required"));
@@ -286,13 +290,13 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
assertFalse((Boolean)modelEntry.get("required"));
// Validate bpm:priority
- modelEntry = modelFieldsByName.get("bpm_priority");
+ modelEntry = modelFieldsByName.get("bpm_workflowPriority");
assertNotNull(modelEntry);
- assertEquals("Priority", modelEntry.get("title"));
- assertEquals("{http://www.alfresco.org/model/bpm/1.0}priority", modelEntry.get("qualifiedName"));
+ assertEquals("Workflow Priority", modelEntry.get("title"));
+ assertEquals("{http://www.alfresco.org/model/bpm/1.0}workflowPriority", modelEntry.get("qualifiedName"));
assertEquals("d:int", modelEntry.get("dataType"));
assertEquals("2", modelEntry.get("defaultValue"));
- assertTrue((Boolean)modelEntry.get("required"));
+ assertFalse((Boolean)modelEntry.get("required"));
// Validate bpm:package
modelEntry = modelFieldsByName.get("bpm_package");
@@ -301,6 +305,196 @@ public class ProcessDefinitionWorkflowApiTest extends EnterpriseWorkflowTestApi
assertEquals("{http://www.alfresco.org/model/bpm/1.0}package", modelEntry.get("qualifiedName"));
assertEquals("bpm:workflowPackage", modelEntry.get("dataType"));
assertFalse((Boolean)modelEntry.get("required"));
+
+ // Validate bpm:status
+ modelEntry = modelFieldsByName.get("bpm_status");
+ assertNotNull(modelEntry);
+ assertEquals("Status", modelEntry.get("title"));
+ assertEquals("{http://www.alfresco.org/model/bpm/1.0}status", modelEntry.get("qualifiedName"));
+ assertEquals("d:text", modelEntry.get("dataType"));
+ assertEquals("Not Yet Started", modelEntry.get("defaultValue"));
+ assertTrue((Boolean)modelEntry.get("required"));
+ JSONArray allowedValues = (JSONArray) modelEntry.get("allowedValues");
+ assertNotNull(allowedValues);
+ assertEquals(5, allowedValues.size());
+ assertTrue(allowedValues.contains("Not Yet Started"));
+ assertTrue(allowedValues.contains("In Progress"));
+ assertTrue(allowedValues.contains("On Hold"));
+ assertTrue(allowedValues.contains("Cancelled"));
+ assertTrue(allowedValues.contains("Completed"));
+ }
+
+ @Test
+ public void testGetProcessDefinitionStartModelUnexisting() throws Exception
+ {
+ initApiClientWithTestUser();
+ ProcessDefinitionsClient processDefinitionsClient = publicApiClient.processDefinitionsClient();
+ try
+ {
+ processDefinitionsClient.findStartFormModel("unexisting");
+ fail("Exception expected");
+ }
+ catch(PublicApiException expected)
+ {
+ assertEquals(HttpStatus.NOT_FOUND.value(), expected.getHttpResponse().getStatusCode());
+ assertErrorSummary("The entity with id: unexisting was not found", expected.getHttpResponse());
+ }
+ }
+
+ @Test
+ public void testMethodNotAllowedURIs() throws Exception
+ {
+ RequestContext requestContext = initApiClientWithTestUser();
+ HttpResponse response = publicApiClient.get("public", "process-definitions", null, null, null, null);
+ assertEquals(200, response.getStatusCode());
+ response = publicApiClient.post("public", "process-definitions", null, null, null, null);
+ assertEquals(405, response.getStatusCode());
+ response = publicApiClient.delete("public", "process-definitions", null, null, null);
+ assertEquals(405, response.getStatusCode());
+ response = publicApiClient.put("public", "process-definitions", null, null, null, null, null);
+ assertEquals(405, response.getStatusCode());
+
+ String adhocKey = createProcessDefinitionKey("activitiAdhoc", requestContext);
+ org.activiti.engine.repository.ProcessDefinition processDefinition = activitiProcessEngine.getRepositoryService()
+ .createProcessDefinitionQuery()
+ .processDefinitionKey(adhocKey)
+ .singleResult();
+
+ assertNotNull(processDefinition);
+
+ response = publicApiClient.get("public", "process-definitions", processDefinition.getId(), null, null, null);
+ assertEquals(200, response.getStatusCode());
+ response = publicApiClient.post("public", "process-definitions", processDefinition.getId(), null, null, null);
+ assertEquals(405, response.getStatusCode());
+ response = publicApiClient.delete("public", "process-definitions", processDefinition.getId(), null, null);
+ assertEquals(405, response.getStatusCode());
+ response = publicApiClient.put("public", "process-definitions", processDefinition.getId(), null, null, null, null);
+ assertEquals(405, response.getStatusCode());
+
+ response = publicApiClient.get("public", "process-definitions", processDefinition.getId(), "start-form-model", null, null);
+ assertEquals(200, response.getStatusCode());
+ response = publicApiClient.post("public", "process-definitions", processDefinition.getId(), "start-form-model", null, null);
+ assertEquals(405, response.getStatusCode());
+ response = publicApiClient.delete("public", "process-definitions", processDefinition.getId(), "start-form-model", null);
+ assertEquals(405, response.getStatusCode());
+ response = publicApiClient.put("public", "process-definitions", processDefinition.getId(), "start-form-model", null, null, null);
+ assertEquals(405, response.getStatusCode());
+ }
+
+ @Test
+ public void testAuthenticationAndAuthorization() throws Exception
+ {
+ // Fetching process definitions as admin should be possible
+ RequestContext requestContext = initApiClientWithTestUser();
+ String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId();
+ publicApiClient.setRequestContext(new RequestContext(requestContext.getNetworkId(), tenantAdmin));
+
+ ProcessDefinitionsClient processDefinitionsClient = publicApiClient.processDefinitionsClient();
+ ListResponse processDefinitionsResponse = processDefinitionsClient.getProcessDefinitions(null);
+ Map processDefinitionMap = getProcessDefinitionMapByKey(processDefinitionsResponse.getList());
+
+ assertTrue(processDefinitionMap.containsKey("activitiReviewPooled"));
+ assertTrue(processDefinitionMap.containsKey("activitiReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelGroupReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
+ assertEquals(5, processDefinitionMap.size());
+
+ // Fetching process definitions as admin from another tenant shouldn't be possible
+ TestNetwork anotherNetwork = getOtherNetwork(requestContext.getNetworkId());
+ tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + anotherNetwork.getId();
+ RequestContext otherContext = new RequestContext(anotherNetwork.getId(), tenantAdmin);
+ publicApiClient.setRequestContext(otherContext);
+
+ processDefinitionsResponse = processDefinitionsClient.getProcessDefinitions(null);
+ processDefinitionMap = getProcessDefinitionMapByKey(processDefinitionsResponse.getList());
+
+ // the response should contain process definitions from the new tenant
+ assertTrue(processDefinitionMap.containsKey("activitiReviewPooled"));
+ assertTrue(processDefinitionMap.containsKey("activitiReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelGroupReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiParallelReview"));
+ assertTrue(processDefinitionMap.containsKey("activitiAdhoc"));
+ assertEquals(5, processDefinitionMap.size());
+
+ // Fetching a specific process definitions as admin should be possible
+ publicApiClient.setRequestContext(requestContext);
+
+ String adhocKey = createProcessDefinitionKey("activitiAdhoc", requestContext);
+ org.activiti.engine.repository.ProcessDefinition activitiDefinition = activitiProcessEngine.getRepositoryService()
+ .createProcessDefinitionQuery()
+ .processDefinitionKey(adhocKey)
+ .singleResult();
+
+ assertNotNull(activitiDefinition);
+
+ // Get a single process definitions
+ ProcessDefinition adhocDefinition = processDefinitionsClient.findProcessDefinitionById(activitiDefinition.getId());
+ assertNotNull(adhocDefinition);
+
+ // Check fields of a resulting process-definition
+ assertEquals(activitiDefinition.getId(), adhocDefinition.getId());
+ assertEquals("activitiAdhoc", adhocDefinition.getKey());
+ assertEquals(activitiDefinition.getDeploymentId(), adhocDefinition.getDeploymentId());
+ assertEquals(activitiDefinition.getCategory(), adhocDefinition.getCategory());
+ assertEquals(activitiDefinition.getName(), adhocDefinition.getName());
+ assertEquals(activitiDefinition.getVersion(), adhocDefinition.getVersion());
+ assertEquals(((ProcessDefinitionEntity) activitiDefinition).isGraphicalNotationDefined(), adhocDefinition.isGraphicNotationDefined());
+ assertEquals("wf:submitAdhocTask", adhocDefinition.getStartFormResourceKey());
+
+ // Fetching a specific process definitions as admin from another tenant should not be possible
+ publicApiClient.setRequestContext(otherContext);
+ try
+ {
+ adhocDefinition = processDefinitionsClient.findProcessDefinitionById(activitiDefinition.getId());
+ fail("not found expected");
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.NOT_FOUND.value(), e.getHttpResponse().getStatusCode());
+ }
+
+ // Fetching the start form model of a process definition as admin should be possible
+ publicApiClient.setRequestContext(requestContext);
+ JSONObject model = processDefinitionsClient.findStartFormModel(activitiDefinition.getId());
+ assertNotNull(model);
+
+ JSONArray entries = (JSONArray) model.get("entries");
+ assertNotNull(entries);
+
+ // Add all entries to a map, to make lookup easier
+ Map modelFieldsByName = new HashMap();
+ JSONObject entry = null;
+ for(int i=0; i processDefinitionsResponse = processDefinitionsClient.getProcessDefinitions(params);
return getProcessDefinitionMapByKey(processDefinitionsResponse.getList());
}
diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java
index 927a0f9909..6450186ad8 100644
--- a/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java
+++ b/source/test-java/org/alfresco/rest/workflow/api/tests/ProcessWorkflowApiTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -31,9 +32,11 @@ import java.util.Map;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.task.Task;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.repo.workflow.activiti.ActivitiScriptNode;
+import org.alfresco.rest.api.tests.RepoService.TestNetwork;
import org.alfresco.rest.api.tests.client.PublicApiClient.ListResponse;
import org.alfresco.rest.api.tests.client.PublicApiException;
import org.alfresco.rest.api.tests.client.RequestContext;
@@ -47,7 +50,6 @@ import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.junit.Test;
import org.springframework.http.HttpStatus;
-
/**
* Process related Rest api tests using http client to communicate with the rest apis in the repository.
*
@@ -89,10 +91,41 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
createProcessObject.put("variables", variablesObject);
- final ProcessInfo processRest = processesClient.createProcess(createProcessObject.toJSONString());
+ ProcessInfo processRest = processesClient.createProcess(createProcessObject.toJSONString());
+ assertNotNull(processRest);
+ assertNotNull(processRest.getId());
+
+ HistoricProcessInstance processInstance = activitiProcessEngine.getHistoryService().createHistoricProcessInstanceQuery()
+ .processInstanceId(processRest.getId()).singleResult();
+
+ assertEquals(processInstance.getId(), processRest.getId());
+ assertEquals(processInstance.getStartActivityId(), processRest.getStartActivityId());
+ assertEquals(processInstance.getStartUserId(), processRest.getStartUserId());
+ assertEquals(processInstance.getStartTime(), processRest.getStartedAt());
+ assertEquals(processInstance.getProcessDefinitionId(), processRest.getProcessDefinitionId());
+ assertEquals("activitiAdhoc", processRest.getProcessDefinitionKey());
+ assertNull(processRest.getBusinessKey());
+ assertNull(processRest.getDeleteReason());
+ assertNull(processRest.getDurationInMs());
+ assertNull(processRest.getEndActivityId());
+ assertNull(processRest.getEndedAt());
+ assertNull(processRest.getSuperProcessInstanceId());
+
+ Map variables = activitiProcessEngine.getRuntimeService().getVariables(processRest.getId());
+
+ assertEquals("test description", variables.get("bpm_description"));
+ assertEquals(1, variables.get("bpm_priority"));
+
+ cleanupProcessInstance(processRest.getId());
+
+ // Test same create method with an admin user
+ String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId();
+ publicApiClient.setRequestContext(new RequestContext(requestContext.getNetworkId(), tenantAdmin));
+
+ processRest = processesClient.createProcess(createProcessObject.toJSONString());
assertNotNull(processRest);
- final Map variables = activitiProcessEngine.getRuntimeService().getVariables(processRest.getId());
+ variables = activitiProcessEngine.getRuntimeService().getVariables(processRest.getId());
assertEquals("test description", variables.get("bpm_description"));
assertEquals(1, variables.get("bpm_priority"));
@@ -100,6 +133,7 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
cleanupProcessInstance(processRest.getId());
// Try with unexisting process definition ID
+ publicApiClient.setRequestContext(requestContext);
createProcessObject = new JSONObject();
createProcessObject.put("processDefinitionId", "unexisting");
try
@@ -145,13 +179,29 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
ProcessInfo processRest = processesClient.createProcess(createProcessObject.toJSONString());
assertNotNull(processRest);
- final Map variables = activitiProcessEngine.getRuntimeService().getVariables(processRest.getId());
+ Map variables = activitiProcessEngine.getRuntimeService().getVariables(processRest.getId());
assertEquals("test description", variables.get("bpm_description"));
assertEquals(1, variables.get("bpm_priority"));
cleanupProcessInstance(processRest.getId());
+ // Test same create method with an admin user
+ String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId();
+ publicApiClient.setRequestContext(new RequestContext(requestContext.getNetworkId(), tenantAdmin));
+
+ processRest = processesClient.createProcess(createProcessObject.toJSONString());
+ assertNotNull(processRest);
+
+ variables = activitiProcessEngine.getRuntimeService().getVariables(processRest.getId());
+
+ assertEquals("test description", variables.get("bpm_description"));
+ assertEquals(1, variables.get("bpm_priority"));
+
+ cleanupProcessInstance(processRest.getId());
+
+ // Test create process with wrong key
+ publicApiClient.setRequestContext(requestContext);
createProcessObject = new JSONObject();
createProcessObject.put("processDefinitionKey", "activitiAdhoc2");
@@ -168,6 +218,61 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
}
}
+ @Test
+ public void testCreateProcessInstanceForPooledReview() throws Exception
+ {
+ final RequestContext requestContext = initApiClientWithTestUser();
+ final ProcessInfo processInfo = startReviewPooledProcess(requestContext);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testCreateProcessInstanceFormOtherNetwork() throws Exception
+ {
+ final RequestContext requestContext = initApiClientWithTestUser();
+
+ org.activiti.engine.repository.ProcessDefinition processDefinition = activitiProcessEngine
+ .getRepositoryService()
+ .createProcessDefinitionQuery()
+ .processDefinitionKey("@" + requestContext.getNetworkId() + "@activitiAdhoc")
+ .singleResult();
+
+ TestNetwork anotherNetwork = getOtherNetwork(requestContext.getNetworkId());
+ String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + anotherNetwork.getId();
+ RequestContext otherContext = new RequestContext(anotherNetwork.getId(), tenantAdmin);
+ publicApiClient.setRequestContext(otherContext);
+
+ ProcessesClient processesClient = publicApiClient.processesClient();
+
+ JSONObject createProcessObject = new JSONObject();
+ createProcessObject.put("processDefinitionId", processDefinition.getId());
+ final JSONObject variablesObject = new JSONObject();
+ variablesObject.put("bpm_dueDate", ISO8601DateFormat.format(new Date()));
+ variablesObject.put("bpm_priority", 1);
+ variablesObject.put("bpm_description", "test description");
+ TenantUtil.runAsUserTenant(new TenantRunAsWork()
+ {
+ @Override
+ public Void doWork() throws Exception
+ {
+ variablesObject.put("bpm_assignee", requestContext.getRunAsUser());
+ return null;
+ }
+ }, requestContext.getRunAsUser(), requestContext.getNetworkId());
+
+
+ createProcessObject.put("variables", variablesObject);
+
+ try
+ {
+ processesClient.createProcess(createProcessObject.toJSONString());
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.BAD_REQUEST.value(), e.getHttpResponse().getStatusCode());
+ }
+ }
+
@Test
public void testCreateProcessInstanceWithItems() throws Exception
{
@@ -236,15 +341,73 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
ProcessInfo processInfo = processesClient.findProcessById(process.getId());
assertNotNull(processInfo);
- assertEquals(process.getId(), processInfo.getId());
- assertEquals(process.getBusinessKey(), processInfo.getBusinessKey());
+ final Map variables = activitiProcessEngine.getRuntimeService().getVariables(processInfo.getId());
+ assertEquals(1, variables.get("bpm_priority"));
+
+ HistoricProcessInstance processInstance = activitiProcessEngine.getHistoryService().createHistoricProcessInstanceQuery()
+ .processInstanceId(processInfo.getId()).singleResult();
+
+ assertNotNull(processInfo.getId());
+ assertEquals(processInstance.getId(), processInfo.getId());
+ assertNotNull(processInfo.getStartActivityId());
+ assertEquals(processInstance.getStartActivityId(), processInfo.getStartActivityId());
+ assertNotNull(processInfo.getStartUserId());
+ assertEquals(processInstance.getStartUserId(), processInfo.getStartUserId());
+ assertNotNull(processInfo.getStartedAt());
+ assertEquals(processInstance.getStartTime(), processInfo.getStartedAt());
+ assertNotNull(processInfo.getProcessDefinitionId());
+ assertEquals(processInstance.getProcessDefinitionId(), processInfo.getProcessDefinitionId());
+ assertNotNull(processInfo.getProcessDefinitionKey());
+ assertEquals("activitiAdhoc", processInfo.getProcessDefinitionKey());
+ assertNull(processInfo.getBusinessKey());
assertNull(processInfo.getDeleteReason());
- assertEquals(process.getDurationInMillis(), processInfo.getDurationInMillis());
- assertEquals(process.getEndedAt(), processInfo.getEndedAt());
- assertEquals(process.getProcessDefinitionId(), processInfo.getProcessDefinitionId());
- assertEquals(process.getProcessDefinitionKey(), processInfo.getProcessDefinitionKey());
- assertEquals(process.getStartedAt(), processInfo.getStartedAt());
- assertEquals(process.getSuperProcessInstanceId(), processInfo.getSuperProcessInstanceId());
+ assertNull(processInfo.getDurationInMs());
+ assertNull(processInfo.getEndActivityId());
+ assertNull(processInfo.getEndedAt());
+ assertNull(processInfo.getSuperProcessInstanceId());
+ assertFalse(processInfo.isCompleted());
+
+ TenantUtil.runAsUserTenant(new TenantRunAsWork()
+ {
+ @Override
+ public Void doWork() throws Exception
+ {
+ // now complete the process and see if ending info is available in the REST response
+ Task task = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(process.getId()).singleResult();
+ activitiProcessEngine.getTaskService().complete(task.getId());
+ task = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(process.getId()).singleResult();
+ activitiProcessEngine.getTaskService().complete(task.getId());
+ return null;
+ }
+ }, requestContext.getRunAsUser(), requestContext.getNetworkId());
+
+ processInstance = activitiProcessEngine.getHistoryService().createHistoricProcessInstanceQuery()
+ .processInstanceId(processInfo.getId()).singleResult();
+
+ processInfo = processesClient.findProcessById(processInfo.getId());
+
+ assertNotNull(processInfo.getId());
+ assertEquals(processInstance.getId(), processInfo.getId());
+ assertNotNull(processInfo.getStartActivityId());
+ assertEquals(processInstance.getStartActivityId(), processInfo.getStartActivityId());
+ assertNotNull(processInfo.getStartUserId());
+ assertEquals(processInstance.getStartUserId(), processInfo.getStartUserId());
+ assertNotNull(processInfo.getStartedAt());
+ assertEquals(processInstance.getStartTime(), processInfo.getStartedAt());
+ assertNotNull(processInfo.getProcessDefinitionId());
+ assertEquals(processInstance.getProcessDefinitionId(), processInfo.getProcessDefinitionId());
+ assertNotNull(processInfo.getProcessDefinitionKey());
+ assertEquals("activitiAdhoc", processInfo.getProcessDefinitionKey());
+ assertNull(processInfo.getBusinessKey());
+ assertNull(processInfo.getDeleteReason());
+ assertNotNull(processInfo.getDurationInMs());
+ assertEquals(processInstance.getDurationInMillis(), processInfo.getDurationInMs());
+ assertNotNull(processInfo.getEndActivityId());
+ assertEquals(processInstance.getEndActivityId(), processInfo.getEndActivityId());
+ assertNotNull(processInfo.getEndedAt());
+ assertEquals(processInstance.getEndTime(), processInfo.getEndedAt());
+ assertNull(processInfo.getSuperProcessInstanceId());
+ assertTrue(processInfo.isCompleted());
}
finally
{
@@ -271,9 +434,18 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
public void testDeleteProcessInstanceById() throws Exception
{
final RequestContext requestContext = initApiClientWithTestUser();
+
+ String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId();
+ final RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin);
+
+ TestNetwork anotherNetwork = getOtherNetwork(requestContext.getNetworkId());
+ tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + anotherNetwork.getId();
+ final RequestContext otherContext = new RequestContext(anotherNetwork.getId(), tenantAdmin);
+
ProcessesClient processesClient = publicApiClient.processesClient();
- final ProcessInfo process = startAdhocProcess(requestContext, null);
+ // delete with user starting the process instance
+ ProcessInfo process = startAdhocProcess(requestContext, null);
try
{
processesClient.deleteProcessById(process.getId());
@@ -292,6 +464,45 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
{
cleanupProcessInstance(process.getId());
}
+
+ // delete with admin in same network as the user starting the process instance
+ process = startAdhocProcess(requestContext, null);
+ try
+ {
+ publicApiClient.setRequestContext(adminContext);
+ processesClient.deleteProcessById(process.getId());
+
+ // Check if the process was actually deleted
+ assertNull(activitiProcessEngine.getRuntimeService().createProcessInstanceQuery()
+ .processInstanceId(process.getId()).singleResult());
+
+ HistoricProcessInstance deletedInstance = activitiProcessEngine.getHistoryService()
+ .createHistoricProcessInstanceQuery().processInstanceId(process.getId()).singleResult();
+ assertNotNull(deletedInstance);
+ assertNotNull(deletedInstance.getEndTime());
+ assertNull(deletedInstance.getDeleteReason());
+ }
+ finally
+ {
+ cleanupProcessInstance(process.getId());
+ }
+
+ // delete with admin from other network as the user starting the process instance
+ process = startAdhocProcess(requestContext, null);
+ try
+ {
+ publicApiClient.setRequestContext(otherContext);
+ processesClient.deleteProcessById(process.getId());
+ fail("Expect permission exception");
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.FORBIDDEN.value(), e.getHttpResponse().getStatusCode());
+ }
+ finally
+ {
+ cleanupProcessInstance(process.getId());
+ }
}
@Test
@@ -409,20 +620,297 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
// Test the variable where-clause
paramMap = new HashMap();
- paramMap.put("where", "(variables/bpm_priority = 'd_int 1'))");
+ paramMap.put("where", "(variables/bpm_priority = 'd_int 1')");
processList = processesClient.getProcesses(paramMap);
assertNotNull(processList);
assertEquals(3, processList.getList().size());
paramMap = new HashMap();
- paramMap.put("where", "(variables/bpm_priority = 'd_int 5'))");
+ paramMap.put("where", "(variables/bpm_priority = 'd:int 1')");
+ processList = processesClient.getProcesses(paramMap);
+ assertNotNull(processList);
+ assertEquals(3, processList.getList().size());
+
+ paramMap = new HashMap();
+ paramMap.put("where", "(variables/bpm_priority = 'd_int 5')");
processList = processesClient.getProcesses(paramMap);
assertNotNull(processList);
assertEquals(0, processList.getList().size());
+ // test with date variable
+ Calendar dateCal = Calendar.getInstance();
+ Map variablesToSet = new HashMap();
+ variablesToSet.put("testVarDate", dateCal.getTime());
+
+ activitiProcessEngine.getRuntimeService().setVariables(process1.getId(), variablesToSet);
+ paramMap = new HashMap();
+ paramMap.put("where", "(variables/testVarDate = 'd_datetime " + ISO8601DateFormat.format(dateCal.getTime())+ "')");
+ processList = processesClient.getProcesses(paramMap);
+ assertNotNull(processList);
+ assertEquals(1, processList.getList().size());
+
cleanupProcessInstance(process1.getId(), process2.getId(), process3.getId());
}
+ // No sorting support yet
+ /*@Test
+ public void testGetProcessInstancesWithSorting() throws Exception
+ {
+ final RequestContext requestContext = initApiClientWithTestUser();
+
+ final ProcessInfo process1 = startAdhocProcess(requestContext, null, "akey");
+ final ProcessInfo process2 = startAdhocProcess(requestContext, null, "bkey");
+ final ProcessInfo process3 = startAdhocProcess(requestContext, null, "aakey");
+
+ try
+ {
+ // sort on business key ascending
+ ProcessesClient processesClient = publicApiClient.processesClient();
+ Map paramMap = new HashMap();
+ paramMap.put("sort", "businessKey");
+ paramMap.put("sortOrder", "asc");
+ ListResponse processList = processesClient.getProcesses(paramMap);
+ assertNotNull(processList);
+ assertEquals(3, processList.getList().size());
+
+ assertEquals(process3.getId(), processList.getList().get(0).getId());
+ assertEquals(process1.getId(), processList.getList().get(1).getId());
+ assertEquals(process2.getId(), processList.getList().get(2).getId());
+
+ // sort on business key descending
+ paramMap.put("sort", "businessKey");
+ paramMap.put("sortOrder", "desc");
+ processList = processesClient.getProcesses(paramMap);
+ assertNotNull(processList);
+ assertEquals(3, processList.getList().size());
+
+ assertEquals(process2.getId(), processList.getList().get(0).getId());
+ assertEquals(process1.getId(), processList.getList().get(1).getId());
+ assertEquals(process3.getId(), processList.getList().get(2).getId());
+
+ // sort on non existing key
+ paramMap.put("sort", "businessKey2");
+ try
+ {
+ processList = processesClient.getProcesses(paramMap);
+ fail();
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.BAD_REQUEST.value(), e.getHttpResponse().getStatusCode());
+ }
+
+ // sort on non existing sort order
+ paramMap.put("sort", "businessKey");
+ paramMap.put("sortOrder", "asc2");
+ try
+ {
+ processList = processesClient.getProcesses(paramMap);
+ fail();
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.BAD_REQUEST.value(), e.getHttpResponse().getStatusCode());
+ }
+ }
+ finally
+ {
+ cleanupProcessInstance(process1.getId(), process2.getId(), process3.getId());
+ }
+ }*/
+
+ @Test
+ public void testGetProcessTasks() throws Exception
+ {
+ final RequestContext requestContext = initApiClientWithTestUser();
+
+ String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId();
+ final RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin);
+
+ TestNetwork anotherNetwork = getOtherNetwork(requestContext.getNetworkId());
+ tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + anotherNetwork.getId();
+ final RequestContext otherContext = new RequestContext(anotherNetwork.getId(), tenantAdmin);
+
+ final ProcessInfo process1 = startAdhocProcess(requestContext, null);
+
+ try
+ {
+ ProcessesClient processesClient = publicApiClient.processesClient();
+ Map paramMap = new HashMap();
+ JSONObject tasksJSON = processesClient.getTasks(process1.getId(), paramMap);
+ assertNotNull(tasksJSON);
+ JSONArray entriesJSON = (JSONArray) tasksJSON.get("entries");
+ assertNotNull(entriesJSON);
+ assertTrue(entriesJSON.size() == 1);
+ JSONObject taskJSONObject = (JSONObject) ((JSONObject) entriesJSON.get(0)).get("entry");
+ assertNotNull(taskJSONObject.get("id"));
+ assertEquals(process1.getId(), taskJSONObject.get("processId"));
+ assertEquals(process1.getProcessDefinitionId(), taskJSONObject.get("processDefinitionId"));
+ assertEquals("adhocTask", taskJSONObject.get("activityDefinitionId"));
+ assertEquals("Adhoc Task", taskJSONObject.get("name"));
+ assertEquals(requestContext.getRunAsUser(), taskJSONObject.get("assignee"));
+ assertEquals(2l, taskJSONObject.get("priority"));
+ assertEquals("wf:adhocTask", taskJSONObject.get("formResourceKey"));
+ assertNull(taskJSONObject.get("endedAt"));
+ assertNull(taskJSONObject.get("durationInMs"));
+
+ paramMap = new HashMap();
+ paramMap.put("status", "active");
+ tasksJSON = processesClient.getTasks(process1.getId(), paramMap);
+ assertNotNull(tasksJSON);
+ entriesJSON = (JSONArray) tasksJSON.get("entries");
+ assertNotNull(entriesJSON);
+ assertTrue(entriesJSON.size() == 1);
+
+ paramMap = new HashMap();
+ paramMap.put("status", "completed");
+ tasksJSON = processesClient.getTasks(process1.getId(), paramMap);
+ assertNotNull(tasksJSON);
+ entriesJSON = (JSONArray) tasksJSON.get("entries");
+ assertNotNull(entriesJSON);
+ assertTrue(entriesJSON.size() == 0);
+
+ paramMap = new HashMap();
+ try {
+ processesClient.getTasks("fakeid", paramMap);
+ fail("Exception expected");
+ } catch(PublicApiException expected) {
+ assertEquals(HttpStatus.NOT_FOUND.value(), expected.getHttpResponse().getStatusCode());
+ assertErrorSummary("The entity with id: fakeid was not found", expected.getHttpResponse());
+ }
+
+ // get tasks with admin from the same tenant as the process initiator
+ publicApiClient.setRequestContext(adminContext);
+ paramMap = new HashMap();
+ tasksJSON = processesClient.getTasks(process1.getId(), paramMap);
+ assertNotNull(tasksJSON);
+ entriesJSON = (JSONArray) tasksJSON.get("entries");
+ assertNotNull(entriesJSON);
+ assertTrue(entriesJSON.size() == 1);
+
+ // get tasks with admin from another tenant as the process initiator
+ publicApiClient.setRequestContext(otherContext);
+ paramMap = new HashMap();
+ try
+ {
+ tasksJSON = processesClient.getTasks(process1.getId(), paramMap);
+ fail("forbidden expected");
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.FORBIDDEN.value(), e.getHttpResponse().getStatusCode());
+ }
+ }
+ finally
+ {
+ cleanupProcessInstance(process1.getId());
+ }
+ }
+
+ @Test
+ public void testGetProcessActivities() throws Exception
+ {
+ final RequestContext requestContext = initApiClientWithTestUser();
+
+ String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId();
+ final RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin);
+
+ TestNetwork anotherNetwork = getOtherNetwork(requestContext.getNetworkId());
+ tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + anotherNetwork.getId();
+ final RequestContext otherContext = new RequestContext(anotherNetwork.getId(), tenantAdmin);
+
+ final ProcessInfo process1 = startAdhocProcess(requestContext, null);
+
+ try
+ {
+ ProcessesClient processesClient = publicApiClient.processesClient();
+ Map paramMap = new HashMap();
+ JSONObject activitiesJSON = processesClient.getActivities(process1.getId(), paramMap);
+ assertNotNull(activitiesJSON);
+ JSONArray entriesJSON = (JSONArray) activitiesJSON.get("entries");
+ assertNotNull(entriesJSON);
+ assertTrue(entriesJSON.size() == 2);
+
+ Map activitiesMap = new HashMap();
+ for (Object entry : entriesJSON) {
+ JSONObject jsonEntry = (JSONObject) entry;
+ JSONObject activityJSONObject = (JSONObject) jsonEntry.get("entry");
+ activitiesMap.put((String) activityJSONObject.get("activityDefinitionId"), activityJSONObject);
+ }
+
+ JSONObject activityJSONObject = activitiesMap.get("start");
+ assertNotNull(activityJSONObject);
+ assertNotNull(activityJSONObject.get("id"));
+ assertEquals("start", activityJSONObject.get("activityDefinitionId"));
+ assertNull(activityJSONObject.get("activityDefinitionName"));
+ assertEquals("startEvent", activityJSONObject.get("activityDefinitionType"));
+ assertNotNull(activityJSONObject.get("startedAt"));
+ assertNotNull(activityJSONObject.get("endedAt"));
+ assertNotNull(activityJSONObject.get("durationInMs"));
+
+ activityJSONObject = activitiesMap.get("adhocTask");
+ assertNotNull(activityJSONObject);
+ assertNotNull(activityJSONObject.get("id"));
+ assertEquals("adhocTask", activityJSONObject.get("activityDefinitionId"));
+ assertEquals("Adhoc Task", activityJSONObject.get("activityDefinitionName"));
+ assertEquals("userTask", activityJSONObject.get("activityDefinitionType"));
+ assertNotNull(activityJSONObject.get("startedAt"));
+ assertNull(activityJSONObject.get("endedAt"));
+ assertNull(activityJSONObject.get("durationInMs"));
+
+ paramMap = new HashMap();
+ paramMap.put("status", "active");
+ activitiesJSON = processesClient.getActivities(process1.getId(), paramMap);
+ assertNotNull(activitiesJSON);
+ entriesJSON = (JSONArray) activitiesJSON.get("entries");
+ assertNotNull(entriesJSON);
+ assertTrue(entriesJSON.size() == 1);
+
+ paramMap = new HashMap();
+ paramMap.put("status", "completed");
+ activitiesJSON = processesClient.getActivities(process1.getId(), paramMap);
+ assertNotNull(activitiesJSON);
+ entriesJSON = (JSONArray) activitiesJSON.get("entries");
+ assertNotNull(entriesJSON);
+ assertTrue(entriesJSON.size() == 1);
+
+ paramMap = new HashMap();
+ try {
+ processesClient.getActivities("fakeid", paramMap);
+ fail("Exception expected");
+ } catch(PublicApiException expected) {
+ assertEquals(HttpStatus.NOT_FOUND.value(), expected.getHttpResponse().getStatusCode());
+ assertErrorSummary("The entity with id: fakeid was not found", expected.getHttpResponse());
+ }
+
+ // get activities with admin from the same tenant as the process initiator
+ publicApiClient.setRequestContext(adminContext);
+ paramMap = new HashMap();
+ activitiesJSON = processesClient.getActivities(process1.getId(), paramMap);
+ assertNotNull(activitiesJSON);
+ entriesJSON = (JSONArray) activitiesJSON.get("entries");
+ assertNotNull(entriesJSON);
+ assertTrue(entriesJSON.size() == 2);
+
+ // get tasks with admin from another tenant as the process initiator
+ publicApiClient.setRequestContext(otherContext);
+ paramMap = new HashMap();
+ try
+ {
+ processesClient.getActivities(process1.getId(), paramMap);
+ fail("forbidden expected");
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.FORBIDDEN.value(), e.getHttpResponse().getStatusCode());
+ }
+ }
+ finally
+ {
+ cleanupProcessInstance(process1.getId());
+ }
+ }
+
@Test
public void testGetProcessItems() throws Exception
{
@@ -447,7 +935,7 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
JSONObject entryJSON = (JSONObject) entryObjectJSON.get("entry");
if (entryJSON.get("name").equals("Test Doc1")) {
doc1Found = true;
- assertEquals(docNodeRefs[0].toString(), entryJSON.get("id"));
+ assertEquals(docNodeRefs[0].getId(), entryJSON.get("id"));
assertEquals("Test Doc1", entryJSON.get("name"));
assertEquals("Test Doc1 Title", entryJSON.get("title"));
assertEquals("Test Doc1 Description", entryJSON.get("description"));
@@ -459,7 +947,7 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
assertNotNull(entryJSON.get("mimeType"));
} else {
doc2Found = true;
- assertEquals(docNodeRefs[1].toString(), entryJSON.get("id"));
+ assertEquals(docNodeRefs[1].getId(), entryJSON.get("id"));
assertEquals("Test Doc2", entryJSON.get("name"));
assertEquals("Test Doc2 Title", entryJSON.get("title"));
assertEquals("Test Doc2 Description", entryJSON.get("description"));
@@ -488,10 +976,11 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
final String newProcessInstanceId = processRest.getId();
ProcessesClient processesClient = publicApiClient.processesClient();
- JSONObject itemJSON = processesClient.findProcessItem(newProcessInstanceId, docNodeRefs[0].toString());
+ System.out.println("node ref " + docNodeRefs[0].toString());
+ JSONObject itemJSON = processesClient.findProcessItem(newProcessInstanceId, docNodeRefs[0].getId());
assertNotNull(itemJSON);
- assertEquals(docNodeRefs[0].toString(), itemJSON.get("id"));
+ assertEquals(docNodeRefs[0].getId(), itemJSON.get("id"));
assertEquals("Test Doc1", itemJSON.get("name"));
assertEquals("Test Doc1 Title", itemJSON.get("title"));
assertEquals("Test Doc1 Description", itemJSON.get("description"));
@@ -505,6 +994,61 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
cleanupProcessInstance(processRest.getId());
}
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testAddProcessItem() throws Exception
+ {
+ final RequestContext requestContext = initApiClientWithTestUser();
+
+ NodeRef[] docNodeRefs = createTestDocuments(requestContext);
+ final ProcessInfo processRest = startAdhocProcess(requestContext, null);
+ try
+ {
+ assertNotNull(processRest);
+
+ final String newProcessInstanceId = processRest.getId();
+ ProcessesClient processesClient = publicApiClient.processesClient();
+
+ JSONObject createItemObject = new JSONObject();
+ createItemObject.put("id", docNodeRefs[0].getId());
+
+ // Add the item
+ processesClient.addProcessItem(newProcessInstanceId, createItemObject.toJSONString());
+
+ // Fetching the item
+ JSONObject itemJSON = publicApiClient.processesClient().findProcessItem(newProcessInstanceId, docNodeRefs[0].getId());
+ assertEquals(docNodeRefs[0].getId(), itemJSON.get("id"));
+ assertEquals("Test Doc1", itemJSON.get("name"));
+ assertEquals("Test Doc1 Title", itemJSON.get("title"));
+ assertEquals("Test Doc1 Description", itemJSON.get("description"));
+ assertNotNull(itemJSON.get("createdAt"));
+ assertEquals(requestContext.getRunAsUser(), itemJSON.get("createdBy"));
+ assertNotNull(itemJSON.get("modifiedAt"));
+ assertEquals(requestContext.getRunAsUser(), itemJSON.get("modifiedBy"));
+ assertNotNull(itemJSON.get("size"));
+ assertNotNull(itemJSON.get("mimeType"));
+
+ // add non existing item
+ createItemObject = new JSONObject();
+ createItemObject.put("id", "blablabla");
+
+ // Add the item
+ try
+ {
+ processesClient.addProcessItem(newProcessInstanceId, createItemObject.toJSONString());
+ fail("not found expected");
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.NOT_FOUND.value(), e.getHttpResponse().getStatusCode());
+ }
+ }
+ finally
+ {
+ cleanupProcessInstance(processRest.getId());
+ }
+ }
+
@Test
public void testDeleteProcessItem() throws Exception
{
@@ -520,16 +1064,31 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
ProcessesClient processesClient = publicApiClient.processesClient();
// Delete the item
- processesClient.deleteProcessItem(newProcessInstanceId, docNodeRefs[0].toString());
+ processesClient.deleteProcessItem(newProcessInstanceId, docNodeRefs[0].getId());
// Fetching the item should result in 404
- try {
- publicApiClient.processesClient().findProcessItem(newProcessInstanceId, docNodeRefs[0].toString());
+ try
+ {
+ publicApiClient.processesClient().findProcessItem(newProcessInstanceId, docNodeRefs[0].getId());
fail("Exception expected");
- } catch(PublicApiException expected) {
+ }
+ catch(PublicApiException expected)
+ {
assertEquals(HttpStatus.NOT_FOUND.value(), expected.getHttpResponse().getStatusCode());
- assertErrorSummary("The entity with id: " + docNodeRefs[0].toString() + " was not found", expected.getHttpResponse());
+ assertErrorSummary("The entity with id: " + docNodeRefs[0].getId() + " was not found", expected.getHttpResponse());
}
+
+ // Deleting the item again should give an error
+ try
+ {
+ processesClient.deleteProcessItem(newProcessInstanceId, docNodeRefs[0].getId());
+ fail("Expected not found");
+ }
+ catch (PublicApiException e)
+ {
+ assertEquals(HttpStatus.NOT_FOUND.value(), e.getHttpResponse().getStatusCode());
+ }
+
}
finally
{
@@ -542,6 +1101,13 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
{
RequestContext requestContext = initApiClientWithTestUser();
+ String tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + requestContext.getNetworkId();
+ RequestContext adminContext = new RequestContext(requestContext.getNetworkId(), tenantAdmin);
+
+ TestNetwork anotherNetwork = getOtherNetwork(requestContext.getNetworkId());
+ tenantAdmin = AuthenticationUtil.getAdminUserName() + "@" + anotherNetwork.getId();
+ final RequestContext otherContext = new RequestContext(anotherNetwork.getId(), tenantAdmin);
+
ProcessInfo processRest = startAdhocProcess(requestContext, null);
try
@@ -551,46 +1117,36 @@ public class ProcessWorkflowApiTest extends EnterpriseWorkflowTestApi
JSONObject processvariables = publicApiClient.processesClient().getProcessvariables(processInstanceId);
assertNotNull(processvariables);
+ validateVariablesResponse(processvariables, requestContext.getRunAsUser());
- // Add process variables to map for easy lookup
- Map variablesByName = new HashMap();
- JSONObject entry = null;
- JSONArray entries = (JSONArray) processvariables.get("entries");
- assertNotNull(entries);
- for(int i=0; i variablesByName = new HashMap();
+ JSONObject entry = null;
+ JSONArray entries = (JSONArray) processvariables.get("entries");
+ assertNotNull(entries);
+ for(int i=0; i
processesRest.setProcessDefinitionKey((String) entry.get("processDefinitionKey"));
processesRest.setStartedAt(WorkflowApiClient.parseDate(entry, "startedAt"));
processesRest.setEndedAt(WorkflowApiClient.parseDate(entry, "endedAt"));
- processesRest.setDurationInMillis((Long) entry.get("durationInMillis"));
+ processesRest.setDurationInMs((Long) entry.get("durationInMs"));
processesRest.setDeleteReason((String) entry.get("deleteReason"));
processesRest.setBusinessKey((String) entry.get("businessKey"));
processesRest.setSuperProcessInstanceId((String) entry.get("superProcessInstanceId"));
+ processesRest.setStartActivityId((String) entry.get("startActivityId"));
+ processesRest.setStartUserId((String) entry.get("startUserId"));
+ processesRest.setEndActivityId((String) entry.get("endActivityId"));
+ processesRest.setCompleted((Boolean) entry.get("completed"));
processesRest.setVariables((Map) entry.get("variables"));
processesRest.setItems((Set) entry.get("item"));
return processesRest;
diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java b/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java
index a1f1113c82..e8e859e365 100644
--- a/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java
+++ b/source/test-java/org/alfresco/rest/workflow/api/tests/TaskWorkflowApiTest.java
@@ -31,7 +31,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -50,7 +49,6 @@ import org.alfresco.repo.workflow.WorkflowConstants;
import org.alfresco.repo.workflow.activiti.ActivitiConstants;
import org.alfresco.repo.workflow.activiti.ActivitiScriptNode;
import org.alfresco.rest.api.tests.RepoService.TestNetwork;
-import org.alfresco.rest.api.tests.RepoService.TestPerson;
import org.alfresco.rest.api.tests.client.PublicApiException;
import org.alfresco.rest.api.tests.client.RequestContext;
import org.alfresco.rest.api.tests.client.data.MemberOfSite;
@@ -806,6 +804,53 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
}
}
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testChangeDueDate() throws Exception
+ {
+ RequestContext requestContext = initApiClientWithTestUser();
+ ProcessInstance processInstance = startAdhocProcess(requestContext.getRunAsUser(), requestContext.getNetworkId(), null);
+ try
+ {
+ Task task = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
+
+ TasksClient tasksClient = publicApiClient.tasksClient();
+ JSONObject taskObject = tasksClient.findTaskById(task.getId());
+ assertNull(taskObject.get("dueAt"));
+
+ List selectedFields = new ArrayList();
+ selectedFields.addAll(Arrays.asList(new String[] { "name", "description", "dueAt", "priority", "assignee", "owner"}));
+
+ // set due date
+ JSONObject taskBody = new JSONObject();
+ String dueAt = formatDate(new Date());
+ taskBody.put("dueAt", dueAt);
+ tasksClient.updateTask(task.getId(), taskBody, selectedFields);
+
+ taskObject = tasksClient.findTaskById(task.getId());
+ assertNotNull(taskObject.get("dueAt"));
+
+ taskBody = new JSONObject();
+ taskBody.put("dueAt", taskObject.get("dueAt"));
+ tasksClient.updateTask(task.getId(), taskBody, selectedFields);
+
+ taskObject = tasksClient.findTaskById(task.getId());
+ assertNotNull(taskObject.get("dueAt"));
+
+ JSONObject variableBody = new JSONObject();
+ variableBody.put("name", "bpm_workflowDueDate");
+ variableBody.put("value", formatDate(new Date()));
+ variableBody.put("type", "d:datetime");
+ variableBody.put("scope", "global");
+
+ tasksClient.updateTaskVariable(task.getId(), "bpm_workflowDueDate", variableBody);
+ }
+ finally
+ {
+ cleanupProcessInstance(processInstance);
+ }
+ }
+
@Test
public void testGetTasks() throws Exception
{
@@ -922,27 +967,28 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
activitiProcessEngine.getTaskService().saveTask(activeTask);
activitiProcessEngine.getTaskService().addCandidateUser(activeTask.getId(), anotherUserId);
activitiProcessEngine.getTaskService().addCandidateGroup(activeTask.getId(), "sales");
+ activitiProcessEngine.getTaskService().setVariableLocal(activeTask.getId(), "numberVar", 10);
TasksClient tasksClient = publicApiClient.tasksClient();
// Test status filtering - active
Map params = new HashMap();
- params.put("where", "(status = 'active' AND processInstanceId = '" + processInstance.getId() + "')");
+ params.put("where", "(status = 'active' AND processId = '" + processInstance.getId() + "')");
assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId());
// Test status filtering - completed
params.clear();
- params.put("where", "(status = 'completed' AND processInstanceId = '" + processInstance.getId() + "')");
+ params.put("where", "(status = 'completed' AND processId = '" + processInstance.getId() + "')");
assertTasksPresentInTaskQuery(params, tasksClient, false, completedTask.getId());
// Test status filtering - any
params.clear();
- params.put("where", "(status = 'any' AND processInstanceId = '" + processInstance.getId() + "')");
+ params.put("where", "(status = 'any' AND processId = '" + processInstance.getId() + "')");
assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId(), completedTask.getId());
// Test status filtering - no value should default to 'active'
params.clear();
- params.put("where", "(processInstanceId = '" + processInstance.getId() + "')");
+ params.put("where", "(processId = '" + processInstance.getId() + "')");
assertTasksPresentInTaskQuery(params, tasksClient, false, activeTask.getId());
// Test status filtering - illegal status
@@ -1021,11 +1067,11 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
// Candidate group filtering, only available for active tasks. When used with completed/any 400 is returned
params.clear();
- params.put("where", "(status = 'active' AND candidateGroup = 'sales' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'active' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
params.clear();
- params.put("where", "(status = 'completed' AND candidateGroup = 'sales' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'completed' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')");
try
{
tasksClient.findTasks(params);
@@ -1038,7 +1084,7 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
}
params.clear();
- params.put("where", "(status = 'any' AND candidateGroup = 'sales' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'any' AND candidateGroup = 'sales' AND processId='" + processInstance.getId() +"')");
try
{
tasksClient.findTasks(params);
@@ -1052,94 +1098,94 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
// Name filtering
params.clear();
- params.put("where", "(status = 'active' AND name = 'Task name' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'active' AND name = 'Task name' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
params.clear();
- params.put("where", "(status = 'completed' AND name = 'Another task name' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'completed' AND name = 'Another task name' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
params.clear();
- params.put("where", "(status = 'any' AND name = 'Another task name' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'any' AND name = 'Another task name' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
// Description filtering
params.clear();
- params.put("where", "(status = 'active' AND description = 'This is a test description' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'active' AND description = 'This is a test description' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
params.clear();
- params.put("where", "(status = 'completed' AND description = 'This is another test description' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'completed' AND description = 'This is another test description' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
params.clear();
- params.put("where", "(status = 'any' AND description = 'This is another test description' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'any' AND description = 'This is another test description' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
// Priority filtering
params.clear();
- params.put("where", "(status = 'active' AND priority = 2 AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'active' AND priority = 2 AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
- params.put("where", "(status = 'completed' AND priority = 3 AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'completed' AND priority = 3 AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
- params.put("where", "(status = 'any' AND priority = 3 AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'any' AND priority = 3 AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
// Process instance business-key filtering
params.clear();
- params.put("where", "(status = 'active' AND processInstanceBusinessKey = '" + businessKey + "')");
+ params.put("where", "(status = 'active' AND processBusinessKey = '" + businessKey + "')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
params.clear();
- params.put("where", "(status = 'completed' AND processInstanceBusinessKey = '" + businessKey + "')");
+ params.put("where", "(status = 'completed' AND processBusinessKey = '" + businessKey + "')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
params.clear();
- params.put("where", "(status = 'any' AND processInstanceBusinessKey = '" + businessKey + "')");
+ params.put("where", "(status = 'any' AND processBusinessKey = '" + businessKey + "')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId());
// Activity definition id filtering
params.clear();
- params.put("where", "(status = 'active' AND activityDefinitionId = 'verifyTaskDone' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'active' AND activityDefinitionId = 'verifyTaskDone' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
params.clear();
- params.put("where", "(status = 'completed' AND activityDefinitionId = 'adhocTask' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'completed' AND activityDefinitionId = 'adhocTask' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
params.clear();
- params.put("where", "(status = 'any' AND activityDefinitionId = 'adhocTask' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'any' AND activityDefinitionId = 'adhocTask' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
// Process definition id filtering
params.clear();
params.put("where", "(status = 'active' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() +
- "' AND processInstanceId='" + processInstance.getId() +"')");
+ "' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
params.clear();
params.put("where", "(status = 'completed' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() +
- "' AND processInstanceId='" + processInstance.getId() +"')");
+ "' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
params.clear();
params.put("where", "(status = 'any' AND processDefinitionId = '" + processInstance.getProcessDefinitionId() +
- "' AND processInstanceId='" + processInstance.getId() +"')");
+ "' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId());
// Process definition name filerting
params.clear();
- params.put("where", "(status = 'active' AND processDefinitionName = 'Adhoc Activiti Process' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'active' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
params.clear();
- params.put("where", "(status = 'completed' AND processDefinitionName = 'Adhoc Activiti Process' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'completed' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId());
params.clear();
- params.put("where", "(status = 'any' AND processDefinitionName = 'Adhoc Activiti Process' AND processInstanceId='" + processInstance.getId() +"')");
+ params.put("where", "(status = 'any' AND processDefinitionName = 'Adhoc Activiti Process' AND processId='" + processInstance.getId() +"')");
assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId(), completedTask.getId());
// Due date filtering
@@ -1167,6 +1213,38 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
params.clear();
params.put("where", "(status = 'any' AND startedAt = '" + ISO8601DateFormat.format(taskCreated.getTime()) +"')");
assertTasksPresentInTaskQuery(params, tasksClient, completedTask.getId(), activeTask.getId());
+
+ params.clear();
+ params.put("where", "(variables/numberVar > 'd:int 5')");
+ assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
+
+ params.clear();
+ params.put("where", "(variables/numberVar > 'd:int 10')");
+ assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
+
+ params.clear();
+ params.put("where", "(variables/numberVar >= 'd_int 10')");
+ assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
+
+ params.clear();
+ params.put("where", "(variables/numberVar >= 'd:int 11')");
+ assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
+
+ params.clear();
+ params.put("where", "(variables/numberVar <= 'd:int 10')");
+ assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
+
+ params.clear();
+ params.put("where", "(variables/numberVar <= 'd:int 9')");
+ assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
+
+ params.clear();
+ params.put("where", "(variables/numberVar < 'd_int 15')");
+ assertTasksPresentInTaskQuery(params, tasksClient, activeTask.getId());
+
+ params.clear();
+ params.put("where", "(variables/numberVar < 'd:int 10')");
+ assertEquals(0, getResultSizeForTaskQuery(params, tasksClient));
}
@Test
@@ -1240,7 +1318,7 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
TasksClient tasksClient = publicApiClient.tasksClient();
Map params = new HashMap();
- params.put("processInstanceId", processInstance.getId());
+ params.put("processId", processInstance.getId());
JSONObject resultingTasks = tasksClient.findTasks(params);
assertNotNull(resultingTasks);
@@ -1864,6 +1942,64 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
}
}
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testCreateTaskVariablesPresentInModel() throws Exception
+ {
+ RequestContext requestContext = initApiClientWithTestUser();
+
+ ProcessInstance processInstance = startAdhocProcess(requestContext.getRunAsUser(), requestContext.getNetworkId(), null);
+ try
+ {
+ Task task = activitiProcessEngine.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
+ assertNotNull(task);
+
+ Map actualLocalVariables = activitiProcessEngine.getTaskService().getVariablesLocal(task.getId());
+ Map actualGlobalVariables = activitiProcessEngine.getRuntimeService().getVariables(processInstance.getId());
+ assertEquals(5, actualGlobalVariables.size());
+ assertEquals(7, actualLocalVariables.size());
+
+ // Update a global value that is present in the model with type given
+ JSONArray variablesArray = new JSONArray();
+ JSONObject variableBody = new JSONObject();
+ variableBody.put("name", "bpm_percentComplete");
+ variableBody.put("value", 20);
+ variableBody.put("type", "d:int");
+ variableBody.put("scope", "global");
+ variablesArray.add(variableBody);
+ variableBody = new JSONObject();
+ variableBody.put("name", "bpm_workflowPriority");
+ variableBody.put("value", 50);
+ variableBody.put("type", "d:int");
+ variableBody.put("scope", "local");
+ variablesArray.add(variableBody);
+
+ TasksClient tasksClient = publicApiClient.tasksClient();
+ JSONObject result = tasksClient.createTaskVariables(task.getId(), variablesArray);
+ assertNotNull(result);
+ JSONObject resultObject = (JSONObject) result.get("list");
+ JSONArray resultList = (JSONArray) resultObject.get("entries");
+ assertEquals(2, resultList.size());
+ JSONObject firstResultObject = (JSONObject) ((JSONObject) resultList.get(0)).get("entry");
+ assertEquals("bpm_percentComplete", firstResultObject.get("name"));
+ assertEquals(20L, firstResultObject.get("value"));
+ assertEquals("d:int", firstResultObject.get("type"));
+ assertEquals("global", firstResultObject.get("scope"));
+ assertEquals(20, activitiProcessEngine.getRuntimeService().getVariable(processInstance.getId(), "bpm_percentComplete"));
+
+ JSONObject secondResultObject = (JSONObject) ((JSONObject) resultList.get(1)).get("entry");
+ assertEquals("bpm_workflowPriority", secondResultObject.get("name"));
+ assertEquals(50L, secondResultObject.get("value"));
+ assertEquals("d:int", secondResultObject.get("type"));
+ assertEquals("local", secondResultObject.get("scope"));
+ assertEquals(50, activitiProcessEngine.getTaskService().getVariable(task.getId(), "bpm_workflowPriority"));
+ }
+ finally
+ {
+ cleanupProcessInstance(processInstance);
+ }
+ }
+
@Test
public void testGetTaskVariablesRawVariableTypes() throws Exception
{
@@ -2244,16 +2380,8 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
// Check well-known properties and their types
- // Validate bpm:description
- JSONObject modelEntry = modelFieldsByName.get("bpm_description");
- assertNotNull(modelEntry);
- assertEquals("Description", modelEntry.get("title"));
- assertEquals("{http://www.alfresco.org/model/bpm/1.0}description", modelEntry.get("qualifiedName"));
- assertEquals("d:text", modelEntry.get("dataType"));
- assertFalse((Boolean)modelEntry.get("required"));
-
- // Validate bpm:description
- modelEntry = modelFieldsByName.get("bpm_completionDate");
+ // Validate bpm:completionDate
+ JSONObject modelEntry = modelFieldsByName.get("bpm_completionDate");
assertNotNull(modelEntry);
assertEquals("Completion Date", modelEntry.get("title"));
assertEquals("{http://www.alfresco.org/model/bpm/1.0}completionDate", modelEntry.get("qualifiedName"));
@@ -2268,15 +2396,6 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
assertEquals("d:text", modelEntry.get("dataType"));
assertFalse((Boolean)modelEntry.get("required"));
- // Validate bpm:priority
- modelEntry = modelFieldsByName.get("bpm_priority");
- assertNotNull(modelEntry);
- assertEquals("Priority", modelEntry.get("title"));
- assertEquals("{http://www.alfresco.org/model/bpm/1.0}priority", modelEntry.get("qualifiedName"));
- assertEquals("d:int", modelEntry.get("dataType"));
- assertEquals("2", modelEntry.get("defaultValue"));
- assertTrue((Boolean)modelEntry.get("required"));
-
// Validate bpm:package
modelEntry = modelFieldsByName.get("bpm_package");
assertNotNull(modelEntry);
@@ -2322,7 +2441,7 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
JSONObject entryJSON = (JSONObject) entryObjectJSON.get("entry");
if (entryJSON.get("name").equals("Test Doc1")) {
doc1Found = true;
- assertEquals(docNodeRefs[0].toString(), entryJSON.get("id"));
+ assertEquals(docNodeRefs[0].getId(), entryJSON.get("id"));
assertEquals("Test Doc1", entryJSON.get("name"));
assertEquals("Test Doc1 Title", entryJSON.get("title"));
assertEquals("Test Doc1 Description", entryJSON.get("description"));
@@ -2334,7 +2453,7 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
assertNotNull(entryJSON.get("mimeType"));
} else {
doc2Found = true;
- assertEquals(docNodeRefs[1].toString(), entryJSON.get("id"));
+ assertEquals(docNodeRefs[1].getId(), entryJSON.get("id"));
assertEquals("Test Doc2", entryJSON.get("name"));
assertEquals("Test Doc2 Title", entryJSON.get("title"));
assertEquals("Test Doc2 Description", entryJSON.get("description"));
@@ -2430,27 +2549,4 @@ public class TaskWorkflowApiTest extends EnterpriseWorkflowTestApi
log("Error while cleaning up process instance");
}
}
-
- protected TestNetwork getOtherNetwork(String usedNetworkId) throws Exception {
- Iterator networkIt = getTestFixture().getNetworksIt();
- while(networkIt.hasNext()) {
- TestNetwork network = networkIt.next();
- if(!usedNetworkId.equals(network.getId())) {
- return network;
- }
- }
- fail("Need more than one network to test permissions");
- return null;
- }
-
- protected TestPerson getOtherPersonInNetwork(String usedPerson, String networkId) throws Exception {
- TestNetwork usedNetwork = getTestFixture().getNetwork(networkId);
- for(TestPerson person : usedNetwork.getPeople()) {
- if(!person.getId().equals(usedPerson)) {
- return person;
- }
- }
- fail("Network doesn't have additonal users, cannot perform test");
- return null;
- }
}
diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiClient.java b/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiClient.java
index ac4d34c33b..6e2e558aec 100644
--- a/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiClient.java
+++ b/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiClient.java
@@ -16,6 +16,7 @@ import org.alfresco.rest.workflow.api.model.Deployment;
import org.alfresco.rest.workflow.api.model.ProcessDefinition;
import org.alfresco.rest.workflow.api.model.ProcessInfo;
import org.apache.commons.lang.StringUtils;
+import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
public class WorkflowApiClient extends PublicApiClient
@@ -143,6 +144,20 @@ public class WorkflowApiClient extends PublicApiClient
return ProcessesParser.INSTANCE.parseEntry(entry);
}
+ public JSONObject getTasks(String processInstanceId, Map params) throws PublicApiException
+ {
+ HttpResponse response = getAll("processes", processInstanceId, "tasks", null, params, "Failed to get task instances of processInstanceId " + processInstanceId);
+ JSONObject list = (JSONObject) response.getJsonResponse().get("list");
+ return list;
+ }
+
+ public JSONObject getActivities(String processInstanceId, Map params) throws PublicApiException
+ {
+ HttpResponse response = getAll("processes", processInstanceId, "activities", null, params, "Failed to get activity instances of processInstanceId " + processInstanceId);
+ JSONObject list = (JSONObject) response.getJsonResponse().get("list");
+ return list;
+ }
+
public JSONObject findProcessItems(String processInstanceId) throws PublicApiException
{
HttpResponse response = getAll("processes", processInstanceId, "items", null, null,
@@ -159,6 +174,12 @@ public class WorkflowApiClient extends PublicApiClient
return list;
}
+ public JSONObject createVariables(String processId, JSONArray variables) throws PublicApiException
+ {
+ HttpResponse response = create("processes", processId, "variables", null, variables.toJSONString(), "Failed to create variables");
+ return response.getJsonResponse();
+ }
+
public JSONObject updateVariable(String processId, String variableName, JSONObject variable) throws PublicApiException
{
HttpResponse response = update("processes", processId, "variables", variableName, variable.toJSONString(), "Failed to update variable");
@@ -170,6 +191,11 @@ public class WorkflowApiClient extends PublicApiClient
remove("processes", processId, "variables", variableName, "Failed to delete variable");
}
+ public void addProcessItem(String processId, String body) throws PublicApiException
+ {
+ create("processes", processId, "items", null, body, "Failed to add item");
+ }
+
public void deleteProcessItem(String processId, String itemId) throws PublicApiException
{
remove("processes", processId, "items", itemId, "Failed to delete item");
@@ -234,6 +260,12 @@ public class WorkflowApiClient extends PublicApiClient
return findTaskVariables(taskId, null);
}
+ public JSONObject createTaskVariables(String taskId, JSONArray variables) throws PublicApiException
+ {
+ HttpResponse response = create("tasks", taskId, "variables", null, variables.toJSONString(), "Failed to create task variables");
+ return response.getJsonResponse();
+ }
+
public JSONObject updateTaskVariable(String taskId, String variableName, JSONObject variable) throws PublicApiException
{
HttpResponse response = update("tasks", taskId, "variables", variableName, variable.toJSONString(), "Failed to update task variable");
diff --git a/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiHttpClient.java b/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiHttpClient.java
new file mode 100644
index 0000000000..4b71072913
--- /dev/null
+++ b/source/test-java/org/alfresco/rest/workflow/api/tests/WorkflowApiHttpClient.java
@@ -0,0 +1,14 @@
+package org.alfresco.rest.workflow.api.tests;
+
+import org.alfresco.rest.api.tests.client.AuthenticatedHttp;
+import org.alfresco.rest.api.tests.client.PublicApiHttpClient;
+
+public class WorkflowApiHttpClient extends PublicApiHttpClient
+{
+ public WorkflowApiHttpClient(String host, int port, String contextPath, String servletName, AuthenticatedHttp authenticatedHttp)
+ {
+ super(host, port, contextPath, servletName, authenticatedHttp);
+ apiName = "workflow";
+ }
+
+}