com.alkacon.opencms.newsletter.CmsNewsletterManager.java Source code

Java tutorial

Introduction

Here is the source code for com.alkacon.opencms.newsletter.CmsNewsletterManager.java

Source

/*
 * File   : $Source: /alkacon/cvs/alkacon/com.alkacon.opencms.newsletter/src/com/alkacon/opencms/newsletter/CmsNewsletterManager.java,v $
 * Date   : $Date: 2010/10/14 13:17:49 $
 * Version: $Revision: 1.20 $
 *
 * This file is part of the Alkacon OpenCms Add-On Module Package
 *
 * Copyright (c) 2007 Alkacon Software GmbH (http://www.alkacon.com)
 *
 * The Alkacon OpenCms Add-On Module Package is free software: 
 * you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * The Alkacon OpenCms Add-On Module Package is distributed 
 * in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with the Alkacon OpenCms Add-On Module Package.  
 * If not, see http://www.gnu.org/licenses/.
 *
 * For further information about Alkacon Software GmbH, please see the
 * company website: http://www.alkacon.com.
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org.
 */

package com.alkacon.opencms.newsletter;

import org.opencms.configuration.CmsConfigurationManager;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsGroup;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsProject;
import org.opencms.file.CmsUser;
import org.opencms.file.types.CmsResourceTypeFolder;
import org.opencms.file.types.CmsResourceTypePlain;
import org.opencms.jsp.CmsJspActionElement;
import org.opencms.lock.CmsLock;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.module.A_CmsModuleAction;
import org.opencms.module.CmsModule;
import org.opencms.security.CmsOrganizationalUnit;
import org.opencms.security.CmsRole;
import org.opencms.util.CmsUUID;
import org.opencms.workplace.CmsWorkplace;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import javax.mail.internet.InternetAddress;

import org.apache.commons.logging.Log;

/**
 * Provides methods to manage the subscribers (users) for the newsletter, to get all newsletter units and to get the
 * initialized mail data class to use for sending the newsletter emails.<p>
 * 
 * @author Andreas Zahner  
 * 
 * @version $Revision: 1.20 $ 
 * 
 * @since 7.0.3 
 */
public class CmsNewsletterManager extends A_CmsModuleAction {

    /** The name of the newsletter module. */
    public static final String MODULE_NAME = CmsNewsletterManager.class.getPackage().getName();

    /** Module parameter name for the class name to use for generating the newsletter mail data. */
    public static final String MODULE_PARAM_CLASS_MAILDATA = "class_maildata";

    /** Module parameter name for the user password of the newsletter users. */
    public static final String MODULE_PARAM_PASSWORD_USER = "user_password";

    /** Module parameter name for the project name to use for user deletion operations. */
    public static final String MODULE_PARAM_PROJECT_NAME = "project_name";

    /** Name of the prefix for newsletter sub-organizational units containing mailing lists and subscribers. */
    public static final String NEWSLETTER_OU_NAMEPREFIX = "nl_";

    /** Pattern to validate email addresses. */
    public static final Pattern PATTERN_VALIDATION_EMAIL = Pattern
            .compile("(\\w[-._\\w]*\\w@\\w[-._\\w]*\\w\\.\\w{2,4})");

    /** The name of the property where the send data (date and mailing list) is written to. */
    public static final String PROPERTY_NEWSLETTER_DATA = "newsletter";

    /** Name of the additional user info: flag to determine if the newsletter user is active. */
    public static final String USER_ADDITIONALINFO_ACTIVE = "AlkNewsletter_ActiveUser:";

    /** Name of the additional user info: flag to determine if the newsletter user is marked for deletion. */
    public static final String USER_ADDITIONALINFO_TODELETE = "AlkNewsletter_UserToDelete:";

    /** The VFS folder path where the information about last sent newsletters is saved. */
    public static String VFS_PATH_NEWSLETTER_INFO = CmsWorkplace.VFS_PATH_SYSTEM + "shared/alkacon_newsletter/";

    /** The default password for all newsletter users, can/should be overwritten in the module parameter. */
    private static final String PASSWORD_USER = "Uw82-Qn!";

    /** The log object for this class. */
    private static final Log LOG = CmsLog.getLog(CmsNewsletterManager.class);

    /** The admin CmsObject that is used for user/group operations. */
    private CmsObject m_adminCms;

