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/06/05 10:21:42 UTC

[2/2] syncope git commit: [SYNCOPE-667] Merge from 1_2_X

[SYNCOPE-667] Merge from 1_2_X


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

Branch: refs/heads/master
Commit: 2f028924d52d5cb48595aa7e5056c20aeadb4945
Parents: 8cc3ffc 18394d3
Author: giacomolm <gi...@hotmail.it>
Authored: Fri Jun 5 09:40:35 2015 +0200
Committer: giacomolm <gi...@hotmail.it>
Committed: Fri Jun 5 09:40:35 2015 +0200

----------------------------------------------------------------------
 .../provisioning/api/notification/NotificationManager.java   | 4 +++-
 .../java/notification/NotificationManagerImpl.java           | 8 ++++++--
 2 files changed, 9 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/2f028924/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationManager.java
----------------------------------------------------------------------
diff --cc core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationManager.java
index 391ab29,0000000..cb41d8c
mode 100644,000000..100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationManager.java
@@@ -1,64 -1,0 +1,66 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *   http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.syncope.core.provisioning.api.notification;
 +
++import java.util.List;
 +import org.apache.syncope.common.lib.types.AuditElements;
++import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
 +import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
 +
 +/**
 + * Create notification tasks that will be executed by NotificationJob.
 + *
 + * @see org.apache.syncope.core.persistence.api.entity.task.NotificationTask
 + */
 +public interface NotificationManager {
 +
 +    /**
 +     * Count the number of task executions of a given task with a given status.
 +     *
 +     * @param taskId task id
 +     * @param status status
 +     * @return number of task executions
 +     */
 +    long countExecutionsWithStatus(final Long taskId, final String status);
 +
 +    /**
 +     * Create notification tasks for each notification matching the given user id and (some of) tasks performed.
 +     */
-     void createTasks(AuditElements.EventCategoryType type, String category, String subcategory,
++    List<NotificationTask> createTasks(AuditElements.EventCategoryType type, String category, String subcategory,
 +            String event, AuditElements.Result condition, Object before, Object output, Object... input);
 +
 +    long getMaxRetries();
 +
 +    /**
 +     * Set execution state of NotificationTask with provided id.
 +     *
 +     * @param taskId task to be updated
 +     * @param executed execution state
 +     */
 +    void setTaskExecuted(final Long taskId, final boolean executed);
 +
 +    /**
 +     * Store execution of a NotificationTask.
 +     *
 +     * @param execution task execution.
 +     * @return merged task execution.
 +     */
 +    TaskExec storeExec(final TaskExec execution);
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2f028924/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
----------------------------------------------------------------------
diff --cc core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
index 7153529,0000000..900abc7
mode 100644,000000..100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
@@@ -1,410 -1,0 +1,414 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *   http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.syncope.core.provisioning.java.notification;
 +
 +import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
 +import java.io.StringWriter;
 +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.lib.SyncopeConstants;
 +import org.apache.syncope.common.lib.to.GroupTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.types.AttributableType;
 +import org.apache.syncope.common.lib.types.AuditElements;
 +import org.apache.syncope.common.lib.types.AuditElements.Result;
 +import org.apache.syncope.common.lib.types.AuditLoggerName;
 +import org.apache.syncope.common.lib.types.IntMappingType;
 +import org.apache.syncope.common.lib.types.SubjectType;
 +import org.apache.syncope.common.lib.CollectionUtils2;
 +import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 +import org.apache.syncope.core.persistence.api.dao.NotificationDAO;
 +import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 +import org.apache.syncope.core.persistence.api.dao.SubjectSearchDAO;
 +import org.apache.syncope.core.persistence.api.dao.TaskDAO;
 +import org.apache.syncope.core.persistence.api.dao.UserDAO;
 +import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 +import org.apache.syncope.core.persistence.api.entity.Attributable;
 +import org.apache.syncope.core.persistence.api.entity.AttributableUtilsFactory;
 +import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 +import org.apache.syncope.core.persistence.api.entity.Notification;
 +import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 +import org.apache.syncope.core.persistence.api.entity.Subject;
 +import org.apache.syncope.core.persistence.api.entity.group.Group;
 +import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
 +import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
 +import org.apache.syncope.core.persistence.api.entity.user.UDerAttr;
 +import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
 +import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
 +import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 +import org.apache.syncope.core.misc.ConnObjectUtils;
 +import org.apache.syncope.core.misc.search.SearchCondConverter;
 +import org.apache.velocity.VelocityContext;
 +import org.apache.velocity.app.VelocityEngine;
 +import org.apache.velocity.context.Context;
 +import org.apache.velocity.exception.VelocityException;
 +import org.apache.velocity.tools.ToolManager;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +import org.springframework.transaction.annotation.Transactional;
 +
 +@Component
 +@Transactional(rollbackFor = { Throwable.class })
 +public class NotificationManagerImpl implements NotificationManager {
 +
 +    /**
 +     * Logger.
 +     */
 +    private static final Logger LOG = LoggerFactory.getLogger(NotificationManager.class);
 +
 +    public static final String MAIL_TEMPLATES = "mailTemplates/";
 +
 +    public static final String MAIL_TEMPLATE_HTML_SUFFIX = ".html.vm";
 +
 +    public static final String MAIL_TEMPLATE_TEXT_SUFFIX = ".txt.vm";
 +
 +    /**
 +     * Notification DAO.
 +     */
 +    @Autowired
 +    private NotificationDAO notificationDAO;
 +
 +    /**
 +     * Configuration DAO.
 +     */
 +    @Autowired
 +    private ConfDAO confDAO;
 +
 +    /**
 +     * User DAO.
 +     */
 +    @Autowired
 +    private UserDAO userDAO;
 +
 +    /**
 +     * Group DAO.
 +     */
 +    @Autowired
 +    private GroupDAO groupDAO;
 +
 +    /**
 +     * User Search DAO.
 +     */
 +    @Autowired
 +    private SubjectSearchDAO searchDAO;
 +
 +    /**
 +     * Task DAO.
 +     */
 +    @Autowired
 +    private TaskDAO taskDAO;
 +
 +    /**
 +     * Velocity template engine.
 +     */
 +    @Autowired
 +    private VelocityEngine velocityEngine;
 +
 +    /**
 +     * Velocity tool manager.
 +     */
 +    @Autowired
 +    private ToolManager velocityToolManager;
 +
 +    @Autowired
 +    private ConnObjectUtils connObjectUtils;
 +
 +    @Autowired
 +    private UserDataBinder userDataBinder;
 +
 +    @Autowired
 +    private GroupDataBinder groupDataBinder;
 +
 +    @Autowired
 +    private EntityFactory entityFactory;
 +
 +    @Autowired
 +    private AttributableUtilsFactory attrUtilsFactory;
 +
 +    @Transactional(readOnly = true)
 +    @Override
 +    public long getMaxRetries() {
 +        return confDAO.find("notification.maxRetries", "0").getValues().get(0).getLongValue();
 +    }
 +
 +    /**
 +     * Create a notification task.
 +     *
 +     * @param notification notification to take as model
 +     * @param attributable the user this task is about
 +     * @param model Velocity model
 +     * @return notification task, fully populated
 +     */
 +    private NotificationTask getNotificationTask(
 +            final Notification notification,
 +            final Attributable<?, ?, ?> attributable,
 +            final Map<String, Object> model) {
 +
 +        if (attributable != null) {
 +            connObjectUtils.retrieveVirAttrValues(attributable,
 +                    attrUtilsFactory.getInstance(
 +                            attributable instanceof User ? AttributableType.USER : AttributableType.GROUP));
 +        }
 +
 +        final List<User> recipients = new ArrayList<>();
 +
 +        if (notification.getRecipients() != null) {
 +            recipients.addAll(searchDAO.<User>search(SyncopeConstants.FULL_ADMIN_REALMS,
 +                    SearchCondConverter.convert(notification.getRecipients()),
 +                    Collections.<OrderByClause>emptyList(), SubjectType.USER));
 +        }
 +
 +        if (notification.isSelfAsRecipient() && attributable instanceof User) {
 +            recipients.add((User) attributable);
 +        }
 +
 +        final Set<String> recipientEmails = new HashSet<>();
 +        final List<UserTO> recipientTOs = new ArrayList<>(recipients.size());
 +        for (User recipient : recipients) {
 +            connObjectUtils.retrieveVirAttrValues(recipient, attrUtilsFactory.getInstance(AttributableType.USER));
 +
 +            String email = getRecipientEmail(notification.getRecipientAttrType(),
 +                    notification.getRecipientAttrName(), recipient);
 +            if (email == null) {
 +                LOG.warn("{} cannot be notified: {} not found", recipient, notification.getRecipientAttrName());
 +            } else {
 +                recipientEmails.add(email);
 +                recipientTOs.add(userDataBinder.getUserTO(recipient));
 +            }
 +        }
 +
 +        if (notification.getStaticRecipients() != null) {
 +            recipientEmails.addAll(notification.getStaticRecipients());
 +        }
 +
 +        model.put("recipients", recipientTOs);
 +        model.put("syncopeConf", this.findAllSyncopeConfs());
 +        model.put("events", notification.getEvents());
 +
 +        NotificationTask task = entityFactory.newEntity(NotificationTask.class);
 +        task.setTraceLevel(notification.getTraceLevel());
 +        task.getRecipients().addAll(recipientEmails);
 +        task.setSender(notification.getSender());
 +        task.setSubject(notification.getSubject());
 +
 +        String htmlBody = mergeTemplateIntoString(
 +                MAIL_TEMPLATES + notification.getTemplate() + MAIL_TEMPLATE_HTML_SUFFIX, model);
 +        String textBody = mergeTemplateIntoString(
 +                MAIL_TEMPLATES + notification.getTemplate() + MAIL_TEMPLATE_TEXT_SUFFIX, model);
 +
 +        task.setHtmlBody(htmlBody);
 +        task.setTextBody(textBody);
 +
 +        return task;
 +    }
 +
 +    private String mergeTemplateIntoString(final String templateLocation, final Map<String, Object> model) {
 +        StringWriter result = new StringWriter();
 +        try {
 +            Context velocityContext = createVelocityContext(model);
 +            velocityEngine.mergeTemplate(templateLocation, SyncopeConstants.DEFAULT_ENCODING, velocityContext, result);
 +        } catch (VelocityException e) {
 +            LOG.error("Could not get mail body", e);
 +        } catch (RuntimeException e) {
 +            // ensure same behaviour as by using Spring VelocityEngineUtils.mergeTemplateIntoString()
 +            throw e;
 +        } catch (Exception e) {
 +            LOG.error("Could not get mail body", e);
 +        }
 +
 +        return result.toString();
 +    }
 +
 +    /**
 +     * Create a Velocity Context for the given model, to be passed to the template for merging.
 +     *
 +     * @param model Velocity model
 +     * @return Velocity context
 +     */
 +    protected Context createVelocityContext(final Map<String, Object> model) {
 +        Context toolContext = velocityToolManager.createContext();
 +        return new VelocityContext(model, toolContext);
 +    }
 +
 +    @Override
-     public void createTasks(
++    public List<NotificationTask> 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) {
 +
 +        SubjectType subjectType = null;
 +        Subject<?, ?, ?> subject = null;
++        List<NotificationTask> notificationList = new ArrayList<NotificationTask>();
 +
 +        if (before instanceof UserTO) {
 +            subjectType = SubjectType.USER;
 +            subject = userDAO.find(((UserTO) before).getKey());
 +        } else if (output instanceof UserTO) {
 +            subjectType = SubjectType.USER;
 +            subject = userDAO.find(((UserTO) output).getKey());
 +        } else if (before instanceof GroupTO) {
 +            subjectType = SubjectType.GROUP;
 +            subject = groupDAO.find(((GroupTO) before).getKey());
 +        } else if (output instanceof GroupTO) {
 +            subjectType = SubjectType.GROUP;
 +            subject = groupDAO.find(((GroupTO) output).getKey());
 +        }
 +
 +        LOG.debug("Search notification for [{}]{}", subjectType, subject);
 +
 +        for (Notification notification : notificationDAO.findAll()) {
 +            LOG.debug("Notification available user about {}", notification.getUserAbout());
 +            LOG.debug("Notification available group about {}", notification.getGroupAbout());
 +
 +            if (notification.isActive()) {
 +                String currentEvent = AuditLoggerName.buildEvent(type, category, subcategory, event, condition);
 +                if (!notification.getEvents().contains(currentEvent)) {
 +                    LOG.debug("No events found about {}", subject);
 +                } else if (subjectType == null || subject == null
 +                        || (subjectType == SubjectType.USER && (notification.getUserAbout() == null
 +                        || searchDAO.matches(subject,
 +                                SearchCondConverter.convert(notification.getUserAbout()), subjectType)))
 +                        || subjectType == SubjectType.GROUP && (notification.getGroupAbout() == null
 +                        || searchDAO.matches(subject,
 +                                SearchCondConverter.convert(notification.getGroupAbout()), subjectType))) {
 +
 +                    LOG.debug("Creating notification task for event {} about {}", currentEvent, subject);
 +
 +                    final Map<String, Object> model = new HashMap<>();
 +                    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 (subject instanceof User) {
 +                        model.put("user", userDataBinder.getUserTO((User) subject));
 +                    } else if (subject instanceof Group) {
 +                        model.put("group", groupDataBinder.getGroupTO((Group) subject));
 +                    }
 +
-                     taskDAO.save(getNotificationTask(notification, subject, model));
++                    NotificationTask notificationTask = getNotificationTask(notification, subject, model);
++                    notificationTask = taskDAO.save(notificationTask);
++                    notificationList.add(notificationTask);     
 +                }
 +            } else {
 +                LOG.debug("Notification {}, userAbout {}, groupAbout {} is deactivated, "
 +                        + "notification task will not be created", notification.getKey(),
 +                        notification.getUserAbout(), notification.getGroupAbout());
 +            }
 +        }
++        return notificationList;
 +    }
 +
 +    private String getRecipientEmail(
 +            final IntMappingType recipientAttrType, final String recipientAttrName, final User user) {
 +
 +        String email = null;
 +
 +        switch (recipientAttrType) {
 +            case Username:
 +                email = user.getUsername();
 +                break;
 +
 +            case UserPlainSchema:
 +                UPlainAttr attr = user.getPlainAttr(recipientAttrName);
 +                if (attr != null) {
 +                    email = CollectionUtils2.getFirstOrNull(attr.getValuesAsStrings());
 +                }
 +                break;
 +
 +            case UserDerivedSchema:
 +                UDerAttr derAttr = user.getDerAttr(recipientAttrName);
 +                if (derAttr != null) {
 +                    email = derAttr.getValue(user.getPlainAttrs());
 +                }
 +                break;
 +
 +            case UserVirtualSchema:
 +                UVirAttr virAttr = user.getVirAttr(recipientAttrName);
 +                if (virAttr != null) {
 +                    email = CollectionUtils2.getFirstOrNull(virAttr.getValues());
 +                }
 +                break;
 +
 +            default:
 +        }
 +
 +        return email;
 +    }
 +
 +    @Override
 +    public TaskExec storeExec(final TaskExec execution) {
 +        NotificationTask task = taskDAO.find(execution.getTask().getKey());
 +        task.addExec(execution);
 +        task.setExecuted(true);
 +        taskDAO.save(task);
 +        // this flush call is needed to generate a value for the execution id
 +        taskDAO.flush();
 +        return execution;
 +    }
 +
 +    @Override
 +    public void setTaskExecuted(final Long taskId, final boolean executed) {
 +        NotificationTask task = taskDAO.find(taskId);
 +        task.setExecuted(executed);
 +        taskDAO.save(task);
 +    }
 +
 +    @Override
 +    public long countExecutionsWithStatus(final Long taskId, final String status) {
 +        NotificationTask task = taskDAO.find(taskId);
 +        long count = 0;
 +        for (TaskExec taskExec : task.getExecs()) {
 +            if (status == null) {
 +                if (taskExec.getStatus() == null) {
 +                    count++;
 +                }
 +            } else if (status.equals(taskExec.getStatus())) {
 +                count++;
 +            }
 +        }
 +        return count;
 +    }
 +
 +    protected Map<String, String> findAllSyncopeConfs() {
 +        Map<String, String> syncopeConfMap = new HashMap<>();
 +        for (PlainAttr attr : confDAO.get().getPlainAttrs()) {
 +            syncopeConfMap.put(attr.getSchema().getKey(), attr.getValuesAsStrings().get(0));
 +        }
 +        return syncopeConfMap;
 +    }
 +}