You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2013/11/20 12:37:36 UTC

svn commit: r1543782 [2/4] - in /syncope/trunk: ./ common/src/main/java/org/apache/syncope/common/services/ common/src/main/java/org/apache/syncope/common/to/ common/src/main/java/org/apache/syncope/common/types/ common/src/main/java/org/apache/syncope...

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/audit/AuditManager.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/audit/AuditManager.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/audit/AuditManager.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/audit/AuditManager.java Wed Nov 20 11:37:34 2013
@@ -18,7 +18,8 @@
  */
 package org.apache.syncope.core.audit;
 
-import org.apache.syncope.common.types.AuditElements.Category;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.types.AuditElements;
 import org.apache.syncope.common.types.AuditElements.Result;
 import org.apache.syncope.common.types.AuditLoggerName;
 import org.apache.syncope.common.types.LoggerLevel;
@@ -29,7 +30,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.transaction.annotation.Transactional;
 
 public class AuditManager {
 
@@ -41,18 +41,45 @@ public class AuditManager {
     @Autowired
     private LoggerDAO loggerDAO;
 
-    @Transactional
-    public void audit(final Category category, final Enum<?> subcategory, final Result result, final String message) {
-        audit(category, subcategory, result, message, null);
-    }
+    public void audit(
+            final AuditElements.EventCategoryType type,
+            final String category,
+            final String subcategory,
+            final String event,
+            final Result result,
+            final Object before,
+            final Object output,
+            final Object... input) {
+
+        final Throwable throwable;
+        final StringBuilder message = new StringBuilder();
+
+        message.append("BEFORE:\n");
+        message.append("\t").append(before == null ? "unknown" : before).append("\n");
+
+        message.append("INPUT:\n");
+
+        if (ArrayUtils.isNotEmpty(input)) {
+            for (Object obj : input) {
+                message.append("\t").append(obj == null ? null : obj.toString()).append("\n");
+            }
+        } else {
+            message.append("\t").append("none").append("\n");
+        }
 
-    @Transactional
-    public void audit(final Category category, final Enum<?> subcategory, final Result result, final String message,
-            final Throwable throwable) {
+        message.append("OUTPUT:\n");
+
+        if (output instanceof Throwable) {
+            throwable = (Throwable) output;
+            message.append("\t").append(throwable.getMessage());
+        } else {
+            throwable = null;
+            message.append("\t").append(output == null ? "none" : output.toString());
+        }
 
         AuditLoggerName auditLoggerName = null;
         try {
-            auditLoggerName = new AuditLoggerName(category, subcategory, result);
+            auditLoggerName = new AuditLoggerName(type, category, subcategory, event, result);
         } catch (IllegalArgumentException e) {
             LOG.error("Invalid audit parameters, aborting...", e);
         }
@@ -68,7 +95,7 @@ public class AuditManager {
                 }
                 auditMessage.append(message);
 
-                Logger logger = LoggerFactory.getLogger(auditLoggerName.toLoggerName());
+                final Logger logger = LoggerFactory.getLogger(auditLoggerName.toLoggerName());
                 if (throwable == null) {
                     logger.debug(auditMessage.toString());
                 } else {

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java Wed Nov 20 11:37:34 2013
@@ -22,8 +22,7 @@ import java.util.Date;
 import javax.mail.internet.MimeMessage;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.SyncopeConstants;
-import org.apache.syncope.common.types.AuditElements.Category;
-import org.apache.syncope.common.types.AuditElements.NotificationSubCategory;
+import org.apache.syncope.common.types.AuditElements;
 import org.apache.syncope.common.types.AuditElements.Result;
 import org.apache.syncope.common.types.TraceLevel;
 import org.apache.syncope.core.audit.AuditManager;
@@ -198,7 +197,15 @@ public class NotificationJob implements 
                         execution.setMessage(report.toString());
                     }
 
-                    auditManager.audit(Category.notification, NotificationSubCategory.send, Result.success,
+                    auditManager.audit(
+                            AuditElements.EventCategoryType.TASK,
+                            "notification",
+                            null,
+                            "send",
+                            Result.SUCCESS,
+                            null,
+                            null,
+                            task,
                             "Successfully sent notification to " + to);
                 } catch (Exception e) {
                     LOG.error("Could not send e-mail", e);
@@ -208,7 +215,15 @@ public class NotificationJob implements 
                         execution.setMessage(ExceptionUtil.getFullStackTrace(e));
                     }
 
-                    auditManager.audit(Category.notification, NotificationSubCategory.send, Result.failure,
+                    auditManager.audit(
+                            AuditElements.EventCategoryType.TASK,
+                            "notification",
+                            null,
+                            "send",
+                            Result.FAILURE,
+                            null,
+                            null,
+                            task,
                             "Could not send notification to " + to, e);
                 }
 
@@ -266,12 +281,28 @@ public class NotificationJob implements 
                     execution.getTask(), failedExecutionsCount, maxRetries);
             notificationManager.setTaskExecuted(execution.getTask().getId(), false);
 
-            auditManager.audit(Category.notification, NotificationSubCategory.retry, Result.success,
+            auditManager.audit(
+                    AuditElements.EventCategoryType.TASK,
+                    "notification",
+                    null,
+                    "retry",
+                    Result.SUCCESS,
+                    null,
+                    null,
+                    execution,
                     "Notification task " + execution.getTask().getId() + " will be retried");
         } else {
             LOG.error("Maximum number of retries reached for task {} - giving up", execution.getTask());
 
-            auditManager.audit(Category.notification, NotificationSubCategory.retry, Result.failure,
+            auditManager.audit(
+                    AuditElements.EventCategoryType.TASK,
+                    "notification",
+                    null,
+                    "retry",
+                    Result.FAILURE,
+                    null,
+                    null,
+                    execution,
                     "Giving up retries on notification task " + execution.getTask().getId());
         }
     }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/notification/NotificationManager.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/notification/NotificationManager.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/notification/NotificationManager.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/notification/NotificationManager.java Wed Nov 20 11:37:34 2013
@@ -19,16 +19,22 @@
 package org.apache.syncope.core.notification;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.apache.syncope.common.SyncopeConstants;
+import org.apache.syncope.common.to.RoleTO;
 import org.apache.syncope.common.to.UserTO;
 import org.apache.syncope.common.types.AttributableType;
+import org.apache.syncope.common.types.AuditElements;
+import org.apache.syncope.common.types.AuditElements.Result;
 import org.apache.syncope.common.types.IntMappingType;
+import org.apache.syncope.common.util.LoggerEventUtils;
 import org.apache.syncope.core.connid.ConnObjectUtil;
+import org.apache.syncope.core.persistence.beans.AbstractAttributable;
 import org.apache.syncope.core.persistence.beans.Notification;
 import org.apache.syncope.core.persistence.beans.NotificationTask;
 import org.apache.syncope.core.persistence.beans.SyncopeConf;
@@ -40,8 +46,8 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.dao.AttributableSearchDAO;
 import org.apache.syncope.core.persistence.dao.ConfDAO;
 import org.apache.syncope.core.persistence.dao.EntitlementDAO;
-import org.apache.syncope.core.persistence.dao.NotFoundException;
 import org.apache.syncope.core.persistence.dao.NotificationDAO;
+import org.apache.syncope.core.persistence.dao.RoleDAO;
 import org.apache.syncope.core.persistence.dao.TaskDAO;
 import org.apache.syncope.core.persistence.dao.UserDAO;
 import org.apache.syncope.core.rest.data.UserDataBinder;
@@ -87,6 +93,12 @@ public class NotificationManager {
     private UserDAO userDAO;
 
     /**
+     * Role DAO.
+     */
+    @Autowired
+    private RoleDAO roleDAO;
+
+    /**
      * User data binder.
      */
     @Autowired
@@ -120,11 +132,18 @@ public class NotificationManager {
      * Create a notification task.
      *
      * @param notification notification to take as model
-     * @param user the user this task is about
+     * @param attributable the user this task is about
+     * @param model Velocity model
      * @return notification task, fully populated
      */
-    private NotificationTask getNotificationTask(final Notification notification, final SyncopeUser user) {
-        connObjectUtil.retrieveVirAttrValues(user, AttributableUtil.getInstance(AttributableType.USER));
+    private NotificationTask getNotificationTask(
+            final Notification notification,
+            final AbstractAttributable attributable,
+            final Map<String, Object> model) {
+
+        if (attributable != null) {
+            connObjectUtil.retrieveVirAttrValues(attributable, AttributableUtil.getInstance(AttributableType.USER));
+        }
 
         final List<SyncopeUser> recipients = new ArrayList<SyncopeUser>();
 
@@ -133,8 +152,8 @@ public class NotificationManager {
                     notification.getRecipients(), AttributableUtil.getInstance(AttributableType.USER)));
         }
 
-        if (notification.isSelfAsRecipient()) {
-            recipients.add(user);
+        if (notification.isSelfAsRecipient() && attributable instanceof SyncopeUser) {
+            recipients.add((SyncopeUser) attributable);
         }
 
         final Set<String> recipientEmails = new HashSet<String>();
@@ -152,18 +171,16 @@ public class NotificationManager {
             }
         }
 
+        model.put("recipients", recipientTOs);
+        model.put("syncopeConf", this.findAllSyncopeConfs());
+        model.put("events", notification.getEvents());
+
         NotificationTask task = new NotificationTask();
         task.setTraceLevel(notification.getTraceLevel());
         task.setRecipients(recipientEmails);
         task.setSender(notification.getSender());
         task.setSubject(notification.getSubject());
 
-        final Map<String, Object> model = new HashMap<String, Object>();
-        model.put("user", userDataBinder.getUserTO(user));
-        model.put("syncopeConf", this.findAllSyncopeConfs());
-        model.put("recipients", recipientTOs);
-        model.put("events", notification.getEvents());
-
         String htmlBody;
         String textBody;
         try {
@@ -185,33 +202,66 @@ public class NotificationManager {
 
     /**
      * Create notification tasks for each notification matching the given user id and (some of) tasks performed.
-     *
-     * @param userId user id
-     * @param performedTasks set of actions performed on given user id
-     * @throws NotFoundException if user contained in the workflow result cannot be found
-     */
-    public void createTasks(final Long userId, final Set<String> performedTasks)
-            throws NotFoundException {
-
-        SyncopeUser user = userDAO.find(userId);
-        if (user == null) {
-            throw new NotFoundException("User " + userId);
+     */
+    public void createTasks(
+            final AuditElements.EventCategoryType type,
+            final String category,
+            final String subcategory,
+            final String event,
+            final Result condition,
+            final Object before,
+            final Object output,
+            final Object... input) {
+
+        AttributableType attributableType = null;
+        AbstractAttributable attributable = null;
+
+        if (before instanceof UserTO) {
+            attributableType = AttributableType.USER;
+            attributable = userDAO.find(((UserTO) before).getId());
+        } else if (output instanceof UserTO) {
+            attributableType = AttributableType.USER;
+            attributable = userDAO.find(((UserTO) output).getId());
+        } else if (before instanceof RoleTO) {
+            attributableType = AttributableType.ROLE;
+            attributable = roleDAO.find(((RoleTO) before).getId());
+        } else if (output instanceof RoleTO) {
+            attributableType = AttributableType.ROLE;
+            attributable = roleDAO.find(((RoleTO) output).getId());
         }
 
+        LOG.debug("Search notification for [{}]{}", attributableType, attributable);
+
         for (Notification notification : notificationDAO.findAll()) {
-            if (notification.getAbout() == null
-                    || searchDAO.matches(user, notification.getAbout(),
-                    AttributableUtil.getInstance(AttributableType.USER))) {
-
-                Set<String> events = new HashSet<String>(notification.getEvents());
-                events.retainAll(performedTasks);
-
-                if (events.isEmpty()) {
-                    LOG.debug("No events found about {}", user);
-                } else {
-                    LOG.debug("Creating notification task for events {} about {}", events, user);
-                    taskDAO.save(getNotificationTask(notification, user));
+            LOG.debug("Notification available about {}", notification.getAbout());
+
+            final Set<String> events = new HashSet<String>(notification.getEvents());
+            events.retainAll(Collections.<String>singleton(LoggerEventUtils.buildEvent(
+                    type, category, subcategory, event, condition)));
+
+            if (events.isEmpty()) {
+                LOG.debug("No events found about {}", attributable);
+            } else if (attributableType == null || attributable == null || notification.getAbout() == null
+                    || searchDAO.matches(attributable, notification.getAbout(),
+                    AttributableUtil.getInstance(attributableType))) {
+
+                LOG.debug("Creating notification task for events {} about {}", events, attributable);
+
+                final Map<String, Object> model = new HashMap<String, Object>();
+                model.put("type", type);
+                model.put("category", category);
+                model.put("subcategory", subcategory);
+                model.put("event", event);
+                model.put("condition", condition);
+                model.put("before", before);
+                model.put("output", output);
+                model.put("input", input);
+
+                if (attributable instanceof SyncopeUser) {
+                    model.put("user", userDataBinder.getUserTO((SyncopeUser) attributable));
                 }
+
+                taskDAO.save(getNotificationTask(notification, attributable, model));
             }
         }
     }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PropagationTask.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PropagationTask.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PropagationTask.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PropagationTask.java Wed Nov 20 11:37:34 2013
@@ -25,7 +25,6 @@ import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
 import javax.persistence.Lob;
 import javax.persistence.ManyToOne;
-
 import org.apache.syncope.common.types.AttributableType;
 import org.apache.syncope.common.types.PropagationMode;
 import org.apache.syncope.common.types.ResourceOperation;

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/role/SyncopeRole.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/role/SyncopeRole.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/role/SyncopeRole.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/role/SyncopeRole.java Wed Nov 20 11:37:34 2013
@@ -62,8 +62,7 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.validation.entity.SyncopeRoleCheck;
 
 @Entity
-@Table(uniqueConstraints =
-        @UniqueConstraint(columnNames = { "name", "parent_id" }))
+@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"name", "parent_id"}))
 @Cacheable
 @SyncopeRoleCheck
 public class SyncopeRole extends AbstractAttributable {
@@ -284,7 +283,7 @@ public class SyncopeRole extends Abstrac
         this.inheritTemplates = getBooleanAsInteger(inheritAttrTemplates);
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @SuppressWarnings({"unchecked", "rawtypes"})
     public <T extends AbstractAttrTemplate> List<T> getAttrTemplates(final Class<T> reference) {
         List<T> result = null;
 
@@ -322,7 +321,7 @@ public class SyncopeRole extends Abstrac
     public <T extends AbstractAttrTemplate<K>, K extends AbstractSchema> List<K> getAttrTemplateSchemas(
             final Class<T> reference) {
 
-        List<K> result = new ArrayList<K>();
+        final List<K> result = new ArrayList<K>();
 
         for (T template : findInheritedTemplates(reference)) {
             result.add(template.getSchema());
@@ -335,7 +334,7 @@ public class SyncopeRole extends Abstrac
     public <T extends AbstractAttrTemplate<K>, K extends AbstractSchema> List<T> findInheritedTemplates(
             final Class<T> reference) {
 
-        List<T> result = new ArrayList<T>(getAttrTemplates(reference));
+        final List<T> result = new ArrayList<T>(getAttrTemplates(reference));
 
         if (isInheritTemplates() && getParent() != null) {
             result.addAll(getParent().findInheritedTemplates(reference));

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java Wed Nov 20 11:37:34 2013
@@ -197,7 +197,6 @@ public class SyncopeUser extends Abstrac
                 result = membership;
             }
         }
-
         return result;
     }
 
@@ -242,7 +241,6 @@ public class SyncopeUser extends Abstrac
         for (SyncopeRole role : getRoles()) {
             result.addAll(role.getResources());
         }
-
         return result;
     }
 
@@ -491,8 +489,8 @@ public class SyncopeUser extends Abstrac
                 res = passwordHistory.subList(size >= passwordHistory.size()
                         ? 0
                         : passwordHistory.size() - size, passwordHistory.size()).contains(cipherAlgorithm == null
-                                ? password
-                                : PasswordEncoder.encode(password, cipherAlgorithm));
+                        ? password
+                        : PasswordEncoder.encode(password, cipherAlgorithm));
             } catch (Exception e) {
                 LOG.error("Error evaluating password history", e);
             }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/dao/NotFoundException.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/dao/NotFoundException.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/dao/NotFoundException.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/dao/NotFoundException.java Wed Nov 20 11:37:34 2013
@@ -23,7 +23,7 @@ package org.apache.syncope.core.persiste
  */
 public class NotFoundException extends RuntimeException {
 
-    private static final long serialVersionUID = 4810651769126663580L;
+    private static final long serialVersionUID = 4810651769126663581L;
 
     public NotFoundException(final String msg) {
         super(msg);

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java Wed Nov 20 11:37:34 2013
@@ -19,6 +19,7 @@
 package org.apache.syncope.core.propagation.impl;
 
 import java.util.ArrayList;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -27,11 +28,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.types.AuditElements;
+import org.apache.syncope.common.types.AuditElements.Result;
 import org.apache.syncope.common.types.MappingPurpose;
 import org.apache.syncope.common.types.PropagationMode;
 import org.apache.syncope.common.types.PropagationTaskExecStatus;
 import org.apache.syncope.common.types.TraceLevel;
+import org.apache.syncope.core.audit.AuditManager;
 import org.apache.syncope.core.connid.ConnObjectUtil;
+import org.apache.syncope.core.notification.NotificationManager;
 import org.apache.syncope.core.persistence.beans.AbstractAttributable;
 import org.apache.syncope.core.persistence.beans.ExternalResource;
 import org.apache.syncope.core.persistence.beans.PropagationTask;
@@ -95,6 +100,18 @@ public abstract class AbstractPropagatio
     @Autowired
     protected RoleDataBinder roleDataBinder;
 
+    /**
+     * Notification Manager.
+     */
+    @Autowired
+    protected NotificationManager notificationManager;
+
+    /**
+     * Audit Manager.
+     */
+    @Autowired
+    protected AuditManager auditManager;
+
     @Override
     public TaskExec execute(final PropagationTask task) {
         return execute(task, null);
@@ -306,6 +323,7 @@ public abstract class AbstractPropagatio
         ConnectorObject afterObj = null;
 
         Connector connector = null;
+        Result result;
         try {
             connector = connLoader.getConnector(task.getResource());
 
@@ -332,7 +350,9 @@ public abstract class AbstractPropagatio
                     : PropagationTaskExecStatus.SUBMITTED.name());
 
             LOG.debug("Successfully propagated to {}", task.getResource());
+            result = Result.SUCCESS;
         } catch (Exception e) {
+            result = Result.FAILURE;
             LOG.error("Exception during provision on resource " + task.getResource().getName(), e);
 
             if (e instanceof ConnectorException && e.getCause() != null) {
@@ -401,6 +421,26 @@ public abstract class AbstractPropagatio
 
         actions.after(task, execution, afterObj);
 
+        notificationManager.createTasks(
+                AuditElements.EventCategoryType.PROPAGATION,
+                task.getSubjectType().name().toLowerCase(),
+                task.getResource().getName(),
+                task.getPropagationOperation().name().toLowerCase(),
+                result,
+                beforeObj, // searching for before object is too much expensive ... 
+                new Object[] { execution, afterObj },
+                task);
+
+        auditManager.audit(
+                AuditElements.EventCategoryType.PROPAGATION,
+                task.getSubjectType().name().toLowerCase(),
+                task.getResource().getName(),
+                task.getPropagationOperation().name().toLowerCase(),
+                result,
+                beforeObj, // searching for before object is too much expensive ... 
+                new Object[] { execution, afterObj },
+                task);
+
         return execution;
     }
 

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java Wed Nov 20 11:37:34 2013
@@ -83,6 +83,7 @@ public class LDAPMembershipPropagationAc
                         JexlUtil.addFieldsToContext(role, jexlContext);
                         JexlUtil.addAttrsToContext(role.getAttrs(), jexlContext);
                         JexlUtil.addDerAttrsToContext(role.getDerAttrs(), role.getAttrs(), jexlContext);
+
                         final String roleAccountLink =
                                 JexlUtil.evaluate(task.getResource().getRmapping().getAccountLink(), jexlContext);
                         LOG.debug("AccountLink for {} is '{}'", role, roleAccountLink);

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PriorityPropagationTaskExecutor.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PriorityPropagationTaskExecutor.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PriorityPropagationTaskExecutor.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PriorityPropagationTaskExecutor.java Wed Nov 20 11:37:34 2013
@@ -24,6 +24,8 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import org.apache.syncope.common.types.AuditElements;
+import org.apache.syncope.common.types.AuditElements.Result;
 import org.apache.syncope.common.types.PropagationTaskExecStatus;
 import org.apache.syncope.core.persistence.beans.PropagationTask;
 import org.apache.syncope.core.persistence.beans.TaskExec;
@@ -41,25 +43,50 @@ public class PriorityPropagationTaskExec
         final List<PropagationTask> prioritizedTasks = new ArrayList<PropagationTask>(tasks);
         Collections.sort(prioritizedTasks, new PriorityComparator());
 
-        for (PropagationTask task : prioritizedTasks) {
-            LOG.debug("Execution started for {}", task);
+        Result result = Result.SUCCESS;
 
-            TaskExec execution = execute(task, reporter);
-
-            LOG.debug("Execution finished for {}, {}", task, execution);
-
-            // Propagation is interrupted as soon as the result of the
-            // communication with a primary resource is in error
-            PropagationTaskExecStatus execStatus;
-            try {
-                execStatus = PropagationTaskExecStatus.valueOf(execution.getStatus());
-            } catch (IllegalArgumentException e) {
-                LOG.error("Unexpected execution status found {}", execution.getStatus());
-                execStatus = PropagationTaskExecStatus.FAILURE;
-            }
-            if (task.getResource().isPropagationPrimary() && !execStatus.isSuccessful()) {
-                throw new PropagationException(task.getResource().getName(), execution.getMessage());
+        try {
+            for (PropagationTask task : prioritizedTasks) {
+                LOG.debug("Execution started for {}", task);
+
+                TaskExec execution = execute(task, reporter);
+
+                LOG.debug("Execution finished for {}, {}", task, execution);
+
+                // Propagation is interrupted as soon as the result of the
+                // communication with a primary resource is in error
+                PropagationTaskExecStatus execStatus;
+                try {
+                    execStatus = PropagationTaskExecStatus.valueOf(execution.getStatus());
+                } catch (IllegalArgumentException e) {
+                    LOG.error("Unexpected execution status found {}", execution.getStatus());
+                    execStatus = PropagationTaskExecStatus.FAILURE;
+                }
+                if (task.getResource().isPropagationPrimary() && !execStatus.isSuccessful()) {
+                    result = Result.FAILURE;
+                    throw new PropagationException(task.getResource().getName(), execution.getMessage());
+                }
             }
+        } finally {
+            notificationManager.createTasks(
+                    AuditElements.EventCategoryType.PROPAGATION,
+                    null,
+                    null,
+                    null,
+                    result,
+                    reporter instanceof DefaultPropagationReporter
+                    ? ((DefaultPropagationReporter) reporter).getStatuses() : null,
+                    tasks);
+
+            auditManager.audit(
+                    AuditElements.EventCategoryType.PROPAGATION,
+                    null,
+                    null,
+                    null,
+                    result,
+                    reporter instanceof DefaultPropagationReporter
+                    ? ((DefaultPropagationReporter) reporter).getStatuses() : null,
+                    tasks);
         }
     }
 

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java Wed Nov 20 11:37:34 2013
@@ -67,7 +67,7 @@ import org.springframework.transaction.a
 /**
  * Manage the data propagation to external resources.
  */
-@Transactional(rollbackFor = { Throwable.class })
+@Transactional(rollbackFor = {Throwable.class})
 public class PropagationManager {
 
     /**
@@ -182,6 +182,7 @@ public class PropagationManager {
         if (vAttrs != null && !vAttrs.isEmpty()) {
             roleDataBinder.fillVirtual(role, vAttrs, AttributableUtil.getInstance(AttributableType.ROLE));
         }
+        
         return getCreateTaskIds(role, null, vAttrs, null, wfResult.getPropByRes(), noPropResourceNames);
     }
 
@@ -653,7 +654,6 @@ public class PropagationManager {
                     }
 
                     task.setAttributes(preparedAttrs.getValue());
-
                     tasks.add(task);
 
                     LOG.debug("PropagationTask created: {}", task);

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/AbstractTaskJob.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/AbstractTaskJob.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/AbstractTaskJob.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/AbstractTaskJob.java Wed Nov 20 11:37:34 2013
@@ -19,6 +19,10 @@
 package org.apache.syncope.core.quartz;
 
 import java.util.Date;
+import org.apache.syncope.common.types.AuditElements;
+import org.apache.syncope.common.types.AuditElements.Result;
+import org.apache.syncope.core.audit.AuditManager;
+import org.apache.syncope.core.notification.NotificationManager;
 
 import org.apache.syncope.core.persistence.beans.Task;
 import org.apache.syncope.core.persistence.beans.TaskExec;
@@ -73,6 +77,18 @@ public abstract class AbstractTaskJob im
     private TaskExecDAO taskExecDAO;
 
     /**
+     * Notification manager.
+     */
+    @Autowired
+    private NotificationManager notificationManager;
+
+    /**
+     * Audit manager.
+     */
+    @Autowired
+    private AuditManager auditManager;
+
+    /**
      * Id, set by the caller, for identifying the task to be executed.
      */
     protected Long taskId;
@@ -103,12 +119,15 @@ public abstract class AbstractTaskJob im
         execution.setStartDate(new Date());
         execution.setTask(task);
 
+        Result result;
+
         try {
             execution.setMessage(doExecute(context.getMergedJobDataMap().getBoolean(DRY_RUN_JOBDETAIL_KEY)));
-
             execution.setStatus(Status.SUCCESS.name());
+            result = Result.SUCCESS;
         } catch (JobExecutionException e) {
             LOG.error("While executing task " + taskId, e);
+            result = Result.FAILURE;
 
             execution.setMessage(ExceptionUtil.getFullStackTrace(e));
             execution.setStatus(Status.FAILURE.name());
@@ -120,6 +139,24 @@ public abstract class AbstractTaskJob im
         }
 
         task = taskDAO.save(task);
+
+        notificationManager.createTasks(
+                AuditElements.EventCategoryType.TASK,
+                task.getClass().getSimpleName(),
+                null,
+                null, // searching for before object is too much expensive ...
+                result,
+                task,
+                (Object[]) null);
+
+        auditManager.audit(
+                AuditElements.EventCategoryType.TASK,
+                task.getClass().getSimpleName(),
+                null,
+                null, // searching for before object is too much expensive ...
+                result,
+                task,
+                (Object[]) null);
     }
 
     /**

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/report/RoleReportlet.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/report/RoleReportlet.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/report/RoleReportlet.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/report/RoleReportlet.java Wed Nov 20 11:37:34 2013
@@ -229,7 +229,6 @@ public class RoleReportlet extends Abstr
 
             // Using RoleTO for attribute values, since the conversion logic of
             // values to String is already encapsulated there
-
             RoleTO roleTO = roleDataBinder.getRoleTO(role);
 
             doExtractAttributes(handler, roleTO, conf.getAttrs(), conf.getDerAttrs(), conf.getVirAttrs());

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/report/UserReportlet.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/report/UserReportlet.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/report/UserReportlet.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/report/UserReportlet.java Wed Nov 20 11:37:34 2013
@@ -85,7 +85,7 @@ public class UserReportlet extends Abstr
         return conf.getMatchingCond() == null
                 ? userDAO.count(adminRoleIds)
                 : searchDAO.count(adminRoleIds, conf.getMatchingCond(),
-                AttributableUtil.getInstance(AttributableType.USER));
+                        AttributableUtil.getInstance(AttributableType.USER));
     }
 
     private void doExtractResources(final ContentHandler handler, final AbstractAttributableTO attributableTO)

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractController.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractController.java Wed Nov 20 11:37:34 2013
@@ -18,16 +18,36 @@
  */
 package org.apache.syncope.core.rest.controller;
 
+import java.lang.reflect.Method;
+import org.apache.syncope.common.AbstractBaseBean;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.transaction.annotation.Transactional;
 
-@Transactional(rollbackFor = {Throwable.class})
-abstract class AbstractController {
+public abstract class AbstractController<T extends AbstractBaseBean> {
 
     /**
      * Logger.
      */
     protected static final Logger LOG = LoggerFactory.getLogger(AbstractController.class);
 
+    /**
+     * Resolves stored bean (if existing) referred by the given CUD method.
+     * <br />
+     * Read-only methods will be unresolved for performance reasons.
+     *
+     * @param method method.
+     * @param args method arguments.
+     * @return referred stored bean.
+     * @throws UnresolvedReferenceException in case of failures, read-only methods and unresolved bean.
+     */
+    public T resolveBeanReference(final Method method, final Object... args) throws UnresolvedReferenceException {
+        final Transactional transactional = method.getAnnotation(Transactional.class);
+        if (transactional != null && transactional.readOnly()) {
+            throw new UnresolvedReferenceException();
+        }
+        return resolveReference(method, args);
+    }
+
+    protected abstract T resolveReference(Method method, Object... args) throws UnresolvedReferenceException;
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractResourceAssociator.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractResourceAssociator.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractResourceAssociator.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractResourceAssociator.java Wed Nov 20 11:37:34 2013
@@ -21,7 +21,7 @@ package org.apache.syncope.core.rest.con
 import java.util.Collection;
 import org.apache.syncope.common.to.AbstractAttributableTO;
 
-public abstract class AbstractResourceAssociator<T extends AbstractAttributableTO> {
+public abstract class AbstractResourceAssociator<T extends AbstractAttributableTO> extends AbstractController<T> {
 
     public abstract T unlink(Long id, Collection<String> resources);
 

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ConfigurationController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ConfigurationController.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ConfigurationController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ConfigurationController.java Wed Nov 20 11:37:34 2013
@@ -20,15 +20,13 @@ package org.apache.syncope.core.rest.con
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.syncope.common.to.ConfigurationTO;
-import org.apache.syncope.common.types.AuditElements.Category;
-import org.apache.syncope.common.types.AuditElements.ConfigurationSubCategory;
-import org.apache.syncope.common.types.AuditElements.Result;
-import org.apache.syncope.core.audit.AuditManager;
 import org.apache.syncope.core.init.ImplementationClassNamesLoader;
 import org.apache.syncope.core.init.WorkflowAdapterLoader;
 import org.apache.syncope.core.persistence.beans.SyncopeConf;
@@ -45,10 +43,7 @@ import org.springframework.stereotype.Co
 import org.springframework.transaction.annotation.Transactional;
 
 @Component
-public class ConfigurationController extends AbstractController {
-
-    @Autowired
-    private AuditManager auditManager;
+public class ConfigurationController extends AbstractTransactionalController<ConfigurationTO> {
 
     @Autowired
     private ConfDAO confDAO;
@@ -75,9 +70,6 @@ public class ConfigurationController ext
         SyncopeConf conf = binder.create(configurationTO);
         conf = confDAO.save(conf);
 
-        auditManager.audit(Category.configuration, ConfigurationSubCategory.create, Result.success,
-                "Successfully created conf: " + conf.getKey());
-
         return binder.getConfigurationTO(conf);
     }
 
@@ -86,9 +78,6 @@ public class ConfigurationController ext
         SyncopeConf conf = confDAO.find(key);
         ConfigurationTO confToDelete = binder.getConfigurationTO(conf);
         confDAO.delete(key);
-
-        auditManager.audit(Category.configuration, ConfigurationSubCategory.delete, Result.success,
-                "Successfully deleted conf: " + key);
         return confToDelete;
     }
 
@@ -101,9 +90,6 @@ public class ConfigurationController ext
             configurationTOs.add(binder.getConfigurationTO(configuration));
         }
 
-        auditManager.audit(Category.configuration, ConfigurationSubCategory.list, Result.success,
-                "Successfully listed all confs: " + configurationTOs.size());
-
         return configurationTOs;
     }
 
@@ -113,17 +99,11 @@ public class ConfigurationController ext
         try {
             SyncopeConf conf = confDAO.find(key);
             result = binder.getConfigurationTO(conf);
-
-            auditManager.audit(Category.configuration, ConfigurationSubCategory.read, Result.success,
-                    "Successfully read conf: " + key);
         } catch (MissingConfKeyException e) {
             LOG.error("Could not find configuration key '" + key + "', returning null");
 
             result = new ConfigurationTO();
             result.setKey(key);
-
-            auditManager.audit(Category.configuration, ConfigurationSubCategory.read, Result.failure,
-                    "Could not find conf: " + key);
         }
 
         return result;
@@ -133,21 +113,12 @@ public class ConfigurationController ext
     public ConfigurationTO update(final ConfigurationTO configurationTO) {
         SyncopeConf conf = confDAO.find(configurationTO.getKey());
         conf.setValue(configurationTO.getValue());
-
-        auditManager.audit(Category.configuration, ConfigurationSubCategory.update, Result.success,
-                "Successfully updated conf: " + conf.getKey());
-
         return binder.getConfigurationTO(conf);
     }
 
     @PreAuthorize("hasRole('CONFIGURATION_LIST')")
     public Set<String> getValidators() {
-        Set<String> validators = classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.VALIDATOR);
-
-        auditManager.audit(Category.configuration, ConfigurationSubCategory.getValidators, Result.success,
-                "Successfully listed all validators: " + validators.size());
-
-        return validators;
+        return classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.VALIDATOR);
     }
 
     @PreAuthorize("hasRole('CONFIGURATION_LIST')")
@@ -175,9 +146,6 @@ public class ConfigurationController ext
         // Only templates available both as HTML and TEXT are considered
         htmlTemplates.retainAll(textTemplates);
 
-        auditManager.audit(Category.configuration, ConfigurationSubCategory.getMailTemplates, Result.success,
-                "Successfully listed all mail templates: " + htmlTemplates.size());
-
         return htmlTemplates;
     }
 
@@ -186,14 +154,39 @@ public class ConfigurationController ext
     public void export(final OutputStream os) {
         try {
             exporter.export(os, wfAdapterLoader.getTablePrefix());
-
-            auditManager.audit(Category.configuration, ConfigurationSubCategory.dbExport, Result.success,
-                    "Successfully exported database content");
             LOG.debug("Database content successfully exported");
         } catch (Exception e) {
-            auditManager.audit(Category.configuration, ConfigurationSubCategory.dbExport, Result.failure,
-                    "Could not export database content", e);
             LOG.error("While exporting database content", e);
         }
     }
-}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected ConfigurationTO resolveReference(final Method method, final Object... args)
+            throws UnresolvedReferenceException {
+        String key = null;
+
+        if (ArrayUtils.isNotEmpty(args)) {
+            for (int i = 0; key == null && i < args.length; i++) {
+                if (args[i] instanceof String) {
+                    key = (String) args[i];
+                } else if (args[i] instanceof ConfigurationTO) {
+                    key = ((ConfigurationTO) args[i]).getKey();
+                }
+            }
+        }
+
+        if (key != null) {
+            try {
+                return binder.getConfigurationTO(confDAO.find(key));
+            } catch (Throwable ignore) {
+                LOG.debug("Unresolved reference", ignore);
+                throw new UnresolvedReferenceException(ignore);
+            }
+        }
+
+        throw new UnresolvedReferenceException();
+    }
+}
\ No newline at end of file

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ConnectorController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ConnectorController.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ConnectorController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ConnectorController.java Wed Nov 20 11:37:34 2013
@@ -18,26 +18,22 @@
  */
 package org.apache.syncope.core.rest.controller;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
-import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.to.BulkAction;
 import org.apache.syncope.common.to.BulkActionRes;
 import org.apache.syncope.common.to.ConnBundleTO;
 import org.apache.syncope.common.to.ConnInstanceTO;
-import org.apache.syncope.common.types.AuditElements.Category;
-import org.apache.syncope.common.types.AuditElements.ConnectorSubCategory;
-import org.apache.syncope.common.types.AuditElements.Result;
 import org.apache.syncope.common.types.ConnConfPropSchema;
 import org.apache.syncope.common.types.ConnConfProperty;
 import org.apache.syncope.common.types.ClientExceptionType;
-import org.apache.syncope.common.validation.SyncopeClientCompositeException;
 import org.apache.syncope.common.validation.SyncopeClientException;
-import org.apache.syncope.core.audit.AuditManager;
 import org.apache.syncope.core.persistence.beans.ConnInstance;
 import org.apache.syncope.core.persistence.beans.ExternalResource;
 import org.apache.syncope.core.persistence.dao.ConnInstanceDAO;
@@ -60,10 +56,7 @@ import org.springframework.stereotype.Co
 import org.springframework.transaction.annotation.Transactional;
 
 @Component
-public class ConnectorController extends AbstractController {
-
-    @Autowired
-    private AuditManager auditManager;
+public class ConnectorController extends AbstractTransactionalController<ConnInstanceTO> {
 
     @Autowired
     private ResourceDAO resourceDAO;
@@ -84,12 +77,7 @@ public class ConnectorController extends
         ConnInstance connInstance = binder.getConnInstance(connInstanceTO);
         try {
             connInstance = connInstanceDAO.save(connInstance);
-            auditManager.audit(Category.connector, ConnectorSubCategory.create, Result.success,
-                    "Successfully created connector instance: " + connInstance.getDisplayName());
         } catch (InvalidEntityException e) {
-            auditManager.audit(Category.connector, ConnectorSubCategory.create, Result.failure,
-                    "Could not create connector instance: " + connInstanceTO.getDisplayName(), e);
-
             SyncopeClientException invalidConnInstance = SyncopeClientException.build(
                     ClientExceptionType.InvalidConnInstance);
             invalidConnInstance.getElements().add(e.getMessage());
@@ -106,12 +94,7 @@ public class ConnectorController extends
         ConnInstance connInstance = binder.updateConnInstance(connInstanceTO.getId(), connInstanceTO);
         try {
             connInstance = connInstanceDAO.save(connInstance);
-            auditManager.audit(Category.connector, ConnectorSubCategory.update, Result.success,
-                    "Successfully update connector instance: " + connInstance.getDisplayName());
         } catch (InvalidEntityException e) {
-            auditManager.audit(Category.connector, ConnectorSubCategory.create, Result.failure,
-                    "Could not update connector instance: " + connInstanceTO.getDisplayName(), e);
-
             SyncopeClientException invalidConnInstance = SyncopeClientException.build(
                     ClientExceptionType.InvalidConnInstance);
             invalidConnInstance.getElements().add(e.getMessage());
@@ -140,8 +123,6 @@ public class ConnectorController extends
         ConnInstanceTO connToDelete = binder.getConnInstanceTO(connInstance);
 
         connInstanceDAO.delete(connInstanceId);
-        auditManager.audit(Category.connector, ConnectorSubCategory.delete, Result.success,
-                "Successfully deleted connector instance: " + connInstanceId);
 
         return connToDelete;
     }
@@ -167,9 +148,6 @@ public class ConnectorController extends
             }
         }
 
-        auditManager.audit(Category.connector, ConnectorSubCategory.list, Result.success,
-                "Successfully listed all connectors: " + connInstanceTOs.size());
-
         return connInstanceTOs;
     }
 
@@ -181,9 +159,6 @@ public class ConnectorController extends
             throw new NotFoundException("Connector '" + connInstanceId + "'");
         }
 
-        auditManager.audit(Category.connector, ConnectorSubCategory.read, Result.success,
-                "Successfully read connector: " + connInstance.getDisplayName());
-
         return binder.getConnInstanceTO(connInstance);
     }
 
@@ -234,9 +209,6 @@ public class ConnectorController extends
             }
         }
 
-        auditManager.audit(Category.connector, ConnectorSubCategory.getBundles, Result.success,
-                "Successfully listed all bundles: " + connectorBundleTOs.size());
-
         return connectorBundleTOs;
     }
 
@@ -258,10 +230,6 @@ public class ConnectorController extends
         final List<String> result = new ArrayList<String>(connFactory.createConnector(connInstance, conf).
                 getSchemaNames(includeSpecial));
 
-        auditManager.audit(Category.connector, ConnectorSubCategory.getSchemaNames, Result.success,
-                "Successfully listed " + (includeSpecial ? "all " : "") + "schema names (" + result.size() + ") "
-                + "for connector " + connInstance.getDisplayName());
-
         return result;
     }
 
@@ -287,10 +255,6 @@ public class ConnectorController extends
             result.add(objectClass.getObjectClassValue());
         }
 
-        auditManager.audit(Category.connector, ConnectorSubCategory.getSupportedObjectClasses, Result.success,
-                "Successfully listed supported object classes (" + result.size() + ") "
-                + "for connector " + connInstance.getDisplayName());
-
         return result;
     }
 
@@ -303,13 +267,7 @@ public class ConnectorController extends
             throw new NotFoundException("Connector '" + connInstanceId + "'");
         }
 