    /**
     * Returns the mail data class generating the newsletter mail and recipients.<p>
     * 
     * The instance must be correctly initialized afterwards using {@link I_CmsNewsletterMailData#initialize(CmsJspActionElement, CmsGroup, String)}.<p>
     * 
     * @return the mail data class generating the newsletter mail and recipients
     * @throws Exception if instanciating the mail data class fails
     */
    public static I_CmsNewsletterMailData getMailData() throws Exception {

        String className = OpenCms.getModuleManager().getModule(MODULE_NAME)
                .getParameter(MODULE_PARAM_CLASS_MAILDATA, CmsNewsletterMailData.class.getName());
        return (I_CmsNewsletterMailData) Class.forName(className).newInstance();
    }

    /**
     * Returns the initialized mail data class generating the newsletter mail and recipients.<p>
     * 
     * @param jsp the current action element
     * @param group the group to send the newsletter to
     * @param fileName the fileName of the newsletter
     * @return the initialized mail data class generating the newsletter mail and recipients
     * @throws Exception if instantiating the mail data class fails
     */
    public static I_CmsNewsletterMailData getMailData(CmsJspActionElement jsp, CmsGroup group, String fileName)
            throws Exception {

        I_CmsNewsletterMailData result = getMailData();
        result.initialize(jsp, group, fileName);
        return result;
    }

    /**
     * Returns the initialized mail data class generating the newsletter mail and recipients.<p>
     * 
     * @param jsp the current action element
     * @param ou the organizational unit to send the newsletter to
     * @param fileName the fileName of the newsletter
     * @return the initialized mail data class generating the newsletter mail and recipients
     * @throws Exception if instantiating the mail data class fails
     */
    public static I_CmsNewsletterMailData getMailData(CmsJspActionElement jsp, CmsOrganizationalUnit ou,
            String fileName) throws Exception {

        I_CmsNewsletterMailData result = getMailData();
        result.initialize(jsp, ou, fileName);
        return result;
    }

    /**
     * Returns the initialized mail data class generating the newsletter mail and recipients.<p>
     * 
     * @param jsp the current action element
     * @param recipients the recipients of the newsletter mail, items have to be of type {@link javax.mail.internet.InternetAddress}
     * @param fileName the fileName of the newsletter
     * @return the initialized mail data class generating the newsletter mail and recipients
     * @throws Exception if instantiating the mail data class fails
     */
    public static I_CmsNewsletterMailData getMailData(CmsJspActionElement jsp, List<InternetAddress> recipients,
            String fileName) throws Exception {

        I_CmsNewsletterMailData result = getMailData();
        result.initialize(jsp, recipients, fileName);
        return result;
    }

    /**
     * Returns the resource type name of the mail data XML content.<p>
     * 
     * @return the resource type name of the mail data XML content
     * @throws Exception if instantiating the mail data class fails
     */
    public static String getMailDataResourceTypeName() throws Exception {

        return getMailData().getResourceTypeName();
    }

    /**
     * Returns the organizational units that can contain mailing lists to display.<p>
     * 
     * @param cms the current cms context
     * 
     * @return the organizational units
     * 
     * @throws CmsException if something goes wrong
     */
    public static List<CmsOrganizationalUnit> getOrgUnits(CmsObject cms) throws CmsException {

        List<CmsOrganizationalUnit> ous = OpenCms.getRoleManager().getOrgUnitsForRole(cms,
                CmsRole.ACCOUNT_MANAGER.forOrgUnit(""), true);
        Iterator<CmsOrganizationalUnit> it = ous.iterator();
        while (it.hasNext()) {
            CmsOrganizationalUnit ou = it.next();
            if (!ou.getSimpleName().startsWith(NEWSLETTER_OU_NAMEPREFIX)) {
                it.remove();
            }
        }
        return ous;
    }

    /**
     * Returns the password to use for all newsletter users.<p>
     * 
     * @return the password to use for all newsletter users
     */
    public static String getPassword() {

        return OpenCms.getModuleManager().getModule(MODULE_NAME).getParameter(MODULE_PARAM_PASSWORD_USER,
                PASSWORD_USER);
    }

