001: /*
002: * $Id: TrackingCodeEvents.java,v 1.2 2003/10/23 06:33:02 jonesde Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: */
024: package org.ofbiz.marketing.tracking;
025:
026: import java.util.ArrayList;
027: import java.util.LinkedList;
028: import java.util.List;
029:
030: import javax.servlet.http.Cookie;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033: import javax.servlet.http.HttpSession;
034:
035: import org.ofbiz.base.util.Debug;
036: import org.ofbiz.base.util.UtilDateTime;
037: import org.ofbiz.base.util.UtilMisc;
038: import org.ofbiz.base.util.UtilProperties;
039: import org.ofbiz.base.util.UtilValidate;
040: import org.ofbiz.content.stats.VisitHandler;
041: import org.ofbiz.content.website.WebSiteWorker;
042: import org.ofbiz.entity.GenericDelegator;
043: import org.ofbiz.entity.GenericEntityException;
044: import org.ofbiz.entity.GenericValue;
045: import org.ofbiz.product.category.CategoryWorker;
046:
047: /**
048: * Events used for maintaining TrackingCode related information
049: *
050: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
051: * @version $Revision: 1.2 $
052: * @since 2.0
053: */
054: public class TrackingCodeEvents {
055:
056: public static final String module = TrackingCodeEvents.class
057: .getName();
058:
059: /** If TrackingCode monitoring is desired this event should be added to the list
060: * of events that run on every request. This event looks for the parameter
061: * <code>autoTrackingCode</code> or a shortened version: <code>atc</code>.
062: */
063: public static String checkTrackingCodeUrlParam(
064: HttpServletRequest request, HttpServletResponse response) {
065: String trackingCodeId = request
066: .getParameter("autoTrackingCode");
067: if (UtilValidate.isEmpty(trackingCodeId))
068: trackingCodeId = request.getParameter("atc");
069:
070: if (UtilValidate.isNotEmpty(trackingCodeId)) {
071: //tracking code is specified on the request, get the TrackingCode value and handle accordingly
072: GenericDelegator delegator = (GenericDelegator) request
073: .getAttribute("delegator");
074: GenericValue trackingCode = null;
075: try {
076: trackingCode = delegator.findByPrimaryKeyCache(
077: "TrackingCode", UtilMisc.toMap(
078: "trackingCodeId", trackingCodeId));
079: } catch (GenericEntityException e) {
080: Debug.logError(e,
081: "Error looking up TrackingCode with trackingCodeId ["
082: + trackingCodeId
083: + "], ignoring this trackingCodeId",
084: module);
085: return "error";
086: }
087:
088: if (trackingCode == null) {
089: Debug.logError(
090: "TrackingCode not found for trackingCodeId ["
091: + trackingCodeId
092: + "], ignoring this trackingCodeId.",
093: module);
094: //this return value will be ignored, but we'll designate this as an error anyway
095: return "error";
096: }
097:
098: return processTrackingCode(trackingCode, request, response);
099: } else {
100: return "success";
101: }
102: }
103:
104: /** If TrackingCode monitoring is desired this event should be added to the list
105: * of events that run on every request. This event looks for the parameter
106: * <code>ptc</code> and handles the value as a Partner Managed Tracking Code.
107: *
108: * If the specified trackingCodeId exists then it is used as is, otherwise a new one
109: * is created with the ptc value as the trackingCodeId. The values for the fields of
110: * the new TrackingCode can come from one of two places: if a <code>dtc</code> parameter
111: * is included the value will be used to lookup a TrackingCode with default values,
112: * otherwise the default trackingCodeId will be looked up in the <code>partner.trackingCodeId.default</code>
113: * in the <code>general.properties</code> file. If that is still not found just use an empty TrackingCode.
114: */
115: public static String checkPartnerTrackingCodeUrlParam(
116: HttpServletRequest request, HttpServletResponse response) {
117: String trackingCodeId = request.getParameter("ptc");
118:
119: if (UtilValidate.isNotEmpty(trackingCodeId)) {
120: //partner managed tracking code is specified on the request
121: GenericDelegator delegator = (GenericDelegator) request
122: .getAttribute("delegator");
123: GenericValue trackingCode = null;
124: try {
125: trackingCode = delegator.findByPrimaryKeyCache(
126: "TrackingCode", UtilMisc.toMap(
127: "trackingCodeId", trackingCodeId));
128: } catch (GenericEntityException e) {
129: Debug.logError(e,
130: "Error looking up TrackingCode with trackingCodeId ["
131: + trackingCodeId
132: + "], ignoring this trackingCodeId",
133: module);
134: return "error";
135: }
136:
137: if (trackingCode == null) {
138: //create new TrackingCode with default values from a "dtc" parameter or from a properties file
139:
140: String dtc = request.getParameter("dtc");
141: if (UtilValidate.isEmpty(dtc)) {
142: dtc = UtilProperties.getPropertyValue("general",
143: "partner.trackingCodeId.default");
144: }
145: if (UtilValidate.isNotEmpty(dtc)) {
146: GenericValue defaultTrackingCode = null;
147: try {
148: defaultTrackingCode = delegator
149: .findByPrimaryKeyCache("TrackingCode",
150: UtilMisc.toMap(
151: "trackingCodeId", dtc));
152: } catch (GenericEntityException e) {
153: Debug
154: .logError(
155: e,
156: "Error looking up Default values TrackingCode with trackingCodeId ["
157: + dtc
158: + "], not using the dtc value for new TrackingCode defaults",
159: module);
160: }
161:
162: if (defaultTrackingCode != null) {
163: defaultTrackingCode.set("trackingCodeId",
164: trackingCodeId);
165: defaultTrackingCode.set("trackingCodeTypeId",
166: "PARTNER_MGD");
167: //null out userLogin fields, no use tracking to customer, or is there?; set dates to current
168: defaultTrackingCode.set("createdDate",
169: UtilDateTime.nowTimestamp());
170: defaultTrackingCode.set("createdByUserLogin",
171: null);
172: defaultTrackingCode.set("lastModifiedDate",
173: UtilDateTime.nowTimestamp());
174: defaultTrackingCode.set(
175: "lastModifiedByUserLogin", null);
176:
177: trackingCode = defaultTrackingCode;
178: try {
179: trackingCode.create();
180: } catch (GenericEntityException e) {
181: Debug
182: .logError(
183: e,
184: "Error creating new Partner TrackingCode with trackingCodeId ["
185: + trackingCodeId
186: + "], ignoring this trackingCodeId",
187: module);
188: return "error";
189: }
190: }
191: }
192:
193: //if trackingCode is still null then the defaultTrackingCode thing didn't work out, use empty TrackingCode
194: if (trackingCode == null) {
195: trackingCode = delegator.makeValue("TrackingCode",
196: null);
197: trackingCode.set("trackingCodeId", trackingCodeId);
198: trackingCode.set("trackingCodeTypeId",
199: "PARTNER_MGD");
200: //leave userLogin fields empty, no use tracking to customer, or is there?; set dates to current
201: trackingCode.set("createdDate", UtilDateTime
202: .nowTimestamp());
203: trackingCode.set("lastModifiedDate", UtilDateTime
204: .nowTimestamp());
205:
206: //use nearly unlimited trackable lifetime: 10 billion seconds, 310 years
207: trackingCode.set("trackableLifetime", new Long(
208: 10000000000L));
209: //use 2592000 seconds as billable lifetime: equals 1 month
210: trackingCode.set("billableLifetime", new Long(
211: 2592000));
212:
213: trackingCode
214: .set(
215: "comments",
216: "This TrackingCode has default values because no default TrackingCode could be found.");
217:
218: Debug
219: .logWarning(
220: "No default TrackingCode record was found, using a TrackingCode with hard coded default values: "
221: + trackingCode, module);
222:
223: try {
224: trackingCode.create();
225: } catch (GenericEntityException e) {
226: Debug
227: .logError(
228: e,
229: "Error creating new Partner TrackingCode with trackingCodeId ["
230: + trackingCodeId
231: + "], ignoring this trackingCodeId",
232: module);
233: return "error";
234: }
235: }
236: }
237:
238: return processTrackingCode(trackingCode, request, response);
239: } else {
240: return "success";
241: }
242: }
243:
244: private static String processTrackingCode(
245: GenericValue trackingCode, HttpServletRequest request,
246: HttpServletResponse response) {
247: GenericDelegator delegator = (GenericDelegator) request
248: .getAttribute("delegator");
249: String trackingCodeId = trackingCode
250: .getString("trackingCodeId");
251:
252: //check effective dates
253: java.sql.Timestamp nowStamp = UtilDateTime.nowTimestamp();
254: if (trackingCode.get("fromDate") != null
255: && nowStamp.before(trackingCode
256: .getTimestamp("fromDate"))) {
257: if (Debug.infoOn())
258: Debug
259: .logInfo(
260: "The TrackingCode with ID ["
261: + trackingCodeId
262: + "] has not yet gone into effect, ignoring this trackingCodeId",
263: module);
264: return "success";
265: }
266: if (trackingCode.get("thruDate") != null
267: && nowStamp
268: .after(trackingCode.getTimestamp("thruDate"))) {
269: if (Debug.infoOn())
270: Debug
271: .logInfo(
272: "The TrackingCode with ID ["
273: + trackingCodeId
274: + "] has expired, ignoring this trackingCodeId",
275: module);
276: return "success";
277: }
278:
279: //persist that info by associating with the current visit
280: GenericValue visit = VisitHandler
281: .getVisit(request.getSession());
282: if (visit == null) {
283: Debug.logWarning(
284: "Could not get visit, not associating trackingCode ["
285: + trackingCodeId + "] with visit", module);
286: } else {
287: GenericValue trackingCodeVisit = delegator.makeValue(
288: "TrackingCodeVisit", UtilMisc.toMap(
289: "trackingCodeId", trackingCodeId,
290: "visitId", visit.get("visitId"),
291: "fromDate", UtilDateTime.nowTimestamp(),
292: "sourceEnumId", "TKCDSRC_URL_PARAM"));
293: try {
294: trackingCodeVisit.create();
295: } catch (GenericEntityException e) {
296: Debug.logError(e,
297: "Error while saving TrackingCodeVisit", module);
298: }
299: }
300:
301: // write trackingCode cookies with the value set to the trackingCodeId
302: // NOTE: just write these cookies and if others exist from other tracking codes they will be overwritten, ie only keep the newest
303:
304: // load the properties from the website entity
305: String cookieDomain = null;
306:
307: String webSiteId = WebSiteWorker.getWebSiteId(request);
308: if (webSiteId != null) {
309: try {
310: GenericValue webSite = delegator.findByPrimaryKeyCache(
311: "WebSite", UtilMisc.toMap("webSiteId",
312: webSiteId));
313: if (webSite != null) {
314: cookieDomain = webSite.getString("cookieDomain");
315: }
316: } catch (GenericEntityException e) {
317: Debug
318: .logWarning(
319: e,
320: "Problems with WebSite entity; using global default cookie domain",
321: module);
322: }
323: }
324:
325: if (cookieDomain == null) {
326: cookieDomain = UtilProperties.getPropertyValue("url",
327: "cookie.domain", "");
328: }
329:
330: // if trackingCode.trackableLifetime not null and is > 0 write a trackable cookie with name in the form: TKCDT_{trackingCode.trackingCodeTypeId} and timeout will be trackingCode.trackableLifetime
331: Long trackableLifetime = trackingCode
332: .getLong("trackableLifetime");
333: if (trackableLifetime != null
334: && trackableLifetime.longValue() > 0) {
335: Cookie trackableCookie = new Cookie("TKCDT_"
336: + trackingCode.getString("trackingCodeTypeId"),
337: trackingCode.getString("trackingCodeId"));
338: trackableCookie.setMaxAge(trackableLifetime.intValue());
339: trackableCookie.setPath("/");
340: trackableCookie.setVersion(1);
341: if (cookieDomain.length() > 0)
342: trackableCookie.setDomain(cookieDomain);
343: response.addCookie(trackableCookie);
344: }
345:
346: // if trackingCode.billableLifetime not null and is > 0 write a billable cookie with name in the form: TKCDB_{trackingCode.trackingCodeTypeId} and timeout will be trackingCode.billableLifetime
347: Long billableLifetime = trackingCode
348: .getLong("billableLifetime");
349: if (billableLifetime != null
350: && billableLifetime.longValue() > 0) {
351: Cookie billableCookie = new Cookie("TKCDB_"
352: + trackingCode.getString("trackingCodeTypeId"),
353: trackingCode.getString("trackingCodeId"));
354: billableCookie.setMaxAge(billableLifetime.intValue());
355: billableCookie.setPath("/");
356: billableCookie.setVersion(1);
357: if (cookieDomain.length() > 0)
358: billableCookie.setDomain(cookieDomain);
359: response.addCookie(billableCookie);
360: }
361:
362: // if we have overridden logo, css and/or catalogId set some session attributes
363: HttpSession session = request.getSession();
364: String overrideLogo = trackingCode.getString("overrideLogo");
365: if (overrideLogo != null)
366: session.setAttribute("overrideLogo", overrideLogo);
367: String overrideCss = trackingCode.getString("overrideCss");
368: if (overrideCss != null)
369: session.setAttribute("overrideCss", overrideCss);
370: String prodCatalogId = trackingCode.getString("prodCatalogId");
371: if (prodCatalogId != null && prodCatalogId.length() > 0) {
372: session.setAttribute("CURRENT_CATALOG_ID", prodCatalogId);
373: CategoryWorker.setTrail(request, new ArrayList());
374: }
375:
376: // if forward/redirect is needed, do a response.sendRedirect and return null to tell the control servlet to not do any other requests/views
377: String redirectUrl = trackingCode.getString("redirectUrl");
378: if (UtilValidate.isNotEmpty(redirectUrl)) {
379: try {
380: response.sendRedirect(redirectUrl);
381: } catch (java.io.IOException e) {
382: Debug.logError(e,
383: "Could not redirect as requested in the trackingCode to: "
384: + redirectUrl, module);
385: }
386: return null;
387: }
388:
389: return "success";
390: }
391:
392: /** If attaching TrackingCode Cookies to the visit is desired this event should be added to the list
393: * of events that run on the first hit in a visit.
394: */
395: public static String checkTrackingCodeCookies(
396: HttpServletRequest request, HttpServletResponse response) {
397: GenericDelegator delegator = (GenericDelegator) request
398: .getAttribute("delegator");
399: java.sql.Timestamp nowStamp = UtilDateTime.nowTimestamp();
400: GenericValue visit = VisitHandler
401: .getVisit(request.getSession());
402: if (visit == null) {
403: Debug
404: .logWarning(
405: "Could not get visit, not checking trackingCode cookies to associate with visit",
406: module);
407: } else {
408: // loop through cookies and look for ones with a name that starts with TKCDT_ for trackable cookies
409: Cookie[] cookies = request.getCookies();
410:
411: if (cookies != null && cookies.length > 0) {
412: for (int i = 0; i < cookies.length; i++) {
413: if (cookies[i].getName().startsWith("TKCDT_")) {
414: String trackingCodeId = cookies[i].getValue();
415: GenericValue trackingCode = null;
416: try {
417: trackingCode = delegator
418: .findByPrimaryKeyCache(
419: "TrackingCode",
420: UtilMisc.toMap(
421: "trackingCodeId",
422: trackingCodeId));
423: } catch (GenericEntityException e) {
424: Debug
425: .logError(
426: e,
427: "Error looking up TrackingCode with trackingCodeId ["
428: + trackingCodeId
429: + "], ignoring this trackingCodeId",
430: module);
431: continue;
432: }
433:
434: if (trackingCode == null) {
435: Debug
436: .logError(
437: "TrackingCode not found for trackingCodeId ["
438: + trackingCodeId
439: + "], ignoring this trackingCodeId.",
440: module);
441: //this return value will be ignored, but we'll designate this as an error anyway
442: continue;
443: }
444:
445: //check effective dates
446: if (trackingCode.get("fromDate") != null
447: && nowStamp.before(trackingCode
448: .getTimestamp("fromDate"))) {
449: if (Debug.infoOn())
450: Debug
451: .logInfo(
452: "The TrackingCode with ID ["
453: + trackingCodeId
454: + "] has not yet gone into effect, ignoring this trackingCodeId",
455: module);
456: continue;
457: }
458: if (trackingCode.get("thruDate") != null
459: && nowStamp.after(trackingCode
460: .getTimestamp("thruDate"))) {
461: if (Debug.infoOn())
462: Debug
463: .logInfo(
464: "The TrackingCode with ID ["
465: + trackingCodeId
466: + "] has expired, ignoring this trackingCodeId",
467: module);
468: continue;
469: }
470:
471: // for each trackingCodeId found in this way attach to the visit with the TKCDSRC_COOKIE sourceEnumId
472: GenericValue trackingCodeVisit = delegator
473: .makeValue("TrackingCodeVisit",
474: UtilMisc.toMap(
475: "trackingCodeId",
476: trackingCodeId,
477: "visitId",
478: visit.get("visitId"),
479: "fromDate", nowStamp,
480: "sourceEnumId",
481: "TKCDSRC_COOKIE"));
482: try {
483: //not doing this inside a transaction, want each one possible to go in
484: trackingCodeVisit.create();
485: } catch (GenericEntityException e) {
486: Debug
487: .logError(
488: e,
489: "Error while saving TrackingCodeVisit",
490: module);
491: //don't return error, want to get as many as possible: return "error";
492: }
493: }
494: }
495: }
496: }
497:
498: return "success";
499: }
500:
501: /** Makes a list of TrackingCodeOrder entities to be attached to the current order; called by the createOrder event; the values in the returned List will not have the orderId set */
502: public static List makeTrackingCodeOrders(HttpServletRequest request) {
503: GenericDelegator delegator = (GenericDelegator) request
504: .getAttribute("delegator");
505: java.sql.Timestamp nowStamp = UtilDateTime.nowTimestamp();
506: List trackingCodeOrders = new LinkedList();
507:
508: Cookie[] cookies = request.getCookies();
509: if (cookies != null && cookies.length > 0) {
510: for (int i = 0; i < cookies.length; i++) {
511: // find any that start with TKCDB_ for billable tracking code cookies with isBillable=Y
512: // also and for each TKCDT_ cookie that doesn't have a corresponding billable code add it to the list with isBillable=N
513:
514: String isBillable = null;
515: String cookieName = cookies[i].getName();
516: if (cookieName.startsWith("TKCDB_")) {
517: isBillable = "Y";
518: } else if (cookieName.startsWith("TKCDT_")) {
519: isBillable = "N";
520: }
521:
522: if (isBillable != null) {
523: String trackingCodeId = cookies[i].getValue();
524: GenericValue trackingCode = null;
525: try {
526: trackingCode = delegator.findByPrimaryKeyCache(
527: "TrackingCode", UtilMisc.toMap(
528: "trackingCodeId",
529: trackingCodeId));
530: } catch (GenericEntityException e) {
531: Debug
532: .logError(
533: e,
534: "Error looking up TrackingCode with trackingCodeId ["
535: + trackingCodeId
536: + "], ignoring this trackingCodeId",
537: module);
538: continue;
539: }
540:
541: if (trackingCode == null) {
542: Debug
543: .logError(
544: "TrackingCode not found for trackingCodeId ["
545: + trackingCodeId
546: + "], ignoring this trackingCodeId.",
547: module);
548: //this return value will be ignored, but we'll designate this as an error anyway
549: continue;
550: }
551:
552: //check effective dates
553: if (trackingCode.get("fromDate") != null
554: && nowStamp.before(trackingCode
555: .getTimestamp("fromDate"))) {
556: if (Debug.infoOn())
557: Debug
558: .logInfo(
559: "The TrackingCode with ID ["
560: + trackingCodeId
561: + "] has not yet gone into effect, ignoring this trackingCodeId",
562: module);
563: continue;
564: }
565: if (trackingCode.get("thruDate") != null
566: && nowStamp.after(trackingCode
567: .getTimestamp("thruDate"))) {
568: if (Debug.infoOn())
569: Debug
570: .logInfo(
571: "The TrackingCode with ID ["
572: + trackingCodeId
573: + "] has expired, ignoring this trackingCodeId",
574: module);
575: continue;
576: }
577:
578: // a quick sanity check here on the trackingCodeTypeId, will just display a warning if this happens but not do anythin about it for now
579:
580: // note: using TKCDB_ only for length because both TKCDB_ and TKCDT_ are the same length
581: String cookieTrackingCodeTypeId = cookieName
582: .substring("TKCDB_".length());
583: if (cookieTrackingCodeTypeId == null
584: || cookieTrackingCodeTypeId.length() == 0) {
585: Debug
586: .logWarning(
587: "The trackingCodeTypeId as part of the cookie name was null or empty",
588: module);
589: } else if (!cookieTrackingCodeTypeId
590: .equals(trackingCode
591: .getString("trackingCodeTypeId"))) {
592: Debug
593: .logWarning(
594: "The trackingCodeTypeId ["
595: + cookieTrackingCodeTypeId
596: + "] as part of the cookie name was equal to the current trackingCodeTypeId ["
597: + trackingCode
598: .getString("trackingCodeTypeId")
599: + "] associated with the trackingCodeId ["
600: + trackingCodeId + "]",
601: module);
602: }
603:
604: // this will have everything except the orderId set, that will be set by the createOrder service
605: GenericValue trackingCodeOrder = delegator
606: .makeValue(
607: "TrackingCodeOrder",
608: UtilMisc
609: .toMap(
610: "trackingCodeTypeId",
611: trackingCode
612: .get("trackingCodeTypeId"),
613: "trackingCodeId",
614: trackingCodeId,
615: "isBillable",
616: isBillable));
617:
618: trackingCodeOrders.add(trackingCodeOrder);
619: }
620: }
621: }
622:
623: return trackingCodeOrders;
624: }
625: }
|