-        List<ConnConfProperty> result = new ArrayList<ConnConfProperty>(connInstance.getConfiguration());
-
-        auditManager.audit(Category.connector, ConnectorSubCategory.getConfigurationProperties, Result.success,
-                "Successfully listed all conf properties (" + result.size() + ") for connector "
-                + connInstance.getDisplayName());
-
-        return result;
+        return new ArrayList<ConnConfProperty>(connInstance.getConfiguration());
     }
 
     @PreAuthorize("hasRole('CONNECTOR_READ')")
@@ -322,13 +280,7 @@ public class ConnectorController extends
         try {
             connector.test();
             result = true;
-
-            auditManager.audit(Category.connector, ConnectorSubCategory.check, Result.success,
-                    "Successfully checked connector: " + connInstanceTO);
         } catch (Exception ex) {
-            auditManager.audit(Category.connector, ConnectorSubCategory.check, Result.failure,
-                    "Unsuccessful check for connector: " + connInstanceTO, ex);
-
             LOG.error("Test connection failure {}", ex);
             result = false;
         }
@@ -343,13 +295,7 @@ public class ConnectorController extends
         if (resource == null) {
             throw new NotFoundException("Resource '" + resourceName + "'");
         }
-
-        final Connector connector = connFactory.getConnector(resource);
-
-        auditManager.audit(Category.connector, ConnectorSubCategory.readConnectorBean, Result.success,
-                "Successfully read connector for resource: " + resourceName);
-
-        return binder.getConnInstanceTO(connector.getActiveConnInstance());
+        return binder.getConnInstanceTO(connFactory.getConnector(resource).getActiveConnInstance());
     }
 
     @PreAuthorize("hasRole('CONNECTOR_RELOAD')")
