/*********************************************************************************
* The contents of this file are subject to the Common Public Attribution
* License Version 1.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.openemm.org/cpal1.html. The License is based on the Mozilla
* Public License Version 1.1 but Sections 14 and 15 have been added to cover
* use of software over a computer network and provide for limited attribution
* for the Original Developer. In addition, Exhibit A has been modified to be
* consistent with Exhibit B.
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is OpenEMM.
* The Original Developer is the Initial Developer.
* The Initial Developer of the Original Code is AGNITAS AG. All portions of
* the code written by AGNITAS AG are Copyright (c) 2007 AGNITAS AG. All Rights
* Reserved.
*
* Contributor(s): AGNITAS AG.
********************************************************************************/
package org.agnitas.web;
import org.agnitas.beans.Mailing;
import org.agnitas.beans.MailingBase;
import org.agnitas.beans.MailingComponent;
import org.agnitas.beans.MediatypeEmail;
import org.agnitas.beans.factory.MailingFactory;
import org.agnitas.cms.utils.CmsUtils;
import org.agnitas.dao.CampaignDao;
import org.agnitas.dao.MailingDao;
import org.agnitas.dao.MailinglistDao;
import org.agnitas.dao.TargetDao;
import org.agnitas.exceptions.CharacterEncodingValidationException;
import org.agnitas.preview.AgnTagException;
import org.agnitas.preview.PreviewHelper;
import org.agnitas.preview.TAGCheck;
import org.agnitas.preview.TAGCheckFactory;
import org.agnitas.service.MailingsQueryWorker;
import org.agnitas.util.AgnUtils;
import org.agnitas.util.CharacterEncodingValidator;
import org.agnitas.util.SafeString;
import org.agnitas.web.forms.MailingBaseForm;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.Globals;
import org.apache.struts.action.*;
import org.springframework.context.ApplicationContext;
import org.springframework.dao.TransientDataAccessResourceException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.mail.internet.InternetAddress;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* Implementation of <strong>Action</strong> that handles Mailings
*
* @author Martin Helff
*/
public class MailingBaseAction extends StrutsActionBase {
public static final String FUTURE_TASK = "GET_MAILING_LIST";
public static final int ACTION_SELECT_TEMPLATE = ACTION_LAST+1;
public static final int ACTION_REMOVE_TARGET = ACTION_LAST+2;
public static final int ACTION_VIEW_WITHOUT_LOAD = ACTION_LAST+3;
public static final int ACTION_CLONE_AS_MAILING = ACTION_LAST+4;
public static final int ACTION_USED_ACTIONS = ACTION_LAST + 5;
public static final int ACTION_VIEW_TABLE_ONLY = ACTION_LAST +6;
public static final int ACTION_MAILING_BASE_LAST = ACTION_LAST+6;
protected MailinglistDao mailinglistDao;
protected MailingDao mailingDao;
protected AbstractMap<String, Future> futureHolder;
protected TargetDao targetDao;
protected TAGCheckFactory tagCheckFactory;
protected ExecutorService executorService;
protected CampaignDao campaignDao;
protected CharacterEncodingValidator characterEncodingValidator;
protected MailingFactory mailingFactory;
// --------------------------------------------------------- Public Methods
/**
* Process the specified HTTP request, and create the corresponding HTTP
* response (or forward to another web component that will create it).
* Return an <code>ActionForward</code> instance describing where and how
* control should be forwarded, or <code>null</code> if the response has
* already been completed.
* <br>
* ACTION_LIST: Initializes columns width list for the mailings-list-table, forwards to "list"
* <br><br>
* ACTION_SAVE: validates character encoding in mailing subject, mailing components and content blocks;
* saves mailing in database;
* if the current mailing is template - updates all mailings using this template with dynamic-template
* property set and saves these mailings to database;
* loads saved mailing into form;
* if the mailing was cloned and the original mailing has cms data, clones cms data for the saved mailing;
* forwards to "view".
* <br><br>
* ACTION_VIEW: loads mailing data from database into a form, forwards to "view". Also resets showTemplate property
* of form which indicates if new need to show the template-section of a mailing.
* <br><br>
* ACTION_NEW: checks if there is at least one mailinglist in database: shows error message if no mailing list was found,
* if the mailinglist exists - clears the form and forwards to "view".
* <br><br>
* ACTION_REMOVE_TARGET: removes given target group from the list of chosen target groups; forwards to "view".
* <br><br>
* ACTION_SELECT_TEMPLATE: loads the settings of chosen template into current form (mailing type, mailinglist,
* target-groups etc.); doesn't save mailing to database; forwards to "view".
* <br><br>
* ACTION_CLONE_AS_MAILING: clears the form; sets the properties of original mailing to form (original mailing
* is mailing used as source for cloning); names the new mailing as "Copy of " + name of original; stores
* the id of original mailing in form as templateID; forwards to mailing view page.
* <br><br>
* ACTION_USED_ACTIONS: loads map of emm actions used by current mailing into form; forwards to mailing actions
* page (forward is "action").
* <br><br>
* ACTION_VIEW_WITHOUT_LOAD: just forwards to "view" without reloading form data (is used after failing form
* validation).
* <br><br>
* ACTION_CONFIRM_DELETE: loads mailing into form; forwards to jsp with question to confirm deletion (forward
* is "delete").
* <br><br>
* ACITON_DELETE: marks the mailing as deleted in database; forwards to "list".
* <br><br>
* Any other ACTION_* would cause a forward to "list"
* <br><br>
* If destination is "list" - calls a FutureHolder to get the list of mailings/templates according to selected
* mailing types and isTemplate form-property (indicates if we we work with templates or mailings). <br>
* If the Future object is not ready, increases the page refresh time by 50ms until it reaches 1 second.
* (The page refresh time - is the wait-time before calling the action again while the FutureHolder is
* running; the initial value is 250ms). While the FutureHolder is running - destination is "loading".<br>
* When the FutureHolder is finished - the list of mailings/templates is set to request, the destination is "list".
* <br><br>
* If destination is "view": updates oldMailFormat property with the current value;<br>
* loads list of templates and template name to form;<br>
* loads mailinglists, campaigns, target groups and selected target groups into form.
* <br><br>
* If destination is null and there are errors found - forwards to "list"
* @param form ActionForm object
* @param req request
* @param res response
* @param mapping The ActionMapping used to select this instance
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet exception occurs
* @return destination
*/
@Override
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest req,
HttpServletResponse res)
throws IOException, ServletException {
// Validate the request parameters specified by the user
MailingBaseForm aForm=null;
ActionMessages errors = new ActionMessages();
ActionMessages messages = new ActionMessages();
ActionForward destination=null;
boolean showTemplates=false;
ApplicationContext aContext = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getSession().getServletContext());
if(!AgnUtils.isUserLoggedIn(req)) {
return mapping.findForward("logon");
}
aForm=(MailingBaseForm)form;
AgnUtils.logger().info("execute: action "+aForm.getAction());
boolean hasAnyPermission = true;
if(aForm.isIsTemplate()) {
if(!allowed("template.show", req)) {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.permissionDenied"));
saveErrors(req, errors);
hasAnyPermission = false;
//return null;
}
} else {
if(!allowed("mailing.show", req)) {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.permissionDenied"));
saveErrors(req, errors);
hasAnyPermission = false;
//return null;
}
}
req.setAttribute("hasPermission", hasAnyPermission);
if(hasAnyPermission){
if (aForm.getAction() != MailingBaseAction.ACTION_SAVE) {
aForm.setOriginalMailingId(0);
}
try {
switch(aForm.getAction()) {
case MailingBaseAction.ACTION_LIST:
if ( aForm.getColumnwidthsList() == null) {
aForm.setColumnwidthsList(getInitializedColumnWidthList(5));
}
destination=mapping.findForward("list");
break;
case MailingBaseAction.ACTION_NEW:
if(allowed("mailing.new", req)) {
List mlists=mailinglistDao.getMailinglists(getCompanyID(req));
if(mlists.size() > 0) {
aForm.setAction(MailingBaseAction.ACTION_SAVE);
int campaignID = aForm.getCampaignID();
aForm.clearData(getCompanyID(req), getDefaultMediaType(req));
aForm.setMailingID(0);
aForm.setCampaignID(campaignID);
destination=mapping.findForward("view");
} else {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.mailing.noMailinglist"));
}
} else {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.permissionDenied"));
}
break;
case MailingBaseAction.ACTION_VIEW:
aForm.setAction(MailingBaseAction.ACTION_SAVE);
resetShowTemplate(req, aForm);
loadMailing(aForm, req);
destination=mapping.findForward("view");
break;
case MailingBaseAction.ACTION_VIEW_WITHOUT_LOAD:
aForm.setAction(MailingBaseAction.ACTION_SAVE);
destination=mapping.findForward("view");
break;
case MailingBaseAction.ACTION_REMOVE_TARGET:
removeTarget(aForm, req);
aForm.setAction(MailingBaseAction.ACTION_SAVE);
destination=mapping.findForward("view");
break;
case MailingBaseAction.ACTION_SAVE:
if(allowed("mailing.change", req)) {
destination=mapping.findForward("view");
try {
validateMailing( aForm, req);
} catch( CharacterEncodingValidationException e) {
if( !e.isSubjectValid())
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.charset.subject"));
for( String mailingComponent : e.getFailedMailingComponents())
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.charset.component", mailingComponent));
for( String dynTag : e.getFailedDynamicTags())
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.charset.content", dynTag));
}
try {
saveMailing(aForm, req, messages);
loadMailing(aForm, req);
// Show "changes saved"
messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("default.changes_saved"));
} catch (AgnTagException e) {
req.setAttribute("errorReport", e.getReport());
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.template.dyntags"));
} catch (TransientDataAccessResourceException e) {
AgnUtils.logger().error("execute: " + e + "\n" + AgnUtils.getStackTrace(e));
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.hibernate.attachmentTooLarge"));
}
showTemplates=aForm.isShowTemplate();
aForm.setShowTemplate(showTemplates);
// copy CMS data of cloned mailing if the original
// mailing included CMS content
if(aForm.getOriginalMailingId() != 0) {
if(CmsUtils.mailingHasCmsData(aForm.getOriginalMailingId(), aContext)) {
CmsUtils.cloneMailingCmsData(aForm.getOriginalMailingId(), aForm.getMailingID(), aContext);
}
aForm.setOriginalMailingId(0);
}
} else {
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.permissionDenied"));
}
break;
case MailingBaseAction.ACTION_SELECT_TEMPLATE:
loadTemplateSettings(aForm, req);
aForm.setAction(MailingBaseAction.ACTION_SAVE);
destination=mapping.findForward("view");
break;
case MailingBaseAction.ACTION_CLONE_AS_MAILING:
if(allowed("mailing.copy", req)) {
aForm.setOriginalMailingId(aForm.getMailingID());
int tmpTemplateID=aForm.getMailingID();
int tmpMlId=aForm.getMailinglistID();
String sname = aForm.getShortname();
int tmpFormat=aForm.getMediaEmail().getMailFormat();
boolean tmpl=aForm.isIsTemplate();
String tempDescription = aForm.getDescription();
aForm.clearData(this.getCompanyID(req), this.getDefaultMediaType(req));
aForm.setTemplateID(tmpTemplateID);
aForm.setIsTemplate(tmpl);
loadTemplateSettings(aForm, req);
aForm.setMailinglistID(tmpMlId);
aForm.getMediaEmail().setMailFormat(tmpFormat);
aForm.setMailingID(0);
aForm.setAction(MailingBaseAction.ACTION_SAVE);
aForm.setShortname(SafeString.getLocaleString("mailing.CopyOf", (Locale)req.getSession().getAttribute(Globals.LOCALE_KEY)) + " " + sname);
// aForm.setDescription(SafeString.getLocaleString("default.description", (Locale)req.getSession().getAttribute(Globals.LOCALE_KEY)));
aForm.setDescription( tempDescription);
aForm.setCopyFlag(true);
destination=mapping.findForward("view");
} else {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.permissionDenied"));
}
break;
case MailingBaseAction.ACTION_CONFIRM_DELETE:
if(allowed("mailing.delete", req)) {
aForm.setAction(MailingBaseAction.ACTION_DELETE);
loadMailing(aForm, req);
destination=mapping.findForward("delete");
} else {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.permissionDenied"));
}
break;
case MailingBaseAction.ACTION_DELETE:
if(allowed("mailing.delete", req)) {
aForm.setAction(MailingBaseAction.ACTION_LIST);
deleteMailing(aForm, req);
destination=mapping.findForward("list");
messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("default.changes_saved"));
aForm.setMessages(messages);
} else {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.permissionDenied"));
}
break;
case MailingBaseAction.ACTION_USED_ACTIONS:
loadActions(aForm, req);
destination = mapping.findForward("action");
break;
default:
aForm.setAction(MailingBaseAction.ACTION_LIST);
destination=mapping.findForward("list");
}
} catch (Exception e) {
AgnUtils.logger().error("execute: "+e+"\n"+AgnUtils.getStackTrace(e));
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.exception"));
}
if(destination != null && "list".equals(destination.getName())) {
try {
setNumberOfRows(req, aForm);
destination = mapping.findForward("loading");
String key = FUTURE_TASK+"@"+ req.getSession(false).getId();
if( !futureHolder.containsKey(key) ) {
Future mailingListFuture = getMailingListFuture(req,aForm.getTypes(), aForm.isIsTemplate(), aForm );
futureHolder.put(key,mailingListFuture);
}
if (futureHolder.containsKey(key) && futureHolder.get(key).isDone()) {
req.setAttribute("mailinglist", futureHolder.get(key).get());
destination = mapping.findForward("list");
futureHolder.remove(key);
aForm.setRefreshMillis(RecipientForm.DEFAULT_REFRESH_MILLIS);
saveMessages(req, aForm.getMessages());
saveErrors(req, aForm.getErrors());
aForm.setMessages(null);
aForm.setErrors(null);
}
else {
if( aForm.getRefreshMillis() < 1000 ) { // raise the refresh time
aForm.setRefreshMillis( aForm.getRefreshMillis() + 50 );
}
aForm.setError(false);
}
} catch (Exception e) {
AgnUtils.logger().error("getMailingList: "+e+"\n"+AgnUtils.getStackTrace(e));
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.exception"));
aForm.setError(true); // do not refresh when an error has been occurred
}
}
checkShowDynamicTemplateCheckbox( aForm, req);
if (destination != null && "view".equals(destination.getName())) {
if (aForm.getMediaEmail() != null) {
aForm.setOldMailFormat(aForm.getMediaEmail().getMailFormat());
}
aForm.setTemplateMailingBases(mailingDao.getTemplateMailingsByCompanyID(getCompanyID(req)));
if(aForm.getTemplateID() != 0) {
MailingBase mb = mailingDao.getMailingForTemplateID(aForm.getTemplateID(),getCompanyID(req));
aForm.setTemplateShortname(mb.getShortname().compareTo("") != 0 ? mb.getShortname() : SafeString.getLocaleString("mailing.No_Template", (Locale) req.getSession().getAttribute(Globals.LOCALE_KEY)));
}
else aForm.setTemplateShortname(SafeString.getLocaleString("mailing.No_Template", (Locale) req.getSession().getAttribute(Globals.LOCALE_KEY)));
aForm.setMailingLists(mailinglistDao.getMailinglists(getCompanyID(req)));
aForm.setCampaigns(campaignDao.getCampaignList(getCompanyID(req),"lower(shortname)",1));
aForm.setTargetGroupsList(targetDao.getTargetGroup(getCompanyID(req), aForm.getTargetGroups()));
aForm.setTargets(targetDao.getUnchoosenTargets(getCompanyID(req),aForm.getTargetGroups()));
}
}
// Report any errors we have discovered back to the original form
if (!errors.isEmpty()) {
saveErrors(req, errors);
if(destination == null) {
destination=mapping.findForward("list");
}
}
// Report any message (non-errors) we have discovered
if (!messages.isEmpty()) {
saveMessages(req, messages);
}
return destination;
}
/**
* Validates mailing subject, mailing components and dynamic tags
*
* @param form MailingBaseForm object
* @param req request
* @throws CharacterEncodingValidationException contains numbers of line and position of wrong character
*/
protected void validateMailing( MailingBaseForm form, HttpServletRequest req) throws CharacterEncodingValidationException {
Mailing mailing = mailingDao.getMailing(form.getMailingID(), getCompanyID(req));
characterEncodingValidator.validate( form, mailing);
}
protected void resetShowTemplate(HttpServletRequest req, MailingBaseForm aForm) {
String showTemplate = req.getParameter("showTemplate");
if(showTemplate == null || !showTemplate.equals("true")) {
aForm.setShowTemplate(false);
}
}
/**
* Loads mailing data from db.
*
* @param aForm MailingBaseForm object
* @param req request
* @throws Exception
*/
protected void loadMailing(MailingBaseForm aForm, HttpServletRequest req) throws Exception {
MediatypeEmail type=null;
MailingComponent comp=null;
Mailing aMailing=mailingDao.getMailing(aForm.getMailingID(), getCompanyID(req));
ApplicationContext aContext = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getSession().getServletContext());
if(aMailing==null) {
aMailing=mailingFactory.newMailing();
aMailing.init(getCompanyID(req), aContext);
aMailing.setId(0);
aForm.setMailingID(0);
}
aForm.setShortname(aMailing.getShortname());
aForm.setDescription(aMailing.getDescription());
aForm.setMailingType(aMailing.getMailingType());
aForm.setMailinglistID(aMailing.getMailinglistID());
aForm.setTemplateID(aMailing.getMailTemplateID());
aForm.setTargetGroups(aMailing.getTargetGroups());
aForm.setMediatypes(aMailing.getMediatypes());
aForm.setArchived(aMailing.getArchived() != 0 );
aForm.setCampaignID(aMailing.getCampaignID());
aForm.setTargetMode( aMailing.getTargetMode() );
aForm.setWorldMailingSend(aMailing.isWorldMailingSend());
aForm.setUseDynamicTemplate(aMailing.getUseDynamicTemplate());
type=aMailing.getEmailParam();
if(type!=null) {
aForm.setEmailSubject(type.getSubject());
aForm.setEmailOnepixel(type.getOnepixel());
try {
aForm.setEmailReplytoEmail(new InternetAddress(type.getReplyAdr()).getAddress());
} catch (Exception e) {
// do nothing
}
try {
aForm.setEmailReplytoFullname(new InternetAddress(type.getReplyAdr()).getPersonal());
} catch (Exception e) {
// do nothing
}
aForm.setEmailLinefeed(type.getLinefeed());
aForm.setEmailCharset(type.getCharset());
}
comp=aMailing.getTextTemplate();
if(comp!=null) {
aForm.setTextTemplate(comp.getEmmBlock());
}
comp=aMailing.getHtmlTemplate();
if(comp!=null) {
aForm.setHtmlTemplate(comp.getEmmBlock());
}
String entityName = aMailing.isIsTemplate() ? "template" : "mailing";
AgnUtils.userlogger().info(AgnUtils.getAdmin(req).getUsername() + ": do load " + entityName + " " + aMailing.getShortname());
AgnUtils.logger().info("loadMailing: mailing loaded");
}
/**
* Removes target group from the list of chosen targets.
*
* @param aForm MailingBaseForm object
* @param req request
* @throws Exception
*/
protected void removeTarget(MailingBaseForm aForm, HttpServletRequest req) throws Exception {
Collection<Integer> allTargets=aForm.getTargetGroups();
Integer tmpInt=null;
if(allTargets!=null) {
Iterator<Integer> aIt=allTargets.iterator();
while(aIt.hasNext()) {
tmpInt = aIt.next();
if(aForm.getTargetID()==tmpInt.intValue()) {
allTargets.remove(tmpInt);
break;
}
}
}
if(allTargets.isEmpty()) {
aForm.setTargetGroups(null);
}
}
/**
* Gets mailing template data from db and calls method for loading the data into form.
*
* @param aForm MailingBaseForm object
* @param req request
* @throws Exception
*/
protected void loadTemplateSettings(MailingBaseForm aForm, HttpServletRequest req) throws Exception {
Mailing aTemplate=null;
if(aForm.getTemplateID()!=0) {
aTemplate=mailingDao.getMailing(aForm.getTemplateID(), this.getCompanyID(req));
if(aTemplate!=null) {
copyTemplateSettingsToMailingForm(aTemplate, aForm);
}
}
}
/**
* Loads chosen mailing template data into form.
*
* @param template Mailing bean object, contains mailing template data
* @param mailingBaseForm MailingBaseForm object
*/
protected void copyTemplateSettingsToMailingForm( Mailing template, MailingBaseForm mailingBaseForm){
MailingComponent tmpComp=null;
mailingBaseForm.setMailingType(template.getMailingType());
mailingBaseForm.setMailinglistID(template.getMailinglistID());
mailingBaseForm.setTargetMode(template.getTargetMode());
mailingBaseForm.setTargetGroups(template.getTargetGroups());
mailingBaseForm.setMediatypes(template.getMediatypes());
mailingBaseForm.setArchived(template.getArchived() != 0);
mailingBaseForm.setCampaignID(template.getCampaignID());
mailingBaseForm.setNeedsTarget(template.getNeedsTarget());
mailingBaseForm.setUseDynamicTemplate(template.getUseDynamicTemplate());
// load template for this mailing
if((tmpComp=template.getHtmlTemplate())!=null) {
mailingBaseForm.setHtmlTemplate(tmpComp.getEmmBlock());
}
if((tmpComp=template.getTextTemplate())!=null) {
mailingBaseForm.setTextTemplate(tmpComp.getEmmBlock());
}
MediatypeEmail type=template.getEmailParam();
if(type!=null) {
mailingBaseForm.setEmailOnepixel(type.getOnepixel());
try {
mailingBaseForm.setEmailReplytoEmail(new InternetAddress(type.getReplyAdr()).getAddress());
} catch (Exception e) {
// do nothing
}
try {
mailingBaseForm.setEmailReplytoFullname(new InternetAddress(type.getReplyAdr()).getPersonal());
} catch (Exception e) {
// do nothing
}
mailingBaseForm.setEmailLinefeed(type.getLinefeed());
mailingBaseForm.setEmailCharset(type.getCharset());
}
}
/**
* Saves current mailing in DB (including mailing components, content blocks, dynamic tags, dynamic tags contents
* and trackable links)
*
* @param aForm MailingBaseForm object
* @param req request
* @param messages not in use
* @throws Exception
*/
protected void saveMailing(MailingBaseForm aForm, HttpServletRequest req, ActionMessages messages) throws Exception {
Mailing aMailing=null;
Mailing aTemplate=null;
MediatypeEmail paramEmail=null;
boolean newMail = false;
ApplicationContext aContext = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getSession().getServletContext());
if(aForm.getMailingID()!=0) {
aMailing=mailingDao.getMailing(aForm.getMailingID(), this.getCompanyID(req));
} else {
newMail = true;
if(aForm.getTemplateID()!=0) {
aTemplate=mailingDao.getMailing(aForm.getTemplateID(), this.getCompanyID(req));
aMailing=(Mailing)aTemplate.clone(aContext);
aMailing.setId(0);
aMailing.setMailTemplateID(aForm.getTemplateID());
aMailing.setCompanyID(this.getCompanyID(req));
}
}
if(aMailing==null) {
aMailing=mailingFactory.newMailing();
aMailing.init(this.getCompanyID(req), aContext);
aMailing.setId(0);
aForm.setMailingID(0);
}
if (aForm.getMediaEmail().getMailFormat() == 0) {
aForm.getMediaEmail().setHtmlTemplate("");
} else if (aForm.getOldMailFormat() == 0) {
if (aForm.getMediaEmail() != null && StringUtils.isEmpty(aForm.getMediaEmail().getHtmlTemplate())) {
aForm.getMediaEmail().setHtmlTemplate("[agnDYN name=\"HTML-Version\"/]");
}
}
aMailing.setIsTemplate(aForm.isIsTemplate());
aMailing.setCampaignID(aForm.getCampaignID());
aMailing.setDescription(aForm.getDescription());
aMailing.setShortname(aForm.getShortname());
aMailing.setMailinglistID(aForm.getMailinglistID());
aMailing.setMailingType(aForm.getMailingType());
aMailing.setArchived(aForm.isArchived()?1:0);
aMailing.setTargetMode(aForm.getTargetMode());
aMailing.setTargetGroups(aForm.getTargetGroups());
aMailing.setMediatypes(aForm.getMediatypes());
aMailing.setUseDynamicTemplate(aForm.getUseDynamicTemplate());
try {
paramEmail=aMailing.getEmailParam();
paramEmail.setSubject(aForm.getEmailSubject());
paramEmail.setLinefeed(aForm.getEmailLinefeed());
paramEmail.setCharset(aForm.getEmailCharset());
paramEmail.setOnepixel(aForm.getEmailOnepixel());
aForm.getMediaEmail().syncTemplate(aMailing, aContext);
aMailing.buildDependencies(true, aContext);
} catch (Exception e) {
AgnUtils.logger().error("Error in save mailing id: "+aForm.getMailingID()+" msg: "+e.getMessage());
}
// validate the components
if(!newMail) {
Set<Entry<String,MailingComponent>> componentEntries = aMailing.getComponents().entrySet();
List<String[]> errorReports = new ArrayList<String[]>();
Vector<String> outFailures = new Vector<String>();
TAGCheck tagCheck =tagCheckFactory.createTAGCheck(aMailing.getId());
for(Entry<String,MailingComponent> mapEntry:componentEntries) {
String tagName = mapEntry.getKey();
MailingComponent component = mapEntry.getValue();
String emmBlock = component.getEmmBlock();
StringBuffer contentOutReport = new StringBuffer();
if(!tagCheck.checkContent(emmBlock, contentOutReport, outFailures) ) {
appendErrorsToList(tagName, errorReports, contentOutReport);
}
}
if( errorReports.size() > 0) {
throw new AgnTagException("error.template.dyntags",errorReports);
}
}
mailingDao.saveMailing(aMailing);
aForm.setMailingID(aMailing.getId());
String entityName = aMailing.isIsTemplate() ? "template" : "mailing";
if( aMailing.isIsTemplate()) {
updateMailingsWithDynamicTemplate( aMailing);
}
if (newMail) {
AgnUtils.userlogger().info(AgnUtils.getAdmin(req).getUsername() + ": create " + entityName + " " + aMailing.getShortname());
} else {
AgnUtils.userlogger().info(AgnUtils.getAdmin(req).getUsername() + ": edit " + entityName + " " + aMailing.getShortname());
}
}
/**
* Marks mailing as deleted and updated mailing data in database
*
* @param aForm MailingBaseForm object
* @param req request
* @throws Exception
*/
protected void deleteMailing(MailingBaseForm aForm, HttpServletRequest req) throws Exception {
mailingDao.deleteMailing(aForm.getMailingID(), this.getCompanyID(req));
String entityName = aForm.isIsTemplate() ? "template" : "mailing";
AgnUtils.userlogger().info(AgnUtils.getAdmin(req).getUsername() + ": delete " + entityName + " " + aForm.getShortname());
}
/**
* Loads list of emm actions into form
*
* @param aForm MailingBaseForm object
* @param req request
* @throws Exception
*/
protected void loadActions(MailingBaseForm aForm, HttpServletRequest req) throws Exception {
Map<String, String> map = new HashMap<String, String>();
map = mailingDao.loadAction(aForm.getMailingID(), this.getCompanyID(req));
aForm.setActions(map);
}
/**
* Creates paginated list by given sorting parameters and filter conditions (templates or mailings, mailings of certain types).
*
* @param req request
* @param types listed mailing types, separated with comma
* @param isTemplate true == templates
* false==mailings
* @param mailingBaseForm MailingBaseForm object
* @return Future object
* @throws IllegalAccessException
* @throws InstantiationException
*/
public Future getMailingListFuture(HttpServletRequest req , String types, boolean isTemplate, MailingBaseForm mailingBaseForm ) throws IllegalAccessException, InstantiationException {
String sort = getSort(req, mailingBaseForm);
String direction = req.getParameter("dir");
if( direction == null ) {
direction = mailingBaseForm.getOrder();
} else {
mailingBaseForm.setOrder(direction);
}
String pageStr = req.getParameter("page");
if ( pageStr == null || "".equals(pageStr.trim()) ) {
if ( mailingBaseForm.getPage() == null || "".equals(mailingBaseForm.getPage().trim())) {
mailingBaseForm.setPage("1");
}
pageStr = mailingBaseForm.getPage();
}
else {
mailingBaseForm.setPage(pageStr);
}
if( mailingBaseForm.isNumberOfRowsChanged() ) {
mailingBaseForm.setPage("1");
mailingBaseForm.setNumberOfRowsChanged(false);
pageStr = "1";
}
int page = Integer.parseInt(pageStr);
int rownums = mailingBaseForm.getNumberofRows();
Future future = executorService.submit(new MailingsQueryWorker(mailingDao, AgnUtils.getCompanyID(req), types, isTemplate, sort, direction, page, rownums ));
return future;
}
protected String getSort(HttpServletRequest request, MailingBaseForm aForm) {
String sort = request.getParameter("sort");
if( sort == null ) {
sort = aForm.getSort();
} else {
aForm.setSort(sort);
}
return sort;
}
/**
* Creates report about errors in dynamic tags.
*
* @param blockName name of content block with invalid content
* @param errorReports list of messages about parsing errors (is changing inside the method)
* @param templateReport content with errors
*/
protected void appendErrorsToList(String blockName, List<String[]> errorReports,
StringBuffer templateReport) {
Map<String,String> tagsWithErrors = PreviewHelper.getTagsWithErrors(templateReport);
for(Entry<String,String> entry:tagsWithErrors.entrySet()) {
String[] errorRow = new String[3];
errorRow[0] = blockName; // block
errorRow[1] = entry.getKey(); // tag
errorRow[2] = entry.getValue(); // value
errorReports.add(errorRow);
}
List<String> errorsWithoutATag = PreviewHelper.getErrorsWithoutATag(templateReport);
for(String error:errorsWithoutATag){
String[] errorRow = new String[3];
errorRow[0] = blockName;
errorRow[1] = "";
errorRow[2] = error;
errorReports.add(errorRow);
}
}
public MailingDao getMailingDao() {
return mailingDao;
}
public void setMailingDao(MailingDao mailingDao) {
this.mailingDao = mailingDao;
}
public void setFutureHolder(AbstractMap<String, Future> futureHolder) {
this.futureHolder = futureHolder;
}
public CampaignDao getCampaignDao() {
return campaignDao;
}
public void setCampaignDao(CampaignDao campaignDao) {
this.campaignDao = campaignDao;
}
public MailinglistDao getMailinglistDao() {
return mailinglistDao;
}
public void setMailinglistDao(MailinglistDao mailinglistDao) {
this.mailinglistDao = mailinglistDao;
}
public CharacterEncodingValidator getCharacterEncodingValidator() {
return characterEncodingValidator;
}
public void setCharacterEncodingValidator(CharacterEncodingValidator characterEncodingValidator) {
this.characterEncodingValidator = characterEncodingValidator;
}
public TargetDao getTargetDao() {
return targetDao;
}
public void setTargetDao(TargetDao targetDao) {
this.targetDao = targetDao;
}
public TAGCheckFactory getTagCheckFactory() {
return tagCheckFactory;
}
public void setTagCheckFactory(TAGCheckFactory tagCheckFactory) {
this.tagCheckFactory = tagCheckFactory;
}
public void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
public MailingFactory getMailingFactory() {
return mailingFactory;
}
public void setMailingFactory(MailingFactory mailingFactory) {
this.mailingFactory = mailingFactory;
}
protected void updateMailingsWithDynamicTemplate( Mailing mailTemplate) {
List<Integer> referencingMailings = mailingDao.getTemplateReferencingMailingIds( mailTemplate);
if( referencingMailings == null)
return;
int companyId = mailTemplate.getCompanyID();
Mailing mailing;
MailingComponent mailingComponent;
MailingComponent templateComponent;
for( int mailingId : referencingMailings) {
mailing = mailingDao.getMailing(mailingId, companyId);
// First, handle text template
templateComponent = mailTemplate.getTextTemplate();
mailingComponent = mailing.getTextTemplate();
// Modify text template only if mailing and template have both a text template
if( templateComponent != null && mailingComponent != null) {
mailingComponent.setEmmBlock( templateComponent.getEmmBlock());
}
// Next, handle HTML template
templateComponent = mailTemplate.getHtmlTemplate();
mailingComponent = mailing.getHtmlTemplate();
// Modify HTML template only if mailing and template have both a HTML template
if( templateComponent != null && mailingComponent != null) {
mailingComponent.setEmmBlock( templateComponent.getEmmBlock());
}
try {
mailing.buildDependencies( true, getWebApplicationContext());
mailingDao.saveMailing( mailing);
} catch( Exception e) {
org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger( this.getClass());
logger.error( "unable to update mailing ID " + mailingId + ": " + e.getMessage());
if( logger.isDebugEnabled())
logger.debug( "unable to update mailing ID " + mailingId, e);
}
}
}
protected void checkShowDynamicTemplateCheckbox( MailingBaseForm mailingBaseForm, HttpServletRequest request) {
boolean showCheckbox = false;
if( mailingBaseForm.isIsTemplate()) {
// For templates checkbox is always show and enabled
showCheckbox = true;
} else if( mailingBaseForm.getTemplateID() != 0) {
// For mailings, checkbox is always shows if and only if referenced mailing-record defines template
// Checkbox is only enabled, if such a mailing has ID 0 (new mailing)
showCheckbox = mailingDao.checkMailingReferencesTemplate( mailingBaseForm.getTemplateID(), AgnUtils.getCompanyID( request));
} else {
// in all other cases, the checkbox is hidden
showCheckbox = false;
}
request.setAttribute("show_dynamic_template_checkbox", showCheckbox);
}
protected WebApplicationContext getApplicationContext(HttpServletRequest req){
return WebApplicationContextUtils.getRequiredWebApplicationContext(req.getSession().getServletContext());
}
}