    /**
     * Returns if the given user is active to receive newsletter emails for the given group.<p>
     * 
     * @param user the user to check
     * @param groupName the name of the group the user is a member of
     * @return true if the given user is active to receive newsletter emails, otherwise false
     */
    public static boolean isActiveUser(CmsUser user, String groupName) {

        Boolean active = (Boolean) user.getAdditionalInfo(USER_ADDITIONALINFO_ACTIVE + groupName);
        return (((active != null) && active.booleanValue()) || (active == null)) && user.isEnabled();
    }

    /**
     * Returns if the email is a valid one using a regular expression pattern.<p>
     * 
     * @param email the email to check
     * @return true if the email is valid, otherwise false
     */
    public static boolean isValidEmail(String email) {

        return PATTERN_VALIDATION_EMAIL.matcher(email).matches();
    }

    /**
     * @see org.opencms.module.A_CmsModuleAction#initialize(org.opencms.file.CmsObject, org.opencms.configuration.CmsConfigurationManager, org.opencms.module.CmsModule)
     */
    @Override
    public void initialize(CmsObject adminCms, CmsConfigurationManager configurationManager, CmsModule module) {

        // store the admin CmsObject as member
        m_adminCms = adminCms;

        // check if the folder exists where the last sent newsletter information is saved
        if (!getAdminCms().existsResource(VFS_PATH_NEWSLETTER_INFO)) {
            try {
                // in order to create the folder, we have to switch to an offline project
                CmsObject cms = OpenCms.initCmsObject(getAdminCms());
                String projectName = OpenCms.getModuleManager().getModule(MODULE_NAME)
                        .getParameter(MODULE_PARAM_PROJECT_NAME, "Offline");
                CmsProject project = cms.readProject(projectName);
                cms.getRequestContext().setCurrentProject(project);
                // create folder where the newsletter info files should be saved to

                cms.createResource(VFS_PATH_NEWSLETTER_INFO, CmsResourceTypeFolder.getStaticTypeId());
                OpenCms.getPublishManager().publishResource(cms, VFS_PATH_NEWSLETTER_INFO);
            } catch (Exception e) {
                // TODO: error creating folder, log info
            }
        }
    }

    /**
     * Activates the newsletter user with the given email address in the given group.<p>
     * 
     * @param email the email address of the user
     * @param groupName the name of the group to activate the newsletter user for
     * @return true if the user was activated, otherwise false
     */
    protected boolean activateNewsletterUser(String email, String groupName) {

        try {
            CmsUser user = getAdminCms().readUser(getAdminCms().readGroup(groupName).getOuFqn() + email);
            if (user.getAdditionalInfo().get(USER_ADDITIONALINFO_ACTIVE) != null) {
                // remove flag that this user is not active at all
                user.deleteAdditionalInfo(USER_ADDITIONALINFO_ACTIVE);
            }
            user.setAdditionalInfo(USER_ADDITIONALINFO_ACTIVE + groupName, Boolean.valueOf(true));
            getAdminCms().writeUser(user);
            return true;
        } catch (CmsException e) {
            // error reading or writing user
            return false;
        }
    }

    /**
     * Creates a new newsletter user with the specified email address.<p>
     * 
     * Returns the created user or null if the user could not be created.<p>
     * 
     * The user will be activated or not depending on the activate parameter value.<p>
     * 
     * @param email the email address of the new user
     * @param groupName the name of the group to add the user to
     * @param activate if true, the user will be activated directly to receive newsletters, otherwise not
     * @return the new created user or null if the creation failed
     */
    protected CmsUser createNewsletterUser(String email, String groupName, boolean activate) {

        CmsUser user = null;
        // create additional infos containing the active flag set to passed parameter

        try {
            String ouFqn = getAdminCms().readGroup(groupName).getOuFqn();
            try {
                // first try to read the user
                user = getAdminCms().readUser(ouFqn + email);
            } catch (CmsException e) {
                // user does not exist
            }
            if (user == null) {
                // create the user with additional infos
                user = getAdminCms().createUser(ouFqn + email, getPassword(), "Alkacon OpenCms Newsletter",
                        Collections.EMPTY_MAP);
                // set the users email address
                user.setEmail(email);
                if (!activate) {
                    // set the additional info as marker that the new user is currently not active at all
                    user.setAdditionalInfo(USER_ADDITIONALINFO_ACTIVE, Boolean.FALSE);
                }
            } else {
                Object o = user.getAdditionalInfo(USER_ADDITIONALINFO_ACTIVE + groupName);
                if (o != null) {
                    // user tried to subscribe to this mailing list group before, return null to show error message
                    return null;
                }
            }
            user.setAdditionalInfo(USER_ADDITIONALINFO_ACTIVE + groupName, Boolean.valueOf(activate));
            if (activate && (user.getAdditionalInfo().get(USER_ADDITIONALINFO_ACTIVE) != null)) {
                // remove flag that this user is not active at all
                user.deleteAdditionalInfo(USER_ADDITIONALINFO_ACTIVE);
            }
            // write the user
            getAdminCms().writeUser(user);
            // add the user to the given mailing list group
            getAdminCms().addUserToGroup(user.getName(), groupName);
        } catch (CmsException e) {
            // error creating or modifying the user
            LOG.error("Error while creating user or modifying user: " + email, e);
        }
        return user;
    }