@@ -357,9 +303,6 @@ public class ConnectorController extends
     public void reload() {
         connFactory.unload();
         connFactory.load();
-
-        auditManager.audit(Category.connector, ConnectorSubCategory.reload, Result.success,
-                "Successfully reloaded all connector bundles and instances");
     }
 
     @PreAuthorize("hasRole('CONNECTOR_DELETE') and #bulkAction.operation == #bulkAction.operation.DELETE")
@@ -381,4 +324,34 @@ public class ConnectorController extends
 
         return res;
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected ConnInstanceTO resolveReference(final Method method, final Object... args) throws
+            UnresolvedReferenceException {
+        Long id = null;
+
+        if (ArrayUtils.isNotEmpty(args)) {
+            for (int i = 0; id == null && i < args.length; i++) {
+                if (args[i] instanceof Long) {
+                    id = (Long) args[i];
+                } else if (args[i] instanceof ConnInstanceTO) {
+                    id = ((ConnInstanceTO) args[i]).getId();
+                }
+            }
+        }
+
+        if (id != null) {
+            try {
+                return binder.getConnInstanceTO(connInstanceDAO.find(id));
+            } catch (Throwable ignore) {
+                LOG.debug("Unresolved reference", ignore);
+                throw new UnresolvedReferenceException(ignore);
+            }
+        }
+
+        throw new UnresolvedReferenceException();
+    }
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/EntitlementController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/EntitlementController.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/EntitlementController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/EntitlementController.java Wed Nov 20 11:37:34 2013
@@ -18,14 +18,11 @@
  */
 package org.apache.syncope.core.rest.controller;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
