You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ja...@apache.org on 2009/05/13 07:01:13 UTC
svn commit: r774198 - in /ofbiz/trunk/applications/party:
servicedef/secas.xml servicedef/services.xml
src/org/ofbiz/party/communication/CommunicationEventServices.java
Author: jaz
Date: Wed May 13 05:01:13 2009
New Revision: 774198
URL: http://svn.apache.org/viewvc?rev=774198&view=rev
Log:
refactored the way communication events are created from emails; there are two services (instead of 1) which run now:
1) in-validate -- creates the communication event so the communication event ID can be used by the send mail service
2) commit -- stores the message content, addresses and now also stores all attachments
Modified:
ofbiz/trunk/applications/party/servicedef/secas.xml
ofbiz/trunk/applications/party/servicedef/services.xml
ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/CommunicationEventServices.java
Modified: ofbiz/trunk/applications/party/servicedef/secas.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/servicedef/secas.xml?rev=774198&r1=774197&r2=774198&view=diff
==============================================================================
--- ofbiz/trunk/applications/party/servicedef/secas.xml (original)
+++ ofbiz/trunk/applications/party/servicedef/secas.xml Wed May 13 05:01:13 2009
@@ -60,11 +60,26 @@
<action service="createWorkEffort" mode="sync"/>
</eca>
- <!-- emails should not be stored as new communication event if there is no partyId or if it is already a commevent being sent out -->
- <eca service="sendMail" event="commit">
+ <!-- email : communication event -->
+ <eca service="sendMailMultiPart" event="in-validate">
+ <condition field-name="partyId" operator="is-not-empty"/>
+ <condition field-name="communicationEventId" operator="is-empty"/>
+ <action service="createCommEventFromEmail" mode="sync" run-as-user="system"/>
+ </eca>
+ <eca service="sendMail" event="in-validate">
<condition field-name="partyId" operator="is-not-empty"/>
- <condition field-name="communicationEventId" operator="is-empty"/>
- <action service="storeEmailAsCommunication" mode="sync"/>
+ <condition field-name="communicationEventId" operator="is-empty"/>
+ <action service="createCommEventFromEmail" mode="sync" run-as-user="system"/>
+ </eca>
+ <eca service="sendMailMultiPart" event="commit">
+ <condition field-name="messageWrapper" operator="is-not-empty"/>
+ <condition field-name="communicationEventId" operator="is-not-empty"/>
+ <action service="updateCommEventAfterEmail" mode="sync" run-as-user="system"/>
+ </eca>
+ <eca service="sendMail" event="commit">
+ <condition field-name="messageWrapper" operator="is-not-empty"/>
+ <condition field-name="communicationEventId" operator="is-not-empty"/>
+ <action service="updateCommEventAfterEmail" mode="sync" run-as-user="system"/>
</eca>
<!-- all these secas are now replaced by a sheduled job (sendEmailDated) which runs every 5 minutes -->
Modified: ofbiz/trunk/applications/party/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/servicedef/services.xml?rev=774198&r1=774197&r2=774198&view=diff
==============================================================================
--- ofbiz/trunk/applications/party/servicedef/services.xml (original)
+++ ofbiz/trunk/applications/party/servicedef/services.xml Wed May 13 05:01:13 2009
@@ -792,18 +792,30 @@
be of type EMAIL_COMMUNICATION. Will look for a contactMechIdTo to send the emails</description>
<attribute name="communicationEventId" type="String" mode="IN" optional="false"/>
</service>
- <service name="storeEmailAsCommunication" engine="java"
- location="org.ofbiz.party.communication.CommunicationEventServices" invoke="storeEmailAsCommunication" auth="true">
- <description>Store email as a communication event with the status COM_COMPLETE and current timestamp as datetimeStarted and datetimeEnded.
- The communication event will be from the party of the userLogin to the party of the partyId parameter.
- It is meant to run a SECA after a sendMail to record outgoing emails.</description>
- <attribute name="partyId" type="String" mode="IN" optional="true"/>
- <attribute name="communicationEventId" type="String" mode="IN" optional="true"/>
+
+ <!-- email to communication event ECA services -->
+ <service name="createCommEventFromEmail" engine="java"
+ location="org.ofbiz.party.communication.CommunicationEventServices" invoke="createCommEventFromEmail" auth="true">
+ <description>
+ Creates a CommunicationEvent record based on information before running a sendMail service (to be used via ECA)
+ </description>
+ <attribute name="partyId" type="String" mode="IN" optional="true"/>
<attribute name="subject" type="String" mode="IN" optional="false"/>
- <attribute name="body" type="String" mode="IN" optional="false" allow-html="any"/>
+ <attribute name="sendFrom" type="String" mode="IN" optional="false"/>
+ <attribute name="sendTo" type="String" mode="IN" optional="false"/>
<attribute name="contentType" type="String" mode="IN" optional="true"/>
- <attribute name="emailType" type="String" mode="IN" optional="true"/>
+ <attribute name="statusId" type="String" mode="IN" optional="true"/>
+ <attribute name="communicationEventId" type="String" mode="OUT"/>
</service>
+ <service name="updateCommEventAfterEmail" engine="java"
+ location="org.ofbiz.party.communication.CommunicationEventServices" invoke="updateCommEventAfterEmail" auth="true">
+ <description>
+ Updates a CommunicationEvent record after running a sendMail service (to be used via ECA)
+ </description>
+ <attribute name="communicationEventId" type="String" mode="IN" optional="false"/>
+ <attribute name="messageWrapper" type="org.ofbiz.service.mail.MimeMessageWrapper" mode="IN" optional="false"/>
+ </service>
+
<service name="storeIncomingEmail" engine="java"
location="org.ofbiz.party.communication.CommunicationEventServices" invoke="storeIncomingEmail" auth="true">
<description>
Modified: ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/CommunicationEventServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/CommunicationEventServices.java?rev=774198&r1=774197&r2=774198&view=diff
==============================================================================
--- ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/CommunicationEventServices.java (original)
+++ ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/CommunicationEventServices.java Wed May 13 05:01:13 2009
@@ -19,9 +19,6 @@
package org.ofbiz.party.communication;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.nio.ByteBuffer;
import java.sql.Timestamp;
import java.util.Enumeration;
@@ -35,14 +32,8 @@
import java.util.regex.Pattern;
import javax.mail.Address;
-import javax.mail.BodyPart;
-import javax.mail.Header;
import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Part;
import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-
import javolution.util.FastList;
import javolution.util.FastMap;
@@ -391,53 +382,133 @@
return ServiceUtil.returnSuccess();
}
- /**
- * Store email as communication event
- *@param dctx The DispatchContext that this service is operating in
- *@param serviceContext Map containing the input parameters
- *@return Map with the result of the service, the output parameters
+ /*
+ * Store an outgoing email as a communication event;
+ * runs as a pre-invoke ECA on sendMail and sendMultipartMail services
+ * - service should run as the 'system' user
*/
- public static Map<String, Object> storeEmailAsCommunication(DispatchContext dctx, Map<String, ? extends Object> serviceContext) {
+ public static Map<String, Object> createCommEventFromEmail(DispatchContext dctx, Map<String, ? extends Object> context) {
LocalDispatcher dispatcher = dctx.getDispatcher();
- GenericValue userLogin = (GenericValue) serviceContext.get("userLogin");
-
- String subject = (String) serviceContext.get("subject");
- String body = (String) serviceContext.get("body");
- String partyId = (String) serviceContext.get("partyId");
- String communicationEventId = (String) serviceContext.get("communicationEventId");
- String contentType = (String) serviceContext.get("contentType");
- String emailType = (String) serviceContext.get("emailType");
-
- // only create a new communication event if the email is not already associated with one
- if (communicationEventId == null) {
- String partyIdFrom = (String) userLogin.get("partyId");
- Map<String, Object> commEventMap = FastMap.newInstance();
- commEventMap.put("communicationEventTypeId", "EMAIL_COMMUNICATION");
- commEventMap.put("statusId", "COM_COMPLETE");
- commEventMap.put("contactMechTypeId", "EMAIL_ADDRESS");
- commEventMap.put("partyIdFrom", partyIdFrom);
- commEventMap.put("partyIdTo", partyId);
- commEventMap.put("datetimeStarted", UtilDateTime.nowTimestamp());
- commEventMap.put("datetimeEnded", UtilDateTime.nowTimestamp());
- commEventMap.put("subject", subject);
- commEventMap.put("content", body);
- commEventMap.put("userLogin", userLogin);
- commEventMap.put("contentMimeTypeId", contentType);
- String runService = "createCommunicationEvent";
- if ("PARTY_REGIS_CONFIRM".equals(emailType)) {
- runService = "createCommunicationEventWithoutPermission"; // used to create a new Customer, Prospect or Employee
- }
- try {
- dispatcher.runSync(runService, commEventMap);
- } catch (Exception e) {
- Debug.logError(e, "Cannot store email as communication event", module);
- return ServiceUtil.returnError("Cannot store email as communication event; see logs");
- }
+ GenericDelegator delegator = dctx.getDelegator();
+
+ GenericValue userLogin = (GenericValue) context.get("userLogin");
+ String subject = (String) context.get("subject");
+ String sendFrom = (String) context.get("sendFrom");
+ String sendTo = (String) context.get("sendTo");
+ String partyId = (String) context.get("partyId");
+ String contentType = (String) context.get("contentType");
+ String statusId = (String) context.get("statusId");
+ if (statusId == null) {
+ statusId = "COM_PENDING";
}
-
+
+ // get the from contact mech info
+ String contactMechIdFrom = null;
+ String partyIdFrom = null;
+ GenericValue fromCm;
+ try {
+ List<GenericValue> fromCms = delegator.findByAnd("PartyAndContactMech", UtilMisc.toMap("infoString", sendFrom), UtilMisc.toList("-fromDate"));
+ fromCms = EntityUtil.filterByDate(fromCms);
+ fromCm = EntityUtil.getFirst(fromCms);
+ } catch (GenericEntityException e) {
+ Debug.logError(e, module);
+ return ServiceUtil.returnError(e.getMessage());
+ }
+ if (fromCm != null) {
+ contactMechIdFrom = fromCm.getString("contactMechId");
+ partyIdFrom = fromCm.getString("partyId");
+ }
+
+ // get the to contact mech info
+ String contactMechIdTo = null;
+ GenericValue toCm;
+ try {
+ List<GenericValue> toCms = delegator.findByAnd("PartyAndContactMech", UtilMisc.toMap("infoString", sendTo, "partyId", partyId), UtilMisc.toList("-fromDate"));
+ toCms = EntityUtil.filterByDate(toCms);
+ toCm = EntityUtil.getFirst(toCms);
+ } catch (GenericEntityException e) {
+ Debug.logError(e, module);
+ return ServiceUtil.returnError(e.getMessage());
+ }
+ if (toCm != null) {
+ contactMechIdTo = toCm.getString("contactMechId");
+ }
+
+ Timestamp now = UtilDateTime.nowTimestamp();
+
+ Map<String, Object> commEventMap = FastMap.newInstance();
+ commEventMap.put("communicationEventTypeId", "EMAIL_COMMUNICATION");
+ commEventMap.put("contactMechTypeId", "EMAIL_ADDRESS");
+ commEventMap.put("contactMechIdFrom", contactMechIdFrom);
+ commEventMap.put("contactMechIdTo", contactMechIdTo);
+ commEventMap.put("statusId", statusId);
+
+ commEventMap.put("partyIdFrom", partyIdFrom);
+ commEventMap.put("partyIdTo", partyId);
+ commEventMap.put("datetimeStarted", now);
+ commEventMap.put("entryDate", now);
+
+ commEventMap.put("subject", subject);
+ commEventMap.put("userLogin", userLogin);
+ commEventMap.put("contentMimeTypeId", contentType);
+
+ Map<String, Object> createResult;
+ try {
+ createResult = dispatcher.runSync("createCommunicationEvent", commEventMap);
+ } catch (GenericServiceException e) {
+ Debug.logError(e, module);
+ return ServiceUtil.returnError(e.getMessage());
+ }
+ if (ServiceUtil.isError(createResult)) {
+ return ServiceUtil.returnError(ServiceUtil.getErrorMessage(createResult));
+ }
+ String communicationEventId = (String) createResult.get("communicationEventId");
+
+ Map<String, Object> result = ServiceUtil.returnSuccess();
+ result.put("communicationEventId", communicationEventId);
+ return result;
+ }
+
+ /*
+ * Update the communication event with information from the email;
+ * runs as a post-commit ECA on sendMail and sendMultiPartMail services
+ * - service should run as the 'system' user
+ */
+ public static Map<String, Object> updateCommEventAfterEmail(DispatchContext dctx, Map<String, ? extends Object> context) {
+ LocalDispatcher dispatcher = dctx.getDispatcher();
+
+ GenericValue userLogin = (GenericValue) context.get("userLogin");
+ String communicationEventId = (String) context.get("communicationEventId");
+ MimeMessageWrapper wrapper = (MimeMessageWrapper) context.get("messageWrapper");
+
+ Map<String, Object> commEventMap = FastMap.newInstance();
+ commEventMap.put("communicationEventId", communicationEventId);
+ commEventMap.put("statusId", "COM_COMPLETE");
+ commEventMap.put("datetimeEnded", UtilDateTime.nowTimestamp());
+ commEventMap.put("messageId", wrapper.getMessageId());
+ commEventMap.put("userLogin", userLogin);
+ commEventMap.put("content", wrapper.getMessageBody());
+
+ // populate the address (to/from/cc/bcc) data
+ populateAddressesFromMessage(wrapper, commEventMap);
+
+ // save the communication event
+ try {
+ dispatcher.runSync("updateCommunicationEvent", commEventMap);
+ } catch (GenericServiceException e) {
+ return ServiceUtil.returnError(e.getMessage());
+ }
+
+ // attachments
+ try {
+ createAttachmentContent(dispatcher, wrapper, communicationEventId, userLogin);
+ } catch (GenericServiceException e) {
+ return ServiceUtil.returnError(e.getMessage());
+ }
+
return ServiceUtil.returnSuccess();
}
-
+
/**
* This service is the main one for processing incoming emails.
*
@@ -623,37 +694,9 @@
}
}
- // Retrieve all the addresses from the email
- Set<String> emailAddressesFrom = new TreeSet<String>();
- Set<String> emailAddressesTo = new TreeSet<String>();
- Set<String> emailAddressesCC = new TreeSet<String>();
- Set<String> emailAddressesBCC = new TreeSet<String>();
- for (int x = 0 ; x < addressesFrom.length ; x++) {
- emailAddressesFrom.add(((InternetAddress) addressesFrom[x]).getAddress());
- }
- for (int x = 0 ; x < addressesTo.length ; x++) {
- emailAddressesTo.add(((InternetAddress) addressesTo[x]).getAddress());
- }
- if (addressesCC != null) {
- for (int x = 0 ; x < addressesCC.length ; x++) {
- emailAddressesCC.add(((InternetAddress) addressesCC[x]).getAddress());
- }
- }
- if (addressesBCC != null) {
- for (int x = 0 ; x < addressesBCC.length ; x++) {
- emailAddressesBCC.add(((InternetAddress) addressesBCC[x]).getAddress());
- }
- }
- String fromString = StringUtil.join(UtilMisc.toList(emailAddressesFrom), ",");
- String toString = StringUtil.join(UtilMisc.toList(emailAddressesTo), ",");
- String ccString = StringUtil.join(UtilMisc.toList(emailAddressesCC), ",");
- String bccString = StringUtil.join(UtilMisc.toList(emailAddressesBCC), ",");
-
- if (UtilValidate.isNotEmpty(fromString)) commEventMap.put("fromString", fromString);
- if (UtilValidate.isNotEmpty(toString)) commEventMap.put("toString", toString);
- if (UtilValidate.isNotEmpty(ccString)) commEventMap.put("ccString", ccString);
- if (UtilValidate.isNotEmpty(bccString)) commEventMap.put("bccString", bccString);
-
+ // populate the address (to/from/cc/bcc) data
+ populateAddressesFromMessage(wrapper, commEventMap);
+
// store from/to parties, but when not found make a note of the email to/from address in the workEffort Note Section.
String commNote = "";
if (partyIdFrom != null) {
@@ -703,51 +746,8 @@
communicationEventId = (String)result.get("communicationEventId");
// handle the attachments
- List<String> attachmentIndexes = wrapper.getAttachmentIndexes();
- if (attachmentIndexes.size() > 0) {
- Debug.logInfo("=== message has attachments [" + attachmentIndexes.size() + "] =====", module);
- for (String attachmentIdx : attachmentIndexes) {
- Map<String, Object> attachmentMap = FastMap.newInstance();
- attachmentMap.put("communicationEventId", communicationEventId);
- attachmentMap.put("contentTypeId", "DOCUMENT");
- attachmentMap.put("mimeTypeId", "text/html");
- attachmentMap.put("userLogin", userLogin);
- if (subject != null && subject.length() > 80) {
- subject = subject.substring(0,80); // make sure not too big for database field. (20 characters for filename)
- }
-
- String attFileName = wrapper.getPartFilename(attachmentIdx);
- String attContentType = wrapper.getPartContentType(attachmentIdx);
- if (attContentType != null && attContentType.indexOf(";") > -1) {
- attContentType = attContentType.toLowerCase().substring(0, attContentType.indexOf(";"));
- }
-
- if (!UtilValidate.isEmpty(attFileName)) {
- attachmentMap.put("contentName", attFileName);
- attachmentMap.put("description", subject + "-" + attachmentIdx);
- } else {
- attachmentMap.put("contentName", subject + "-" + attachmentIdx);
- }
-
- attachmentMap.put("drMimeTypeId", attContentType);
- if (attContentType.startsWith("text")) {
- String text = wrapper.getPartText(attachmentIdx);
- attachmentMap.put("drDataResourceTypeId", "ELECTRONIC_TEXT");
- attachmentMap.put("textData", text);
- } else {
- ByteBuffer data = wrapper.getPartByteBuffer(attachmentIdx);
- if (Debug.infoOn()) Debug.logInfo("Binary attachment size: " + data.limit(), module);
- attachmentMap.put("drDataResourceName", attFileName);
- attachmentMap.put("imageData", data);
- attachmentMap.put("drDataResourceTypeId", "IMAGE_OBJECT"); // TODO: why always use IMAGE
- attachmentMap.put("_imageData_contentType", attContentType);
- }
-
- // save the content
- dispatcher.runSync("createCommContentDataResource", attachmentMap);
- }
- }
-
+ createAttachmentContent(dispatcher, wrapper, communicationEventId, userLogin);
+
// For all addresses create a CommunicationEventRoles
createCommEventRoles(userLogin, delegator, dispatcher, communicationEventId, toParties, "ADDRESSEE");
createCommEventRoles(userLogin, delegator, dispatcher, communicationEventId, ccParties, "CC");
@@ -769,6 +769,94 @@
}
}
+ private static void populateAddressesFromMessage(MimeMessageWrapper wrapper, Map<String, Object> commEventMap) {
+ // Retrieve all the addresses from the email
+ Address[] addressesFrom = wrapper.getFrom();
+ Address[] addressesTo = wrapper.getTo();
+ Address[] addressesCC = wrapper.getCc();
+ Address[] addressesBCC = wrapper.getBcc();
+
+ Set<String> emailAddressesFrom = new TreeSet<String>();
+ Set<String> emailAddressesTo = new TreeSet<String>();
+ Set<String> emailAddressesCC = new TreeSet<String>();
+ Set<String> emailAddressesBCC = new TreeSet<String>();
+ for (int x = 0 ; x < addressesFrom.length ; x++) {
+ emailAddressesFrom.add(((InternetAddress) addressesFrom[x]).getAddress());
+ }
+ for (int x = 0 ; x < addressesTo.length ; x++) {
+ emailAddressesTo.add(((InternetAddress) addressesTo[x]).getAddress());
+ }
+ if (addressesCC != null) {
+ for (int x = 0 ; x < addressesCC.length ; x++) {
+ emailAddressesCC.add(((InternetAddress) addressesCC[x]).getAddress());
+ }
+ }
+ if (addressesBCC != null) {
+ for (int x = 0 ; x < addressesBCC.length ; x++) {
+ emailAddressesBCC.add(((InternetAddress) addressesBCC[x]).getAddress());
+ }
+ }
+ String fromString = StringUtil.join(UtilMisc.toList(emailAddressesFrom), ",");
+ String toString = StringUtil.join(UtilMisc.toList(emailAddressesTo), ",");
+ String ccString = StringUtil.join(UtilMisc.toList(emailAddressesCC), ",");
+ String bccString = StringUtil.join(UtilMisc.toList(emailAddressesBCC), ",");
+
+ if (UtilValidate.isNotEmpty(fromString)) commEventMap.put("fromString", fromString);
+ if (UtilValidate.isNotEmpty(toString)) commEventMap.put("toString", toString);
+ if (UtilValidate.isNotEmpty(ccString)) commEventMap.put("ccString", ccString);
+ if (UtilValidate.isNotEmpty(bccString)) commEventMap.put("bccString", bccString);
+ }
+
+ private static void createAttachmentContent(LocalDispatcher dispatcher, MimeMessageWrapper wrapper, String communicationEventId, GenericValue userLogin) throws GenericServiceException {
+ // handle the attachments
+ String subject = wrapper.getSubject();
+ List<String> attachmentIndexes = wrapper.getAttachmentIndexes();
+
+ if (attachmentIndexes.size() > 0) {
+ Debug.logInfo("=== message has attachments [" + attachmentIndexes.size() + "] =====", module);
+ for (String attachmentIdx : attachmentIndexes) {
+ Map<String, Object> attachmentMap = FastMap.newInstance();
+ attachmentMap.put("communicationEventId", communicationEventId);
+ attachmentMap.put("contentTypeId", "DOCUMENT");
+ attachmentMap.put("mimeTypeId", "text/html");
+ attachmentMap.put("userLogin", userLogin);
+ if (subject != null && subject.length() > 80) {
+ subject = subject.substring(0,80); // make sure not too big for database field. (20 characters for filename)
+ }
+
+ String attFileName = wrapper.getPartFilename(attachmentIdx);
+ String attContentType = wrapper.getPartContentType(attachmentIdx);
+ if (attContentType != null && attContentType.indexOf(";") > -1) {
+ attContentType = attContentType.toLowerCase().substring(0, attContentType.indexOf(";"));
+ }
+
+ if (!UtilValidate.isEmpty(attFileName)) {
+ attachmentMap.put("contentName", attFileName);
+ attachmentMap.put("description", subject + "-" + attachmentIdx);
+ } else {
+ attachmentMap.put("contentName", subject + "-" + attachmentIdx);
+ }
+
+ attachmentMap.put("drMimeTypeId", attContentType);
+ if (attContentType.startsWith("text")) {
+ String text = wrapper.getPartText(attachmentIdx);
+ attachmentMap.put("drDataResourceTypeId", "ELECTRONIC_TEXT");
+ attachmentMap.put("textData", text);
+ } else {
+ ByteBuffer data = wrapper.getPartByteBuffer(attachmentIdx);
+ if (Debug.infoOn()) Debug.logInfo("Binary attachment size: " + data.limit(), module);
+ attachmentMap.put("drDataResourceName", attFileName);
+ attachmentMap.put("imageData", data);
+ attachmentMap.put("drDataResourceTypeId", "IMAGE_OBJECT"); // TODO: why always use IMAGE
+ attachmentMap.put("_imageData_contentType", attContentType);
+ }
+
+ // save the content
+ dispatcher.runSync("createCommContentDataResource", attachmentMap);
+ }
+ }
+ }
+
private static void createCommEventRoles(GenericValue userLogin, GenericDelegator delegator, LocalDispatcher dispatcher, String communicationEventId, List<Map<String, Object>> parties, String roleTypeId) {
// It's not clear what the "role" of this communication event should be, so we'll just put _NA_
// check and see if this role was already created and ignore if true