You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by gi...@apache.org on 2015/05/29 11:51:09 UTC

[1/3] syncope git commit: [SYNCOPE-660] Added console utilities for runtime task management

Repository: syncope
Updated Branches:
  refs/heads/master 8ea1e6acc -> 34a0422ae


[SYNCOPE-660] Added console utilities for runtime task management


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/790704c0
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/790704c0
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/790704c0

Branch: refs/heads/master
Commit: 790704c08790f8a2536af84ed46290f1596851f0
Parents: f672ce4
Author: giacomolm <gi...@hotmail.it>
Authored: Thu May 28 17:27:12 2015 +0200
Committer: giacomolm <gi...@hotmail.it>
Committed: Fri May 29 10:30:57 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/console/pages/Reports.java   |  11 ++
 .../org/apache/syncope/console/pages/Tasks.java |  15 ++-
 .../console/pages/panels/NotificationTasks.java |   4 +
 .../console/pages/panels/RuntimePanel.java      | 105 +++++++++++++++++++
 .../console/pages/panels/SchedTasks.java        |   6 ++
 .../console/pages/panels/SyncTasksPanel.java    |   4 +
 .../syncope/console/rest/JobRestClient.java     |  31 ++++++
 .../syncope/console/rest/ReportRestClient.java  |  25 ++++-
 .../syncope/console/rest/TaskRestClient.java    |  23 +++-
 .../html/repeater/data/table/JobColumn.java     |  94 +++++++++++++++++
 .../apache/syncope/console/pages/Reports.html   |  13 +++
 .../org/apache/syncope/console/pages/Tasks.html |  15 +++
 .../console/pages/panels/RuntimePanel.html      |  49 +++++++++
 .../rest/controller/AbstractJobController.java  |  15 ++-
 14 files changed, 404 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/pages/Reports.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/pages/Reports.java b/console/src/main/java/org/apache/syncope/console/pages/Reports.java
index 3f09762..88fdf1c 100644
--- a/console/src/main/java/org/apache/syncope/console/pages/Reports.java
+++ b/console/src/main/java/org/apache/syncope/console/pages/Reports.java
@@ -38,6 +38,7 @@ import org.apache.syncope.console.rest.LoggerRestClient;
 import org.apache.syncope.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
 import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
 import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.JobColumn;
 import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.console.wicket.markup.html.form.ActionLinksPanel;
 import org.apache.wicket.Component;
@@ -61,6 +62,7 @@ import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.PropertyModel;
 import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.model.StringResourceModel;
 import org.apache.wicket.model.util.ListModel;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.spring.injection.annot.SpringBean;