-
-import org.apache.syncope.common.types.AuditElements.AuthenticationSubCategory;
-import org.apache.syncope.common.types.AuditElements.Category;
-import org.apache.syncope.common.types.AuditElements.Result;
-import org.apache.syncope.core.audit.AuditManager;
+import org.apache.syncope.common.to.EntitlementTO;
 import org.apache.syncope.core.persistence.beans.Entitlement;
 import org.apache.syncope.core.persistence.dao.EntitlementDAO;
 import org.apache.syncope.core.util.EntitlementUtil;
@@ -33,10 +30,7 @@ import org.springframework.beans.factory
 import org.springframework.stereotype.Component;
 
 @Component
-public class EntitlementController extends AbstractController {
-
-    @Autowired
-    private AuditManager auditManager;
+public class EntitlementController extends AbstractTransactionalController<EntitlementTO> {
 
     @Autowired
     private EntitlementDAO entitlementDAO;
@@ -52,11 +46,11 @@ public class EntitlementController exten
     }
 
     public Set<String> getOwn() {
-        Set<String> result = EntitlementUtil.getOwnedEntitlementNames();
-
-        auditManager.audit(Category.authentication, AuthenticationSubCategory.getEntitlements, Result.success,
-                "Owned entitlements: " + result.toString());
+        return EntitlementUtil.getOwnedEntitlementNames();
+    }
 
-        return result;
+    @Override
+    protected EntitlementTO resolveReference(Method method, Object... args) throws UnresolvedReferenceException {
+        throw new UnresolvedReferenceException();
     }
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/LoggerController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/LoggerController.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/LoggerController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/LoggerController.java Wed Nov 20 11:37:34 2013
@@ -18,43 +18,61 @@
  */
 package org.apache.syncope.core.rest.controller;
 
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
-import javax.ws.rs.core.Response;
+import java.util.Set;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.LoggerConfig;
 import org.apache.syncope.common.SyncopeConstants;
+import org.apache.syncope.common.to.EventCategoryTO;
 import org.apache.syncope.common.to.LoggerTO;
-import org.apache.syncope.common.types.AuditElements.Category;
-import org.apache.syncope.common.types.AuditElements.LoggerSubCategory;
-import org.apache.syncope.common.types.AuditElements.Result;
+import org.apache.syncope.common.types.AttributableType;
+import org.apache.syncope.common.types.AuditElements.EventCategoryType;
 import org.apache.syncope.common.types.AuditLoggerName;
 import org.apache.syncope.common.types.ClientExceptionType;
 import org.apache.syncope.common.types.LoggerLevel;
 import org.apache.syncope.common.types.LoggerType;
-import org.apache.syncope.common.validation.SyncopeClientCompositeException;
+import org.apache.syncope.common.types.ResourceOperation;
+import org.apache.syncope.common.util.BeanUtils;
 import org.apache.syncope.common.validation.SyncopeClientException;
-import org.apache.syncope.core.audit.AuditManager;
+import org.apache.syncope.core.persistence.beans.ExternalResource;
+import org.apache.syncope.core.persistence.beans.SchedTask;
+import org.apache.syncope.core.persistence.beans.SyncTask;
 import org.apache.syncope.core.persistence.beans.SyncopeLogger;
 import org.apache.syncope.core.persistence.dao.LoggerDAO;
 import org.apache.syncope.core.persistence.dao.NotFoundException;
+import org.apache.syncope.core.persistence.dao.ResourceDAO;
+import org.apache.syncope.core.persistence.dao.TaskDAO;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.transaction.annotation.Transactional;
-import org.apache.syncope.common.util.BeanUtils;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.SystemPropertyUtils;
 
 @Component
-public class LoggerController extends AbstractController {
+public class LoggerController extends AbstractTransactionalController<LoggerTO> {
 
     @Autowired
-    private AuditManager auditManager;
+    private LoggerDAO loggerDAO;
 
     @Autowired
-    private LoggerDAO loggerDAO;
+    private ResourceDAO resourceDAO;
+
+    @Autowired
+    private TaskDAO taskDAO;
 
     private List<LoggerTO> list(final LoggerType type) {
         List<LoggerTO> result = new ArrayList<LoggerTO>();
@@ -64,9 +82,6 @@ public class LoggerController extends Ab
             result.add(loggerTO);
         }
 
-        auditManager.audit(Category.logger, LoggerSubCategory.list, Result.success,
-                "Successfully listed all loggers (" + type + "): " + result.size());
-
         return result;
     }
 
@@ -85,7 +100,7 @@ public class LoggerController extends Ab
             try {
                 result.add(AuditLoggerName.fromLoggerName(logger.getName()));
             } catch (Exception e) {
-                LOG.error("Unexpected audit logger name: {}", logger.getName(), e);
+                LOG.warn("Unexpected audit logger name: {}", logger.getName(), e);
             }
         }
 
@@ -128,9 +143,6 @@ public class LoggerController extends Ab
         LoggerTO result = new LoggerTO();
         BeanUtils.copyProperties(syncopeLogger, result);
 
-        auditManager.audit(Category.logger, LoggerSubCategory.setLevel, Result.success,
-                String.format("Successfully set level %s to logger %s (%s)", level, name, expectedType));
-
         return result;
     }
 