    /**
     * Deletes a newsletter user with given email address from the specified group.<p>
     * 
     * If the delete flag should be checked, the user has to be marked for deletion for a successful delete operation.<p>
     * 
     * @param email the email address of the user to delete
     * @param groupName the name of the group the user should be deleted from
     * @param checkDeleteFlag determines if the delete flag chould be checked before deleting the user
     * @return true if deletion was successful, otherwise false
     */
    protected boolean deleteNewsletterUser(String email, String groupName, boolean checkDeleteFlag) {

        try {
            String ouFqn = getAdminCms().readGroup(groupName).getOuFqn();
            CmsUser user = getAdminCms().readUser(ouFqn + email);
            boolean isToDelete = !checkDeleteFlag
                    || ((Boolean) user.getAdditionalInfo(USER_ADDITIONALINFO_TODELETE + groupName)).booleanValue();
            if (isToDelete) {
                // in order to delete a user, we have to switch to an offline project
                CmsObject cms = OpenCms.initCmsObject(getAdminCms());
                String projectName = OpenCms.getModuleManager().getModule(MODULE_NAME)
                        .getParameter(MODULE_PARAM_PROJECT_NAME, "Offline");
                CmsProject project = cms.readProject(projectName);
                cms.getRequestContext().setCurrentProject(project);
                // remove the user from the specified group
                cms.removeUserFromGroup(user.getName(), groupName);

                if (cms.getGroupsOfUser(user.getName(), true).size() < 1) {
                    // delete the user if this was the last group the user belonged to
                    cms.deleteUser(user.getName());
                } else {
                    // remove the additional info attributes for the mailing list group
                    user.getAdditionalInfo().remove(USER_ADDITIONALINFO_TODELETE + groupName);
                    user.getAdditionalInfo().remove(USER_ADDITIONALINFO_ACTIVE + groupName);
                    cms.writeUser(user);
                }
                return true;
            }
        } catch (CmsException e) {
            // error reading or deleting user
            LOG.error("Error while deleting the webuser: " + email, e);
        }
        return false;
    }

    /**
     * Returns if a newsletter user with the given email address exists in the given group.<p>
     * 
     * @param email the email address of the user
     * @param groupName the name of the group the user could be a member of
     * @return true if a newsletter user with the given email address exists, otherwise false
     */
    protected boolean existsNewsletterUser(String email, String groupName) {

        try {
            String ouFqn = getAdminCms().readGroup(groupName).getOuFqn();
            CmsUser user = getAdminCms().readUser(ouFqn + email);
            CmsGroup group = getAdminCms().readGroup(groupName);
            return getAdminCms().getGroupsOfUser(user.getName(), true).contains(group);
        } catch (CmsException e) {
            // error reading user, does not exist
            return false;
        }
    }

    /**
     * Returns if information about the last sent newsletter exists for the given group ID.<p>
     * 
     * @param groupId the group ID to check the presence of an information file
     * 
     * @return <code>true</code> if information about the last sent newsletter exists, otherwise <code>false</code>
     */
    protected boolean existsSentNewsletterInfo(CmsUUID groupId) {

        // file path where the newsletter info file is saved
        String infoFilePath = VFS_PATH_NEWSLETTER_INFO + NEWSLETTER_OU_NAMEPREFIX + groupId.hashCode();
        return getAdminCms().existsResource(infoFilePath);
    }

