/*********************************************************************************
* 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 java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.agnitas.actions.EmmAction;
import org.agnitas.beans.Company;
import static org.agnitas.beans.Company.STATUS_ACTIVE;
import org.agnitas.dao.CompanyDao;
import org.agnitas.dao.EmmActionDao;
import org.agnitas.dao.MailingDao;
import org.agnitas.dao.OnepixelDao;
import org.agnitas.emm.core.commons.uid.ExtensibleUID;
import org.agnitas.emm.core.commons.uid.ExtensibleUIDConstants;
import org.agnitas.emm.core.commons.uid.ExtensibleUIDService;
import org.agnitas.emm.core.commons.uid.parser.exception.UIDParseException;
import org.agnitas.util.AgnUtils;
import org.apache.commons.collections.map.CaseInsensitiveMap;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* The servlet is used for registration of opening emails have been sent to customers and loading one pixel gif image
* that is automatically adding into content of each OpenEMM mailing.
* Each time the customer opens the email, the request is sent to the server, the data about the mailing and customer
* are logged in database and the server returns http response that contains one pixel gif image.
*/
public class OnePixelCount extends HttpServlet {
private static final transient Logger logger = Logger.getLogger( OnePixelCount.class);
private static final long serialVersionUID = -3837933074485365451L;
protected byte[] onePixelGif={71 ,73 ,70 ,56 ,57 ,97 ,1 ,0 ,1 ,0 ,-128 ,-1 ,0 ,-64 ,-64 ,-64 ,0 ,0 ,0 ,33 ,-7 ,4 ,1 ,0 ,0 ,0 ,0 ,44 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,2 ,2 ,68 ,1 ,0 ,59};
private static Company cachedCompany=null;
/**
* Gets company data from database and stores it in cachedCompany variable.
* @param companyID
* @return
*/
protected Company getCompany(int companyID) {
if(cachedCompany == null) {
ApplicationContext con=WebApplicationContextUtils.getWebApplicationContext(getServletContext());
CompanyDao cDao=(CompanyDao)con.getBean("CompanyDao");
cachedCompany=cDao.getCompany(companyID);
}
return cachedCompany;
}
/**
* Servlet service-method, is invoked on calling the servlet.
* Parses data from uid parameter (company id, mailing id and customer id),
* stores the data from the request in database,
* writes one pixel gif image into response.
* Also executes mailing open action, if the mailing has one.
* Returns nothing if the company is not in status "active" or if some execution error occurs.
* @param req HTTP request; should contain "uid" parameter with values of company id, mailing id and customer id
* @param res HTTP response, contains one pixel gif image
* @throws IOException if an input/output error occurs
* @throws ServletException if a servlet exception occurs
*/
@Override
public void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
ApplicationContext con=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
String param=null;
OnepixelDao pixelDao=(OnepixelDao)con.getBean("OnepixelDao");
ExtensibleUIDService uidService = (ExtensibleUIDService) con.getBean( ExtensibleUIDConstants.SERVICE_BEAN_NAME);
// send gif to Browser.
res.setContentType("image/gif");
OutputStream out=res.getOutputStream();
out.write(onePixelGif);
out.close();
param=req.getParameter("uid");
if(param == null) {
logger.error( "service: no uid set");
return;
}
try {
// validate uid
ExtensibleUID uid = null;
Company company = null;
try {
uid = uidService.parse( param);
} catch( UIDParseException e) {
logger.warn("Error parsing UID: " + param + " (" + e.getMessage() + ")");
logger.debug( e);
}
if(uid == null || uid.getCompanyID()==0) {
return;
}
company=getCompany((int)uid.getCompanyID());
if(company == null ) {
logger.error("Company with ID: "+ uid.getCompanyID()+ " not found ");
return;
}
/*
// TODO: Create a separate Helper class to validate the old UIDs
if(uid.validateUID(company.getSecret())==false) {
logger.warn("uid invalid: " + param);
return;
}
*/
if(!STATUS_ACTIVE.equals(company.getStatus())){
return;
}
persistLog(req, pixelDao, uid);
executeMailingOpenAction(uid, con, req);
} catch (Exception e) {
logger.error(e);
return;
}
}
/**
* Calls writePixelLogToDB method and logs to console in case of its successful execution.
* @param req HTTP request
* @param pixelDao OnePixelDao object
* @param uid ExtensibleUID object, contains parsed data from the "uid" request parameter
*/
protected void persistLog(HttpServletRequest req, OnepixelDao pixelDao, ExtensibleUID uid) {
if(writePixelLogToDB(req, pixelDao, uid)) {
logger.info("Onepixel: cust: "+uid.getCustomerID()+" mi: "+uid.getMailingID()+" ci: "+uid.getCompanyID());
}
}
/**
* Stores opened email data (company id, mailing id, customer id, client IP address) in database.
* @param req HTTP request, is used fot getting the IP address of the client that sent the request
* @param pixelDao OnePixelDao object
* @param uid ExtensibleUID object, contains parsed data from the "uid" request parameter
* @return true==success
* false==error
*/
protected boolean writePixelLogToDB(HttpServletRequest req, OnepixelDao pixelDao, ExtensibleUID uid) {
return pixelDao.writePixel( uid.getCompanyID(), uid.getCustomerID(), uid.getMailingID(), req.getRemoteAddr());
}
/**
* Gets the id of action to be exequted on opening the mailing; if the action id > 0, executes the action with
* parameters from the request.
* @param uid ExtensibleUID object, contains parsed data from the "uid" request parameter
* @param context application context
* @param req HTTP request
*/
protected void executeMailingOpenAction(ExtensibleUID uid, ApplicationContext context, HttpServletRequest req){
MailingDao mailingDao = (MailingDao) context.getBean("MailingDao");
EmmActionDao actionDao = (EmmActionDao) context.getBean("EmmActionDao");
int companyID = uid.getCompanyID();
int mailingID = uid.getMailingID();
int customerID = uid.getCustomerID();
int openActionID = mailingDao.getMailingOpenAction(mailingID, companyID);
if(openActionID != 0){
EmmAction emmAction = actionDao.getEmmAction(openActionID, companyID);
if(emmAction != null){
// execute configured actions
CaseInsensitiveMap params = new CaseInsensitiveMap();
params.put("requestParameters", AgnUtils.getReqParameters(req));
params.put("_request", req);
params.put("customerID", customerID);
params.put("mailingID", mailingID);
emmAction.executeActions(context, params);
}
}
}
}