@@ -171,9 +183,6 @@ public class LoggerController extends Ab
         logger.setLevel(Level.OFF);
         ctx.updateLoggers();
 
-        auditManager.audit(Category.logger, LoggerSubCategory.setLevel, Result.success, String.format(
-                "Successfully deleted logger %s (%s)", name, expectedType));
-
         return loggerToDelete;
     }
 
@@ -194,4 +203,91 @@ public class LoggerController extends Ab
             throw sce;
         }
     }
+
+    @PreAuthorize("hasRole('AUDIT_LIST') or hasRole('NOTIFICATION_LIST')")
+    public List<EventCategoryTO> listAuditEvents() {
+        // use set to avoi duplications or null elements
+        final Set<EventCategoryTO> events = new HashSet<EventCategoryTO>();
+
+        try {
+            final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
+            final MetadataReaderFactory metadataReaderFactory =
+                    new CachingMetadataReaderFactory(resourcePatternResolver);
+
+            final String packageSearchPath =
+                    ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+                    + ClassUtils.convertClassNameToResourcePath(
+                    SystemPropertyUtils.resolvePlaceholders(this.getClass().getPackage().getName()))
+                    + "/" + "**/*.class";
+
+            final Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
+            for (Resource resource : resources) {
+                if (resource.isReadable()) {
+                    final MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
+                    final Class<?> clazz = Class.forName(metadataReader.getClassMetadata().getClassName());
+
+                    if (clazz.isAnnotationPresent(Component.class)
+                            && AbstractController.class.isAssignableFrom(clazz)) {
+                        final EventCategoryTO eventCategoryTO = new EventCategoryTO();
+                        eventCategoryTO.setCategory(clazz.getSimpleName());
+                        for (Method method : clazz.getDeclaredMethods()) {
+                            if (Modifier.isPublic(method.getModifiers())) {
+                                eventCategoryTO.getEvents().add(method.getName());
+                            }
+                        }
+                        events.add(eventCategoryTO);
+                    }
+                }
+            }
+
+            events.add(new EventCategoryTO(EventCategoryType.PROPAGATION));
+            events.add(new EventCategoryTO(EventCategoryType.SYNCHRONIZATION));
+
+            for (AttributableType attributableType : AttributableType.values()) {
+                for (ExternalResource resource : resourceDAO.findAll()) {
+                    final EventCategoryTO propEventCategoryTO = new EventCategoryTO(EventCategoryType.PROPAGATION);
+                    final EventCategoryTO syncEventCategoryTO = new EventCategoryTO(EventCategoryType.SYNCHRONIZATION);
+
+                    propEventCategoryTO.setCategory(attributableType.name().toLowerCase());
+                    propEventCategoryTO.setSubcategory(resource.getName());
+
+                    syncEventCategoryTO.setCategory(attributableType.name().toLowerCase());
+                    syncEventCategoryTO.setSubcategory(resource.getName());
+
+                    for (ResourceOperation resourceOperation : ResourceOperation.values()) {
+                        propEventCategoryTO.getEvents().add(resourceOperation.name().toLowerCase());
+                        syncEventCategoryTO.getEvents().add(resourceOperation.name().toLowerCase());
+                    }
+
+                    events.add(propEventCategoryTO);
+                    events.add(syncEventCategoryTO);
+                }
+            }
+
+            for (SchedTask task : taskDAO.findAll(SchedTask.class)) {
+                final EventCategoryTO eventCategoryTO = new EventCategoryTO(EventCategoryType.TASK);
+                eventCategoryTO.setCategory(Class.forName(task.getJobClassName()).getSimpleName());
+                events.add(eventCategoryTO);
+            }
+
+            for (SyncTask task : taskDAO.findAll(SyncTask.class)) {
+                final EventCategoryTO eventCategoryTO = new EventCategoryTO(EventCategoryType.TASK);
+                eventCategoryTO.setCategory(Class.forName(task.getJobClassName()).getSimpleName());
+                events.add(eventCategoryTO);
+            }
+        } catch (Exception e) {
+            LOG.error("Failure retrieving audit/notification events", e);
+        }
+
+        return new ArrayList<EventCategoryTO>(events);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected LoggerTO resolveReference(final Method method, final Object... args)
+            throws UnresolvedReferenceException {
+        throw new UnresolvedReferenceException();
+    }
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java Wed Nov 20 11:37:34 2013
@@ -18,15 +18,11 @@
  */
 package org.apache.syncope.core.rest.controller;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
-
-
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.syncope.common.to.NotificationTO;
-import org.apache.syncope.common.types.AuditElements.Category;
-import org.apache.syncope.common.types.AuditElements.NotificationSubCategory;
-import org.apache.syncope.common.types.AuditElements.Result;
-import org.apache.syncope.core.audit.AuditManager;
 import org.apache.syncope.core.persistence.beans.Notification;
 import org.apache.syncope.core.persistence.dao.NotFoundException;
 import org.apache.syncope.core.persistence.dao.NotificationDAO;
@@ -36,10 +32,7 @@ import org.springframework.security.acce
 import org.springframework.stereotype.Component;
 
 @Component
-public class NotificationController extends AbstractController {
-
-    @Autowired
-    private AuditManager auditManager;
+public class NotificationController extends AbstractTransactionalController<NotificationTO> {
 
     @Autowired
     private NotificationDAO notificationDAO;
@@ -68,22 +61,13 @@ public class NotificationController exte
             notificationTOs.add(binder.getNotificationTO(notification));
         }
 
-        auditManager.audit(Category.notification, NotificationSubCategory.list, Result.success,
-                "Successfully listed all notifications: " + notificationTOs.size());
-
         return notificationTOs;
     }
 
     @PreAuthorize("hasRole('NOTIFICATION_CREATE')")
     public NotificationTO create(final NotificationTO notificationTO) {
         LOG.debug("Notification create called with parameter {}", notificationTO);
-
-        Notification notification = notificationDAO.save(binder.createNotification(notificationTO));
-
-        auditManager.audit(Category.notification, NotificationSubCategory.create, Result.success,
-                "Successfully created notification: " + notification.getId());
-
-        return binder.getNotificationTO(notification);
+        return binder.getNotificationTO(notificationDAO.save(binder.createNotification(notificationTO)));
     }
 
     @PreAuthorize("hasRole('NOTIFICATION_UPDATE')")
@@ -93,16 +77,12 @@ public class NotificationController exte
         Notification notification = notificationDAO.find(notificationTO.getId());
         if (notification == null) {
             LOG.error("Could not find notification '" + notificationTO.getId() + "'");
-
             throw new NotFoundException(String.valueOf(notificationTO.getId()));
         }
 
         binder.updateNotification(notification, notificationTO);
         notification = notificationDAO.save(notification);
 
-        auditManager.audit(Category.notification, NotificationSubCategory.update, Result.success,
-                "Successfully updated notification: " + notification.getId());
-
         return binder.getNotificationTO(notification);
     }
 
