You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/03/02 11:47:25 UTC
[06/11] syncope git commit: [SYNCOPE-1279] Now providing runtime
status updates from running Tasks and Reports
[SYNCOPE-1279] Now providing runtime status updates from running Tasks and Reports
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/799f079f
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/799f079f
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/799f079f
Branch: refs/heads/2_0_X
Commit: 799f079f132d6a2f9dc36a0bfd20475eb988febc
Parents: 988dfee
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Mar 2 11:45:34 2018 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Mar 2 11:45:34 2018 +0100
----------------------------------------------------------------------
.../console/reports/ReportDirectoryPanel.java | 56 ++++
.../console/rest/AnyObjectRestClient.java | 2 -
.../client/console/rest/ReportRestClient.java | 4 +
.../client/console/rest/TaskRestClient.java | 4 +
.../tasks/ProvisioningTaskDirectoryPanel.java | 61 ++++
.../client/console/widgets/JobActionPanel.java | 23 +-
.../client/console/widgets/JobWidget.java | 4 +-
.../META-INF/resources/css/syncopeConsole.css | 6 +-
.../client/console/widgets/JobActionPanel.html | 2 +
.../org/apache/syncope/common/lib/to/JobTO.java | 11 +
.../rest/api/service/ExecutableService.java | 11 +
.../core/logic/AbstractExecutableLogic.java | 2 +
.../syncope/core/logic/AbstractJobLogic.java | 63 ++--
.../apache/syncope/core/logic/ReportLogic.java | 25 ++
.../apache/syncope/core/logic/TaskLogic.java | 27 +-
.../core/persistence/api/dao/Reportlet.java | 4 +-
.../core/provisioning/api/Connector.java | 7 +-
.../core/provisioning/api/job/JobDelegate.java | 27 ++
.../api/job/SchedTaskJobDelegate.java | 2 +-
.../api/job/report/ReportJobDelegate.java | 27 ++
.../notification/NotificationJobDelegate.java | 31 ++
.../api/pushpull/SyncopePullExecutor.java | 3 +
.../provisioning/java/ConnectorFacadeProxy.java | 13 +-
.../java/job/AbstractInterruptableJob.java | 21 +-
.../java/job/AbstractSchedTaskJobDelegate.java | 12 +
.../GroupMemberProvisionTaskJobDelegate.java | 28 +-
.../java/job/IdentityRecertification.java | 9 +-
.../core/provisioning/java/job/TaskJob.java | 19 +-
.../DefaultNotificationJobDelegate.java | 296 +++++++++++++++++++
.../java/job/notification/NotificationJob.java | 7 +
.../notification/NotificationJobDelegate.java | 278 -----------------
.../java/job/report/AbstractReportlet.java | 13 +-
.../java/job/report/AuditReportlet.java | 16 +-
.../job/report/DefaultReportJobDelegate.java | 216 ++++++++++++++
.../java/job/report/GroupReportlet.java | 19 +-
.../job/report/ReconciliationReportlet.java | 106 +++++--
.../provisioning/java/job/report/ReportJob.java | 7 +
.../java/job/report/ReportJobDelegate.java | 197 ------------
.../java/job/report/StaticReportlet.java | 8 +-
.../java/job/report/UserReportlet.java | 17 +-
.../AbstractPropagationTaskExecutor.java | 11 +-
.../pushpull/AbstractPullResultHandler.java | 2 +
.../pushpull/DefaultRealmPullResultHandler.java | 2 +
.../java/pushpull/PullJobDelegate.java | 40 +++
.../java/pushpull/PushJobDelegate.java | 52 ++++
.../cxf/service/AbstractExecutableService.java | 5 +
46 files changed, 1215 insertions(+), 581 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
index 01f77db..e0c5d6f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
@@ -34,27 +34,36 @@ import org.apache.syncope.client.console.pages.BasePage;
import org.apache.syncope.client.console.panels.DirectoryPanel;
import org.apache.syncope.client.console.panels.MultilevelPanel;
import org.apache.syncope.client.console.rest.ReportRestClient;
+import org.apache.syncope.client.console.wicket.ajax.IndicatorAjaxTimerBehavior;
import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn;
import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.client.console.widgets.JobActionPanel;
import org.apache.syncope.client.console.wizards.AjaxWizard;
import org.apache.syncope.common.lib.types.StandardEntitlement;
import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.JobTO;
import org.apache.syncope.common.lib.to.ReportTO;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;
+import org.apache.wicket.util.time.Duration;
/**
* Reports page.
@@ -76,6 +85,17 @@ public abstract class ReportDirectoryPanel
modal.size(Modal.Size.Large);
initResultTable();
+ container.add(new IndicatorAjaxTimerBehavior(Duration.seconds(10)) {
+
+ private static final long serialVersionUID = -4661303265651934868L;
+
+ @Override
+ protected void onTimer(final AjaxRequestTarget target) {
+ container.modelChanged();
+ target.add(container);
+ }
+ });
+
startAt = new ReportStartAtTogglePanel(container, pageRef);
addInnerObject(startAt);
}
@@ -107,10 +127,46 @@ public abstract class ReportDirectoryPanel
columns.add(new BooleanPropertyColumn<ReportTO>(
new StringResourceModel("active", this), "active", "active"));
+ columns.add(new AbstractColumn<ReportTO, String>(new Model<>(""), "running") {
+
+ private static final long serialVersionUID = 4209532514416998046L;
+
+ @Override
+ public void populateItem(
+ final Item<ICellPopulator<ReportTO>> cellItem,
+ final String componentId,
+ final IModel<ReportTO> rowModel) {
+
+ JobTO jobTO = restClient.getJob(rowModel.getObject().getKey());
+ JobActionPanel panel = new JobActionPanel(
+ componentId, jobTO, false, ReportDirectoryPanel.this, pageRef);
+ MetaDataRoleAuthorizationStrategy.authorize(panel, WebPage.ENABLE,
+ String.format("%s,%s",
+ StandardEntitlement.TASK_EXECUTE,
+ StandardEntitlement.TASK_UPDATE));
+ cellItem.add(panel);
+ }
+
+ @Override
+ public String getCssClass() {
+ return "col-xs-1";
+ }
+ });
+
return columns;
}
@Override
+ public void onEvent(final IEvent<?> event) {
+ if (event.getPayload() instanceof JobActionPanel.JobActionPayload) {
+ container.modelChanged();
+ JobActionPanel.JobActionPayload.class.cast(event.getPayload()).getTarget().add(container);
+ } else {
+ super.onEvent(event);
+ }
+ }
+
+ @Override
public ActionsPanel<ReportTO> getActions(final IModel<ReportTO> model) {
final ActionsPanel<ReportTO> panel = super.getActions(model);
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
index 31cd3a8..a885764 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/AnyObjectRestClient.java
@@ -18,8 +18,6 @@
*/
package org.apache.syncope.client.console.rest;
-import static org.apache.syncope.client.console.rest.BaseRestClient.getService;
-
import java.util.List;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
index 0c96627..e65ce7e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
@@ -54,6 +54,10 @@ public class ReportRestClient extends BaseRestClient
return getService(ReportService.class).list();
}
+ public JobTO getJob(final String key) {
+ return getService(ReportService.class).getJob(key);
+ }
+
public List<JobTO> listJobs() {
return getService(ReportService.class).listJobs();
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
index d184085..723ae2e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
@@ -47,6 +47,10 @@ public class TaskRestClient extends BaseRestClient implements ExecutionRestClien
private static final long serialVersionUID = 6284485820911028843L;
+ public JobTO getJob(final String key) {
+ return getService(TaskService.class).getJob(key);
+ }
+
public List<JobTO> listJobs() {
return getService(TaskService.class).listJobs();
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
index 91f17b8..cacd6f7 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
@@ -23,18 +23,32 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.wicket.ajax.IndicatorAjaxTimerBehavior;
import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn;
import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn;
import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.widgets.JobActionPanel;
+import org.apache.syncope.common.lib.to.JobTO;
import org.apache.syncope.common.lib.to.ProvisioningTaskTO;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
import org.apache.syncope.common.lib.types.TaskType;
import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;
+import org.apache.wicket.util.time.Duration;
/**
* Tasks page.
@@ -63,6 +77,17 @@ public abstract class ProvisioningTaskDirectoryPanel<T extends ProvisioningTaskT
// super in order to call the parent implementation
super.initResultTable();
+
+ container.add(new IndicatorAjaxTimerBehavior(Duration.seconds(10)) {
+
+ private static final long serialVersionUID = -4661303265651934868L;
+
+ @Override
+ protected void onTimer(final AjaxRequestTarget target) {
+ container.modelChanged();
+ target.add(container);
+ }
+ });
}
@Override
@@ -103,9 +128,45 @@ public abstract class ProvisioningTaskDirectoryPanel<T extends ProvisioningTaskT
columns.add(new BooleanPropertyColumn<T>(
new StringResourceModel("active", this), "active", "active"));
+ columns.add(new AbstractColumn<T, String>(new Model<>(""), "running") {
+
+ private static final long serialVersionUID = -4008579357070833846L;
+
+ @Override
+ public void populateItem(
+ final Item<ICellPopulator<T>> cellItem,
+ final String componentId,
+ final IModel<T> rowModel) {
+
+ JobTO jobTO = restClient.getJob(rowModel.getObject().getKey());
+ JobActionPanel panel = new JobActionPanel(
+ componentId, jobTO, false, ProvisioningTaskDirectoryPanel.this, pageRef);
+ MetaDataRoleAuthorizationStrategy.authorize(panel, WebPage.ENABLE,
+ String.format("%s,%s",
+ StandardEntitlement.TASK_EXECUTE,
+ StandardEntitlement.TASK_UPDATE));
+ cellItem.add(panel);
+ }
+
+ @Override
+ public String getCssClass() {
+ return "col-xs-1";
+ }
+ });
+
return columns;
}
+ @Override
+ public void onEvent(final IEvent<?> event) {
+ if (event.getPayload() instanceof JobActionPanel.JobActionPayload) {
+ container.modelChanged();
+ JobActionPanel.JobActionPayload.class.cast(event.getPayload()).getTarget().add(container);
+ } else {
+ super.onEvent(event);
+ }
+ }
+
protected class ProvisioningTasksProvider<T extends ProvisioningTaskTO> extends SchedTasksProvider<T> {
private static final long serialVersionUID = 4725679400450513556L;
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobActionPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobActionPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobActionPanel.java
index 82665f8..5e03e2d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobActionPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobActionPanel.java
@@ -18,6 +18,9 @@
*/
package org.apache.syncope.client.console.widgets;
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverBehavior;
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverConfig;
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.console.SyncopeConsoleSession;
@@ -30,10 +33,13 @@ import org.apache.syncope.client.console.wicket.ajax.markup.html.IndicatorAjaxLi
import org.apache.syncope.client.console.wizards.WizardMgtPanel;
import org.apache.syncope.common.lib.to.JobTO;
import org.apache.syncope.common.lib.types.JobAction;
+import org.apache.wicket.Component;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.model.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,14 +58,21 @@ public class JobActionPanel extends WizardMgtPanel<Serializable> {
public JobActionPanel(
final String id,
final JobTO jobTO,
- final JobWidget widget,
+ final boolean showNotRunning,
+ final Component container,
final PageReference pageRef) {
+
super(id, true);
setOutputMarkupId(true);
Fragment controls;
if (jobTO.isRunning()) {
controls = new Fragment("controls", "runningFragment", this);
+ controls.add(new Label("status", Model.of()).add(new PopoverBehavior(
+ Model.<String>of(),
+ Model.of("<pre>" + (jobTO.getStatus() == null ? StringUtils.EMPTY : jobTO.getStatus()) + "</pre>"),
+ new PopoverConfig().withAnimation(true).withHoverTrigger().withHtml(true).
+ withPlacement(TooltipConfig.Placement.left))));
controls.add(new IndicatorAjaxLink<Void>("stop") {
private static final long serialVersionUID = -7978723352517770644L;
@@ -83,7 +96,7 @@ public class JobActionPanel extends WizardMgtPanel<Serializable> {
default:
}
SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
- send(widget, Broadcast.EXACT, new JobActionPayload(target));
+ send(container, Broadcast.EXACT, new JobActionPayload(target));
} catch (Exception e) {
LOG.error("While stopping {}", jobTO.getRefDesc(), e);
SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName()
@@ -117,7 +130,7 @@ public class JobActionPanel extends WizardMgtPanel<Serializable> {
default:
}
SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
- send(widget, Broadcast.EXACT, new JobActionPayload(target));
+ send(container, Broadcast.EXACT, new JobActionPayload(target));
} catch (Exception e) {
LOG.error("While starting {}", jobTO.getRefDesc(), e);
SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName()
@@ -126,6 +139,10 @@ public class JobActionPanel extends WizardMgtPanel<Serializable> {
((BasePage) getPage()).getNotificationPanel().refresh(target);
}
});
+ if (!showNotRunning) {
+ controls.setOutputMarkupPlaceholderTag(true);
+ controls.setVisible(false);
+ }
}
addInnerObject(controls);
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java b/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java
index cd10c70..98a53e4 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java
@@ -357,9 +357,9 @@ public class JobWidget extends BaseWidget {
final IModel<JobTO> rowModel) {
JobTO jobTO = rowModel.getObject();
- JobActionPanel panel = new JobActionPanel(componentId, jobTO, JobWidget.this, pageRef);
+ JobActionPanel panel = new JobActionPanel(componentId, jobTO, true, JobWidget.this, pageRef);
MetaDataRoleAuthorizationStrategy.authorize(panel, WebPage.ENABLE,
- String.format("%s,%s%s,%s",
+ String.format("%s,%s,%s,%s",
StandardEntitlement.TASK_EXECUTE,
StandardEntitlement.REPORT_EXECUTE,
StandardEntitlement.TASK_UPDATE,
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css b/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
index 294c978..c2dcf2c 100644
--- a/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
+++ b/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
@@ -879,6 +879,10 @@ li.todoitem a {
cursor: default;
}
+.popover{
+ max-width: 100%;
+}
+
#popover:hover {
cursor: pointer;
}
@@ -1157,4 +1161,4 @@ div#inline-actions ul.menu i, div#tablehandling ul.menu i {
div#tablehandling ul.menu li a {
padding: 0px !important;
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JobActionPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JobActionPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JobActionPanel.html
index e94f292..8e31f36 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JobActionPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JobActionPanel.html
@@ -22,6 +22,8 @@ under the License.
<wicket:fragment wicket:id="runningFragment">
<i id="actionLink" class="fa fa-refresh fa-spin"></i>
+ <div wicket:id="status" class="fa fa-binoculars"/>
+
<a href="#" wicket:id="stop" class="fa fa-stop-circle"></a>
</wicket:fragment>
<wicket:fragment wicket:id="notRunningFragment">
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/common/lib/src/main/java/org/apache/syncope/common/lib/to/JobTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/JobTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/JobTO.java
index 2cb5690..cee8db2 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/JobTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/JobTO.java
@@ -42,6 +42,8 @@ public class JobTO extends AbstractBaseBean {
private Date start;
+ private String status;
+
public JobType getType() {
return type;
}
@@ -93,4 +95,13 @@ public class JobTO extends AbstractBaseBean {
? null
: new Date(start.getTime());
}
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(final String status) {
+ this.status = status;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ExecutableService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ExecutableService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ExecutableService.java
index e7271b2..37301bd 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ExecutableService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ExecutableService.java
@@ -101,6 +101,17 @@ public interface ExecutableService extends JAXRSService {
ExecTO execute(@BeanParam ExecuteQuery query);
/**
+ * Returns job (running or scheduled) for the executable matching the given key.
+ *
+ * @param key executable key
+ * @return job (running or scheduled) for the given key
+ */
+ @GET
+ @Path("jobs/{key}")
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ JobTO getJob(@PathParam("key") String key);
+
+ /**
* List jobs (running and / or scheduled).
*
* @return jobs (running and / or scheduled)
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractExecutableLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractExecutableLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractExecutableLogic.java
index d1b7cb3..6b34bc7 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractExecutableLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractExecutableLogic.java
@@ -42,6 +42,8 @@ public abstract class AbstractExecutableLogic<T extends AbstractBaseBean> extend
public abstract BulkActionResult deleteExecutions(
String key, Date startedBefore, Date startedAfter, Date endedBefore, Date endedAfter);
+ public abstract JobTO getJob(String key);
+
public abstract List<JobTO> listJobs();
public abstract void actionJob(String key, JobAction action);
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractJobLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractJobLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractJobLogic.java
index a93ae2d..844d353 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractJobLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractJobLogic.java
@@ -26,11 +26,14 @@ import org.apache.syncope.common.lib.to.JobTO;
import org.apache.syncope.common.lib.types.JobAction;
import org.apache.syncope.common.lib.types.JobType;
import org.apache.syncope.core.provisioning.api.job.JobManager;
+import org.apache.syncope.core.provisioning.java.job.AbstractInterruptableJob;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.matchers.GroupMatcher;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@@ -44,32 +47,54 @@ abstract class AbstractJobLogic<T extends AbstractBaseBean> extends AbstractTran
protected abstract Triple<JobType, String, String> getReference(final JobKey jobKey);
- protected List<JobTO> doListJobs() {
- List<JobTO> jobTOs = new ArrayList<>();
+ protected JobTO getJobTO(final JobKey jobKey) throws SchedulerException {
+ JobTO jobTO = null;
- try {
- for (JobKey jobKey : scheduler.getScheduler().
- getJobKeys(GroupMatcher.jobGroupEquals(Scheduler.DEFAULT_GROUP))) {
+ Triple<JobType, String, String> reference = getReference(jobKey);
+ if (reference != null) {
+ jobTO = new JobTO();
- JobTO jobTO = new JobTO();
+ jobTO.setType(reference.getLeft());
+ jobTO.setRefKey(reference.getMiddle());
+ jobTO.setRefDesc(reference.getRight());
- Triple<JobType, String, String> reference = getReference(jobKey);
- if (reference != null) {
- jobTOs.add(jobTO);
+ List<? extends Trigger> jobTriggers = scheduler.getScheduler().getTriggersOfJob(jobKey);
+ if (jobTriggers.isEmpty()) {
+ jobTO.setScheduled(false);
+ } else {
+ jobTO.setScheduled(true);
+ jobTO.setStart(jobTriggers.get(0).getStartTime());
+ }
+
+ jobTO.setRunning(jobManager.isRunning(jobKey));
- jobTO.setType(reference.getLeft());
- jobTO.setRefKey(reference.getMiddle());
- jobTO.setRefDesc(reference.getRight());
+ jobTO.setStatus("UNKNOWN");
+ if (jobTO.isRunning()) {
+ try {
+ Object job = ApplicationContextProvider.getBeanFactory().getBean(jobKey.getName());
+ if (job instanceof AbstractInterruptableJob
+ && ((AbstractInterruptableJob) job).getDelegate() != null) {
- List<? extends Trigger> jobTriggers = scheduler.getScheduler().getTriggersOfJob(jobKey);
- if (jobTriggers.isEmpty()) {
- jobTO.setScheduled(false);
- } else {
- jobTO.setScheduled(true);
- jobTO.setStart(jobTriggers.get(0).getStartTime());
+ jobTO.setStatus(((AbstractInterruptableJob) job).getDelegate().currentStatus());
}
+ } catch (NoSuchBeanDefinitionException e) {
+ LOG.warn("Could not find job {} implementation", jobKey, e);
+ }
+ }
+ }
+
+ return jobTO;
+ }
+
+ protected List<JobTO> doListJobs() {
+ List<JobTO> jobTOs = new ArrayList<>();
+ try {
+ for (JobKey jobKey : scheduler.getScheduler().
+ getJobKeys(GroupMatcher.jobGroupEquals(Scheduler.DEFAULT_GROUP))) {
- jobTO.setRunning(jobManager.isRunning(jobKey));
+ JobTO jobTO = getJobTO(jobKey);
+ if (jobTO != null) {
+ jobTOs.add(jobTO);
}
}
} catch (SchedulerException e) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
index 9505303..da8f2b7 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
@@ -66,6 +66,7 @@ import org.apache.syncope.core.provisioning.api.data.ReportDataBinder;
import org.apache.syncope.core.provisioning.api.job.JobNamer;
import org.apache.xmlgraphics.util.MimeConstants;
import org.quartz.JobKey;
+import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@@ -387,6 +388,30 @@ public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
return super.doListJobs();
}
+ @PreAuthorize("hasRole('" + StandardEntitlement.REPORT_READ + "')")
+ @Override
+ public JobTO getJob(final String key) {
+ Report report = reportDAO.find(key);
+ if (report == null) {
+ throw new NotFoundException("Report " + key);
+ }
+
+ JobTO jobTO = null;
+ try {
+ jobTO = getJobTO(JobNamer.getJobKey(report));
+ } catch (SchedulerException e) {
+ LOG.error("Problems while retrieving scheduled job {}", JobNamer.getJobKey(report), e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Scheduling);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+ if (jobTO == null) {
+ throw new NotFoundException("Job for report " + key);
+ }
+ return jobTO;
+ }
+
@PreAuthorize("hasRole('" + StandardEntitlement.REPORT_EXECUTE + "')")
@Override
public void actionJob(final String key, final JobAction action) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
index 9603bc8..25f06a1 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
@@ -57,10 +57,11 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecu
import org.apache.syncope.core.persistence.api.dao.ConfDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.NotificationDAO;
+import org.apache.syncope.core.provisioning.api.notification.NotificationJobDelegate;
import org.apache.syncope.core.provisioning.java.job.TaskJob;
-import org.apache.syncope.core.provisioning.java.job.notification.NotificationJobDelegate;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
+import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@@ -402,6 +403,30 @@ public class TaskLogic extends AbstractExecutableLogic<TaskTO> {
return super.doListJobs();
}
+ @PreAuthorize("hasRole('" + StandardEntitlement.TASK_READ + "')")
+ @Override
+ public JobTO getJob(final String key) {
+ Task task = taskDAO.find(key);
+ if (task == null) {
+ throw new NotFoundException("Task " + key);
+ }
+
+ JobTO jobTO = null;
+ try {
+ jobTO = getJobTO(JobNamer.getJobKey(task));
+ } catch (SchedulerException e) {
+ LOG.error("Problems while retrieving scheduled job {}", JobNamer.getJobKey(task), e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Scheduling);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+ if (jobTO == null) {
+ throw new NotFoundException("Job for task " + key);
+ }
+ return jobTO;
+ }
+
@PreAuthorize("hasRole('" + StandardEntitlement.TASK_EXECUTE + "')")
@Override
public void actionJob(final String key, final JobAction action) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/Reportlet.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/Reportlet.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/Reportlet.java
index 8180831..11e6b25 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/Reportlet.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/Reportlet.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.persistence.api.dao;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.syncope.common.lib.report.ReportletConf;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
@@ -34,7 +35,8 @@ public interface Reportlet {
*
* @param conf configuration
* @param handler SAX content handler for streaming result
+ * @param status current report status (for job reporting)
* @throws SAXException if there is any problem in SAX handling
*/
- void extract(ReportletConf conf, ContentHandler handler) throws SAXException;
+ void extract(ReportletConf conf, ContentHandler handler, AtomicReference<String> status) throws SAXException;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
index 901cdc7..2098466 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.api;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.entity.ConnInstance;
import org.identityconnectors.framework.common.objects.Attribute;
@@ -63,7 +64,7 @@ public interface Connector {
ObjectClass objectClass,
Set<Attribute> attrs,
OperationOptions options,
- Boolean[] propagationAttempted);
+ AtomicReference<Boolean> propagationAttempted);
/**
* Update user / group on a connector instance.
@@ -80,7 +81,7 @@ public interface Connector {
Uid uid,
Set<Attribute> attrs,
OperationOptions options,
- Boolean[] propagationAttempted);
+ AtomicReference<Boolean> propagationAttempted);
/**
* Delete user / group on a connector instance.
@@ -94,7 +95,7 @@ public interface Connector {
ObjectClass objectClass,
Uid uid,
OperationOptions options,
- Boolean[] propagationAttempted);
+ AtomicReference<Boolean> propagationAttempted);
/**
* Fetches all remote objects (for use during full reconciliation).
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/JobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/JobDelegate.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/JobDelegate.java
new file mode 100644
index 0000000..3bfa292
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/JobDelegate.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.api.job;
+
+/**
+ * Implementations of this interface will perform the actual operations required to Quartz's {@link org.quartz.Job}.
+ */
+public interface JobDelegate {
+
+ String currentStatus();
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/SchedTaskJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/SchedTaskJobDelegate.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/SchedTaskJobDelegate.java
index a03f36b..bb69b10 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/SchedTaskJobDelegate.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/SchedTaskJobDelegate.java
@@ -21,7 +21,7 @@ package org.apache.syncope.core.provisioning.api.job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
-public interface SchedTaskJobDelegate {
+public interface SchedTaskJobDelegate extends JobDelegate {
void execute(String taskKey, boolean dryRun, JobExecutionContext context) throws JobExecutionException;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/report/ReportJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/report/ReportJobDelegate.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/report/ReportJobDelegate.java
new file mode 100644
index 0000000..bbf455f
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/report/ReportJobDelegate.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.api.job.report;
+
+import org.apache.syncope.core.provisioning.api.job.JobDelegate;
+import org.quartz.JobExecutionException;
+
+public interface ReportJobDelegate extends JobDelegate {
+
+ void execute(String reportKey) throws JobExecutionException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationJobDelegate.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationJobDelegate.java
new file mode 100644
index 0000000..3dfcddd
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationJobDelegate.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.api.notification;
+
+import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.core.provisioning.api.job.JobDelegate;
+import org.quartz.JobExecutionException;
+
+public interface NotificationJobDelegate extends JobDelegate {
+
+ TaskExec executeSingle(NotificationTask task);
+
+ void execute() throws JobExecutionException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopePullExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopePullExecutor.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopePullExecutor.java
index ab02282..39eed32 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopePullExecutor.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopePullExecutor.java
@@ -18,10 +18,13 @@
*/
package org.apache.syncope.core.provisioning.api.pushpull;
+import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.SyncToken;
public interface SyncopePullExecutor {
void setLatestSyncToken(ObjectClass objectClass, SyncToken latestSyncToken);
+
+ void reportHandled(ObjectClass objectClass, Name name);
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
index 7e94c5b..aea4e27 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Transformer;
import org.apache.syncope.common.lib.types.ConnConfProperty;
@@ -165,12 +166,12 @@ public class ConnectorFacadeProxy implements Connector {
final ObjectClass objectClass,
final Set<Attribute> attrs,
final OperationOptions options,
- final Boolean[] propagationAttempted) {
+ final AtomicReference<Boolean> propagationAttempted) {
Uid result = null;
if (connInstance.getCapabilities().contains(ConnectorCapability.CREATE)) {
- propagationAttempted[0] = true;
+ propagationAttempted.set(true);
Future<Uid> future = asyncFacade.create(connector, objectClass, attrs, options);
try {
@@ -200,12 +201,12 @@ public class ConnectorFacadeProxy implements Connector {
final Uid uid,
final Set<Attribute> attrs,
final OperationOptions options,
- final Boolean[] propagationAttempted) {
+ final AtomicReference<Boolean> propagationAttempted) {
Uid result = null;
if (connInstance.getCapabilities().contains(ConnectorCapability.UPDATE)) {
- propagationAttempted[0] = true;
+ propagationAttempted.set(true);
Future<Uid> future = asyncFacade.update(connector, objectClass, uid, attrs, options);
@@ -236,10 +237,10 @@ public class ConnectorFacadeProxy implements Connector {
final ObjectClass objectClass,
final Uid uid,
final OperationOptions options,
- final Boolean[] propagationAttempted) {
+ final AtomicReference<Boolean> propagationAttempted) {
if (connInstance.getCapabilities().contains(ConnectorCapability.DELETE)) {
- propagationAttempted[0] = true;
+ propagationAttempted.set(true);
Future<Uid> future = asyncFacade.delete(connector, objectClass, uid, options);
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractInterruptableJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractInterruptableJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractInterruptableJob.java
index 19bbf1e..86a7f49 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractInterruptableJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractInterruptableJob.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.java.job;
import java.util.Date;
import java.util.concurrent.atomic.AtomicReference;
+import org.apache.syncope.core.provisioning.api.job.JobDelegate;
import org.apache.syncope.core.provisioning.api.utils.FormatUtils;
import org.apache.syncope.core.provisioning.api.job.JobManager;
import org.quartz.DisallowConcurrentExecution;
@@ -40,13 +41,25 @@ public abstract class AbstractInterruptableJob implements InterruptableJob {
*/
private final AtomicReference<Thread> runningThread = new AtomicReference<>();
+ private final JobDelegate embeddedDelegate = new JobDelegate() {
+
+ @Override
+ public String currentStatus() {
+ return "RUNNING THREAD: " + runningThread.get();
+ }
+ };
+
private long interruptMaxRetries = 1;
+ public JobDelegate getDelegate() {
+ return embeddedDelegate;
+ }
+
@Override
public void execute(final JobExecutionContext context) throws JobExecutionException {
- this.runningThread.set(Thread.currentThread());
+ runningThread.set(Thread.currentThread());
try {
- this.interruptMaxRetries = context.getMergedJobDataMap().getLong(JobManager.INTERRUPT_MAX_RETRIES_KEY);
+ interruptMaxRetries = context.getMergedJobDataMap().getLong(JobManager.INTERRUPT_MAX_RETRIES_KEY);
} catch (Exception e) {
LOG.debug("Could not set {}, defaults to {}", JobManager.INTERRUPT_MAX_RETRIES_KEY, interruptMaxRetries, e);
}
@@ -54,7 +67,7 @@ public abstract class AbstractInterruptableJob implements InterruptableJob {
@Override
public void interrupt() throws UnableToInterruptJobException {
- Thread thread = this.runningThread.getAndSet(null);
+ Thread thread = runningThread.getAndSet(null);
if (thread == null) {
LOG.warn("Unable to retrieve the thread of the current job execution");
} else {
@@ -68,7 +81,7 @@ public abstract class AbstractInterruptableJob implements InterruptableJob {
}
// if the thread is still alive, it should be available in the next stop
if (thread.isAlive()) {
- this.runningThread.set(thread);
+ runningThread.set(thread);
}
}
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java
index 5fc5405..7103b7b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java
@@ -19,6 +19,7 @@
package org.apache.syncope.core.provisioning.java.job;
import java.util.Date;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.core.provisioning.api.utils.ExceptionUtils2;
import org.apache.syncope.core.persistence.api.dao.TaskDAO;
@@ -72,6 +73,13 @@ public abstract class AbstractSchedTaskJobDelegate implements SchedTaskJobDelega
@Autowired
protected AuditManager auditManager;
+ protected final AtomicReference<String> status = new AtomicReference<>();
+
+ @Override
+ public String currentStatus() {
+ return status.get();
+ }
+
@Transactional
@Override
public void execute(final String taskKey, final boolean dryRun, final JobExecutionContext context)
@@ -90,6 +98,8 @@ public abstract class AbstractSchedTaskJobDelegate implements SchedTaskJobDelega
execution.setStart(new Date());
execution.setTask(task);
+ status.set("Initialization completed");
+
AuditElements.Result result;
try {
@@ -110,6 +120,8 @@ public abstract class AbstractSchedTaskJobDelegate implements SchedTaskJobDelega
}
task = taskDAO.save(task);
+ status.set("Done");
+
notificationManager.createTasks(
AuditElements.EventCategoryType.TASK,
this.getClass().getSimpleName(),
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/GroupMemberProvisionTaskJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/GroupMemberProvisionTaskJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/GroupMemberProvisionTaskJobDelegate.java
index 4868bbc..4f1a1eb 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/GroupMemberProvisionTaskJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/GroupMemberProvisionTaskJobDelegate.java
@@ -82,20 +82,25 @@ public class GroupMemberProvisionTaskJobDelegate extends AbstractSchedTaskJobDel
}
result.append("provision\n\n");
+ status.set(result.toString());
+
MembershipCond membershipCond = new MembershipCond();
membershipCond.setGroup(groupKey);
List<User> users = searchDAO.search(SearchCond.getLeafCond(membershipCond), AnyTypeKind.USER);
Collection<String> groupResourceKeys = groupDAO.findAllResourceKeys(groupKey);
+ status.set("About to "
+ + (actionType == BulkMembersActionType.DEPROVISION ? "de" : "") + "provision "
+ + users.size() + " users from " + groupResourceKeys);
for (User user : users) {
List<PropagationStatus> statuses = actionType == BulkMembersActionType.DEPROVISION
? userProvisioningManager.deprovision(user.getKey(), groupResourceKeys, false)
: userProvisioningManager.provision(user.getKey(), true, null, groupResourceKeys, false);
- for (PropagationStatus status : statuses) {
+ for (PropagationStatus propagationStatus : statuses) {
result.append("User ").append(user.getKey()).append('\t').
- append("Resource ").append(status.getResource()).append('\t').
- append(status.getStatus());
- if (StringUtils.isNotBlank(status.getFailureReason())) {
- result.append('\n').append(status.getFailureReason()).append('\n');
+ append("Resource ").append(propagationStatus.getResource()).append('\t').
+ append(propagationStatus.getStatus());
+ if (StringUtils.isNotBlank(propagationStatus.getFailureReason())) {
+ result.append('\n').append(propagationStatus.getFailureReason()).append('\n');
}
result.append("\n");
}
@@ -105,17 +110,20 @@ public class GroupMemberProvisionTaskJobDelegate extends AbstractSchedTaskJobDel
membershipCond = new MembershipCond();
membershipCond.setGroup(groupKey);
List<AnyObject> anyObjects = searchDAO.search(SearchCond.getLeafCond(membershipCond), AnyTypeKind.ANY_OBJECT);
+ status.set("About to "
+ + (actionType == BulkMembersActionType.DEPROVISION ? "de" : "") + "provision "
+ + anyObjects.size() + " any objects from " + groupResourceKeys);
for (AnyObject anyObject : anyObjects) {
List<PropagationStatus> statuses = actionType == BulkMembersActionType.DEPROVISION
? anyObjectProvisioningManager.deprovision(anyObject.getKey(), groupResourceKeys, false)
: anyObjectProvisioningManager.provision(anyObject.getKey(), groupResourceKeys, false);
- for (PropagationStatus status : statuses) {
+ for (PropagationStatus propagationStatus : statuses) {
result.append(anyObject.getType().getKey()).append(' ').append(anyObject.getKey()).append('\t').
- append("Resource ").append(status.getResource()).append('\t').
- append(status.getStatus());
- if (StringUtils.isNotBlank(status.getFailureReason())) {
- result.append('\n').append(status.getFailureReason()).append('\n');
+ append("Resource ").append(propagationStatus.getResource()).append('\t').
+ append(propagationStatus.getStatus());
+ if (StringUtils.isNotBlank(propagationStatus.getFailureReason())) {
+ result.append('\n').append(propagationStatus.getFailureReason()).append('\n');
}
result.append("\n");
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/IdentityRecertification.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/IdentityRecertification.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/IdentityRecertification.java
index 8b3f4e5..332af19 100755
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/IdentityRecertification.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/IdentityRecertification.java
@@ -87,8 +87,15 @@ public class IdentityRecertification extends AbstractSchedTaskJobDelegate {
return "DRY RUN";
}
+ int total = userDAO.count();
+ int pages = (total / AnyDAO.DEFAULT_PAGE_SIZE) + 1;
+
+ status.set("Processing " + total + " users in " + pages + " pages");
+
long now = System.currentTimeMillis();
- for (int page = 1; page <= (userDAO.count() / AnyDAO.DEFAULT_PAGE_SIZE) + 1; page++) {
+ for (int page = 1; page <= pages; page++) {
+ status.set("Processing " + total + " users: page " + page + " of " + pages);
+
for (User user : userDAO.findAll(page, AnyDAO.DEFAULT_PAGE_SIZE)) {
LOG.debug("Processing user: {}", user.getUsername());
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
index 041d3b4..d688179 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
@@ -19,6 +19,7 @@
package org.apache.syncope.core.provisioning.java.job;
import org.apache.commons.lang3.ClassUtils;
+import org.apache.syncope.core.provisioning.api.job.JobDelegate;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
@@ -52,6 +53,8 @@ public class TaskJob extends AbstractInterruptableJob {
*/
private String taskKey;
+ private SchedTaskJobDelegate delegate;
+
/**
* Task key setter.
*
@@ -62,6 +65,11 @@ public class TaskJob extends AbstractInterruptableJob {
}
@Override
+ public JobDelegate getDelegate() {
+ return delegate;
+ }
+
+ @Override
public void execute(final JobExecutionContext context) throws JobExecutionException {
super.execute(context);
@@ -75,11 +83,12 @@ public class TaskJob extends AbstractInterruptableJob {
Class<?> delegateClass =
ClassUtils.getClass(context.getMergedJobDataMap().getString(DELEGATE_CLASS_KEY));
- ((SchedTaskJobDelegate) ApplicationContextProvider.getBeanFactory().
- createBean(delegateClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false)).
- execute(taskKey,
- context.getMergedJobDataMap().getBoolean(DRY_RUN_JOBDETAIL_KEY),
- context);
+ delegate = ((SchedTaskJobDelegate) ApplicationContextProvider.getBeanFactory().
+ createBean(delegateClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false));
+ delegate.execute(
+ taskKey,
+ context.getMergedJobDataMap().getBoolean(DRY_RUN_JOBDETAIL_KEY),
+ context);
} catch (Exception e) {
LOG.error("While executing task {}", taskKey, e);
throw new RuntimeException(e);
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/DefaultNotificationJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/DefaultNotificationJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/DefaultNotificationJobDelegate.java
new file mode 100644
index 0000000..7ab218b
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/DefaultNotificationJobDelegate.java
@@ -0,0 +1,296 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java.job.notification;
+
+import java.io.PrintStream;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.LogOutputStream;
+import org.apache.syncope.common.lib.PropertyUtils;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.lib.types.TraceLevel;
+import org.apache.syncope.core.provisioning.api.utils.ExceptionUtils2;
+import org.apache.syncope.core.persistence.api.dao.TaskDAO;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.core.provisioning.api.AuditManager;
+import org.apache.syncope.core.provisioning.api.notification.NotificationJobDelegate;
+import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
+import org.apache.syncope.core.spring.security.Encryptor;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class DefaultNotificationJobDelegate implements InitializingBean, NotificationJobDelegate {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationJobDelegate.class);
+
+ @Autowired
+ private TaskDAO taskDAO;
+
+ @Autowired
+ private JavaMailSender mailSender;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ @Autowired
+ private AuditManager auditManager;
+
+ @Autowired
+ private NotificationManager notificationManager;
+
+ private final AtomicReference<String> status = new AtomicReference<>();
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ if (mailSender instanceof JavaMailSenderImpl) {
+ JavaMailSenderImpl javaMailSender = (JavaMailSenderImpl) mailSender;
+
+ Properties javaMailProperties = javaMailSender.getJavaMailProperties();
+
+ Properties props = PropertyUtils.read(Encryptor.class, "mail.properties", "conf.directory").getLeft();
+ for (Enumeration<?> e = props.propertyNames(); e.hasMoreElements();) {
+ String prop = (String) e.nextElement();
+ if (prop.startsWith("mail.smtp.")) {
+ javaMailProperties.setProperty(prop, props.getProperty(prop));
+ }
+ }
+
+ if (StringUtils.isNotBlank(javaMailSender.getUsername())) {
+ javaMailProperties.setProperty("mail.smtp.auth", "true");
+ }
+
+ javaMailSender.setJavaMailProperties(javaMailProperties);
+
+ String mailDebug = props.getProperty("mail.debug", "false");
+ if (BooleanUtils.toBoolean(mailDebug)) {
+ Session session = javaMailSender.getSession();
+ session.setDebug(true);
+ session.setDebugOut(new PrintStream(new LogOutputStream(LOG)));
+ }
+ }
+ }
+
+ @Override
+ public String currentStatus() {
+ return status.get();
+ }
+
+ @Transactional
+ @Override
+ public TaskExec executeSingle(final NotificationTask task) {
+ TaskExec execution = entityFactory.newEntity(TaskExec.class);
+ execution.setTask(task);
+ execution.setStart(new Date());
+
+ boolean retryPossible = true;
+
+ if (StringUtils.isBlank(task.getSubject()) || task.getRecipients().isEmpty()
+ || StringUtils.isBlank(task.getHtmlBody()) || StringUtils.isBlank(task.getTextBody())) {
+
+ String message = "Could not fetch all required information for sending e-mails:\n"
+ + task.getRecipients() + "\n"
+ + task.getSender() + "\n"
+ + task.getSubject() + "\n"
+ + task.getHtmlBody() + "\n"
+ + task.getTextBody();
+ LOG.error(message);
+
+ execution.setStatus(NotificationJob.Status.NOT_SENT.name());
+ retryPossible = false;
+
+ if (task.getTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal()) {
+ execution.setMessage(message);
+ }
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("About to send e-mails:\n"
+ + task.getRecipients() + "\n"
+ + task.getSender() + "\n"
+ + task.getSubject() + "\n"
+ + task.getHtmlBody() + "\n"
+ + task.getTextBody() + "\n");
+ }
+
+ status.set("Sending notifications to " + task.getRecipients());
+
+ for (String to : task.getRecipients()) {
+ try {
+ MimeMessage message = mailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(message, true);
+ helper.setTo(to);
+ helper.setFrom(task.getSender());
+ helper.setSubject(task.getSubject());
+ helper.setText(task.getTextBody(), task.getHtmlBody());
+
+ mailSender.send(message);
+
+ execution.setStatus(NotificationJob.Status.SENT.name());
+
+ StringBuilder report = new StringBuilder();
+ switch (task.getTraceLevel()) {
+ case ALL:
+ report.append("FROM: ").append(task.getSender()).append('\n').
+ append("TO: ").append(to).append('\n').
+ append("SUBJECT: ").append(task.getSubject()).append('\n').append('\n').
+ append(task.getTextBody()).append('\n').append('\n').
+ append(task.getHtmlBody()).append('\n');
+ break;
+
+ case SUMMARY:
+ report.append("E-mail sent to ").append(to).append('\n');
+ break;
+
+ case FAILURES:
+ case NONE:
+ default:
+ }
+ if (report.length() > 0) {
+ execution.setMessage(report.toString());
+ }
+
+ notificationManager.createTasks(
+ AuditElements.EventCategoryType.TASK,
+ "notification",
+ null,
+ "send",
+ AuditElements.Result.SUCCESS,
+ null,
+ null,
+ task,
+ "Successfully sent notification to " + to);
+ } catch (Exception e) {
+ LOG.error("Could not send e-mail", e);
+
+ execution.setStatus(NotificationJob.Status.NOT_SENT.name());
+ if (task.getTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal()) {
+ execution.setMessage(ExceptionUtils2.getFullStackTrace(e));
+ }
+
+ notificationManager.createTasks(
+ AuditElements.EventCategoryType.TASK,
+ "notification",
+ null,
+ "send",
+ AuditElements.Result.FAILURE,
+ null,
+ null,
+ task,
+ "Could not send notification to " + to, e);
+ }
+
+ execution.setEnd(new Date());
+ }
+ }
+
+ if (hasToBeRegistered(execution)) {
+ execution = notificationManager.storeExec(execution);
+ if (retryPossible
+ && (NotificationJob.Status.valueOf(execution.getStatus()) == NotificationJob.Status.NOT_SENT)) {
+
+ handleRetries(execution);
+ }
+ } else {
+ notificationManager.setTaskExecuted(execution.getTask().getKey(), true);
+ }
+
+ return execution;
+ }
+
+ @Transactional
+ @Override
+ public void execute() throws JobExecutionException {
+ List<NotificationTask> tasks = taskDAO.<NotificationTask>findToExec(TaskType.NOTIFICATION);
+
+ status.set("Sending out " + tasks.size() + " notifications");
+
+ for (NotificationTask task : tasks) {
+ LOG.debug("Found notification task {} to be executed: starting...", task);
+ executeSingle(task);
+ LOG.debug("Notification task {} executed", task);
+ }
+ }
+
+ private boolean hasToBeRegistered(final TaskExec execution) {
+ NotificationTask task = (NotificationTask) execution.getTask();
+
+ // True if either failed and failures have to be registered, or if ALL
+ // has to be registered.
+ return (NotificationJob.Status.valueOf(execution.getStatus()) == NotificationJob.Status.NOT_SENT
+ && task.getTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal())
+ || task.getTraceLevel() == TraceLevel.ALL;
+ }
+
+ private void handleRetries(final TaskExec execution) {
+ if (notificationManager.getMaxRetries() <= 0) {
+ return;
+ }
+
+ long failedExecutionsCount = notificationManager.countExecutionsWithStatus(
+ execution.getTask().getKey(), NotificationJob.Status.NOT_SENT.name());
+
+ if (failedExecutionsCount <= notificationManager.getMaxRetries()) {
+ LOG.debug("Execution of notification task {} will be retried [{}/{}]",
+ execution.getTask(), failedExecutionsCount, notificationManager.getMaxRetries());
+ notificationManager.setTaskExecuted(execution.getTask().getKey(), false);
+
+ auditManager.audit(
+ AuditElements.EventCategoryType.TASK,
+ "notification",
+ null,
+ "retry",
+ AuditElements.Result.SUCCESS,
+ null,
+ null,
+ execution,
+ "Notification task " + execution.getTask().getKey() + " will be retried");
+ } else {
+ LOG.error("Maximum number of retries reached for task {} - giving up", execution.getTask());
+
+ auditManager.audit(
+ AuditElements.EventCategoryType.TASK,
+ "notification",
+ null,
+ "retry",
+ AuditElements.Result.FAILURE,
+ null,
+ null,
+ execution,
+ "Giving up retries on notification task " + execution.getTask().getKey());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/799f079f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/NotificationJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/NotificationJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/NotificationJob.java
index 153a221..7edcce2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/NotificationJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/notification/NotificationJob.java
@@ -20,6 +20,8 @@ package org.apache.syncope.core.provisioning.java.job.notification;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.apache.syncope.core.persistence.api.DomainsHolder;
+import org.apache.syncope.core.provisioning.api.job.JobDelegate;
+import org.apache.syncope.core.provisioning.api.notification.NotificationJobDelegate;
import org.apache.syncope.core.provisioning.java.job.AbstractInterruptableJob;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
@@ -54,6 +56,11 @@ public class NotificationJob extends AbstractInterruptableJob {
private NotificationJobDelegate delegate;
@Override
+ public JobDelegate getDelegate() {
+ return delegate;
+ }
+
+ @Override
public void execute(final JobExecutionContext context) throws JobExecutionException {
super.execute(context);