@@ -123,6 +125,8 @@ public class Reports extends BasePage {
         columns.add(new DatePropertyColumn<ReportTO>(new ResourceModel("endDate"), "endDate", "endDate"));
         columns.add(new PropertyColumn<ReportTO, String>(
                 new ResourceModel("latestExecStatus"), "latestExecStatus", "latestExecStatus"));
+        columns.add(new JobColumn<ReportTO, String>(new StringResourceModel("", this, null, ""), "runtime",
+                getPageReference(), reportRestClient));
         columns.add(new ActionColumn<ReportTO, String>(new ResourceModel("actions", "")) {
 
             private static final long serialVersionUID = 2054811145491901166L;
@@ -411,4 +415,11 @@ public class Reports extends BasePage {
             };
         }
     }
+    /**
+     * IndicatorMarkupId behaviour is embedded in Reports.html
+     */
+    @Override
+    public String getAjaxIndicatorMarkupId() {
+        return "";
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/pages/Tasks.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/pages/Tasks.java b/console/src/main/java/org/apache/syncope/console/pages/Tasks.java
index aae3622..11819c6 100644
--- a/console/src/main/java/org/apache/syncope/console/pages/Tasks.java
+++ b/console/src/main/java/org/apache/syncope/console/pages/Tasks.java
@@ -152,10 +152,10 @@ public class Tasks extends BasePage {
         @Override
         public Iterator<T> iterator(final long first, final long count) {
             final List<T> tasks = new ArrayList<T>();
-            
+
             final int page = ((int) first / paginatorRows);
-            
-            for (T task : restClient.list(reference, (page < 0 ? 0 : page)  + 1, paginatorRows, getSort())) {
+
+            for (T task : restClient.list(reference, (page < 0 ? 0 : page) + 1, paginatorRows, getSort())) {
                 if (task instanceof SchedTaskTO && ((SchedTaskTO) task).getLastExec() == null
                         && task.getExecutions() != null && !task.getExecutions().isEmpty()) {
 
@@ -227,4 +227,13 @@ public class Tasks extends BasePage {
 
         return table;
     }
+
+    /**
+     * IndicatorMarkupId behaviour is embedded in Tasks.html
+     */
+    @Override
+    public String getAjaxIndicatorMarkupId() {
+        return "";
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/pages/panels/NotificationTasks.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/pages/panels/NotificationTasks.java b/console/src/main/java/org/apache/syncope/console/pages/panels/NotificationTasks.java
index 86fd7bc..9c7b458 100644
--- a/console/src/main/java/org/apache/syncope/console/pages/panels/NotificationTasks.java
+++ b/console/src/main/java/org/apache/syncope/console/pages/panels/NotificationTasks.java
@@ -28,6 +28,7 @@ import org.apache.syncope.console.pages.NotificationTaskModalPage;
 import org.apache.syncope.console.pages.Tasks;
 import org.apache.syncope.console.pages.Tasks.TasksProvider;
 import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
+import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.JobColumn;
 import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.console.wicket.markup.html.form.ActionLinksPanel;
 import org.apache.wicket.Component;
@@ -152,6 +153,9 @@ public class NotificationTasks extends AbstractTasks {
         columns.add(new PropertyColumn<AbstractTaskTO, String>(
                 new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
 
+        columns.add(new JobColumn<AbstractTaskTO, String>(new StringResourceModel("", this, null, ""), "runtime",
+                pageRef, restClient)); 
+
         columns.add(new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) {
 
             private static final long serialVersionUID = 2054811145491901166L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/pages/panels/RuntimePanel.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/pages/panels/RuntimePanel.java b/console/src/main/java/org/apache/syncope/console/pages/panels/RuntimePanel.java
new file mode 100644
index 0000000..3bc525c
--- /dev/null
+++ b/console/src/main/java/org/apache/syncope/console/pages/panels/RuntimePanel.java
@@ -0,0 +1,105 @@
+/*
+ * 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.console.pages.panels;
+
+import org.apache.syncope.console.rest.JobRestClient;
+import org.apache.syncope.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class RuntimePanel extends Panel {
+
+    private static final long serialVersionUID = -9002724127542172464L;
+
+    private boolean latestStatus;
+
+    private Fragment fragmentStop, fragmentSpinner;
+
+    public AbstractAjaxTimerBehavior timer;
+
+    private final PageReference pageRef;
+
+    private final long jobId;
+
+    private final JobRestClient jobRestClient;
+
+    public RuntimePanel(final String componentId, final IModel<?> model, final PageReference pageRef, final long jobId,
+            final JobRestClient jobRestClient) {
+        super(componentId, model);
+        this.pageRef = pageRef;
+        this.jobId = jobId;
+        this.jobRestClient = jobRestClient;
+        latestStatus = false;
+        this.refresh();
+
+    }
+
+    public final void refresh() {
+        boolean currentStatus = jobRestClient.isJobRunning(jobId);
+        if (currentStatus && !latestStatus) {
+            setRunning();
+        } else if (!currentStatus) {
+            setNotRunning();
+        }
+        latestStatus = currentStatus;
+    }
+
+    public void setRunning() {
+        fragmentStop = new Fragment("panelStop", "fragmentStop", this);
+        fragmentStop.addOrReplace(new ClearIndicatingAjaxLink<Void>("stopLink", pageRef) {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            protected void onClickInternal(final AjaxRequestTarget target) {
+                jobRestClient.stopJob(jobId);
+                this.setEnabled(false);
+                target.add(this);
+            }
+
+            @Override
+            public String getAjaxIndicatorMarkupId() {
+                return "";
+            }
+        });
+        addOrReplace(fragmentStop);
+        fragmentSpinner = new Fragment("panelSpinner", "fragmentSpinner", this);
+        addOrReplace(fragmentSpinner);
+    }
+
+    public void setNotRunning() {
+        fragmentStop = new Fragment("panelStop", "emptyFragment", this);
+        addOrReplace(fragmentStop);
+        fragmentSpinner = new Fragment("panelSpinner", "emptyFragment", this);
+        addOrReplace(fragmentSpinner);
+    }
+
+    public void setTimer(AbstractAjaxTimerBehavior timer) {
+        if (this.timer != null) {
+            remove(this.timer);
+        }
+        this.timer = timer;
+        this.add(this.timer);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/pages/panels/SchedTasks.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/pages/panels/SchedTasks.java b/console/src/main/java/org/apache/syncope/console/pages/panels/SchedTasks.java
index f092e55..78591a8 100644
--- a/console/src/main/java/org/apache/syncope/console/pages/panels/SchedTasks.java
+++ b/console/src/main/java/org/apache/syncope/console/pages/panels/SchedTasks.java
@@ -18,6 +18,8 @@
  */
 package org.apache.syncope.console.pages.panels;
 
+import static org.apache.syncope.console.pages.panels.AbstractTasks.TASKS;
+
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.syncope.common.to.SchedTaskTO;
@@ -30,6 +32,7 @@ import org.apache.syncope.console.pages.Tasks.TasksProvider;
 import org.apache.syncope.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
 import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
 import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.JobColumn;
 import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.console.wicket.markup.html.form.ActionLinksPanel;
 import org.apache.wicket.Component;
@@ -167,6 +170,9 @@ public class SchedTasks extends AbstractTasks {
         columns.add(new PropertyColumn<AbstractTaskTO, String>(
                 new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
 
+        columns.add(new JobColumn<AbstractTaskTO, String>(new StringResourceModel("", this, null, ""), "runtime",
+                pageRef, restClient)); 
+
         columns.add(new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) {
 
             private static final long serialVersionUID = 2054811145491901166L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/pages/panels/SyncTasksPanel.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/pages/panels/SyncTasksPanel.java b/console/src/main/java/org/apache/syncope/console/pages/panels/SyncTasksPanel.java
index 71fd2b5..032f4e4 100644
--- a/console/src/main/java/org/apache/syncope/console/pages/panels/SyncTasksPanel.java
+++ b/console/src/main/java/org/apache/syncope/console/pages/panels/SyncTasksPanel.java
@@ -29,6 +29,7 @@ import org.apache.syncope.console.pages.SyncTaskModalPage;
 import org.apache.syncope.console.pages.UserTemplateModalPage;
 import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
 import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.JobColumn;
 import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.console.wicket.markup.html.form.ActionLinksPanel;
 import org.apache.wicket.Component;
@@ -69,6 +70,9 @@ public class SyncTasksPanel extends AbstractSyncTasksPanel<SyncTaskTO> {
                 new StringResourceModel("nextExec", this, null), "nextExec", "nextExec"));
         syncTaskscolumns.add(new PropertyColumn<AbstractTaskTO, String>(
                 new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
+        
+        syncTaskscolumns.add(new JobColumn<AbstractTaskTO, String>(new StringResourceModel("", this, null, ""), "runtime",
+                pageRef, restClient));        
 
         syncTaskscolumns.add(
                 new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/rest/JobRestClient.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/rest/JobRestClient.java b/console/src/main/java/org/apache/syncope/console/rest/JobRestClient.java
new file mode 100644
index 0000000..de361f3
--- /dev/null
+++ b/console/src/main/java/org/apache/syncope/console/rest/JobRestClient.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.console.rest;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public abstract class JobRestClient extends BaseRestClient{
+
+    public abstract boolean isJobRunning(final long id);
+
+    public abstract void startJob(final long id);
+
+    public abstract void stopJob(final long id);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/rest/ReportRestClient.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/rest/ReportRestClient.java b/console/src/main/java/org/apache/syncope/console/rest/ReportRestClient.java
index dff42bf..9b8afdb 100644
--- a/console/src/main/java/org/apache/syncope/console/rest/ReportRestClient.java
+++ b/console/src/main/java/org/apache/syncope/console/rest/ReportRestClient.java
@@ -25,12 +25,15 @@ import org.apache.syncope.common.services.ReportService;
 import org.apache.syncope.common.to.ReportTO;
 import org.apache.syncope.common.types.ReportExecExportFormat;
 import org.apache.syncope.common.SyncopeClientException;
+import org.apache.syncope.common.to.ReportExecTO;
+import org.apache.syncope.common.types.JobAction;
+import org.apache.syncope.common.types.JobStatusType;
 import org.apache.syncope.common.wrap.ReportletConfClass;
 import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
 import org.springframework.stereotype.Component;
 
 @Component
-public class ReportRestClient extends BaseRestClient implements ExecutionRestClient {
+public class ReportRestClient extends JobRestClient implements ExecutionRestClient {
 
     private static final long serialVersionUID = 1644689667998953604L;
 
@@ -105,4 +108,24 @@ public class ReportRestClient extends BaseRestClient implements ExecutionRestCli
     public Response exportExecutionResult(final Long executionId, final ReportExecExportFormat fmt) {
         return getService(ReportService.class).exportExecutionResult(executionId, fmt);
     }
+
+    @Override
+    public boolean isJobRunning(final long reportId) {
+        for (ReportExecTO reportExecTO : getService(ReportService.class).listJobs(JobStatusType.RUNNING)) {
+            if (reportExecTO.getReport() == reportId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void startJob(final long reportId) {
+        getService(ReportService.class).actionJob(reportId, JobAction.START);
+    }
+
+    @Override
+    public void stopJob(final long reportId) {
+        getService(ReportService.class).actionJob(reportId, JobAction.STOP);
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/rest/TaskRestClient.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/rest/TaskRestClient.java b/console/src/main/java/org/apache/syncope/console/rest/TaskRestClient.java
index 863e51a..c83ce88 100644
--- a/console/src/main/java/org/apache/syncope/console/rest/TaskRestClient.java
+++ b/console/src/main/java/org/apache/syncope/console/rest/TaskRestClient.java
@@ -34,6 +34,9 @@ import org.apache.syncope.common.types.TaskType;
 import org.apache.syncope.common.util.CollectionWrapper;
 import org.apache.syncope.common.SyncopeClientException;
 import org.apache.syncope.common.to.PushTaskTO;
+import org.apache.syncope.common.to.TaskExecTO;
+import org.apache.syncope.common.types.JobAction;
+import org.apache.syncope.common.types.JobStatusType;
 import org.apache.syncope.common.wrap.PushActionClass;
 import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
 import org.springframework.stereotype.Component;
@@ -42,7 +45,7 @@ import org.springframework.stereotype.Component;
  * Console client for invoking Rest Tasks services.
  */
 @Component
-public class TaskRestClient extends BaseRestClient implements ExecutionRestClient {
+public class TaskRestClient extends JobRestClient implements ExecutionRestClient {
 
     private static final long serialVersionUID = 6284485820911028843L;
 
@@ -167,4 +170,22 @@ public class TaskRestClient extends BaseRestClient implements ExecutionRestClien
     public BulkActionResult bulkAction(final BulkAction action) {
         return getService(TaskService.class).bulk(action);
     }
+    
+    @Override
+    public boolean isJobRunning(final long taskId){
+        for(TaskExecTO taskExecTO : getService(TaskService.class).listJobs(JobStatusType.RUNNING)){
+            if(taskExecTO.getTask()== taskId) return true;
+        }
+        return false;
+    }
+    
+    @Override
+    public void startJob(final long taskId){
+        getService(TaskService.class).actionJob(taskId, JobAction.START);
+    }
+
+    @Override
+    public void stopJob(final long taskId) {
+        getService(TaskService.class).actionJob(taskId, JobAction.STOP);
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/java/org/apache/syncope/console/wicket/extensions/markup/html/repeater/data/table/JobColumn.java
----------------------------------------------------------------------
diff --git a/console/src/main/java/org/apache/syncope/console/wicket/extensions/markup/html/repeater/data/table/JobColumn.java b/console/src/main/java/org/apache/syncope/console/wicket/extensions/markup/html/repeater/data/table/JobColumn.java
new file mode 100644
index 0000000..563e3cb
--- /dev/null
+++ b/console/src/main/java/org/apache/syncope/console/wicket/extensions/markup/html/repeater/data/table/JobColumn.java
@@ -0,0 +1,94 @@
+/*
+ * 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.console.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.syncope.common.to.AbstractTaskTO;
+import org.apache.syncope.common.to.ReportTO;
+import org.apache.syncope.console.pages.panels.RuntimePanel;
+import org.apache.syncope.console.rest.JobRestClient;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+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.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JobColumn<T, S> extends AbstractColumn<T, S> {
+
+    private static final long serialVersionUID = 7955560320949560725L;
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JobColumn.class);
+
+    private final PageReference pageRef;
+
+    private RuntimePanel panel;
+
+    private final JobRestClient jobRestClient;
+
+    public JobColumn(final IModel<String> displayModel, final S sortProperty, final PageReference pageRef,
+            final JobRestClient jobRestClient) {
+        super(displayModel, sortProperty);
+        this.pageRef = pageRef;
+        this.jobRestClient = jobRestClient;
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> model) {
+        Long jobId = null;
+        if (model.getObject() instanceof AbstractTaskTO) {
+            jobId = ((AbstractTaskTO) model.getObject()).getId();
+        } else if (model.getObject() instanceof ReportTO) {
+            jobId = ((ReportTO) model.getObject()).getId();
+        }
+        if (jobId != null) {
+            panel = new RuntimePanel(componentId, model, pageRef, jobId, jobRestClient);
+            startPolling(10);
+            item.add(panel);
+        }
+    }
+
+    public void startPolling(final int seconds) {
+        AbstractAjaxTimerBehavior timer = new AbstractAjaxTimerBehavior(Duration.seconds(seconds)) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void onTimer(AjaxRequestTarget target) {
+                panel.refresh();
+                target.add(panel);
+            }
+
+            @Override
+            protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
+                super.updateAjaxAttributes(attributes);
+                attributes.getExtraParameters().put("pollingTimeout", "true");
+            }
+
+        };
+
+        panel.setTimer(timer);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/resources/org/apache/syncope/console/pages/Reports.html
----------------------------------------------------------------------
diff --git a/console/src/main/resources/org/apache/syncope/console/pages/Reports.html b/console/src/main/resources/org/apache/syncope/console/pages/Reports.html
index 456f7a3..ff5fb37 100644
--- a/console/src/main/resources/org/apache/syncope/console/pages/Reports.html
+++ b/console/src/main/resources/org/apache/syncope/console/pages/Reports.html
@@ -18,7 +18,20 @@ under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:extend>
+    <script type="text/javascript">
+      window.onload = setupFunc;
 
+      function setupFunc() {
+        Wicket.Event.subscribe('/ajax/call/beforeSend', function (attributes, jqXHR, settings) {
+          if (!jqXHR.ep || !jqXHR.ep[0] || !jqXHR.ep[0]["value"]) {
+            document.getElementById("veil").style.display = "block";
+          }
+        });
+        Wicket.Event.subscribe('/ajax/call/complete', function (attributes, jqXHR, textStatus) {
+          document.getElementById("veil").style.display = "none";
+        });
+      }
+    </script>
     <div id="tabs">
       <ul>
         <li class="tabs-selected"><a href="#tabs-1"><span><wicket:message key="reports"/></span></a></li>

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/resources/org/apache/syncope/console/pages/Tasks.html
----------------------------------------------------------------------
diff --git a/console/src/main/resources/org/apache/syncope/console/pages/Tasks.html b/console/src/main/resources/org/apache/syncope/console/pages/Tasks.html
index 7df418a..81c9237 100644
--- a/console/src/main/resources/org/apache/syncope/console/pages/Tasks.html
+++ b/console/src/main/resources/org/apache/syncope/console/pages/Tasks.html
@@ -18,6 +18,21 @@ under the License.
 -->
 <wicket:extend>
 
+  <script type="text/javascript">
+    window.onload = setupFunc;
+
+    function setupFunc() {
+      Wicket.Event.subscribe('/ajax/call/beforeSend', function (attributes, jqXHR, settings) {
+        if (!jqXHR.ep || !jqXHR.ep[0] || !jqXHR.ep[0]["value"]){
+          document.getElementById("veil").style.display = "block";
+        }
+      });
+      Wicket.Event.subscribe('/ajax/call/complete', function (attributes, jqXHR, textStatus) {
+        document.getElementById("veil").style.display = "none";
+      });
+    }
+  </script>
+
   <div id="tabs">
     <ul>
       <li class="tabs-selected"><a href="#tabs-1"><span><wicket:message key="tab1"/></span></a></li>

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/console/src/main/resources/org/apache/syncope/console/pages/panels/RuntimePanel.html
----------------------------------------------------------------------
diff --git a/console/src/main/resources/org/apache/syncope/console/pages/panels/RuntimePanel.html b/console/src/main/resources/org/apache/syncope/console/pages/panels/RuntimePanel.html
new file mode 100644
index 0000000..828192c
--- /dev/null
+++ b/console/src/main/resources/org/apache/syncope/console/pages/panels/RuntimePanel.html
@@ -0,0 +1,49 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:head>
+    <style>
+      #runtime{
+        text-align: center;
+      }
+    </style>
+  </wicket:head>
+  <wicket:panel wicket:id="runtime">
+    <div>
+      <div id="runtime">
+        <div id="runtimePanel">
+          <span wicket:id="panelStop"></span>
+          <span wicket:id="panelSpinner"></span>
+
+          <wicket:fragment wicket:id="fragmentStop">
+            <a href="#" wicket:id="stopLink"><img src="img/actions/suspend.png" alt="stop icon" title="Stop Now"/></a>
+          </wicket:fragment>
+
+          <wicket:fragment wicket:id="fragmentSpinner">
+            <img src="img/loading.gif" alt="spinner icon" title="Spinner"/>
+          </wicket:fragment>
+
+          <wicket:fragment wicket:id="emptyFragment"></wicket:fragment>
+
+        </div>
+
+      </div>
+    </div>
+  </wicket:panel>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/790704c0/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractJobController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractJobController.java b/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractJobController.java
index ca759d9..e7aa31e 100644
--- a/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractJobController.java
+++ b/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractJobController.java
@@ -158,7 +158,20 @@ abstract class AbstractJobController<T extends AbstractBaseBean> extends Abstrac
                 if (scheduler.getScheduler().checkExists(jobKey)) {
                     switch (action) {
                         case START:
-                            scheduler.getScheduler().triggerJob(jobKey);
+                            Long currentId = getIdFromJobName(jobKey);
+                            boolean found = false;
+                            //Two or more equals jobs cannot be executed concurrently
+                            for (int i = 0; i < scheduler.getScheduler().getCurrentlyExecutingJobs().size() && !found;
+                                    i++) {
+                                JobExecutionContext jec = scheduler.getScheduler().getCurrentlyExecutingJobs().get(i);
+                                Long jobId = getIdFromJobName(jec.getJobDetail().getKey());
+                                if (jobId == currentId) {
+                                    found = true;
+                                }
+                            }
+                            if (!found) {
+                                scheduler.getScheduler().triggerJob(jobKey);
+                            }
                             break;
 
                         case STOP:


[3/3] syncope git commit: [SYNCOPE-660] Merge from 1_2_X; This closes #6

Posted by gi...@apache.org.
[SYNCOPE-660] Merge from 1_2_X; This closes #6


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/34a0422a
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/34a0422a
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/34a0422a

Branch: refs/heads/master
Commit: 34a0422aec960f6e9bb459e69e8453bd8bf21b6f
Parents: 8ea1e6a 790704c
Author: giacomolm <gi...@hotmail.it>
Authored: Fri May 29 11:50:07 2015 +0200
Committer: giacomolm <gi...@hotmail.it>
Committed: Fri May 29 11:50:07 2015 +0200

----------------------------------------------------------------------
 .../syncope/client/console/pages/Reports.java   |  79 ++++++++------
 .../syncope/client/console/pages/Tasks.java     |  49 +++++----
 .../console/panels/NotificationTasks.java       |  34 +++---
 .../client/console/panels/RuntimePanel.java     | 105 +++++++++++++++++++
 .../client/console/panels/SchedTasks.java       |  40 ++++---
 .../client/console/panels/SyncTasksPanel.java   |  49 +++++----
 .../client/console/rest/JobRestClient.java      |  31 ++++++
 .../client/console/rest/ReportRestClient.java   |  39 +++++--
 .../client/console/rest/TaskRestClient.java     |  88 ++++++++++++----
 .../html/repeater/data/table/JobColumn.java     |  94 +++++++++++++++++
 .../syncope/client/console/pages/Reports.html   |  13 +++
 .../syncope/client/console/pages/Tasks.html     |  15 +++
 .../client/console/panels/RuntimePanel.html     |  49 +++++++++
 .../syncope/core/logic/AbstractJobLogic.java    |  15 ++-
 14 files changed, 566 insertions(+), 134 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/pages/Reports.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/pages/Reports.java
index e484701,0000000..88fdf1c
mode 100644,000000..100644
--- a/client/old_console/src/main/java/org/apache/syncope/client/console/pages/Reports.java
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/pages/Reports.java
@@@ -1,412 -1,0 +1,425 @@@
 +/*
 + * 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.client.console.pages;
++package org.apache.syncope.console.pages;
 +
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.Iterator;
 +import java.util.List;
- import org.apache.commons.lang3.tuple.Pair;
- import org.apache.syncope.client.console.commons.Constants;
- import org.apache.syncope.client.console.commons.PreferenceManager;
- import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
- import org.apache.syncope.client.console.panels.LoggerCategoryPanel;
- import org.apache.syncope.client.console.panels.SelectedEventsPanel;
- import org.apache.syncope.client.console.rest.LoggerRestClient;
- import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
- import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
- import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
- import org.apache.syncope.common.lib.SyncopeClientException;
- import org.apache.syncope.common.lib.to.EventCategoryTO;
- import org.apache.syncope.common.lib.to.ReportTO;
- import org.apache.syncope.common.lib.types.AuditElements.Result;
- import org.apache.syncope.common.lib.types.AuditLoggerName;
++import java.util.Map;
++import org.apache.syncope.common.to.EventCategoryTO;
++import org.apache.syncope.common.to.ReportTO;
++import org.apache.syncope.common.types.AuditElements.Result;
++import org.apache.syncope.common.types.AuditLoggerName;
++import org.apache.syncope.common.util.LoggerEventUtils;
++import org.apache.syncope.common.SyncopeClientException;
++import org.apache.syncope.console.commons.Constants;
++import org.apache.syncope.console.commons.PreferenceManager;
++import org.apache.syncope.console.commons.SortableDataProviderComparator;
++import org.apache.syncope.console.pages.panels.LoggerCategoryPanel;
++import org.apache.syncope.console.pages.panels.SelectedEventsPanel;
++import org.apache.syncope.console.rest.LoggerRestClient;
++import org.apache.syncope.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.JobColumn;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLinksPanel;
 +import org.apache.wicket.Component;
 +import org.apache.wicket.Page;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 +import org.apache.wicket.ajax.markup.html.AjaxLink;
 +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
 +import org.apache.wicket.event.IEvent;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
 +import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
 +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.extensions.markup.html.repeater.util.SortableDataProvider;
 +import org.apache.wicket.markup.html.WebMarkupContainer;
 +import org.apache.wicket.markup.html.form.DropDownChoice;
 +import org.apache.wicket.markup.html.form.Form;
 +import org.apache.wicket.model.AbstractReadOnlyModel;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.Model;
 +import org.apache.wicket.model.PropertyModel;
 +import org.apache.wicket.model.ResourceModel;
++import org.apache.wicket.model.StringResourceModel;
 +import org.apache.wicket.model.util.ListModel;
 +import org.apache.wicket.request.mapper.parameter.PageParameters;
 +import org.apache.wicket.spring.injection.annot.SpringBean;
 +import org.springframework.util.CollectionUtils;
 +
 +/**
 + * Auditing and Reporting.
 + */
 +public class Reports extends BasePage {
 +
 +    private static final long serialVersionUID = -2071214196989178694L;
 +
 +    private static final int WIN_HEIGHT = 500;
 +
 +    private static final int WIN_WIDTH = 700;
 +
 +    @SpringBean
 +    private LoggerRestClient loggerRestClient;
 +
 +    @SpringBean
 +    private PreferenceManager prefMan;
 +
 +    private WebMarkupContainer reportContainer;
 +
 +    private WebMarkupContainer auditContainer;
 +
 +    private int paginatorRows;
 +
 +    private final ModalWindow window;
 +
 +    public Reports(final PageParameters parameters) {
 +        super(parameters);
 +
 +        window = new ModalWindow("reportWin");
 +        window.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
 +        window.setInitialHeight(WIN_HEIGHT);
 +        window.setInitialWidth(WIN_WIDTH);
 +        window.setCookieName("view-report-win");
 +        add(window);
 +
 +        setupReport();
 +        setupAudit();
 +    }
 +
 +    private void setupReport() {
 +        reportContainer = new WebMarkupContainer("reportContainer");
 +        setWindowClosedCallback(window, reportContainer);
 +
 +        MetaDataRoleAuthorizationStrategy.authorize(reportContainer, RENDER,
 +                xmlRolesReader.getEntitlement("Reports", "list"));
 +
 +        paginatorRows = prefMan.getPaginatorRows(getRequest(), Constants.PREF_REPORT_PAGINATOR_ROWS);
 +
-         List<IColumn<ReportTO, String>> columns = new ArrayList<>();
-         columns.add(new PropertyColumn<ReportTO, String>(new ResourceModel("key"), "key", "key"));
++        List<IColumn<ReportTO, String>> columns = new ArrayList<IColumn<ReportTO, String>>();
++        columns.add(new PropertyColumn<ReportTO, String>(new ResourceModel("id"), "id", "id"));
 +        columns.add(new PropertyColumn<ReportTO, String>(new ResourceModel("name"), "name", "name"));
 +        columns.add(new DatePropertyColumn<ReportTO>(new ResourceModel("lastExec"), "lastExec", "lastExec"));
 +        columns.add(new DatePropertyColumn<ReportTO>(new ResourceModel("nextExec"), "nextExec", "nextExec"));
 +        columns.add(new DatePropertyColumn<ReportTO>(new ResourceModel("startDate"), "startDate", "startDate"));
 +        columns.add(new DatePropertyColumn<ReportTO>(new ResourceModel("endDate"), "endDate", "endDate"));
 +        columns.add(new PropertyColumn<ReportTO, String>(
 +                new ResourceModel("latestExecStatus"), "latestExecStatus", "latestExecStatus"));
++        columns.add(new JobColumn<ReportTO, String>(new StringResourceModel("", this, null, ""), "runtime",
++                getPageReference(), reportRestClient));
 +        columns.add(new ActionColumn<ReportTO, String>(new ResourceModel("actions", "")) {
 +
 +            private static final long serialVersionUID = 2054811145491901166L;
 +
 +            @Override
 +            public ActionLinksPanel getActions(final String componentId, final IModel<ReportTO> model) {
 +
 +                final ReportTO reportTO = model.getObject();
 +
 +                final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, getPageReference());
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +
 +                        window.setPageCreator(new ModalWindow.PageCreator() {
 +
 +                            private static final long serialVersionUID = -7834632442532690940L;
 +
 +                            @Override
 +                            public Page createPage() {
 +                                return new ReportModalPage(window, reportTO, Reports.this.getPageReference());
 +                            }
 +                        });
 +
 +                        window.show(target);
 +                    }
 +                }, ActionLink.ActionType.EDIT, "Reports");
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        try {
-                             reportRestClient.startExecution(reportTO.getKey());
++                            reportRestClient.startExecution(reportTO.getId());
 +                            getSession().info(getString(Constants.OPERATION_SUCCEEDED));
 +                        } catch (SyncopeClientException scce) {
 +                            error(scce.getMessage());
 +                        }
 +
 +                        feedbackPanel.refresh(target);
 +                        target.add(reportContainer);
 +                    }
 +                }, ActionLink.ActionType.EXECUTE, "Reports");
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        try {
-                             reportRestClient.delete(reportTO.getKey());
++                            reportRestClient.delete(reportTO.getId());
 +                            info(getString(Constants.OPERATION_SUCCEEDED));
 +                        } catch (SyncopeClientException scce) {
 +                            error(scce.getMessage());
 +                        }
 +                        target.add(reportContainer);
 +                        feedbackPanel.refresh(target);
 +                    }
 +                }, ActionLink.ActionType.DELETE, "Reports");
 +
 +                return panel;
 +            }
 +
 +            @Override
 +            public Component getHeader(final String componentId) {
 +                final ActionLinksPanel panel = new ActionLinksPanel(componentId, new Model(), getPageReference());
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -7978723352517770644L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        if (target != null) {
 +                            target.add(reportContainer);
 +                        }
 +                    }
 +                }, ActionLink.ActionType.RELOAD, TASKS, "list");
 +
 +                return panel;
 +            }
 +        });
 +
 +        final AjaxFallbackDefaultDataTable<ReportTO, String> reportTable =
-                 new AjaxFallbackDefaultDataTable<>("reportTable", columns, new ReportProvider(), paginatorRows);
++                new AjaxFallbackDefaultDataTable<ReportTO, String>(
++                        "reportTable", columns, new ReportProvider(), paginatorRows);
 +
 +        reportContainer.add(reportTable);
 +        reportContainer.setOutputMarkupId(true);
 +
 +        add(reportContainer);
 +
 +        @SuppressWarnings("rawtypes")
 +        Form paginatorForm = new Form("paginatorForm");
 +
 +        MetaDataRoleAuthorizationStrategy.authorize(paginatorForm, RENDER,
 +                xmlRolesReader.getEntitlement("Reports", "list"));
 +
 +        @SuppressWarnings({ "unchecked", "rawtypes" })
 +        final DropDownChoice rowsChooser = new DropDownChoice("rowsChooser", new PropertyModel(this, "paginatorRows"),
 +                prefMan.getPaginatorChoices());
 +
 +        rowsChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
 +
 +            private static final long serialVersionUID = -1107858522700306810L;
 +
 +            @Override
 +            protected void onUpdate(final AjaxRequestTarget target) {
 +                prefMan.set(getRequest(), getResponse(), Constants.PREF_REPORT_PAGINATOR_ROWS,
 +                        String.valueOf(paginatorRows));
 +                reportTable.setItemsPerPage(paginatorRows);
 +
 +                target.add(reportContainer);
 +            }
 +        });
 +
 +        paginatorForm.add(rowsChooser);
 +        add(paginatorForm);
 +
-         AjaxLink<Void> createLink = new ClearIndicatingAjaxLink<Void>("createLink", getPageReference()) {
++        AjaxLink createLink = new ClearIndicatingAjaxLink("createLink", getPageReference()) {
 +
 +            private static final long serialVersionUID = -7978723352517770644L;
 +
 +            @Override
 +            protected void onClickInternal(final AjaxRequestTarget target) {
 +                window.setPageCreator(new ModalWindow.PageCreator() {
 +
 +                    private static final long serialVersionUID = -7834632442532690940L;
 +
 +                    @Override
 +                    public Page createPage() {
 +                        return new ReportModalPage(window, new ReportTO(), Reports.this.getPageReference());
 +                    }
 +                });
 +
 +                window.show(target);
 +            }
 +        };
 +
 +        MetaDataRoleAuthorizationStrategy.authorize(createLink, RENDER, xmlRolesReader.getEntitlement("Reports",
 +                "create"));
 +
 +        add(createLink);
 +    }
 +
 +    @SuppressWarnings("rawtypes")
 +    private void setupAudit() {
 +        auditContainer = new WebMarkupContainer("auditContainer");
 +        auditContainer.setOutputMarkupId(true);
 +        add(auditContainer);
 +
 +        MetaDataRoleAuthorizationStrategy.authorize(
 +                auditContainer, RENDER, xmlRolesReader.getEntitlement("Audit", "list"));
 +
 +        final Form form = new Form("auditForm");
 +        auditContainer.add(form);
 +
-         final List<String> events = new ArrayList<>();
++        final List<String> events = new ArrayList<String>();
 +
 +        final List<AuditLoggerName> audits = loggerRestClient.listAudits();
 +        for (AuditLoggerName audit : audits) {
-             events.add(AuditLoggerName.buildEvent(
++            events.add(LoggerEventUtils.buildEvent(
 +                    audit.getType(),
 +                    audit.getCategory(),
 +                    audit.getSubcategory(),
 +                    audit.getEvent(),
 +                    audit.getResult()));
 +        }
 +
-         final ListModel<String> model = new ListModel<>(new ArrayList<>(events));
++        final ListModel<String> model = new ListModel<String>(new ArrayList<String>(events));
 +
 +        form.add(new LoggerCategoryPanel(
 +                "events", loggerRestClient.listEvents(), model, getPageReference(), "Reports") {
 +
 +                    private static final long serialVersionUID = 6113164334533550277L;
 +
 +                    @Override
 +                    protected String[] getListRoles() {
 +                        return new String[] {
 +                            xmlRolesReader.getEntitlement("Audit", "list")
 +                        };
 +                    }
 +
 +                    @Override
 +                    protected String[] getChangeRoles() {
 +                        return new String[] {
 +                            xmlRolesReader.getEntitlement("Audit", "enable"),
 +                            xmlRolesReader.getEntitlement("Audit", "disable")
 +                        };
 +                    }
 +
 +                    @Override
 +                    public void onEventAction(final IEvent<?> event) {
 +                        if (event.getPayload() instanceof SelectedEventsPanel.EventSelectionChanged) {
 +
 +                            final SelectedEventsPanel.EventSelectionChanged eventSelectionChanged =
 +                            (SelectedEventsPanel.EventSelectionChanged) event.getPayload();
 +
 +                            for (String toBeRemoved : eventSelectionChanged.getToBeRemoved()) {
 +                                if (events.contains(toBeRemoved)) {
-                                     Pair<EventCategoryTO, Result> eventCategory =
-                                     AuditLoggerName.parseEventCategory(toBeRemoved);
++                                    final Map.Entry<EventCategoryTO, Result> eventCategory =
++                                    LoggerEventUtils.parseEventCategory(toBeRemoved);
 +
 +                                    final AuditLoggerName auditLoggerName = new AuditLoggerName(
 +                                            eventCategory.getKey().getType(),
 +                                            eventCategory.getKey().getCategory(),
 +                                            eventCategory.getKey().getSubcategory(),
 +                                            CollectionUtils.isEmpty(eventCategory.getKey().getEvents())
 +                                                    ? null : eventCategory.getKey().getEvents().iterator().next(),
 +                                            eventCategory.getValue());
 +
 +                                    loggerRestClient.disableAudit(auditLoggerName);
 +                                    events.remove(toBeRemoved);
 +                                }
 +                            }
 +
 +                            for (String toBeAdded : eventSelectionChanged.getToBeAdded()) {
 +                                if (!events.contains(toBeAdded)) {
-                                     Pair<EventCategoryTO, Result> eventCategory =
-                                     AuditLoggerName.parseEventCategory(toBeAdded);
++                                    final Map.Entry<EventCategoryTO, Result> eventCategory =
++                                    LoggerEventUtils.parseEventCategory(toBeAdded);
 +
 +                                    final AuditLoggerName auditLoggerName = new AuditLoggerName(
 +                                            eventCategory.getKey().getType(),
 +                                            eventCategory.getKey().getCategory(),
 +                                            eventCategory.getKey().getSubcategory(),
 +                                            CollectionUtils.isEmpty(eventCategory.getKey().getEvents())
 +                                                    ? null : eventCategory.getKey().getEvents().iterator().next(),
 +                                            eventCategory.getValue());
 +
 +                                    loggerRestClient.enableAudit(auditLoggerName);
 +                                    events.add(toBeAdded);
 +                                }
 +                            }
 +                        }
 +                    }
 +                });
 +    }
 +
 +    private class ReportProvider extends SortableDataProvider<ReportTO, String> {
 +
 +        private static final long serialVersionUID = -2311716167583335852L;
 +
 +        private final SortableDataProviderComparator<ReportTO> comparator;
 +
 +        public ReportProvider() {
 +            super();
 +
 +            //Default sorting
-             setSort("key", SortOrder.ASCENDING);
-             comparator = new SortableDataProviderComparator<>(this);
++            setSort("id", SortOrder.ASCENDING);
++            comparator = new SortableDataProviderComparator<ReportTO>(this);
 +        }
 +
 +        @Override
 +        public Iterator<ReportTO> iterator(final long first, final long count) {
 +            final int page = ((int) first / paginatorRows);
 +
 +            final List<ReportTO> list =
 +                    reportRestClient.list((page < 0 ? 0 : page) + 1, paginatorRows, getSort());
 +            Collections.sort(list, comparator);
 +            return list.iterator();
 +        }
 +
 +        @Override
 +        public long size() {
 +            return reportRestClient.count();
 +        }
 +
 +        @Override
 +        public IModel<ReportTO> model(final ReportTO configuration) {
 +
 +            return new AbstractReadOnlyModel<ReportTO>() {
 +
 +                private static final long serialVersionUID = 4921104837546595602L;
 +
 +                @Override
 +                public ReportTO getObject() {
 +                    return configuration;
 +                }
 +            };
 +        }
 +    }
++    /**
++     * IndicatorMarkupId behaviour is embedded in Reports.html
++     */
++    @Override
++    public String getAjaxIndicatorMarkupId() {
++        return "";
++    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/pages/Tasks.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/pages/Tasks.java
index 296c365,0000000..11819c6
mode 100644,000000..100644
--- a/client/old_console/src/main/java/org/apache/syncope/client/console/pages/Tasks.java
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/pages/Tasks.java
@@@ -1,230 -1,0 +1,239 @@@
 +/*
 + * 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.client.console.pages;
++package org.apache.syncope.console.pages;
 +
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.Collections;
 +import java.util.Comparator;
 +import java.util.Iterator;
 +import java.util.List;
- import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
- import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
- import org.apache.syncope.client.console.panels.NotificationTasks;
- import org.apache.syncope.client.console.panels.PropagationTasks;
- import org.apache.syncope.client.console.panels.PushTasksPanel;
- import org.apache.syncope.client.console.panels.SchedTasks;
- import org.apache.syncope.client.console.panels.SyncTasksPanel;
- import org.apache.syncope.client.console.rest.BaseRestClient;
- import org.apache.syncope.client.console.rest.TaskRestClient;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
- import org.apache.syncope.common.lib.to.AbstractTaskTO;
- import org.apache.syncope.common.lib.to.SchedTaskTO;
- import org.apache.syncope.common.lib.to.TaskExecTO;
++import org.apache.syncope.common.to.SchedTaskTO;
++import org.apache.syncope.common.to.TaskExecTO;
++import org.apache.syncope.common.to.AbstractTaskTO;
++import org.apache.syncope.console.commons.SortableDataProviderComparator;
++import org.apache.syncope.console.pages.panels.AjaxDataTablePanel;
++import org.apache.syncope.console.pages.panels.NotificationTasks;
++import org.apache.syncope.console.pages.panels.PropagationTasks;
++import org.apache.syncope.console.pages.panels.SchedTasks;
++import org.apache.syncope.console.pages.panels.PushTasksPanel;
++import org.apache.syncope.console.pages.panels.SyncTasksPanel;
++import org.apache.syncope.console.rest.BaseRestClient;
++import org.apache.syncope.console.rest.TaskRestClient;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
 +import org.apache.wicket.PageReference;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
 +import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
 +import org.apache.wicket.markup.html.WebMarkupContainer;
 +import org.apache.wicket.model.AbstractReadOnlyModel;
 +import org.apache.wicket.model.CompoundPropertyModel;
 +import org.apache.wicket.model.IModel;
 +
 +public class Tasks extends BasePage {
 +
 +    private static final long serialVersionUID = 5289215853622289061L;
 +
 +    public Tasks() {
 +        super();
 +
 +        add(new PropagationTasks("propagation", getPageReference()));
 +        add(new NotificationTasks("notification", getPageReference()));
 +        add(new SchedTasks("sched", getPageReference()));
 +        add(new SyncTasksPanel("sync", getPageReference()));
 +        add(new PushTasksPanel("push", getPageReference()));
 +
 +        getPageReference();
 +    }
 +
 +    @Override
 +    public void setWindowClosedCallback(final ModalWindow window, final WebMarkupContainer container) {
 +
 +        super.setWindowClosedCallback(window, container);
 +    }
 +
 +    public static class TaskExecutionsProvider extends SortableDataProvider<TaskExecTO, String> {
 +
 +        private static final long serialVersionUID = -5401263348984206145L;
 +
 +        private SortableDataProviderComparator<TaskExecTO> comparator;
 +
 +        private AbstractTaskTO taskTO;
 +
 +        public TaskExecutionsProvider(final AbstractTaskTO taskTO) {
 +            super();
 +
 +            //Default sorting
 +            this.taskTO = taskTO;
 +            setSort("startDate", SortOrder.DESCENDING);
 +            comparator = new SortableDataProviderComparator<TaskExecTO>(this);
 +        }
 +
 +        @Override
 +        public Iterator<TaskExecTO> iterator(final long first, final long count) {
 +
 +            List<TaskExecTO> list = getTaskDB();
 +
 +            Collections.sort(list, comparator);
 +
 +            return list.subList((int) first, (int) first + (int) count).iterator();
 +        }
 +
 +        @Override
 +        public long size() {
 +            return getTaskDB().size();
 +        }
 +
 +        @Override
 +        public IModel<TaskExecTO> model(final TaskExecTO taskExecution) {
 +
 +            return new AbstractReadOnlyModel<TaskExecTO>() {
 +
 +                private static final long serialVersionUID = 7485475149862342421L;
 +
 +                @Override
 +                public TaskExecTO getObject() {
 +                    return taskExecution;
 +                }
 +            };
 +        }
 +
 +        public List<TaskExecTO> getTaskDB() {
 +            return taskTO.getExecutions();
 +        }
 +    }
 +
 +    public static class TasksProvider<T extends AbstractTaskTO> extends SortableDataProvider<T, String> {
 +
 +        private static final long serialVersionUID = -20112718133295756L;
 +
 +        private SortableDataProviderComparator<T> comparator;
 +
 +        private TaskRestClient restClient;
 +
 +        private int paginatorRows;
 +
 +        private String id;
 +
 +        private Class<T> reference;
 +
 +        public TasksProvider(
 +                final TaskRestClient restClient, final int paginatorRows, final String id, final Class<T> reference) {
 +
 +            super();
 +
 +            //Default sorting
-             setSort("key", SortOrder.DESCENDING);
-             comparator = new SortableDataProviderComparator<>(this);
++            setSort("id", SortOrder.DESCENDING);
++            comparator = new SortableDataProviderComparator<T>(this);
 +            this.paginatorRows = paginatorRows;
 +            this.restClient = restClient;
 +            this.id = id;
 +            this.reference = reference;
 +        }
 +
 +        @Override
 +        public Iterator<T> iterator(final long first, final long count) {
-             final List<T> tasks = new ArrayList<>();
++            final List<T> tasks = new ArrayList<T>();
 +
 +            final int page = ((int) first / paginatorRows);
 +
 +            for (T task : restClient.list(reference, (page < 0 ? 0 : page) + 1, paginatorRows, getSort())) {
 +                if (task instanceof SchedTaskTO && ((SchedTaskTO) task).getLastExec() == null
 +                        && task.getExecutions() != null && !task.getExecutions().isEmpty()) {
 +
 +                    Collections.sort(task.getExecutions(), new Comparator<TaskExecTO>() {
 +
 +                        @Override
 +                        public int compare(final TaskExecTO left, final TaskExecTO right) {
 +                            return left.getStartDate().compareTo(right.getStartDate());
 +                        }
 +                    });
 +
 +                    ((SchedTaskTO) task).setLastExec(task.getExecutions().get(task.getExecutions().size() - 1).
 +                            getStartDate());
 +                }
 +                tasks.add(task);
 +            }
 +
 +            Collections.sort(tasks, comparator);
 +            return tasks.iterator();
 +        }
 +
 +        @Override
 +        public long size() {
 +            return restClient.count(id);
 +        }
 +
 +        @Override
 +        public IModel<T> model(final T object) {
-             return new CompoundPropertyModel<>(object);
++            return new CompoundPropertyModel<T>(object);
 +        }
 +    }
 +
 +    /**
 +     * Update task table.
 +     *
 +     * @param columns columns.
 +     * @param dataProvider data provider.
 +     * @param container container.
 +     * @param currentPage current page index.
 +     * @param pageRef page reference
 +     * @param restClient syncope base rest client
 +     * @return data table.
 +     */
 +    public static AjaxDataTablePanel<AbstractTaskTO, String> updateTaskTable(
 +            final List<IColumn<AbstractTaskTO, String>> columns,
 +            final TasksProvider<? extends AbstractTaskTO> dataProvider,
 +            final WebMarkupContainer container,
 +            final int currentPage,
 +            final PageReference pageRef,
 +            final BaseRestClient restClient) {
 +
 +        @SuppressWarnings("unchecked")
-         final AjaxDataTablePanel<AbstractTaskTO, String> table = new AjaxDataTablePanel<>(
++        final AjaxDataTablePanel<AbstractTaskTO, String> table = new AjaxDataTablePanel<AbstractTaskTO, String>(
 +                "datatable",
 +                columns,
 +                (ISortableDataProvider<AbstractTaskTO, String>) dataProvider,
 +                dataProvider.paginatorRows,
 +                Arrays.asList(new ActionLink.ActionType[] {
 +                    ActionLink.ActionType.DELETE, ActionLink.ActionType.DRYRUN, ActionLink.ActionType.EXECUTE }),
 +                restClient,
-                 "key",
++                "id",
 +                TASKS,
 +                pageRef);
 +
 +        table.setCurrentPage(currentPage);
 +        table.setOutputMarkupId(true);
 +
 +        container.addOrReplace(table);
 +
 +        return table;
 +    }
++
++    /**
++     * IndicatorMarkupId behaviour is embedded in Tasks.html
++     */
++    @Override
++    public String getAjaxIndicatorMarkupId() {
++        return "";
++    }
++
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java
index d7f52e1,0000000..9c7b458
mode 100644,000000..100644
--- a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java
@@@ -1,254 -1,0 +1,258 @@@
 +/*
 + * 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.client.console.panels;
++package org.apache.syncope.console.pages.panels;
 +
 +import java.util.ArrayList;
 +import java.util.List;
- import org.apache.syncope.client.console.commons.Constants;
- import org.apache.syncope.client.console.pages.NotificationTaskModalPage;
- import org.apache.syncope.client.console.pages.Tasks;
- import org.apache.syncope.client.console.pages.Tasks.TasksProvider;
- import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
- import org.apache.syncope.common.lib.SyncopeClientException;
- import org.apache.syncope.common.lib.to.AbstractTaskTO;
- import org.apache.syncope.common.lib.to.NotificationTaskTO;
++import org.apache.syncope.common.to.NotificationTaskTO;
++import org.apache.syncope.common.to.AbstractTaskTO;
++import org.apache.syncope.common.SyncopeClientException;
++import org.apache.syncope.console.commons.Constants;
++import org.apache.syncope.console.pages.NotificationTaskModalPage;
++import org.apache.syncope.console.pages.Tasks;
++import org.apache.syncope.console.pages.Tasks.TasksProvider;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.JobColumn;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLinksPanel;
 +import org.apache.wicket.Component;
 +import org.apache.wicket.Page;
 +import org.apache.wicket.PageReference;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 +import org.apache.wicket.event.IEvent;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +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.WebMarkupContainer;
 +import org.apache.wicket.markup.html.form.DropDownChoice;
 +import org.apache.wicket.markup.html.form.Form;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.Model;
 +import org.apache.wicket.model.PropertyModel;
 +import org.apache.wicket.model.StringResourceModel;
 +import org.apache.wicket.request.http.WebResponse;
 +
 +public class NotificationTasks extends AbstractTasks {
 +
 +    private static final long serialVersionUID = 4984337552918213290L;
 +
 +    private int paginatorRows;
 +
 +    private WebMarkupContainer container;
 +
 +    private boolean operationResult = false;
 +
 +    private ModalWindow window;
 +
 +    private AjaxDataTablePanel<AbstractTaskTO, String> table;
 +
 +    public NotificationTasks(final String id, final PageReference pageRef) {
 +        super(id, pageRef);
 +
 +        container = new WebMarkupContainer("container");
 +        container.setOutputMarkupId(true);
 +        add(container);
 +
 +        add(window = new ModalWindow("taskWin"));
 +
 +        paginatorRows = prefMan.getPaginatorRows(getWebRequest(), Constants.PREF_NOTIFICATION_TASKS_PAGINATOR_ROWS);
 +
 +        table = Tasks.updateTaskTable(
 +                getColumns(),
 +                new TasksProvider<NotificationTaskTO>(restClient, paginatorRows, getId(), NotificationTaskTO.class),
 +                container,
 +                0,
 +                pageRef,
 +                restClient);
 +
 +        container.add(table);
 +
 +        window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
 +
 +            private static final long serialVersionUID = 8804221891699487139L;
 +
 +            @Override
 +            public void onClose(final AjaxRequestTarget target) {
 +                target.add(container);
 +                if (operationResult) {
 +                    info(getString(Constants.OPERATION_SUCCEEDED));
 +                    target.add(getPage().get(Constants.FEEDBACK));
 +                    operationResult = false;
 +                }
 +            }
 +        });
 +
 +        window.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
 +        window.setInitialHeight(WIN_HEIGHT);
 +        window.setInitialWidth(WIN_WIDTH);
 +        window.setCookieName(VIEW_TASK_WIN_COOKIE_NAME);
 +
 +        @SuppressWarnings("rawtypes")
 +        final Form paginatorForm = new Form("PaginatorForm");
 +
 +        @SuppressWarnings({ "unchecked", "rawtypes" })
 +        final DropDownChoice rowsChooser = new DropDownChoice("rowsChooser", new PropertyModel(this, "paginatorRows"),
 +                prefMan.getPaginatorChoices());
 +
 +        rowsChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
 +
 +            private static final long serialVersionUID = -1107858522700306810L;
 +
 +            @Override
 +            protected void onUpdate(final AjaxRequestTarget target) {
 +                prefMan.set(getWebRequest(), (WebResponse) getResponse(),
 +                        Constants.PREF_NOTIFICATION_TASKS_PAGINATOR_ROWS, String.valueOf(paginatorRows));
 +
 +                table = Tasks.updateTaskTable(
 +                        getColumns(),
 +                        new TasksProvider<NotificationTaskTO>(restClient, paginatorRows, getId(),
 +                                NotificationTaskTO.class),
 +                        container,
 +                        table == null ? 0 : (int) table.getCurrentPage(),
 +                        pageRef,
 +                        restClient);
 +
 +                target.add(container);
 +            }
 +        });
 +
 +        paginatorForm.add(rowsChooser);
 +        add(paginatorForm);
 +    }
 +
 +    private List<IColumn<AbstractTaskTO, String>> getColumns() {
-         final List<IColumn<AbstractTaskTO, String>> columns = new ArrayList<>();
++        final List<IColumn<AbstractTaskTO, String>> columns = new ArrayList<IColumn<AbstractTaskTO, String>>();
 +
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
-                 new StringResourceModel("key", this, null), "key", "key"));
++                new StringResourceModel("id", this, null), "id", "id"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("sender", this, null), "sender", "sender"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("recipients", this, null), "recipients", "recipients"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("subject", this, null), "subject", "subject"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("traceLevel", this, null), "traceLevel", "traceLevel"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
 +
++        columns.add(new JobColumn<AbstractTaskTO, String>(new StringResourceModel("", this, null, ""), "runtime",
++                pageRef, restClient)); 
++
 +        columns.add(new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) {
 +
 +            private static final long serialVersionUID = 2054811145491901166L;
 +
 +            @Override
 +            public ActionLinksPanel getActions(final String componentId, final IModel<AbstractTaskTO> model) {
 +
 +                final AbstractTaskTO taskTO = model.getObject();
 +
 +                final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, pageRef);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +
 +                        window.setPageCreator(new ModalWindow.PageCreator() {
 +
 +                            private static final long serialVersionUID = -7834632442532690940L;
 +
 +                            @Override
 +                            public Page createPage() {
 +                                return new NotificationTaskModalPage(taskTO);
 +                            }
 +                        });
 +
 +                        window.show(target);
 +                    }
 +                }, ActionLink.ActionType.EDIT, TASKS);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        try {
-                             restClient.startExecution(taskTO.getKey(), false);
++                            restClient.startExecution(taskTO.getId(), false);
 +                            getSession().info(getString(Constants.OPERATION_SUCCEEDED));
 +                        } catch (SyncopeClientException scce) {
 +                            error(scce.getMessage());
 +                        }
 +
 +                        ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
 +                        target.add(container);
 +                    }
 +                }, ActionLink.ActionType.EXECUTE, TASKS);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        try {
-                             restClient.delete(taskTO.getKey(), NotificationTaskTO.class);
++                            restClient.delete(taskTO.getId(), NotificationTaskTO.class);
 +                            info(getString(Constants.OPERATION_SUCCEEDED));
 +                        } catch (SyncopeClientException scce) {
 +                            error(scce.getMessage());
 +                        }
 +                        target.add(container);
 +                        ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
 +                    }
 +                }, ActionLink.ActionType.DELETE, TASKS);
 +
 +                return panel;
 +            }
 +
 +            @Override
 +            public Component getHeader(String componentId) {
 +                final ActionLinksPanel panel = new ActionLinksPanel(componentId, new Model(), pageRef);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -7978723352517770644L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        if (target != null) {
 +                            target.add(table);
 +                        }
 +                    }
 +                }, ActionLink.ActionType.RELOAD, TASKS, "list");
 +
 +                return panel;
 +            }
 +        });
 +
 +        return columns;
 +    }
 +
 +    @Override
 +    public void onEvent(final IEvent<?> event) {
 +        if (event.getPayload() instanceof AbstractSearchResultPanel.EventDataWrapper) {
 +            ((AbstractSearchResultPanel.EventDataWrapper) event.getPayload()).getTarget().add(container);
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/RuntimePanel.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/panels/RuntimePanel.java
index 0000000,0000000..34e058e
new file mode 100644
--- /dev/null
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/RuntimePanel.java
@@@ -1,0 -1,0 +1,105 @@@
++/*
++ * 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.client.console.panels;
++
++import org.apache.syncope.client.console.rest.JobRestClient;
++import org.apache.syncope.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
++import org.apache.wicket.PageReference;
++import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.markup.html.panel.Fragment;
++import org.apache.wicket.model.IModel;
++import org.apache.wicket.markup.html.panel.Panel;
++
++public class RuntimePanel extends Panel {
++
++    private static final long serialVersionUID = -9002724127542172464L;
++
++    private boolean latestStatus;
++
++    private Fragment fragmentStop, fragmentSpinner;
++
++    public AbstractAjaxTimerBehavior timer;
++
++    private final PageReference pageRef;
++
++    private final long jobId;
++
++    private final JobRestClient jobRestClient;
++
++    public RuntimePanel(final String componentId, final IModel<?> model, final PageReference pageRef, final long jobId,
++            final JobRestClient jobRestClient) {
++        super(componentId, model);
++        this.pageRef = pageRef;
++        this.jobId = jobId;
++        this.jobRestClient = jobRestClient;
++        latestStatus = false;
++        this.refresh();
++
++    }
++
++    public final void refresh() {
++        boolean currentStatus = jobRestClient.isJobRunning(jobId);
++        if (currentStatus && !latestStatus) {
++            setRunning();
++        } else if (!currentStatus) {
++            setNotRunning();
++        }
++        latestStatus = currentStatus;
++    }
++
++    public void setRunning() {
++        fragmentStop = new Fragment("panelStop", "fragmentStop", this);
++        fragmentStop.addOrReplace(new ClearIndicatingAjaxLink<Void>("stopLink", pageRef) {
++
++            private static final long serialVersionUID = -7978723352517770644L;
++
++            @Override
++            protected void onClickInternal(final AjaxRequestTarget target) {
++                jobRestClient.stopJob(jobId);
++                this.setEnabled(false);
++                target.add(this);
++            }
++
++            @Override
++            public String getAjaxIndicatorMarkupId() {
++                return "";
++            }
++        });
++        addOrReplace(fragmentStop);
++        fragmentSpinner = new Fragment("panelSpinner", "fragmentSpinner", this);
++        addOrReplace(fragmentSpinner);
++    }
++
++    public void setNotRunning() {
++        fragmentStop = new Fragment("panelStop", "emptyFragment", this);
++        addOrReplace(fragmentStop);
++        fragmentSpinner = new Fragment("panelSpinner", "emptyFragment", this);
++        addOrReplace(fragmentSpinner);
++    }
++
++    public void setTimer(AbstractAjaxTimerBehavior timer) {
++        if (this.timer != null) {
++            remove(this.timer);
++        }
++        this.timer = timer;
++        this.add(this.timer);
++    }
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/SchedTasks.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/panels/SchedTasks.java
index 205bfa5,0000000..78591a8
mode 100644,000000..100644
--- a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/SchedTasks.java
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/SchedTasks.java
@@@ -1,286 -1,0 +1,292 @@@
 +/*
 + * 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.client.console.panels;
++package org.apache.syncope.console.pages.panels;
++
++import static org.apache.syncope.console.pages.panels.AbstractTasks.TASKS;
 +
 +import java.util.ArrayList;
 +import java.util.List;
- import org.apache.syncope.client.console.commons.Constants;
- import org.apache.syncope.client.console.pages.SchedTaskModalPage;
- import org.apache.syncope.client.console.pages.Tasks;
- import org.apache.syncope.client.console.pages.Tasks.TasksProvider;
- import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
- import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
- import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
- import org.apache.syncope.common.lib.SyncopeClientException;
- import org.apache.syncope.common.lib.to.AbstractTaskTO;
- import org.apache.syncope.common.lib.to.SchedTaskTO;
++import org.apache.syncope.common.to.SchedTaskTO;
++import org.apache.syncope.common.to.AbstractTaskTO;
++import org.apache.syncope.common.SyncopeClientException;
++import org.apache.syncope.console.commons.Constants;
++import org.apache.syncope.console.pages.SchedTaskModalPage;
++import org.apache.syncope.console.pages.Tasks;
++import org.apache.syncope.console.pages.Tasks.TasksProvider;
++import org.apache.syncope.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.JobColumn;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLinksPanel;
 +import org.apache.wicket.Component;
 +import org.apache.wicket.Page;
 +import org.apache.wicket.PageReference;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 +import org.apache.wicket.ajax.markup.html.AjaxLink;
 +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
 +import org.apache.wicket.event.IEvent;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +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.WebMarkupContainer;
 +import org.apache.wicket.markup.html.form.DropDownChoice;
 +import org.apache.wicket.markup.html.form.Form;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.Model;
 +import org.apache.wicket.model.PropertyModel;
 +import org.apache.wicket.model.StringResourceModel;
 +import org.apache.wicket.request.http.WebResponse;
 +
 +public class SchedTasks extends AbstractTasks {
 +
 +    private static final long serialVersionUID = 525486152284253354L;
 +
 +    private int paginatorRows;
 +
 +    private WebMarkupContainer container;
 +
 +    private ModalWindow window;
 +
 +    private AjaxDataTablePanel<AbstractTaskTO, String> table;
 +
 +    public SchedTasks(final String id, final PageReference pageRef) {
 +        super(id, pageRef);
 +
 +        container = new WebMarkupContainer("container");
 +        container.setOutputMarkupId(true);
 +        add(container);
 +
 +        window = new ModalWindow("taskWin");
 +        window.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
 +        window.setInitialHeight(WIN_HEIGHT);
 +        window.setInitialWidth(WIN_WIDTH);
 +        window.setCookieName(VIEW_TASK_WIN_COOKIE_NAME);
 +        add(window);
 +
 +        ((Tasks) pageRef.getPage()).setWindowClosedCallback(window, container);
 +
 +        paginatorRows = prefMan.getPaginatorRows(getWebRequest(), Constants.PREF_SCHED_TASKS_PAGINATOR_ROWS);
 +
 +        table = Tasks.updateTaskTable(
 +                getColumns(),
 +                new TasksProvider<SchedTaskTO>(restClient, paginatorRows, getId(), SchedTaskTO.class),
 +                container,
 +                0,
 +                pageRef,
 +                restClient);
 +
 +        container.add(table);
 +
 +        @SuppressWarnings("rawtypes")
 +        Form paginatorForm = new Form("PaginatorForm");
 +
 +        @SuppressWarnings({ "unchecked", "rawtypes" })
 +        final DropDownChoice rowsChooser = new DropDownChoice("rowsChooser", new PropertyModel(this, "paginatorRows"),
 +                prefMan.getPaginatorChoices());
 +
 +        rowsChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
 +
 +            private static final long serialVersionUID = -1107858522700306810L;
 +
 +            @Override
 +            protected void onUpdate(final AjaxRequestTarget target) {
 +                prefMan.set(getWebRequest(), (WebResponse) getResponse(), Constants.PREF_SCHED_TASKS_PAGINATOR_ROWS,
 +                        String.valueOf(paginatorRows));
 +
 +                table = Tasks.updateTaskTable(
 +                        getColumns(),
 +                        new TasksProvider<SchedTaskTO>(restClient, paginatorRows, getId(), SchedTaskTO.class),
 +                        container,
 +                        table == null ? 0 : (int) table.getCurrentPage(),
 +                        pageRef,
 +                        restClient);
 +
 +                target.add(container);
 +            }
 +        });
 +
 +        paginatorForm.add(rowsChooser);
 +        add(paginatorForm);
 +
 +        AjaxLink createLink = new ClearIndicatingAjaxLink("createLink", pageRef) {
 +
 +            private static final long serialVersionUID = -7978723352517770644L;
 +
 +            @Override
 +            protected void onClickInternal(final AjaxRequestTarget target) {
 +                window.setPageCreator(new ModalWindow.PageCreator() {
 +
 +                    private static final long serialVersionUID = -7834632442532690940L;
 +
 +                    @Override
 +                    public Page createPage() {
 +                        return new SchedTaskModalPage(window, new SchedTaskTO(), pageRef);
 +                    }
 +                });
 +
 +                window.show(target);
 +            }
 +        };
 +
 +        MetaDataRoleAuthorizationStrategy.authorize(
 +                createLink, RENDER, xmlRolesReader.getEntitlement(TASKS, "create"));
 +
 +        add(createLink);
 +    }
 +
 +    private List<IColumn<AbstractTaskTO, String>> getColumns() {
 +        final List<IColumn<AbstractTaskTO, String>> columns = new ArrayList<IColumn<AbstractTaskTO, String>>();
 +
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
-                 new StringResourceModel("key", this, null), "key", "key"));
++                new StringResourceModel("id", this, null), "id", "id"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("name", this, null), "name", "name"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("description", this, null), "description", "description"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("class", this, null), "jobClassName", "jobClassName"));
 +        columns.add(new DatePropertyColumn<AbstractTaskTO>(
 +                new StringResourceModel("lastExec", this, null), "lastExec", "lastExec"));
 +        columns.add(new DatePropertyColumn<AbstractTaskTO>(
 +                new StringResourceModel("nextExec", this, null), "nextExec", "nextExec"));
 +        columns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
 +
++        columns.add(new JobColumn<AbstractTaskTO, String>(new StringResourceModel("", this, null, ""), "runtime",
++                pageRef, restClient)); 
++
 +        columns.add(new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) {
 +
 +            private static final long serialVersionUID = 2054811145491901166L;
 +
 +            @Override
 +            public ActionLinksPanel getActions(final String componentId, final IModel<AbstractTaskTO> model) {
 +
 +                final SchedTaskTO taskTO = (SchedTaskTO) model.getObject();
 +
 +                final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, pageRef);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        window.setPageCreator(new ModalWindow.PageCreator() {
 +
 +                            private static final long serialVersionUID = -7834632442532690940L;
 +
 +                            @Override
 +                            public Page createPage() {
 +                                return new SchedTaskModalPage(window, taskTO, pageRef);
 +                            }
 +                        });
 +
 +                        window.show(target);
 +                    }
 +                }, ActionLink.ActionType.EDIT, TASKS);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        try {
-                             restClient.startExecution(taskTO.getKey(), false);
++                            restClient.startExecution(taskTO.getId(), false);
 +                            getSession().info(getString(Constants.OPERATION_SUCCEEDED));
 +                        } catch (SyncopeClientException scce) {
 +                            error(scce.getMessage());
 +                        }
 +
 +                        ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
 +                        target.add(container);
 +                    }
 +                }, ActionLink.ActionType.EXECUTE, TASKS);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        try {
-                             restClient.startExecution(taskTO.getKey(), true);
++                            restClient.startExecution(taskTO.getId(), true);
 +                            getSession().info(getString(Constants.OPERATION_SUCCEEDED));
 +                        } catch (SyncopeClientException scce) {
 +                            error(scce.getMessage());
 +                        }
 +
 +                        ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
 +                        target.add(container);
 +                    }
 +                }, ActionLink.ActionType.DRYRUN, TASKS);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -3722207913631435501L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        try {
-                             restClient.delete(taskTO.getKey(), SchedTaskTO.class);
++                            restClient.delete(taskTO.getId(), SchedTaskTO.class);
 +                            info(getString(Constants.OPERATION_SUCCEEDED));
 +                        } catch (SyncopeClientException scce) {
 +                            error(scce.getMessage());
 +                        }
 +                        target.add(container);
 +                        ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
 +                    }
 +                }, ActionLink.ActionType.DELETE, TASKS);
 +
 +                return panel;
 +            }
 +
 +            @Override
 +            public Component getHeader(final String componentId) {
 +                @SuppressWarnings("rawtypes")
 +                final ActionLinksPanel panel = new ActionLinksPanel(componentId, new Model(), pageRef);
 +
 +                panel.add(new ActionLink() {
 +
 +                    private static final long serialVersionUID = -7978723352517770644L;
 +
 +                    @Override
 +                    public void onClick(final AjaxRequestTarget target) {
 +                        if (target != null) {
 +                            target.add(table);
 +                        }
 +                    }
 +                }, ActionLink.ActionType.RELOAD, TASKS, "list");
 +
 +                return panel;
 +            }
 +        });
 +        return columns;
 +    }
 +
 +    @Override
 +    public void onEvent(final IEvent<?> event) {
 +        if (event.getPayload() instanceof AbstractSearchResultPanel.EventDataWrapper) {
 +            ((AbstractSearchResultPanel.EventDataWrapper) event.getPayload()).getTarget().add(container);
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/SyncTasksPanel.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/panels/SyncTasksPanel.java
index 5561716,0000000..032f4e4
mode 100644,000000..100644
--- a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/SyncTasksPanel.java
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/SyncTasksPanel.java
@@@ -1,225 -1,0 +1,230 @@@
 +/*
 + * 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.client.console.panels;
++package org.apache.syncope.console.pages.panels;
 +
 +import java.util.ArrayList;
 +import java.util.List;
- import org.apache.syncope.client.console.commons.Constants;
- import org.apache.syncope.client.console.pages.GroupTemplateModalPage;
- import org.apache.syncope.client.console.pages.SyncTaskModalPage;
- import org.apache.syncope.client.console.pages.UserTemplateModalPage;
- import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
- import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
- import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
- import org.apache.syncope.common.lib.SyncopeClientException;
- import org.apache.syncope.common.lib.to.AbstractTaskTO;
- import org.apache.syncope.common.lib.to.SyncTaskTO;
++import org.apache.syncope.common.SyncopeClientException;
++import org.apache.syncope.common.to.AbstractTaskTO;
++import org.apache.syncope.common.to.SyncTaskTO;
++import org.apache.syncope.console.commons.Constants;
++import org.apache.syncope.console.pages.RoleTemplateModalPage;
++import org.apache.syncope.console.pages.SyncTaskModalPage;
++import org.apache.syncope.console.pages.UserTemplateModalPage;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
++import org.apache.syncope.console.wicket.extensions.markup.html.repeater.data.table.JobColumn;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
++import org.apache.syncope.console.wicket.markup.html.form.ActionLinksPanel;
 +import org.apache.wicket.Component;
 +import org.apache.wicket.Page;
 +import org.apache.wicket.PageReference;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +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.model.IModel;
 +import org.apache.wicket.model.Model;
 +import org.apache.wicket.model.StringResourceModel;
 +
- public class SyncTasksPanel extends AbstractProvisioningTasksPanel<SyncTaskTO> {
++public class SyncTasksPanel extends AbstractSyncTasksPanel<SyncTaskTO> {
 +
 +    private static final long serialVersionUID = 53189199346016099L;
 +
 +    public SyncTasksPanel(final String id, final PageReference pageRef) {
 +        super(id, pageRef, SyncTaskTO.class);
 +        initTasksTable();
 +    }
 +
 +    @Override
 +    protected List<IColumn<AbstractTaskTO, String>> getColumns() {
-         final List<IColumn<AbstractTaskTO, String>> syncTaskscolumns = new ArrayList<>();
++        final List<IColumn<AbstractTaskTO, String>> syncTaskscolumns = new ArrayList<IColumn<AbstractTaskTO, String>>();
 +
 +        syncTaskscolumns.add(new PropertyColumn<AbstractTaskTO, String>(
-                 new StringResourceModel("key", this, null), "key", "key"));
++                new StringResourceModel("id", this, null), "id", "id"));
 +        syncTaskscolumns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("name", this, null), "name", "name"));
 +        syncTaskscolumns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("description", this, null), "description", "description"));
 +        syncTaskscolumns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("resourceName", this, null), "resource", "resource"));
 +        syncTaskscolumns.add(new DatePropertyColumn<AbstractTaskTO>(
 +                new StringResourceModel("lastExec", this, null), "lastExec", "lastExec"));
 +        syncTaskscolumns.add(new DatePropertyColumn<AbstractTaskTO>(
 +                new StringResourceModel("nextExec", this, null), "nextExec", "nextExec"));
 +        syncTaskscolumns.add(new PropertyColumn<AbstractTaskTO, String>(
 +                new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
++        
++        syncTaskscolumns.add(new JobColumn<AbstractTaskTO, String>(new StringResourceModel("", this, null, ""), "runtime",
++                pageRef, restClient));        
 +
-         syncTaskscolumns.add(new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) {
++        syncTaskscolumns.add(
++                new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) {
 +
 +                    private static final long serialVersionUID = 2054811145491901166L;
 +
 +                    @Override
 +                    public ActionLinksPanel getActions(final String componentId, final IModel<AbstractTaskTO> model) {
 +
 +                        final SyncTaskTO taskTO = (SyncTaskTO) model.getObject();
 +
 +                        final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, pageRef);
 +
 +                        panel.add(new ActionLink() {
 +
 +                            private static final long serialVersionUID = -3722207913631435501L;
 +
 +                            @Override
 +                            public void onClick(final AjaxRequestTarget target) {
 +
 +                                window.setPageCreator(new ModalWindow.PageCreator() {
 +
 +                                    private static final long serialVersionUID = -7834632442532690940L;
 +
 +                                    @Override
 +                                    public Page createPage() {
 +                                        return new SyncTaskModalPage(window, taskTO, pageRef);
 +                                    }
 +                                });
 +
 +                                window.show(target);
 +                            }
 +                        }, ActionLink.ActionType.EDIT, TASKS);
 +
 +                        panel.add(new ActionLink() {
 +
 +                            private static final long serialVersionUID = -3722207913631435501L;
 +
 +                            @Override
 +                            public void onClick(final AjaxRequestTarget target) {
 +
 +                                window.setPageCreator(new ModalWindow.PageCreator() {
 +
 +                                    private static final long serialVersionUID = -7834632442532690940L;
 +
 +                                    @Override
 +                                    public Page createPage() {
 +                                        return new UserTemplateModalPage(pageRef, window, taskTO);
 +                                    }
 +                                });
 +
 +                                window.show(target);
 +                            }
 +                        }, ActionLink.ActionType.USER_TEMPLATE, TASKS);
 +
 +                        panel.add(new ActionLink() {
 +
 +                            private static final long serialVersionUID = -3722207913631435501L;
 +
 +                            @Override
 +                            public void onClick(final AjaxRequestTarget target) {
 +
 +                                window.setPageCreator(new ModalWindow.PageCreator() {
 +
 +                                    private static final long serialVersionUID = -7834632442532690940L;
 +
 +                                    @Override
 +                                    public Page createPage() {
-                                         return new GroupTemplateModalPage(pageRef, window, taskTO);
++                                        return new RoleTemplateModalPage(pageRef, window, taskTO);
 +                                    }
 +                                });
 +
 +                                window.show(target);
 +                            }
-                         }, ActionLink.ActionType.GROUP_TEMPLATE, TASKS);
++                        }, ActionLink.ActionType.ROLE_TEMPLATE, TASKS);
 +
 +                        panel.add(new ActionLink() {
 +
 +                            private static final long serialVersionUID = -3722207913631435501L;
 +
 +                            @Override
 +                            public void onClick(final AjaxRequestTarget target) {
 +                                try {
-                                     restClient.startExecution(taskTO.getKey(), false);
++                                    restClient.startExecution(taskTO.getId(), false);
 +                                    getSession().info(getString(Constants.OPERATION_SUCCEEDED));
 +                                } catch (SyncopeClientException scce) {
 +                                    error(scce.getMessage());
 +                                }
 +
 +                                target.add(container);
 +                                ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
 +                            }
 +                        }, ActionLink.ActionType.EXECUTE, TASKS);
 +
 +                        panel.add(new ActionLink() {
 +
 +                            private static final long serialVersionUID = -3722207913631435501L;
 +
 +                            @Override
 +                            public void onClick(final AjaxRequestTarget target) {
 +                                try {
-                                     restClient.startExecution(taskTO.getKey(), true);
++                                    restClient.startExecution(taskTO.getId(), true);
 +                                    getSession().info(getString(Constants.OPERATION_SUCCEEDED));
 +                                } catch (SyncopeClientException scce) {
 +                                    error(scce.getMessage());
 +                                }
 +
 +                                target.add(container);
 +                                ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
 +                            }
 +                        }, ActionLink.ActionType.DRYRUN, TASKS);
 +
 +                        panel.add(new ActionLink() {
 +
 +                            private static final long serialVersionUID = -3722207913631435501L;
 +
 +                            @Override
 +                            public void onClick(final AjaxRequestTarget target) {
 +                                try {
-                                     restClient.delete(taskTO.getKey(), SyncTaskTO.class);
++                                    restClient.delete(taskTO.getId(), SyncTaskTO.class);
 +                                    info(getString(Constants.OPERATION_SUCCEEDED));
 +                                } catch (SyncopeClientException scce) {
 +                                    error(scce.getMessage());
 +                                }
 +                                target.add(container);
 +                                ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
 +                            }
 +                        }, ActionLink.ActionType.DELETE, TASKS);
 +
 +                        return panel;
 +                    }
 +
 +                    @Override
-                     public Component getHeader(final String componentId) {
++                    public Component getHeader(String componentId) {
 +                        final ActionLinksPanel panel = new ActionLinksPanel(componentId, new Model(), pageRef);
 +
 +                        panel.add(new ActionLink() {
 +
 +                            private static final long serialVersionUID = -7978723352517770644L;
 +
 +                            @Override
 +                            public void onClick(final AjaxRequestTarget target) {
 +                                if (target != null) {
 +                                    target.add(table);
 +                                }
 +                            }
 +                        }, ActionLink.ActionType.RELOAD, TASKS, "list");
 +
 +                        return panel;
 +                    }
 +                });
 +
 +        return syncTaskscolumns;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/rest/JobRestClient.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/rest/JobRestClient.java
index 0000000,0000000..0634658
new file mode 100644
--- /dev/null
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/rest/JobRestClient.java
@@@ -1,0 -1,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.client.console.rest;
++
++import org.springframework.stereotype.Component;
++
++@Component
++public abstract class JobRestClient extends BaseRestClient{
++
++    public abstract boolean isJobRunning(final long id);
++
++    public abstract void startJob(final long id);
++
++    public abstract void stopJob(final long id);
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
index 81b58ac,0000000..9b8afdb
mode 100644,000000..100644
--- a/client/old_console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
@@@ -1,108 -1,0 +1,131 @@@
 +/*
 + * 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.client.console.rest;
++package org.apache.syncope.console.rest;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import javax.ws.rs.core.Response;
- import org.apache.syncope.common.lib.SyncopeClientException;
- import org.apache.syncope.common.lib.to.ReportTO;
- import org.apache.syncope.common.lib.types.ReportExecExportFormat;
- import org.apache.syncope.common.lib.wrap.ReportletConfClass;
- import org.apache.syncope.common.rest.api.service.ReportService;
++import org.apache.syncope.common.services.ReportService;
++import org.apache.syncope.common.to.ReportTO;
++import org.apache.syncope.common.types.ReportExecExportFormat;
++import org.apache.syncope.common.SyncopeClientException;
++import org.apache.syncope.common.to.ReportExecTO;
++import org.apache.syncope.common.types.JobAction;
++import org.apache.syncope.common.types.JobStatusType;
++import org.apache.syncope.common.wrap.ReportletConfClass;
 +import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
 +import org.springframework.stereotype.Component;
 +
 +@Component
- public class ReportRestClient extends BaseRestClient implements ExecutionRestClient {
++public class ReportRestClient extends JobRestClient implements ExecutionRestClient {
 +
 +    private static final long serialVersionUID = 1644689667998953604L;
 +
 +    public List<String> getReportletConfClasses() {
 +        List<String> result = new ArrayList<String>();
 +
 +        try {
 +            List<ReportletConfClass> reportletConfClasses = getService(ReportService.class).getReportletConfClasses();
 +            for (ReportletConfClass clazz : reportletConfClasses) {
 +                result.add(clazz.getElement());
 +            }
 +        } catch (SyncopeClientException e) {
 +            LOG.error("While getting available reportlet classes", e);
 +        }
 +
 +        return result;
 +    }
 +
 +    public ReportTO read(final Long reportId) {
 +        return getService(ReportService.class).read(reportId);
 +    }
 +
 +    public List<ReportTO> list() {
 +        return getService(ReportService.class).list().getResult();
 +    }
 +
 +    public List<ReportTO> list(final int page, final int size, final SortParam<String> sort) {
 +        return getService(ReportService.class).list(page, size, toOrderBy(sort)).getResult();
 +    }
 +
 +    public int count() {
 +        return getService(ReportService.class).list(1, 1).getTotalCount();
 +    }
 +
 +    public void create(final ReportTO reportTO) {
 +        getService(ReportService.class).create(reportTO);
 +    }
 +
 +    public void update(final ReportTO reportTO) {
-         getService(ReportService.class).update(reportTO.getKey(), reportTO);
++        getService(ReportService.class).update(reportTO.getId(), reportTO);
 +    }
 +
 +    /**
 +     * Delete specified report.
 +     *
 +     * @param reportId report to delete
 +     */
 +    public void delete(final Long reportId) {
 +        getService(ReportService.class).delete(reportId);
 +    }
 +
 +    /**
 +     * Start execution for the specified report.
 +     *
 +     * @param reportId report id
 +     */
 +    @Override
 +    public void startExecution(final long reportId) {
 +        getService(ReportService.class).execute(reportId);
 +    }
 +
 +    /**
 +     * Delete specified report execution.
 +     *
 +     * @param reportExecId report execution id
 +     */
 +    @Override
 +    public void deleteExecution(final long reportExecId) {
 +        getService(ReportService.class).deleteExecution(reportExecId);
 +    }
 +
 +    public Response exportExecutionResult(final Long executionId, final ReportExecExportFormat fmt) {
 +        return getService(ReportService.class).exportExecutionResult(executionId, fmt);
 +    }
++
++    @Override
++    public boolean isJobRunning(final long reportId) {
++        for (ReportExecTO reportExecTO : getService(ReportService.class).listJobs(JobStatusType.RUNNING)) {
++            if (reportExecTO.getReport() == reportId) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++    @Override
++    public void startJob(final long reportId) {
++        getService(ReportService.class).actionJob(reportId, JobAction.START);
++    }
++
++    @Override
++    public void stopJob(final long reportId) {
++        getService(ReportService.class).actionJob(reportId, JobAction.STOP);
++    }
 +}


[2/3] syncope git commit: [SYNCOPE-660] Merge from 1_2_X; This closes #6

Posted by gi...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
index 541b5cd,0000000..c83ce88
mode 100644,000000..100644
--- a/client/old_console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
@@@ -1,139 -1,0 +1,191 @@@
 +/*
 + * 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.client.console.rest;
++package org.apache.syncope.console.rest;
 +
++import java.util.ArrayList;
 +import java.util.List;
- import org.apache.syncope.client.console.SyncopeSession;
- import org.apache.syncope.common.lib.to.AbstractTaskTO;
- import org.apache.syncope.common.lib.to.BulkAction;
- import org.apache.syncope.common.lib.to.BulkActionResult;
- import org.apache.syncope.common.lib.to.NotificationTaskTO;
- import org.apache.syncope.common.lib.to.PropagationTaskTO;
- import org.apache.syncope.common.lib.to.PushTaskTO;
- import org.apache.syncope.common.lib.to.SchedTaskTO;
- import org.apache.syncope.common.lib.to.SyncTaskTO;
- import org.apache.syncope.common.lib.types.TaskType;
- import org.apache.syncope.common.rest.api.service.TaskService;
++import org.apache.syncope.common.services.TaskService;
++import org.apache.syncope.common.reqres.BulkAction;
++import org.apache.syncope.common.reqres.BulkActionResult;
++import org.apache.syncope.common.wrap.JobClass;
++import org.apache.syncope.common.to.NotificationTaskTO;
++import org.apache.syncope.common.to.PropagationTaskTO;
++import org.apache.syncope.common.to.SchedTaskTO;
++import org.apache.syncope.common.wrap.SyncActionClass;
++import org.apache.syncope.common.to.SyncTaskTO;
++import org.apache.syncope.common.to.AbstractTaskTO;
++import org.apache.syncope.common.types.TaskType;
++import org.apache.syncope.common.util.CollectionWrapper;
++import org.apache.syncope.common.SyncopeClientException;
++import org.apache.syncope.common.to.PushTaskTO;
++import org.apache.syncope.common.to.TaskExecTO;
++import org.apache.syncope.common.types.JobAction;
++import org.apache.syncope.common.types.JobStatusType;
++import org.apache.syncope.common.wrap.PushActionClass;
 +import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
 +import org.springframework.stereotype.Component;
 +
 +/**
 + * Console client for invoking Rest Tasks services.
 + */
 +@Component
- public class TaskRestClient extends BaseRestClient implements ExecutionRestClient {
++public class TaskRestClient extends JobRestClient implements ExecutionRestClient {
 +
 +    private static final long serialVersionUID = 6284485820911028843L;
 +
++    /**
++     * Return a list of job classes.
++     *
++     * @return list of classes.
++     */
 +    public List<String> getJobClasses() {
-         return SyncopeSession.get().getSyncopeTO().getTaskJobs();
++        List<JobClass> jobClasses = null;
++
++        try {
++            jobClasses = new ArrayList<JobClass>(getService(TaskService.class).getJobClasses());
++        } catch (SyncopeClientException e) {
++            LOG.error("While getting all job classes", e);
++        }
++        return CollectionWrapper.unwrap(jobClasses);
 +    }
 +
 +    public List<String> getSyncActionsClasses() {
-         return SyncopeSession.get().getSyncopeTO().getSyncActions();
++        List<SyncActionClass> actions = null;
++
++        try {
++            actions = new ArrayList<SyncActionClass>(getService(TaskService.class).getSyncActionsClasses());
++        } catch (SyncopeClientException e) {
++            LOG.error("While getting all sync actions classes", e);
++        }
++        return CollectionWrapper.unwrap(actions);
 +    }
 +
 +    public List<String> getPushActionsClasses() {
-         return SyncopeSession.get().getSyncopeTO().getPushActions();
++        List<PushActionClass> actions = null;
++
++        try {
++            actions = new ArrayList<PushActionClass>(getService(TaskService.class).getPushActionsClasses());
++        } catch (SyncopeClientException e) {
++            LOG.error("While getting all sync actions classes", e);
++        }
++        return CollectionWrapper.unwrap(actions);
 +    }
 +
 +    /**
 +     * Return the number of tasks.
 +     *
 +     * @param kind of task (propagation, sched, sync).
 +     * @return number of stored tasks.
 +     */
 +    public int count(final String kind) {
 +        return getService(TaskService.class).list(TaskType.fromString(kind), 1, 1).getTotalCount();
 +    }
 +
 +    @SuppressWarnings("unchecked")
 +    public <T extends AbstractTaskTO> List<T> list(final Class<T> reference,
 +            final int page, final int size, final SortParam<String> sort) {
 +
 +        return (List<T>) getService(TaskService.class).list(getTaskType(reference), page, size, toOrderBy(sort)).
 +                getResult();
 +    }
 +
 +    private TaskType getTaskType(final Class<?> reference) {
 +        TaskType result = null;
 +        if (PropagationTaskTO.class.equals(reference)) {
 +            result = TaskType.PROPAGATION;
 +        } else if (NotificationTaskTO.class.equals(reference)) {
 +            result = TaskType.NOTIFICATION;
 +        } else if (SchedTaskTO.class.equals(reference)) {
 +            result = TaskType.SCHEDULED;
 +        } else if (SyncTaskTO.class.equals(reference)) {
 +            result = TaskType.SYNCHRONIZATION;
 +        } else if (PushTaskTO.class.equals(reference)) {
 +            result = TaskType.PUSH;
 +        }
 +        return result;
 +    }
 +
 +    public PropagationTaskTO readPropagationTask(final Long taskId) {
 +        return getService(TaskService.class).read(taskId);
 +    }
 +
 +    public NotificationTaskTO readNotificationTask(final Long taskId) {
 +        return getService(TaskService.class).read(taskId);
 +    }
 +
 +    public <T extends SchedTaskTO> T readSchedTask(final Class<T> reference, final Long taskId) {
 +        return getService(TaskService.class).read(taskId);
 +    }
 +
 +    public void delete(final Long taskId, final Class<? extends AbstractTaskTO> taskToClass) {
 +        getService(TaskService.class).delete(taskId);
 +    }
 +
 +    @Override
 +    public void startExecution(final long taskId) {
 +        startExecution(taskId, false);
 +    }
 +
 +    public void startExecution(final long taskId, final boolean dryRun) {
 +        getService(TaskService.class).execute(taskId, dryRun);
 +    }
 +
 +    @Override
 +    public void deleteExecution(final long taskExecId) {
 +        getService(TaskService.class).deleteExecution(taskExecId);
 +    }
 +
 +    public void createSyncTask(final SyncTaskTO taskTO) {
 +        getService(TaskService.class).create(taskTO);
 +    }
 +
 +    public void createSchedTask(final SchedTaskTO taskTO) {
 +        getService(TaskService.class).create(taskTO);
 +    }
 +
 +    public void updateSchedTask(final SchedTaskTO taskTO) {
-         getService(TaskService.class).update(taskTO.getKey(), taskTO);
++        getService(TaskService.class).update(taskTO.getId(), taskTO);
 +    }
 +
 +    public void updateSyncTask(final SyncTaskTO taskTO) {
-         getService(TaskService.class).update(taskTO.getKey(), taskTO);
++        getService(TaskService.class).update(taskTO.getId(), taskTO);
 +    }
 +
 +    public BulkActionResult bulkAction(final BulkAction action) {
 +        return getService(TaskService.class).bulk(action);
 +    }
++    
++    @Override
++    public boolean isJobRunning(final long taskId){
++        for(TaskExecTO taskExecTO : getService(TaskService.class).listJobs(JobStatusType.RUNNING)){
++            if(taskExecTO.getTask()== taskId) return true;
++        }
++        return false;
++    }
++    
++    @Override
++    public void startJob(final long taskId){
++        getService(TaskService.class).actionJob(taskId, JobAction.START);
++    }
++
++    @Override
++    public void stopJob(final long taskId) {
++        getService(TaskService.class).actionJob(taskId, JobAction.STOP);
++    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/JobColumn.java
----------------------------------------------------------------------
diff --cc client/old_console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/JobColumn.java
index 0000000,0000000..ba47421
new file mode 100644
--- /dev/null
+++ b/client/old_console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/JobColumn.java
@@@ -1,0 -1,0 +1,94 @@@
++/*
++ * 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.client.console.wicket.extensions.markup.html.repeater.data.table;
++
++import org.apache.syncope.client.console.panels.RuntimePanel;
++import org.apache.syncope.client.console.rest.JobRestClient;
++import org.apache.syncope.common.to.AbstractTaskTO;
++import org.apache.syncope.common.to.ReportTO;
++import org.apache.wicket.PageReference;
++import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
++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.markup.repeater.Item;
++import org.apache.wicket.model.IModel;
++import org.apache.wicket.util.time.Duration;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++public class JobColumn<T, S> extends AbstractColumn<T, S> {
++
++    private static final long serialVersionUID = 7955560320949560725L;
++
++    protected static final Logger LOG = LoggerFactory.getLogger(JobColumn.class);
++
++    private final PageReference pageRef;
++
++    private RuntimePanel panel;
++
++    private final JobRestClient jobRestClient;
++
++    public JobColumn(final IModel<String> displayModel, final S sortProperty, final PageReference pageRef,
++            final JobRestClient jobRestClient) {
++        super(displayModel, sortProperty);
++        this.pageRef = pageRef;
++        this.jobRestClient = jobRestClient;
++    }
++
++    @Override
++    public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> model) {
++        Long jobId = null;
++        if (model.getObject() instanceof AbstractTaskTO) {
++            jobId = ((AbstractTaskTO) model.getObject()).getId();
++        } else if (model.getObject() instanceof ReportTO) {
++            jobId = ((ReportTO) model.getObject()).getId();
++        }
++        if (jobId != null) {
++            panel = new RuntimePanel(componentId, model, pageRef, jobId, jobRestClient);
++            startPolling(10);
++            item.add(panel);
++        }
++    }
++
++    public void startPolling(final int seconds) {
++        AbstractAjaxTimerBehavior timer = new AbstractAjaxTimerBehavior(Duration.seconds(seconds)) {
++
++            private static final long serialVersionUID = 1L;
++
++            @Override
++            protected void onTimer(AjaxRequestTarget target) {
++                panel.refresh();
++                target.add(panel);
++            }
++
++            @Override
++            protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
++                super.updateAjaxAttributes(attributes);
++                attributes.getExtraParameters().put("pollingTimeout", "true");
++            }
++
++        };
++
++        panel.setTimer(timer);
++
++    }
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/resources/org/apache/syncope/client/console/pages/Reports.html
----------------------------------------------------------------------
diff --cc client/old_console/src/main/resources/org/apache/syncope/client/console/pages/Reports.html
index 456f7a3,0000000..ff5fb37
mode 100644,000000..100644
--- a/client/old_console/src/main/resources/org/apache/syncope/client/console/pages/Reports.html
+++ b/client/old_console/src/main/resources/org/apache/syncope/client/console/pages/Reports.html
@@@ -1,58 -1,0 +1,71 @@@
 +<!--
 +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.
 +-->
 +<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
 +  <wicket:extend>
++    <script type="text/javascript">
++      window.onload = setupFunc;
 +
++      function setupFunc() {
++        Wicket.Event.subscribe('/ajax/call/beforeSend', function (attributes, jqXHR, settings) {
++          if (!jqXHR.ep || !jqXHR.ep[0] || !jqXHR.ep[0]["value"]) {
++            document.getElementById("veil").style.display = "block";
++          }
++        });
++        Wicket.Event.subscribe('/ajax/call/complete', function (attributes, jqXHR, textStatus) {
++          document.getElementById("veil").style.display = "none";
++        });
++      }
++    </script>
 +    <div id="tabs">
 +      <ul>
 +        <li class="tabs-selected"><a href="#tabs-1"><span><wicket:message key="reports"/></span></a></li>
 +        <li><a href="#tabs-2"><span><wicket:message key="audit"/></span></a></li>
 +      </ul>
 +
 +      <div id="tabs-1">
 +        <div id="users-contain" class="ui-widget" style="width:inherit;">
 +          <span wicket:id="reportContainer">
 +            <table class="ui-widget ui-widget-content table-hover" wicket:id="reportTable"/>
 +          </span>
 +          <span style="float:right">
 +            <form wicket:id="paginatorForm" style="display:inline">
 +              <label><wicket:message key="displayRows"/></label>
 +              <select class="text ui-widget-content ui-corner-all" wicket:id="rowsChooser"/>
 +            </form>
 +          </span>
 +        </div>
 +
 +        <div wicket:id="reportWin">[Show modal window for report editing]</div>
 +        <a class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" wicket:id="createLink">
 +          <wicket:message key="create"/>
 +        </a>
 +
 +      </div>
 +
 +      <div id="tabs-2">
 +        <span wicket:id="auditContainer">
 +          <form wicket:id="auditForm">
 +            <span wicket:id="events">[event builder]</span>
 +          </form>
 +        </span>
 +      </div>
 +    </div>
 +
 +  </wicket:extend>
 +</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/resources/org/apache/syncope/client/console/pages/Tasks.html
----------------------------------------------------------------------
diff --cc client/old_console/src/main/resources/org/apache/syncope/client/console/pages/Tasks.html
index 7df418a,0000000..81c9237
mode 100644,000000..100644
--- a/client/old_console/src/main/resources/org/apache/syncope/client/console/pages/Tasks.html
+++ b/client/old_console/src/main/resources/org/apache/syncope/client/console/pages/Tasks.html
@@@ -1,46 -1,0 +1,61 @@@
 +<!--
 +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.
 +-->
 +<wicket:extend>
 +
++  <script type="text/javascript">
++    window.onload = setupFunc;
++
++    function setupFunc() {
++      Wicket.Event.subscribe('/ajax/call/beforeSend', function (attributes, jqXHR, settings) {
++        if (!jqXHR.ep || !jqXHR.ep[0] || !jqXHR.ep[0]["value"]){
++          document.getElementById("veil").style.display = "block";
++        }
++      });
++      Wicket.Event.subscribe('/ajax/call/complete', function (attributes, jqXHR, textStatus) {
++        document.getElementById("veil").style.display = "none";
++      });
++    }
++  </script>
++
 +  <div id="tabs">
 +    <ul>
 +      <li class="tabs-selected"><a href="#tabs-1"><span><wicket:message key="tab1"/></span></a></li>
 +      <li><a href="#tabs-2"><span><wicket:message key="tab2"/></span></a></li>
 +      <li><a href="#tabs-3"><span><wicket:message key="tab3"/></span></a></li>
 +      <li><a href="#tabs-4"><span><wicket:message key="tab4"/></span></a></li>
 +      <li><a href="#tabs-5"><span><wicket:message key="tab5"/></span></a></li>
 +    </ul>
 +    <div id="tabs-1">
 +      <span wicket:id="propagation">[propagation tasks]</span>
 +    </div>
 +    <div id="tabs-2">
 +      <span wicket:id="notification">[notification tasks]</span>
 +    </div>
 +    <div id="tabs-3">
 +      <span wicket:id="sched">[scheduled tasks]</span>
 +    </div>
 +    <div id="tabs-4">
 +      <span wicket:id="sync">[synchronization tasks]</span>
 +    </div>
 +    <div id="tabs-5">
 +      <span wicket:id="push">[push tasks]</span>
 +    </div>
 +  </div>
 +
 +</wicket:extend>

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/client/old_console/src/main/resources/org/apache/syncope/client/console/panels/RuntimePanel.html
----------------------------------------------------------------------
diff --cc client/old_console/src/main/resources/org/apache/syncope/client/console/panels/RuntimePanel.html
index 0000000,0000000..828192c
new file mode 100644
--- /dev/null
+++ b/client/old_console/src/main/resources/org/apache/syncope/client/console/panels/RuntimePanel.html
@@@ -1,0 -1,0 +1,49 @@@
++<!--
++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.
++-->
++<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
++  <wicket:head>
++    <style>
++      #runtime{
++        text-align: center;
++      }
++    </style>
++  </wicket:head>
++  <wicket:panel wicket:id="runtime">
++    <div>
++      <div id="runtime">
++        <div id="runtimePanel">
++          <span wicket:id="panelStop"></span>
++          <span wicket:id="panelSpinner"></span>
++
++          <wicket:fragment wicket:id="fragmentStop">
++            <a href="#" wicket:id="stopLink"><img src="img/actions/suspend.png" alt="stop icon" title="Stop Now"/></a>
++          </wicket:fragment>
++
++          <wicket:fragment wicket:id="fragmentSpinner">
++            <img src="img/loading.gif" alt="spinner icon" title="Spinner"/>
++          </wicket:fragment>
++
++          <wicket:fragment wicket:id="emptyFragment"></wicket:fragment>
++
++        </div>
++
++      </div>
++    </div>
++  </wicket:panel>
++</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a0422a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractJobLogic.java
----------------------------------------------------------------------
diff --cc core/logic/src/main/java/org/apache/syncope/core/logic/AbstractJobLogic.java
index e423174,0000000..fb5648f
mode 100644,000000..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
@@@ -1,174 -1,0 +1,187 @@@
 +/*
 + * 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.logic;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import org.apache.syncope.common.lib.AbstractBaseBean;
 +import org.apache.syncope.common.lib.to.AbstractExecTO;
 +import org.apache.syncope.common.lib.to.ReportExecTO;
 +import org.apache.syncope.common.lib.to.TaskExecTO;
 +import org.apache.syncope.common.lib.types.JobAction;
 +import org.apache.syncope.common.lib.types.JobStatusType;
 +import org.quartz.JobExecutionContext;
 +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.annotation.Autowired;
 +import org.springframework.scheduling.quartz.SchedulerFactoryBean;
 +
 +abstract class AbstractJobLogic<T extends AbstractBaseBean> extends AbstractTransactionalLogic<T> {
 +
 +    @Autowired
 +    protected SchedulerFactoryBean scheduler;
 +
 +    protected abstract Long getKeyFromJobName(final JobKey jobKey);
 +
 +    private <E extends AbstractExecTO> void setTaskOrReportKey(final E jobExecTO, final Long taskOrReportKey) {
 +        if (jobExecTO instanceof TaskExecTO) {
 +            ((TaskExecTO) jobExecTO).setTask(taskOrReportKey);
 +        } else if (jobExecTO instanceof ReportExecTO) {
 +            ((ReportExecTO) jobExecTO).setReport(taskOrReportKey);
 +        }
 +    }
 +
 +    public <E extends AbstractExecTO> List<E> listJobs(final JobStatusType type, final Class<E> reference) {
 +        List<E> jobExecTOs = new ArrayList<>();
 +
 +        switch (type) {
 +            case ALL:
 +                try {
 +                    for (String groupName : scheduler.getScheduler().getJobGroupNames()) {
 +                        for (JobKey jobKey
 +                                : scheduler.getScheduler().getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
 +
 +                            Long key = getKeyFromJobName(jobKey);
 +                            if (key != null) {
 +                                List<? extends Trigger> jobTriggers = scheduler.getScheduler().getTriggersOfJob(jobKey);
 +                                if (jobTriggers.isEmpty()) {
 +                                    E jobExecTO = reference.newInstance();
 +                                    setTaskOrReportKey(jobExecTO, key);
 +                                    jobExecTO.setStatus("Not Scheduled");
 +
 +                                    jobExecTOs.add(jobExecTO);
 +                                } else {
 +                                    for (Trigger t : jobTriggers) {
 +                                        E jobExecTO = reference.newInstance();
 +                                        jobExecTO.setKey(key);
 +                                        jobExecTO.
 +                                                setStatus(scheduler.getScheduler().getTriggerState(t.getKey()).name());
 +                                        jobExecTO.setStartDate(t.getStartTime());
 +
 +                                        jobExecTOs.add(jobExecTO);
 +                                    }
 +                                }
 +                            }
 +                        }
 +                    }
 +                } catch (SchedulerException e) {
 +                    LOG.debug("Problems while retrieving all scheduled jobs", e);
 +                } catch (InstantiationException e) {
 +                    LOG.debug("Problems while instantiating {}", reference, e);
 +                } catch (IllegalAccessException e) {
 +                    LOG.debug("Problems while accessing {}", reference, e);
 +                }
 +                break;
 +
 +            case RUNNING:
 +                try {
 +                    for (JobExecutionContext jec : scheduler.getScheduler().getCurrentlyExecutingJobs()) {
 +                        Long key = getKeyFromJobName(jec.getJobDetail().getKey());
 +                        if (key != null) {
 +                            E jobExecTO = reference.newInstance();
 +                            setTaskOrReportKey(jobExecTO, key);
 +                            jobExecTO.setStatus(
 +                                    scheduler.getScheduler().getTriggerState(jec.getTrigger().getKey()).name());
 +                            jobExecTO.setStartDate(jec.getFireTime());
 +
 +                            jobExecTOs.add(jobExecTO);
 +                        }
 +                    }
 +                } catch (SchedulerException e) {
 +                    LOG.debug("Problems while retrieving all currently executing jobs", e);
 +                } catch (InstantiationException e) {
 +                    LOG.debug("Problems while instantiating {}", reference, e);
 +                } catch (IllegalAccessException e) {
 +                    LOG.debug("Problems while accessing {}", reference, e);
 +                }
 +                break;
 +
 +            case SCHEDULED:
 +                try {
 +                    for (String groupName : scheduler.getScheduler().getJobGroupNames()) {
 +                        for (JobKey jobKey
 +                                : scheduler.getScheduler().getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
 +
 +                            Long key = getKeyFromJobName(jobKey);
 +                            if (key != null) {
 +                                List<? extends Trigger> jobTriggers = scheduler.getScheduler().getTriggersOfJob(jobKey);
 +                                for (Trigger t : jobTriggers) {
 +                                    E jobExecTO = reference.newInstance();
 +                                    setTaskOrReportKey(jobExecTO, key);
 +                                    jobExecTO.setStatus(scheduler.getScheduler().getTriggerState(t.getKey()).name());
 +                                    jobExecTO.setStartDate(t.getStartTime());
 +
 +                                    jobExecTOs.add(jobExecTO);
 +                                }
 +                            }
 +                        }
 +                    }
 +                } catch (SchedulerException e) {
 +                    LOG.debug("Problems while retrieving all scheduled jobs", e);
 +                } catch (InstantiationException e) {
 +                    LOG.debug("Problems while instantiating {}", reference, e);
 +                } catch (IllegalAccessException e) {
 +                    LOG.debug("Problems while accessing {}", reference, e);
 +                }
 +                break;
 +
 +            default:
 +        }
 +        return jobExecTOs;
 +    }
 +
 +    protected void actionJob(final String jobName, final JobAction action) {
 +        if (jobName != null) {
 +            JobKey jobKey = new JobKey(jobName, Scheduler.DEFAULT_GROUP);
 +            try {
 +                if (scheduler.getScheduler().checkExists(jobKey)) {
 +                    switch (action) {
 +                        case START:
-                             scheduler.getScheduler().triggerJob(jobKey);
++                            Long currentKey = getKeyFromJobName(jobKey);
++                            boolean found = false;
++                            //Two or more equals jobs cannot be executed concurrently
++                            for (int i = 0; i < scheduler.getScheduler().getCurrentlyExecutingJobs().size() && !found;
++                                    i++) {
++                                JobExecutionContext jec = scheduler.getScheduler().getCurrentlyExecutingJobs().get(i);
++                                Long execJobKey = getKeyFromJobName(jec.getJobDetail().getKey());
++                                if (execJobKey == currentKey) {
++                                    found = true;
++                                }
++                            }
++                            if (!found) {
++                                scheduler.getScheduler().triggerJob(jobKey);
++                            }
 +                            break;
 +
 +                        case STOP:
 +                            scheduler.getScheduler().interrupt(jobKey);
 +                            break;
 +
 +                        default:
 +                    }
 +                }
 +            } catch (SchedulerException e) {
 +                LOG.debug("Problems during {} operation on job {}", action.toString(), jobName, e);
 +            }
 +        }
 +    }
 +}