@@ -116,12 +96,37 @@ public class NotificationController exte
         }
 
         NotificationTO notificationToDelete = binder.getNotificationTO(notification);
+        notificationDAO.delete(notificationId);
+        return notificationToDelete;
+    }
 
-        auditManager.audit(Category.notification, NotificationSubCategory.delete, Result.success,
-                "Successfully deleted notification: " + notification.getId());
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected NotificationTO resolveReference(final Method method, final Object... args)
+            throws UnresolvedReferenceException {
+        Long id = null;
+
+        if (ArrayUtils.isNotEmpty(args)) {
+            for (int i = 0; id == null && i < args.length; i++) {
+                if (args[i] instanceof Long) {
+                    id = (Long) args[i];
+                } else if (args[i] instanceof NotificationTO) {
+                    id = ((NotificationTO) args[i]).getId();
+                }
+            }
+        }
 
-        notificationDAO.delete(notificationId);
+        if (id != null) {
+            try {
+                return binder.getNotificationTO(notificationDAO.find(id));
+            } catch (Throwable ignore) {
+                LOG.debug("Unresolved reference", ignore);
+                throw new UnresolvedReferenceException(ignore);
+            }
+        }
 
-        return notificationToDelete;
+        throw new UnresolvedReferenceException();
     }
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/PolicyController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/PolicyController.java?rev=1543782&r1=1543781&r2=1543782&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/PolicyController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/PolicyController.java Wed Nov 20 11:37:34 2013
@@ -18,19 +18,16 @@
  */
 package org.apache.syncope.core.rest.controller;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.syncope.common.to.AccountPolicyTO;
 import org.apache.syncope.common.to.PasswordPolicyTO;
 import org.apache.syncope.common.to.AbstractPolicyTO;
 import org.apache.syncope.common.to.SyncPolicyTO;