    /**
     * Returns if information about the last sent newsletter exists for the given group name.<p>
     * 
     * @param groupName the group name to check the presence of an information file
     * 
     * @return <code>true</code> if information about the last sent newsletter exists, otherwise <code>false</code>
     */
    protected boolean existsSentNewsletterInfo(String groupName) {

        try {
            CmsUUID groupId = getAdminCms().readGroup(groupName).getId();
            return existsSentNewsletterInfo(groupId);
        } catch (CmsException e) {
            // error reading group
            return false;
        }
    }

    /**
     * Returns the UUID of the last sent newsletter resource or <code>null</code>, if the information is not found.<p>
     * 
     * @param groupName the group name to get the last sent newsletter resource UUID
     * 
     * @return the UUID of the last sent newsletter resource
     */
    protected CmsUUID getSentNewsletterInfo(String groupName) {

        try {
            CmsUUID groupId = getAdminCms().readGroup(groupName).getId();
            String infoFilePath = VFS_PATH_NEWSLETTER_INFO + NEWSLETTER_OU_NAMEPREFIX + groupId.hashCode();
            if (getAdminCms().existsResource(infoFilePath)) {
                // we have an info file, read the content and return it as UUID
                String idStr = new String(getAdminCms().readFile(infoFilePath).getContents());
                return new CmsUUID(idStr);
            }
        } catch (CmsException e) {
            // error reading info file
        }
        return null;
    }

    /**
     * Marks a newsletter user to be deleted, this is necessary for the deletion confirmation.<p>
     * 
     * @param email the email address of the user
     * @param groupName the name of the group the user should be marked for deletion
     * @return true if the user was successfully marked to be deleted, otherwise false
     */
    protected boolean markToDeleteNewsletterUser(String email, String groupName) {

        try {
            String ouFqn = getAdminCms().readGroup(groupName).getOuFqn();
            CmsUser user = getAdminCms().readUser(ouFqn + email);
            user.setAdditionalInfo(USER_ADDITIONALINFO_TODELETE + groupName, Boolean.valueOf(true));
            getAdminCms().writeUser(user);
            return true;
        } catch (CmsException e) {
            // error reading or writing user
            return false;
        }
    }

    /**
     * Saves the information about the last sent newsletter resource to a file in <code>/system/shared/alkacon_newsletter/</code>.<p>
     * 
     * This can be used to send the last newsletter to newly registered subscribers.<p>
     * 
     * @param groupId the ID of the mailing list group to which the newsletter has been sent
     * @param id the structure ID of the newsletter resource
     */
    protected void saveSentNewsletterInfo(CmsUUID groupId, CmsUUID id) {

        try {
            // in order to write the info, we have to switch to an offline project
            CmsObject cms = OpenCms.initCmsObject(getAdminCms());
            String projectName = OpenCms.getModuleManager().getModule(MODULE_NAME)
                    .getParameter(MODULE_PARAM_PROJECT_NAME, "Offline");
            CmsProject project = cms.readProject(projectName);
            cms.getRequestContext().setCurrentProject(project);
            // file name of the info file containing the path of the sent newsletter
            String infoFileName = NEWSLETTER_OU_NAMEPREFIX + groupId.hashCode();
            // folder where the newsletter info file should be saved
            String infoFilePath = VFS_PATH_NEWSLETTER_INFO + infoFileName;

            if (!cms.existsResource(infoFilePath)) {
                cms.createResource(infoFilePath, CmsResourceTypePlain.getStaticTypeId(), id.toString().getBytes(),
                        null);
            } else {
                CmsLock lock = cms.getLock(infoFilePath);
                if (lock.isNullLock()) {
                    cms.lockResource(infoFilePath);
                    lock = cms.getLock(infoFilePath);
                }
                if (lock.isOwnedBy(cms.getRequestContext().currentUser())) {
                    CmsFile file = cms.readFile(infoFilePath);
                    file.setContents(id.toString().getBytes());
                    cms.writeFile(file);
                }
            }
            cms.unlockResource(infoFilePath);
            OpenCms.getPublishManager().publishResource(cms, infoFilePath);
        } catch (Exception e) {
            // TODO: failed to save the information
            return;
        }

    }

    /**
     * Returns the admin CmsObject that is used for user/group operations.<p>
     * 
     * @return the admin CmsObject that is used for user/group operations
     */
    private CmsObject getAdminCms() {

        return m_adminCms;
    }
}