-import org.apache.syncope.common.types.AuditElements;
-import org.apache.syncope.common.types.AuditElements.Category;
-import org.apache.syncope.common.types.AuditElements.PolicySubCategory;
-import org.apache.syncope.common.types.AuditElements.Result;
 import org.apache.syncope.common.types.PolicyType;
-import org.apache.syncope.core.audit.AuditManager;
 import org.apache.syncope.core.init.ImplementationClassNamesLoader;
 import org.apache.syncope.core.persistence.beans.AccountPolicy;
 import org.apache.syncope.core.persistence.beans.PasswordPolicy;
@@ -44,15 +41,12 @@ import org.springframework.security.acce
 import org.springframework.stereotype.Component;
 
 @Component
-public class PolicyController extends AbstractController {
+public class PolicyController extends AbstractTransactionalController<AbstractPolicyTO> {
 
     @Autowired
     private ImplementationClassNamesLoader classNamesLoader;
 
     @Autowired
-    private AuditManager auditManager;
-
-    @Autowired
     private PolicyDAO policyDAO;
 
     @Autowired
@@ -61,24 +55,13 @@ public class PolicyController extends Ab
     @PreAuthorize("hasRole('POLICY_CREATE')")
     public <T extends AbstractPolicyTO> T create(final T policyTO) {
         LOG.debug("Creating policy " + policyTO);
-
-        final Policy policy = binder.getPolicy(null, policyTO);
-
-        auditManager.audit(Category.policy, PolicySubCategory.create, Result.success,
-                "Successfully created " + policy.getType().toString() + " policy: " + policy.getId());
-
-        return binder.getPolicyTO(policyDAO.save(policy));
+        return binder.getPolicyTO(policyDAO.save(binder.getPolicy(null, policyTO)));
     }
 
     private <T extends AbstractPolicyTO, K extends Policy> T update(final T policyTO, final K policy) {
         LOG.debug("Updating policy " + policyTO);
-
         binder.getPolicy(policy, policyTO);
         K savedPolicy = policyDAO.save(policy);
-
-        auditManager.audit(Category.policy, PolicySubCategory.update, Result.success,
-                "Successfully updated policy (" + savedPolicy.getType() + "): " + savedPolicy.getId());
-
         return binder.getPolicyTO(savedPolicy);
     }
 
@@ -124,9 +107,6 @@ public class PolicyController extends Ab
             policyTOs.add((T) binder.getPolicyTO(policy));
         }
 
-        auditManager.audit(Category.policy, PolicySubCategory.list, Result.success,
-                "Successfully listed all policies (" + type + "): " + policyTOs.size());
-
         return policyTOs;
     }
 
@@ -139,9 +119,6 @@ public class PolicyController extends Ab
             throw new NotFoundException("No password policy found");
         }
 
-        auditManager.audit(Category.policy, PolicySubCategory.read, Result.success,
-                "Successfully read global password policy: " + policy.getId());
-
         return (PasswordPolicyTO) binder.getPolicyTO(policy);
     }
 
@@ -154,9 +131,6 @@ public class PolicyController extends Ab
             throw new NotFoundException("No account policy found");
         }
 
-        auditManager.audit(Category.policy, PolicySubCategory.read, Result.success,
-                "Successfully read global account policy: " + policy.getId());
-
         return (AccountPolicyTO) binder.getPolicyTO(policy);
     }
 
@@ -169,9 +143,6 @@ public class PolicyController extends Ab
             throw new NotFoundException("No sync policy found");
         }
 
-        auditManager.audit(Category.policy, PolicySubCategory.read, Result.success,
-                "Successfully read global sync policy: " + policy.getId());
-
         return (SyncPolicyTO) binder.getPolicyTO(policy);
     }
 
@@ -184,9 +155,6 @@ public class PolicyController extends Ab
             throw new NotFoundException("Policy " + id + " not found");
         }
 
-        auditManager.audit(Category.policy, PolicySubCategory.read, Result.success,
-                "Successfully read policy (" + policy.getType() + "): " + policy.getId());
-
         return binder.getPolicyTO(policy);
     }
 
@@ -200,20 +168,41 @@ public class PolicyController extends Ab
         T policyToDelete = binder.getPolicyTO(policy);
         policyDAO.delete(policy);
 
-        auditManager.audit(Category.policy, PolicySubCategory.delete, Result.success,
-                "Successfully deleted policy: " + id);
-
         return policyToDelete;
     }
 
     @PreAuthorize("hasRole('POLICY_LIST')")
     public Set<String> getSyncCorrelationRuleClasses() {
-        final Set<String> correlationRules =
-                classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.SYNC_CORRELATION_RULES);
+        return classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.SYNC_CORRELATION_RULES);
+    }
 
-        auditManager.audit(Category.policy, AuditElements.PolicySubCategory.getCorrelationRuleClasses,
-                Result.success, "Successfully listed all correlation rule classes: " + correlationRules.size());
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected AbstractPolicyTO resolveReference(final Method method, final Object... args)
+            throws UnresolvedReferenceException {
+        Long id = null;
+
+        if (ArrayUtils.isNotEmpty(args)) {
+            for (int i = 0; id == null && i < args.length; i++) {
+                if (args[i] instanceof Long) {
+                    id = (Long) args[i];
+                } else if (args[i] instanceof AbstractPolicyTO) {
+                    id = ((AbstractPolicyTO) args[i]).getId();
+                }
+            }
+        }
+
+        if (id != null) {
+            try {
+                return binder.getPolicyTO(policyDAO.find(id));
+            } catch (Throwable ignore) {
+                LOG.debug("Unresolved reference", ignore);
+                throw new UnresolvedReferenceException(ignore);
+            }
+        }
 
-        return correlationRules;
+        throw new UnresolvedReferenceException();
     }
 }