Author: jonesde
Date: Sun Feb 15 19:34:49 2009 New Revision: 744727 URL: http://svn.apache.org/viewvc?rev=744727&view=rev Log: No functional changes, just reorganizing code: moved email services from content to the framework/common component except the CommunicationEvent related ones which are now in the party component along with other CommunicationEvent resources; changed framework components so that webapp no longer depends on common and common is higher level than the various tool components which was an odd dependency before; one new thing is in here and that is an entity called EmailTemplateSetting which is meant to be a generic version of the ProductStoreEmailSetting entity so we can have configurable email templates without depending on ProductStore, still need to write the service to send email from this (sendMailFromTemplateSetting) Added: ofbiz/trunk/framework/base/lib/fop-0.94.jar - copied unchanged from r744706, ofbiz/trunk/framework/webapp/lib/fop-0.94.jar ofbiz/trunk/framework/common/servicedef/services_email.xml - copied, changed from r744706, ofbiz/trunk/applications/content/servicedef/services_email.xml ofbiz/trunk/framework/common/src/org/ofbiz/common/email/ ofbiz/trunk/framework/common/src/org/ofbiz/common/email/EmailServices.java - copied, changed from r744706, ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java ofbiz/trunk/framework/common/src/org/ofbiz/common/email/NotificationServices.java - copied, changed from r744706, ofbiz/trunk/applications/content/src/org/ofbiz/content/email/NotificationServices.java Removed: ofbiz/trunk/applications/content/servicedef/services_email.xml ofbiz/trunk/applications/content/src/org/ofbiz/content/email/ ofbiz/trunk/framework/webapp/lib/fop-0.94.jar Modified: ofbiz/trunk/.classpath ofbiz/trunk/applications/content/build.xml ofbiz/trunk/applications/content/entitydef/entitymodel.xml ofbiz/trunk/applications/content/ofbiz-component.xml ofbiz/trunk/applications/content/src/org/ofbiz/content/data/DataResourceWorker.java ofbiz/trunk/applications/party/servicedef/services.xml ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/CommunicationEventServices.java ofbiz/trunk/framework/build.xml ofbiz/trunk/framework/common/build.xml ofbiz/trunk/framework/common/entitydef/entitymodel.xml ofbiz/trunk/framework/common/ofbiz-component.xml ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java ofbiz/trunk/framework/webapp/build.xml ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/LoginWorker.java Modified: ofbiz/trunk/.classpath URL: http://svn.apache.org/viewvc/ofbiz/trunk/.classpath?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/.classpath (original) +++ ofbiz/trunk/.classpath Sun Feb 15 19:34:49 2009 @@ -135,7 +135,7 @@ <classpathentry kind="lib" path="framework/base/lib/scripting/groovy-1.5.6.jar"/> <classpathentry kind="lib" path="framework/base/lib/jpim-0.1.jar"/> <classpathentry kind="lib" path="framework/base/lib/freemarker-2.3.15.jar"/> - <classpathentry kind="lib" path="framework/base/lib/owasp-esapi-full-java-1.4.jar"/> + <classpathentry kind="lib" path="framework/base/lib/owasp-esapi-full-java-1.4.jar"/> <classpathentry kind="lib" path="framework/webapp/lib/json-lib-2.2.3-jdk15.jar"/> <classpathentry kind="lib" path="framework/webapp/lib/ezmorph-0.9.1.jar"/> <classpathentry kind="lib" path="specialpurpose/pos/lib/looks-2.0.2.jar"/> @@ -145,7 +145,6 @@ <classpathentry kind="lib" path="framework/webapp/lib/xmlgraphics-commons-1.2.jar"/> <classpathentry kind="lib" path="framework/webapp/lib/rome-0.9.jar"/> <classpathentry kind="lib" path="framework/webapp/lib/jdom-1.0.jar"/> - <classpathentry kind="lib" path="framework/webapp/lib/fop-0.94.jar"/> <classpathentry kind="lib" path="framework/webapp/lib/barcode4j-fop-ext-0.93.jar"/> <classpathentry kind="lib" path="framework/webapp/lib/ws-commons-java5-1.0.1.jar"/> <classpathentry kind="lib" path="framework/webapp/lib/ws-commons-util-1.0.1.jar"/> @@ -153,5 +152,8 @@ <classpathentry kind="lib" path="framework/webapp/lib/xmlrpc-server-3.0.jar"/> <classpathentry kind="lib" path="framework/webapp/lib/xmlrpc-client-3.0.jar"/> <classpathentry exported="true" kind="con" path="GROOVY_SUPPORT"/> + <classpathentry kind="lib" path="framework/base/lib/antisamy-bin.1.2.jar"/> + <classpathentry kind="lib" path="framework/base/lib/fop-0.94.jar"/> + <classpathentry kind="lib" path="framework/base/lib/nekohtml.jar"/> <classpathentry kind="output" path="bin"/> </classpath> Modified: ofbiz/trunk/applications/content/build.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/build.xml?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/applications/content/build.xml (original) +++ ofbiz/trunk/applications/content/build.xml Sun Feb 15 19:34:49 2009 @@ -46,6 +46,7 @@ <fileset dir="../../framework/webapp/lib" includes="*.jar"/> <fileset dir="../../framework/webapp/build/lib" includes="*.jar"/> <fileset dir="../../framework/widget/build/lib" includes="*.jar"/> + <fileset dir="../../framework/common/build/lib" includes="*.jar"/> </path> <patternset id="src.exc.set"> Modified: ofbiz/trunk/applications/content/entitydef/entitymodel.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/entitydef/entitymodel.xml?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/applications/content/entitydef/entitymodel.xml (original) +++ ofbiz/trunk/applications/content/entitydef/entitymodel.xml Sun Feb 15 19:34:49 2009 @@ -36,6 +36,7 @@ <!-- - org.ofbiz.content.content --> <!-- - org.ofbiz.content.data --> <!-- - org.ofbiz.content.document --> + <!-- - org.ofbiz.content.email --> <!-- - org.ofbiz.content.preference --> <!-- - org.ofbiz.content.survey --> <!-- - org.ofbiz.content.website --> @@ -1123,7 +1124,7 @@ <!-- ========================================================= --> <!-- org.ofbiz.content.preference --> <!-- ========================================================= --> - + <entity entity-name="WebPreferenceType" package-name="org.ofbiz.content.preference" title="Web Preference Type Entity"> Modified: ofbiz/trunk/applications/content/ofbiz-component.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/ofbiz-component.xml?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/applications/content/ofbiz-component.xml (original) +++ ofbiz/trunk/applications/content/ofbiz-component.xml Sun Feb 15 19:34:49 2009 @@ -50,7 +50,6 @@ <service-resource type="model" loader="main" location="servicedef/services_content.xml"/> <service-resource type="model" loader="main" location="servicedef/services_contenttypes.xml"/> <service-resource type="model" loader="main" location="servicedef/services_data.xml"/> - <service-resource type="model" loader="main" location="servicedef/services_email.xml"/> <service-resource type="model" loader="main" location="servicedef/services_output.xml"/> <service-resource type="model" loader="main" location="servicedef/services_survey.xml"/> <service-resource type="model" loader="main" location="servicedef/services_commevent.xml"/> Modified: ofbiz/trunk/applications/content/src/org/ofbiz/content/data/DataResourceWorker.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/src/org/ofbiz/content/data/DataResourceWorker.java?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/applications/content/src/org/ofbiz/content/data/DataResourceWorker.java (original) +++ ofbiz/trunk/applications/content/src/org/ofbiz/content/data/DataResourceWorker.java Sun Feb 15 19:34:49 2009 @@ -18,13 +18,21 @@ *******************************************************************************/ package org.ofbiz.content.data; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringWriter; +import java.io.Writer; import java.net.URL; import java.net.URLConnection; import java.nio.ByteBuffer; import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -41,6 +49,7 @@ import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.ofbiz.base.location.FlexibleLocation; import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.FileUtil; import org.ofbiz.base.util.GeneralException; @@ -51,9 +60,8 @@ import org.ofbiz.base.util.UtilXml; import org.ofbiz.base.util.collections.MapStack; import org.ofbiz.base.util.template.FreeMarkerWorker; -import org.ofbiz.base.location.FlexibleLocation; +import org.ofbiz.common.email.NotificationServices; import org.ofbiz.content.content.UploadContentAndImage; -import org.ofbiz.content.email.NotificationServices; import org.ofbiz.entity.GenericDelegator; import org.ofbiz.entity.GenericEntityException; import org.ofbiz.entity.GenericValue; @@ -69,7 +77,6 @@ import freemarker.template.Template; import freemarker.template.TemplateException; -import javolution.util.FastMap; /** * DataResourceWorker Class Modified: ofbiz/trunk/applications/party/servicedef/services.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/servicedef/services.xml?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/applications/party/servicedef/services.xml (original) +++ ofbiz/trunk/applications/party/servicedef/services.xml Sun Feb 15 19:34:49 2009 @@ -773,7 +773,33 @@ 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"/> + <attribute name="subject" type="String" mode="IN" optional="false"/> + <attribute name="body" type="String" mode="IN" optional="false" allow-html="any"/> + <attribute name="contentType" type="String" mode="IN" optional="true"/> + <attribute name="emailType" type="String" mode="IN" optional="true"/> + </service> + <service name="storeIncomingEmail" engine="java" + location="org.ofbiz.party.communication.CommunicationEventServices" invoke="storeIncomingEmail" auth="true"> + <description> + Process incoming email. Try to determine partyIdFrom from the first SendFrom email address. datetimeStarted and datetimeEnded are the + sent and received dates respectively, partyIdTo is from the first SendTo email address or the delivered-to address. If the parties are not found, + the email addresses are stored in CommunicationEvent.note + If however it is detected as spam (external) or when the 'from' email address is missing, the service will not return a communicationEventId. + If the party cannot be found the status of the communicationEvent will be set to: COM_UNKNOWN_PARTY. + If the parties are found the status is set to COM_ENTERED + </description> + <attribute name="messageWrapper" type="org.ofbiz.service.mail.MimeMessageWrapper" mode="IN"/> + <attribute name="communicationEventId" type="String" mode="OUT" optional="true"/> + <attribute name="statusId" type="String" mode="OUT" optional="true"/> + </service> + <service name="sendEmailToContactList" engine="java" location="org.ofbiz.party.communication.CommunicationEventServices" invoke="sendEmailToContactList" auth="true" use-transaction="false" max-retry="3"> <!-- Individual emails will be wrapped in their own transactions --> 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=744727&r1=744726&r2=744727&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 Sun Feb 15 19:34:49 2009 @@ -19,12 +19,35 @@ package org.ofbiz.party.communication; -import java.util.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.sql.Timestamp; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import javax.mail.Address; +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; -import org.ofbiz.base.util.*; +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.StringUtil; +import org.ofbiz.base.util.UtilDateTime; +import org.ofbiz.base.util.UtilMisc; +import org.ofbiz.base.util.UtilProperties; +import org.ofbiz.base.util.UtilValidate; import org.ofbiz.entity.GenericDelegator; import org.ofbiz.entity.GenericEntityException; import org.ofbiz.entity.GenericValue; @@ -37,6 +60,7 @@ import org.ofbiz.service.GenericServiceException; import org.ofbiz.service.LocalDispatcher; import org.ofbiz.service.ServiceUtil; +import org.ofbiz.service.mail.MimeMessageWrapper; public class CommunicationEventServices { @@ -324,4 +348,570 @@ 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 + */ + public static Map<String, Object> storeEmailAsCommunication(DispatchContext dctx, Map<String, ? extends Object> serviceContext) { + 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 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"); + } + } + + return ServiceUtil.returnSuccess(); + } + + /** + * This service is the main one for processing incoming emails. + * + * Its only argument is a wrapper for the JavaMail MimeMessage object. + * From this object, all the fields, headers and content of the message can be accessed. + * + * The first thing this service does is try to discover the partyId of the message sender + * by doing a reverse find on the email address. It uses the findPartyFromEmailAddress service to do this. + * + * It then creates a CommunicationEvent entity by calling the createCommunicationEvent service using the appropriate fields from the email and the + * discovered partyId, if it exists, as the partyIdFrom. Note that it sets the communicationEventTypeId + * field to AUTO_EMAIL_COMM. This is useful for tracking email generated communications. + * + * The service tries to find appropriate content for inclusion in the CommunicationEvent.content field. + * If the contentType of the content starts with "text", the getContent() call returns a string and it is used. + * If the contentType starts with "multipart", then the "parts" of the content are iterated thru and the first + * one of mime type, "text/..." is used. + * + * If the contentType has a value of "multipart" then the parts of the content (except the one used in the main + * CommunicationEvent.content field) are cycled thru and attached to the CommunicationEvent entity using the + * createCommContentDataResource service. This happens in the EmailWorker.addAttachmentsToCommEvent method. + * + * However multiparts can contain multiparts. A recursive function has been added. + * + * -Al Byers - Hans Bakker + * @param dctx + * @param context + * @return + */ + public static Map<String, Object> storeIncomingEmail(DispatchContext dctx, Map<String, ? extends Object> context) { + + GenericDelegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + MimeMessageWrapper wrapper = (MimeMessageWrapper) context.get("messageWrapper"); + MimeMessage message = wrapper.getMessage(); + Timestamp nowTimestamp = UtilDateTime.nowTimestamp(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + String partyIdTo = null; + String partyIdFrom = null; + String contentType = null; + String communicationEventId = null; + String contactMechIdFrom = null; + String contactMechIdTo = null; + + Map result = null; + try { + String contentTypeRaw = message.getContentType(); + int idx = contentTypeRaw.indexOf(";"); + if (idx == -1) idx = contentTypeRaw.length(); + contentType = contentTypeRaw.substring(0, idx); + if (contentType == null || contentType.equals("")) contentType = "text/html"; + contentType = contentType.toLowerCase(); + Address[] addressesFrom = message.getFrom(); + Address[] addressesTo = message.getRecipients(MimeMessage.RecipientType.TO); + Address[] addressesCC = message.getRecipients(MimeMessage.RecipientType.CC); + Address[] addressesBCC = message.getRecipients(MimeMessage.RecipientType.BCC); + String messageId = message.getMessageID(); + + String aboutThisEmail = "message [" + messageId + "] from [" + + (addressesFrom[0] == null? "not found" : addressesFrom[0].toString()) + "] to [" + + (addressesTo[0] == null? "not found" : addressesTo[0].toString()) + "]"; + if (Debug.verboseOn()) Debug.logVerbose("Processing Incoming Email " + aboutThisEmail, module); + + // ignore the message when the spam status = yes + String spamHeaderName = UtilProperties.getPropertyValue("general.properties", "mail.spam.name", "N"); + String configHeaderValue = UtilProperties.getPropertyValue("general.properties", "mail.spam.value"); + // only execute when config file has been set && header variable found + if (!spamHeaderName.equals("N") && message.getHeader(spamHeaderName) != null && message.getHeader(spamHeaderName).length > 0) { + String msgHeaderValue = message.getHeader(spamHeaderName)[0]; + if(msgHeaderValue != null && msgHeaderValue.startsWith(configHeaderValue)) { + Debug.logInfo("Incoming Email message ignored, was detected by external spam checker", module); + return ServiceUtil.returnSuccess(" Message Ignored: detected by external spam checker"); + } + } + + // if no 'from' addresses specified ignore the message + if (addressesFrom == null) { + Debug.logInfo("Incoming Email message ignored, had not 'from' email address", module); + return ServiceUtil.returnSuccess(" Message Ignored: no 'From' address specified"); + } + + // make sure this isn't a duplicate + List commEvents; + try { + commEvents = delegator.findByAnd("CommunicationEvent", UtilMisc.toMap("messageId", messageId)); + } catch (GenericEntityException e) { + Debug.logError(e, module); + return ServiceUtil.returnError(e.getMessage()); + } + if (!commEvents.isEmpty()) { + Debug.logInfo("Ignoring Duplicate Email: " + aboutThisEmail, module); + return ServiceUtil.returnSuccess(" Message Ignored: deplicate messageId"); + } else { + Debug.logInfo("Persisting New Email: " + aboutThisEmail, module); + } + + + // get the related partId's + List toParties = buildListOfPartyInfoFromEmailAddresses(addressesTo, userLogin, dispatcher); + List ccParties = buildListOfPartyInfoFromEmailAddresses(addressesCC, userLogin, dispatcher); + List bccParties = buildListOfPartyInfoFromEmailAddresses(addressesBCC, userLogin, dispatcher); + + //Get the first address from the list - this is the partyIdTo field of the CommunicationEvent + if (!toParties.isEmpty()) { + Iterator itr = toParties.iterator(); + Map firstAddressTo = (Map) itr.next(); + partyIdTo = (String)firstAddressTo.get("partyId"); + contactMechIdTo = (String)firstAddressTo.get("contactMechId"); + } + + String deliveredTo = null; + if (message.getHeader("Delivered-To") != null) { + deliveredTo = message.getHeader("Delivered-To")[0]; + // check if started with the domain name if yes remove including the dash. + String dn = deliveredTo.substring(deliveredTo.indexOf("@")+1, deliveredTo.length()); + if (deliveredTo.startsWith(dn)) { + deliveredTo = deliveredTo.substring(dn.length()+1, deliveredTo.length()); + } + } + + // if partyIdTo not found try to find the "to" address using the delivered-to header + if ((partyIdTo == null) && (deliveredTo != null)) { + result = dispatcher.runSync("findPartyFromEmailAddress", UtilMisc.<String, Object>toMap("address", deliveredTo, "userLogin", userLogin)); + partyIdTo = (String)result.get("partyId"); + contactMechIdTo = (String)result.get("contactMechId"); + } + if (userLogin.get("partyId") == null && partyIdTo != null) { + int ch = 0; + for (ch=partyIdTo.length(); ch > 0 && Character.isDigit(partyIdTo.charAt(ch-1)); ch--) { + ; + } + userLogin.put("partyId", partyIdTo.substring(0,ch)); //allow services to be called to have prefix + } + + // get the 'from' partyId + result = getParyInfoFromEmailAddress(addressesFrom, userLogin, dispatcher); + partyIdFrom = (String)result.get("partyId"); + contactMechIdFrom = (String)result.get("contactMechId"); + + Map commEventMap = FastMap.newInstance(); + commEventMap.put("communicationEventTypeId", "AUTO_EMAIL_COMM"); + commEventMap.put("contactMechTypeId", "EMAIL_ADDRESS"); + commEventMap.put("messageId", messageId); + + String subject = message.getSubject(); + commEventMap.put("subject", subject); + + // Set sent and received dates + commEventMap.put("entryDate", nowTimestamp); + commEventMap.put("datetimeStarted", UtilDateTime.toTimestamp(message.getSentDate())); + commEventMap.put("datetimeEnded", UtilDateTime.toTimestamp(message.getReceivedDate())); + + // default role types (_NA_) + commEventMap.put("roleTypeIdFrom", "_NA_"); + commEventMap.put("roleTypeIdTo", "_NA_"); + + // get the content(type) part + Object messageContent = message.getContent(); + if (contentType.startsWith("text")) { + commEventMap.put("content", messageContent); + commEventMap.put("contentMimeTypeId", contentType); + } else if (messageContent instanceof Multipart) { + contentIndex = ""; + commEventMap = addMessageBody(commEventMap, (Multipart) messageContent); + } + + // check for for a reply to communication event (using in-reply-to the parent messageID) + String[] inReplyTo = message.getHeader("In-Reply-To"); + if (inReplyTo != null && inReplyTo[0] != null) { + GenericValue parentCommEvent = null; + try { + List events = delegator.findByAnd("CommunicationEvent", UtilMisc.toMap("messageId", inReplyTo[0])); + parentCommEvent = EntityUtil.getFirst(events); + } catch (GenericEntityException e) { + Debug.logError(e, module); + } + if (parentCommEvent != null) { + String parentCommEventId = parentCommEvent.getString("communicationEventId"); + String orgCommEventId = parentCommEvent.getString("origCommEventId"); + if (orgCommEventId == null) orgCommEventId = parentCommEventId; + commEventMap.put("parentCommEventId", parentCommEventId); + commEventMap.put("origCommEventId", orgCommEventId); + } + } + + // Retrieve all the addresses from the email + Set emailAddressesFrom = new TreeSet(); + Set emailAddressesTo = new TreeSet(); + Set emailAddressesCC = new TreeSet(); + Set emailAddressesBCC = new TreeSet(); + 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); + + // 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) { + commEventMap.put("partyIdFrom", partyIdFrom); + commEventMap.put("contactMechIdFrom", contactMechIdFrom); + } else { + commNote += "Sent from: " + ((InternetAddress)addressesFrom[0]).getAddress() + "; "; + commNote += "Sent Name from: " + ((InternetAddress)addressesFrom[0]).getPersonal() + "; "; + } + + if (partyIdTo != null) { + commEventMap.put("partyIdTo", partyIdTo); + commEventMap.put("contactMechIdTo", contactMechIdTo); + } else { + commNote += "Sent to: " + ((InternetAddress)addressesTo[0]).getAddress() + "; "; + if (deliveredTo != null) { + commNote += "Delivered-To: " + deliveredTo + "; "; + } + } + + commNote += "Sent to: " + ((InternetAddress)addressesTo[0]).getAddress() + "; "; + commNote += "Delivered-To: " + deliveredTo + "; "; + + if (partyIdTo != null && partyIdFrom != null) { + commEventMap.put("statusId", "COM_ENTERED"); + } else { + commEventMap.put("statusId", "COM_UNKNOWN_PARTY"); + } + if (commNote.length() > 255) commNote = commNote.substring(0,255); + + if (!("".equals(commNote))) { + commEventMap.put("note", commNote); + } + + commEventMap.put("userLogin", userLogin); + + // Populate the CommunicationEvent.headerString field with the email headers + String headerString = ""; + Enumeration headerLines = message.getAllHeaderLines(); + while (headerLines.hasMoreElements()) { + headerString += System.getProperty("line.separator"); + headerString += headerLines.nextElement(); + } + commEventMap.put("headerString", headerString); + + result = dispatcher.runSync("createCommunicationEvent", commEventMap); + communicationEventId = (String)result.get("communicationEventId"); + + if (messageContent instanceof Multipart) { + Debug.logInfo("===message has attachments=====", module); + int attachmentCount = addAttachmentsToCommEvent((Multipart) messageContent, subject, communicationEventId, dispatcher, userLogin); + if (Debug.infoOn()) Debug.logInfo(attachmentCount + " attachments added to CommunicationEvent:" + communicationEventId,module); + } + + // For all addresses create a CommunicationEventRoles + createCommEventRoles(userLogin, delegator, dispatcher, communicationEventId, toParties, "ADDRESSEE"); + createCommEventRoles(userLogin, delegator, dispatcher, communicationEventId, ccParties, "CC"); + createCommEventRoles(userLogin, delegator, dispatcher, communicationEventId, bccParties, "BCC"); + + Map results = ServiceUtil.returnSuccess(); + results.put("communicationEventId", communicationEventId); + results.put("statusId", commEventMap.get("statusId")); + return results; + } catch (MessagingException e) { + Debug.logError(e, module); + return ServiceUtil.returnError(e.getMessage()); + } catch (GenericServiceException e) { + Debug.logError(e, module); + return ServiceUtil.returnError(e.getMessage()); + } catch (IOException e) { + Debug.logError(e, module); + return ServiceUtil.returnError(e.getMessage()); + } catch (Exception e) { + Debug.logError(e, module); + return ServiceUtil.returnError(e.getMessage()); + } + } + + private static void createCommEventRoles(GenericValue userLogin, GenericDelegator delegator, LocalDispatcher dispatcher, String communicationEventId, List 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 + try { + Iterator it = parties.iterator(); + while (it.hasNext()) { + Map result = (Map) it.next(); + String partyId = (String) result.get("partyId"); + GenericValue commEventRole = delegator.findByPrimaryKey("CommunicationEventRole", + UtilMisc.toMap("communicationEventId", communicationEventId, "partyId", partyId, "roleTypeId", roleTypeId)); + if (commEventRole == null) { + Map input = UtilMisc.toMap("communicationEventId", communicationEventId, + "partyId", partyId, "roleTypeId", roleTypeId, "userLogin", userLogin, + "contactMechId", (String) result.get("contactMechId"), + "statusId", "COM_ROLE_CREATED"); + dispatcher.runSync("createCommunicationEventRole", input); + } + } + } catch (GenericServiceException e) { + Debug.logError(e, module); + } catch (Exception e) { + Debug.logError(e, module); + } + } + + /* + * Helper method to retrieve the party information from the first email address of the Address[] specified. + */ + private static Map getParyInfoFromEmailAddress(Address [] addresses, GenericValue userLogin, LocalDispatcher dispatcher) throws GenericServiceException { + InternetAddress emailAddress = null; + Map map = null; + Map result = null; + + if (addresses == null) { + return null; + } + + if (addresses.length > 0) { + Address addr = addresses[0]; + if (addr instanceof InternetAddress) { + emailAddress = (InternetAddress)addr; + } + } + + if (!UtilValidate.isEmpty(emailAddress)) { + map = FastMap.newInstance(); + map.put("address", emailAddress.getAddress()); + map.put("userLogin", userLogin); + result = dispatcher.runSync("findPartyFromEmailAddress", map); + } + + return result; + } + + /* + * Calls findPartyFromEmailAddress service and returns a List of the results for the array of addresses + */ + private static List buildListOfPartyInfoFromEmailAddresses(Address [] addresses, GenericValue userLogin, LocalDispatcher dispatcher) throws GenericServiceException { + InternetAddress emailAddress = null; + Address addr = null; + Map map = null; + Map result = null; + List tempResults = FastList.newInstance(); + + if (addresses != null) { + for (int i = 0; i < addresses.length; i++) { + addr = addresses[i]; + if (addr instanceof InternetAddress) { + emailAddress = (InternetAddress)addr; + + if (!UtilValidate.isEmpty(emailAddress)) { + result = dispatcher.runSync("findPartyFromEmailAddress", + UtilMisc.<String, Object>toMap("address", emailAddress.getAddress(), "userLogin", userLogin)); + if (result.get("partyId") != null) { + tempResults.add(result); + } + } + } + } + } + return tempResults; + } + + public static String contentIndex = ""; + private static Map addMessageBody( Map commEventMap, Multipart multipart) throws MessagingException, IOException { + try { + int multipartCount = multipart.getCount(); + for (int i=0; i < multipartCount && i < 10; i++) { + Part part = multipart.getBodyPart(i); + String thisContentTypeRaw = part.getContentType(); + String content = null; + int idx2 = thisContentTypeRaw.indexOf(";"); + if (idx2 == -1) { + idx2 = thisContentTypeRaw.length(); + } + String thisContentType = thisContentTypeRaw.substring(0, idx2); + if (thisContentType == null || thisContentType.equals("")) thisContentType = "text/html"; + thisContentType = thisContentType.toLowerCase(); + String disposition = part.getDisposition(); + + if (thisContentType.startsWith("multipart") || thisContentType.startsWith("Multipart")) { + contentIndex = contentIndex.concat("." + i); + return addMessageBody(commEventMap, (Multipart) part.getContent()); + } + // See this case where the disposition of the inline text is null + else if ((disposition == null) && (i == 0) && thisContentType.startsWith("text")) { + content = (String)part.getContent(); + if (UtilValidate.isNotEmpty(content)) { + contentIndex = contentIndex.concat("." + i); + commEventMap.put("content", content); + commEventMap.put("contentMimeTypeId", thisContentType); + return commEventMap; + } + } else if ((disposition != null) + && (disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE)) + && thisContentType.startsWith("text")) { + contentIndex = contentIndex.concat("." + i); + commEventMap.put("content", part.getContent()); + commEventMap.put("contentMimeTypeId", thisContentType); + return commEventMap; + } + } + return commEventMap; + } catch (MessagingException e) { + Debug.logError(e, module); + return ServiceUtil.returnError(e.getMessage()); + } catch (IOException e) { + Debug.logError(e, module); + return ServiceUtil.returnError(e.getMessage()); + } + } + + public String getForwardedField(MimeMessage message) { + String fieldValue = null; + return fieldValue; + } + + public static int addAttachmentsToCommEvent(Multipart messageContent, String subject, String communicationEventId, LocalDispatcher dispatcher, GenericValue userLogin) + throws MessagingException, IOException, GenericServiceException { + Map commEventMap = FastMap.newInstance(); + commEventMap.put("communicationEventId", communicationEventId); + commEventMap.put("contentTypeId", "DOCUMENT"); + commEventMap.put("mimeTypeId", "text/html"); + commEventMap.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) + } + currentIndex = ""; + attachmentCount = 0; + return addMultipartAttachementToComm(messageContent, commEventMap, subject, dispatcher, userLogin); + } + private static String currentIndex = ""; + private static int attachmentCount = 0; + private static int addMultipartAttachementToComm(Multipart multipart, Map commEventMap, String subject, LocalDispatcher dispatcher, GenericValue userLogin) + throws MessagingException, IOException, GenericServiceException { + try { + int multipartCount = multipart.getCount(); + // Debug.logInfo(currentIndex + "====number of attachments: " + multipartCount, module); + for (int i=0; i < multipartCount; i++) { + // Debug.logInfo(currentIndex + "====processing attachment: " + i, module); + Part part = multipart.getBodyPart(i); + String thisContentTypeRaw = part.getContentType(); + // Debug.logInfo("====thisContentTypeRaw: " + thisContentTypeRaw, module); + int idx2 = thisContentTypeRaw.indexOf(";"); + if (idx2 == -1) idx2 = thisContentTypeRaw.length(); + String thisContentType = thisContentTypeRaw.substring(0, idx2); + String disposition = part.getDisposition(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + if (part instanceof Multipart) { + currentIndex = currentIndex.concat("." + i); + // Debug.logInfo("=====attachment contain attachment, index:" + currentIndex, module); + return addMultipartAttachementToComm((Multipart) part.getContent(), commEventMap, subject, dispatcher, userLogin); + } + // Debug.logInfo("=====attachment not contains attachment, index:" + currentIndex, module); + // Debug.logInfo("=====check for currentIndex(" + currentIndex + ") against master contentIndex(" + EmailServices.contentIndex + ")", module); + if(currentIndex.concat("." + i).equals(CommunicationEventServices.contentIndex)) continue; + + // The first test should not pass, because if it exists, it should be the bodyContentIndex part + // Debug.logInfo("====check for disposition: " + disposition + " contentType: '" + thisContentType + "' variable i:" + i, module); + if ((disposition == null && thisContentType.startsWith("text")) + || ((disposition != null) + && (disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE)) + ) ) + { + String attFileName = part.getFileName(); + Debug.logInfo("===processing attachment: " + attFileName, module); + if (!UtilValidate.isEmpty(attFileName)) { + commEventMap.put("contentName", attFileName); + commEventMap.put("description", subject + "-" + attachmentCount); + } else { + commEventMap.put("contentName", subject + "-" + attachmentCount); + } + commEventMap.put("drMimeTypeId", thisContentType); + if (thisContentType.startsWith("text")) { + String content = (String)part.getContent(); + commEventMap.put("drDataResourceTypeId", "ELECTRONIC_TEXT"); + commEventMap.put("textData", content); + } else { + InputStream is = part.getInputStream(); + int c; + while ((c = is.read()) > -1) { + baos.write(c); + } + ByteBuffer imageData = ByteBuffer.wrap(baos.toByteArray()); + int len = imageData.limit(); + if (Debug.infoOn()) Debug.logInfo("imageData length: " + len, module); + commEventMap.put("drDataResourceName", part.getFileName()); + commEventMap.put("imageData", imageData); + commEventMap.put("drDataResourceTypeId", "IMAGE_OBJECT"); + commEventMap.put("_imageData_contentType", thisContentType); + } + dispatcher.runSync("createCommContentDataResource", commEventMap); + attachmentCount++; + } + } + } catch (MessagingException e) { + Debug.logError(e, module); + } catch (IOException e) { + Debug.logError(e, module); + } catch (GenericServiceException e) { + Debug.logError(e, module); + } + return attachmentCount; + } } Modified: ofbiz/trunk/framework/build.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/build.xml?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/framework/build.xml (original) +++ ofbiz/trunk/framework/build.xml Sun Feb 15 19:34:49 2009 @@ -27,8 +27,8 @@ catalina/build.xml,jetty/build.xml, security/build.xml,service/build.xml,entityext/build.xml, bi/build.xml,datafile/build.xml,minilang/build.xml, - common/build.xml, webapp/build.xml,guiapp/build.xml,widget/build.xml, + common/build.xml, testtools/build.xml, appserver/build.xml,webtools/build.xml,example/build.xml"/> Modified: ofbiz/trunk/framework/common/build.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/build.xml?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/framework/common/build.xml (original) +++ ofbiz/trunk/framework/common/build.xml Sun Feb 15 19:34:49 2009 @@ -40,6 +40,8 @@ <fileset dir="../service/lib" includes="*.jar"/> <fileset dir="../service/build/lib" includes="*.jar"/> <fileset dir="../entityext/build/lib" includes="*.jar"/> + <fileset dir="../webapp/build/lib" includes="*.jar"/> + <fileset dir="../widget/build/lib" includes="*.jar"/> </path> <!-- ================================================================== --> Modified: ofbiz/trunk/framework/common/entitydef/entitymodel.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/entitydef/entitymodel.xml?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/framework/common/entitydef/entitymodel.xml (original) +++ ofbiz/trunk/framework/common/entitydef/entitymodel.xml Sun Feb 15 19:34:49 2009 @@ -71,6 +71,23 @@ </entity> <!-- ========================================================= --> + <!-- org.ofbiz.common.email --> + <!-- ========================================================= --> + + <entity entity-name="EmailTemplateSetting" package-name="org.ofbiz.common.email" title="Email Template Setting Entity"> + <field name="emailTemplateSettingId" type="id-ne"></field> + <field name="description" type="description"></field> + <field name="bodyScreenLocation" type="long-varchar"><description>if empty defaults to a screen based on the emailType</description></field> + <field name="xslfoAttachScreenLocation" type="long-varchar"><description>if specified is used to generate XSL:FO that is transformed to a PDF via Apache FOP and attached to the email</description></field> + <field name="fromAddress" type="email"></field> + <field name="ccAddress" type="email"></field> + <field name="bccAddress" type="email"></field> + <field name="subject" type="comment"></field> + <field name="contentType" type="long-varchar"></field> + <prim-key field="emailTemplateSettingId"/> + </entity> + + <!-- ========================================================= --> <!-- org.ofbiz.common.enum --> <!-- ========================================================= --> Modified: ofbiz/trunk/framework/common/ofbiz-component.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/ofbiz-component.xml?rev=744727&r1=744726&r2=744727&view=diff ============================================================================== --- ofbiz/trunk/framework/common/ofbiz-component.xml (original) +++ ofbiz/trunk/framework/common/ofbiz-component.xml Sun Feb 15 19:34:49 2009 @@ -56,9 +56,10 @@ <entity-resource type="data" reader-name="seed" loader="main" location="data/PortalSeedData.xml"/> <service-resource type="model" loader="main" location="servicedef/services.xml"/> - <service-resource type="model" loader="main" location="servicedef/services_test.xml"/> <service-resource type="model" loader="main" location="servicedef/services_cdyne.xml"/> + <service-resource type="model" loader="main" location="servicedef/services_email.xml"/> <service-resource type="model" loader="main" location="servicedef/services_olap.xml"/> + <service-resource type="model" loader="main" location="servicedef/services_test.xml"/> <service-resource type="group" loader="main" location="servicedef/groups_test.xml"/> <service-resource type="eca" loader="main" location="servicedef/secas_test.xml"/> <service-resource type="eca" loader="main" location="servicedef/secas_cdyne.xml"/> Copied: ofbiz/trunk/framework/common/servicedef/services_email.xml (from r744706, ofbiz/trunk/applications/content/servicedef/services_email.xml) URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/servicedef/services_email.xml?p2=ofbiz/trunk/framework/common/servicedef/services_email.xml&p1=ofbiz/trunk/applications/content/servicedef/services_email.xml&r1=744706&r2=744727&rev=744727&view=diff ============================================================================== --- ofbiz/trunk/applications/content/servicedef/services_email.xml (original) +++ ofbiz/trunk/framework/common/servicedef/services_email.xml Sun Feb 15 19:34:49 2009 @@ -42,7 +42,7 @@ <attribute name="emailType" type="String" mode="INOUT" optional="true"/> </service> <service name="sendMail" engine="java" - location="org.ofbiz.content.email.EmailServices" invoke="sendMail"> + location="org.ofbiz.common.email.EmailServices" invoke="sendMail"> <description>Send E-Mail Service. partyId and communicationEventId aren't used by sendMail but are passed down to storeEmailAsCommunication during the SECA chain. See sednMailInterface for more comments.</description> <implements service="sendMailInterface"/> @@ -53,7 +53,7 @@ <override name="emailType" type="String" mode="INOUT" optional="true"/> </service> <service name="sendMailMultiPart" engine="java" - location="org.ofbiz.content.email.EmailServices" invoke="sendMail"> + location="org.ofbiz.common.email.EmailServices" invoke="sendMail"> <description>Send Multi-Part E-Mail Service</description> <implements service="sendMailInterface"/> <attribute name="bodyParts" type="java.util.List" mode="INOUT" optional="false"/> @@ -62,7 +62,7 @@ <override name="contentType" mode="INOUT"/> </service> <service name="sendMailFromUrl" engine="java" - location="org.ofbiz.content.email.EmailServices" invoke="sendMailFromUrl"> + location="org.ofbiz.common.email.EmailServices" invoke="sendMailFromUrl"> <description>Send E-Mail From URL Service</description> <implements service="sendMailInterface"/> <attribute name="bodyUrl" type="String" mode="IN" optional="false" allow-html="any"/> @@ -70,7 +70,7 @@ <attribute name="body" type="String" mode="OUT" optional="false" allow-html="any"/> </service> <service name="sendMailFromScreen" max-retry="3" engine="java" - location="org.ofbiz.content.email.EmailServices" invoke="sendMailFromScreen"> + location="org.ofbiz.common.email.EmailServices" invoke="sendMailFromScreen"> <description>Send E-Mail From Screen Widget Service</description> <implements service="sendMailInterface"/> <attribute name="bodyText" type="String" mode="IN" optional="true" allow-html="any"/> @@ -102,39 +102,15 @@ <attribute name="webSiteId" type="String" mode="IN" optional="true"/> </service> <service name="sendGenericNotificationEmail" engine="java" - location="org.ofbiz.content.email.NotificationServices" invoke="sendNotification"> + location="org.ofbiz.common.email.NotificationServices" invoke="sendNotification"> <description>Generic Template Based Notification Service</description> <implements service="sendNotificationInterface"/> </service> - <service name="storeEmailAsCommunication" engine="java" - location="org.ofbiz.content.email.EmailServices" 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"/> - <attribute name="subject" type="String" mode="IN" optional="false"/> - <attribute name="body" type="String" mode="IN" optional="false" allow-html="any"/> - <attribute name="contentType" type="String" mode="IN" optional="true"/> - <attribute name="emailType" type="String" mode="IN" optional="true"/> - </service> - <service name="storeIncomingEmail" engine="java" - location="org.ofbiz.content.email.EmailServices" invoke="storeIncomingEmail" auth="true"> - <description> - Process incoming email. Try to determine partyIdFrom from the first SendFrom email address. datetimeStarted and datetimeEnded are the - sent and received dates respectively, partyIdTo is from the first SendTo email address or the delivered-to address. If the parties are not found, - the email addresses are stored in CommunicationEvent.note - If however it is detected as spam (external) or when the 'from' email address is missing, the service will not return a communicationEventId. - If the party cannot be found the status of the communicationEvent will be set to: COM_UNKNOWN_PARTY. - If the parties are found the status is set to COM_ENTERED - </description> - <attribute name="messageWrapper" type="org.ofbiz.service.mail.MimeMessageWrapper" mode="IN"/> - <attribute name="communicationEventId" type="String" mode="OUT" optional="true"/> - <attribute name="statusId" type="String" mode="OUT" optional="true"/> - </service> + <!-- this service does not seem to exist, is not in the EmailServices.java file <service name="storeForwardedEmail" engine="java" - location="org.ofbiz.content.email.EmailServices" invoke="storeForwardedEmail" auth="true"> + location="org.ofbiz.common.email.EmailServices" invoke="storeForwardedEmail" auth="true"> <description>Process incoming email. Try to determine partyIdFrom from email address.</description> <implements service="mailProcessInterface"/> </service> + --> </services> Copied: ofbiz/trunk/framework/common/src/org/ofbiz/common/email/EmailServices.java (from r744706, ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java) URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/email/EmailServices.java?p2=ofbiz/trunk/framework/common/src/org/ofbiz/common/email/EmailServices.java&p1=ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java&r1=744706&r2=744727&rev=744727&view=diff ============================================================================== --- ofbiz/trunk/applications/content/src/org/ofbiz/content/email/EmailServices.java (original) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/email/EmailServices.java Sun Feb 15 19:34:49 2009 @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. *******************************************************************************/ -package org.ofbiz.content.email; +package org.ofbiz.common.email; import java.io.ByteArrayInputStream; @@ -30,24 +30,16 @@ import java.net.MalformedURLException; import java.net.URL; import java.security.Security; -import java.sql.Timestamp; import java.util.Date; -import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; import javax.activation.DataHandler; import javax.activation.DataSource; -import javax.mail.Address; import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.Part; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; @@ -58,7 +50,6 @@ import javax.xml.transform.stream.StreamSource; import javolution.util.FastList; -import javolution.util.FastMap; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.Fop; @@ -67,22 +58,15 @@ import org.ofbiz.base.util.GeneralException; import org.ofbiz.base.util.HttpClient; import org.ofbiz.base.util.HttpClientException; -import org.ofbiz.base.util.StringUtil; -import org.ofbiz.base.util.UtilDateTime; import org.ofbiz.base.util.UtilMisc; import org.ofbiz.base.util.UtilProperties; import org.ofbiz.base.util.UtilValidate; import org.ofbiz.base.util.collections.MapStack; import org.ofbiz.base.util.string.FlexibleStringExpander; -import org.ofbiz.entity.GenericDelegator; -import org.ofbiz.entity.GenericEntityException; import org.ofbiz.entity.GenericValue; -import org.ofbiz.entity.util.EntityUtil; import org.ofbiz.service.DispatchContext; -import org.ofbiz.service.GenericServiceException; import org.ofbiz.service.LocalDispatcher; import org.ofbiz.service.ServiceUtil; -import org.ofbiz.service.mail.MimeMessageWrapper; import org.ofbiz.webapp.view.ApacheFopWorker; import org.ofbiz.widget.fo.FoScreenRenderer; import org.ofbiz.widget.html.HtmlScreenRenderer; @@ -513,53 +497,6 @@ return result; } - /** - * 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 - */ - public static Map<String, Object> storeEmailAsCommunication(DispatchContext dctx, Map<String, ? extends Object> serviceContext) { - 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 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"); - } - } - - return ServiceUtil.returnSuccess(); - } - /** class to create a file in memory required for sending as an attachment */ public static class StringDataSource implements DataSource { private String contentType; @@ -616,434 +553,4 @@ throw new IOException("Cannot write to this read-only resource"); } } - - /* - * Helper method to retrieve the party information from the first email address of the Address[] specified. - */ - private static Map getParyInfoFromEmailAddress(Address [] addresses, GenericValue userLogin, LocalDispatcher dispatcher) throws GenericServiceException - { - InternetAddress emailAddress = null; - Map map = null; - Map result = null; - - if (addresses == null) { - return null; - } - - if (addresses.length > 0) { - Address addr = addresses[0]; - if (addr instanceof InternetAddress) { - emailAddress = (InternetAddress)addr; - } - } - - if (!UtilValidate.isEmpty(emailAddress)) { - map = FastMap.newInstance(); - map.put("address", emailAddress.getAddress()); - map.put("userLogin", userLogin); - result = dispatcher.runSync("findPartyFromEmailAddress", map); - } - - return result; - } - - /* - * Calls findPartyFromEmailAddress service and returns a List of the results for the array of addresses - */ - private static List buildListOfPartyInfoFromEmailAddresses(Address [] addresses, GenericValue userLogin, LocalDispatcher dispatcher) throws GenericServiceException - { - InternetAddress emailAddress = null; - Address addr = null; - Map map = null; - Map result = null; - List tempResults = FastList.newInstance(); - - if (addresses != null) { - for (int i = 0; i < addresses.length; i++) { - addr = addresses[i]; - if (addr instanceof InternetAddress) { - emailAddress = (InternetAddress)addr; - - if (!UtilValidate.isEmpty(emailAddress)) { - result = dispatcher.runSync("findPartyFromEmailAddress", - UtilMisc.<String, Object>toMap("address", emailAddress.getAddress(), "userLogin", userLogin)); - if (result.get("partyId") != null) { - tempResults.add(result); - } - } - } - } - } - return tempResults; - } - - public static String contentIndex = ""; - private static Map addMessageBody( Map commEventMap, Multipart multipart) - throws MessagingException, IOException { - try { - int multipartCount = multipart.getCount(); - for (int i=0; i < multipartCount && i < 10; i++) { - Part part = multipart.getBodyPart(i); - String thisContentTypeRaw = part.getContentType(); - String content = null; - int idx2 = thisContentTypeRaw.indexOf(";"); - if (idx2 == -1) { - idx2 = thisContentTypeRaw.length(); - } - String thisContentType = thisContentTypeRaw.substring(0, idx2); - if (thisContentType == null || thisContentType.equals("")) thisContentType = "text/html"; - thisContentType = thisContentType.toLowerCase(); - String disposition = part.getDisposition(); - - if (thisContentType.startsWith("multipart") || thisContentType.startsWith("Multipart")) { - contentIndex = contentIndex.concat("." + i); - return addMessageBody(commEventMap, (Multipart) part.getContent()); - } - // See this case where the disposition of the inline text is null - else if ((disposition == null) && (i == 0) && thisContentType.startsWith("text")) { - content = (String)part.getContent(); - if (UtilValidate.isNotEmpty(content)) { - contentIndex = contentIndex.concat("." + i); - commEventMap.put("content", content); - commEventMap.put("contentMimeTypeId", thisContentType); - return commEventMap; - } - } else if ((disposition != null) - && (disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE)) - && thisContentType.startsWith("text")) { - contentIndex = contentIndex.concat("." + i); - commEventMap.put("content", part.getContent()); - commEventMap.put("contentMimeTypeId", thisContentType); - return commEventMap; - } - } - return commEventMap; - } catch (MessagingException e) { - Debug.logError(e, module); - return ServiceUtil.returnError(e.getMessage()); - } catch (IOException e) { - Debug.logError(e, module); - return ServiceUtil.returnError(e.getMessage()); - } - } - - /** - * This service is the main one for processing incoming emails. - * - * Its only argument is a wrapper for the JavaMail MimeMessage object. - * From this object, all the fields, headers and content of the message can be accessed. - * - * The first thing this service does is try to discover the partyId of the message sender - * by doing a reverse find on the email address. It uses the findPartyFromEmailAddress service to do this. - * - * It then creates a CommunicationEvent entity by calling the createCommunicationEvent service using the appropriate fields from the email and the - * discovered partyId, if it exists, as the partyIdFrom. Note that it sets the communicationEventTypeId - * field to AUTO_EMAIL_COMM. This is useful for tracking email generated communications. - * - * The service tries to find appropriate content for inclusion in the CommunicationEvent.content field. - * If the contentType of the content starts with "text", the getContent() call returns a string and it is used. - * If the contentType starts with "multipart", then the "parts" of the content are iterated thru and the first - * one of mime type, "text/..." is used. - * - * If the contentType has a value of "multipart" then the parts of the content (except the one used in the main - * CommunicationEvent.content field) are cycled thru and attached to the CommunicationEvent entity using the - * createCommContentDataResource service. This happens in the EmailWorker.addAttachmentsToCommEvent method. - * - * However multiparts can contain multiparts. A recursive function has been added. - * - * -Al Byers - Hans Bakker - * @param dctx - * @param context - * @return - */ - public static Map<String, Object> storeIncomingEmail(DispatchContext dctx, Map<String, ? extends Object> context) { - - GenericDelegator delegator = dctx.getDelegator(); - LocalDispatcher dispatcher = dctx.getDispatcher(); - MimeMessageWrapper wrapper = (MimeMessageWrapper) context.get("messageWrapper"); - MimeMessage message = wrapper.getMessage(); - Timestamp nowTimestamp = UtilDateTime.nowTimestamp(); - GenericValue userLogin = (GenericValue) context.get("userLogin"); - String partyIdTo = null; - String partyIdFrom = null; - String contentType = null; - String communicationEventId = null; - String contactMechIdFrom = null; - String contactMechIdTo = null; - - Map result = null; - try { - String contentTypeRaw = message.getContentType(); - int idx = contentTypeRaw.indexOf(";"); - if (idx == -1) idx = contentTypeRaw.length(); - contentType = contentTypeRaw.substring(0, idx); - if (contentType == null || contentType.equals("")) contentType = "text/html"; - contentType = contentType.toLowerCase(); - Address[] addressesFrom = message.getFrom(); - Address[] addressesTo = message.getRecipients(MimeMessage.RecipientType.TO); - Address[] addressesCC = message.getRecipients(MimeMessage.RecipientType.CC); - Address[] addressesBCC = message.getRecipients(MimeMessage.RecipientType.BCC); - String messageId = message.getMessageID(); - - String aboutThisEmail = "message [" + messageId + "] from [" + - (addressesFrom[0] == null? "not found" : addressesFrom[0].toString()) + "] to [" + - (addressesTo[0] == null? "not found" : addressesTo[0].toString()) + "]"; - if (Debug.verboseOn()) Debug.logVerbose("Processing Incoming Email " + aboutThisEmail, module); - - // ignore the message when the spam status = yes - String spamHeaderName = UtilProperties.getPropertyValue("general.properties", "mail.spam.name", "N"); - String configHeaderValue = UtilProperties.getPropertyValue("general.properties", "mail.spam.value"); - // only execute when config file has been set && header variable found - if (!spamHeaderName.equals("N") && message.getHeader(spamHeaderName) != null && message.getHeader(spamHeaderName).length > 0) { - String msgHeaderValue = message.getHeader(spamHeaderName)[0]; - if(msgHeaderValue != null && msgHeaderValue.startsWith(configHeaderValue)) { - Debug.logInfo("Incoming Email message ignored, was detected by external spam checker", module); - return ServiceUtil.returnSuccess(" Message Ignored: detected by external spam checker"); - } - } - - // if no 'from' addresses specified ignore the message - if (addressesFrom == null) { - Debug.logInfo("Incoming Email message ignored, had not 'from' email address", module); - return ServiceUtil.returnSuccess(" Message Ignored: no 'From' address specified"); - } - - // make sure this isn't a duplicate - List commEvents; - try { - commEvents = delegator.findByAnd("CommunicationEvent", UtilMisc.toMap("messageId", messageId)); - } catch (GenericEntityException e) { - Debug.logError(e, module); - return ServiceUtil.returnError(e.getMessage()); - } - if (!commEvents.isEmpty()) { - Debug.logInfo("Ignoring Duplicate Email: " + aboutThisEmail, module); - return ServiceUtil.returnSuccess(" Message Ignored: deplicate messageId"); - } else { - Debug.logInfo("Persisting New Email: " + aboutThisEmail, module); - } - - - // get the related partId's - List toParties = buildListOfPartyInfoFromEmailAddresses(addressesTo, userLogin, dispatcher); - List ccParties = buildListOfPartyInfoFromEmailAddresses(addressesCC, userLogin, dispatcher); - List bccParties = buildListOfPartyInfoFromEmailAddresses(addressesBCC, userLogin, dispatcher); - - //Get the first address from the list - this is the partyIdTo field of the CommunicationEvent - if (!toParties.isEmpty()) { - Iterator itr = toParties.iterator(); - Map firstAddressTo = (Map) itr.next(); - partyIdTo = (String)firstAddressTo.get("partyId"); - contactMechIdTo = (String)firstAddressTo.get("contactMechId"); - } - - String deliveredTo = null; - if (message.getHeader("Delivered-To") != null) { - deliveredTo = message.getHeader("Delivered-To")[0]; - // check if started with the domain name if yes remove including the dash. - String dn = deliveredTo.substring(deliveredTo.indexOf("@")+1, deliveredTo.length()); - if (deliveredTo.startsWith(dn)) { - deliveredTo = deliveredTo.substring(dn.length()+1, deliveredTo.length()); - } - } - - // if partyIdTo not found try to find the "to" address using the delivered-to header - if ((partyIdTo == null) && (deliveredTo != null)) { - result = dispatcher.runSync("findPartyFromEmailAddress", UtilMisc.<String, Object>toMap("address", deliveredTo, "userLogin", userLogin)); - partyIdTo = (String)result.get("partyId"); - contactMechIdTo = (String)result.get("contactMechId"); - } - if (userLogin.get("partyId") == null && partyIdTo != null) { - int ch = 0; - for (ch=partyIdTo.length(); ch > 0 && Character.isDigit(partyIdTo.charAt(ch-1)); ch--) { - ; - } - userLogin.put("partyId", partyIdTo.substring(0,ch)); //allow services to be called to have prefix - } - - // get the 'from' partyId - result = getParyInfoFromEmailAddress(addressesFrom, userLogin, dispatcher); - partyIdFrom = (String)result.get("partyId"); - contactMechIdFrom = (String)result.get("contactMechId"); - - Map commEventMap = FastMap.newInstance(); - commEventMap.put("communicationEventTypeId", "AUTO_EMAIL_COMM"); - commEventMap.put("contactMechTypeId", "EMAIL_ADDRESS"); - commEventMap.put("messageId", messageId); - - String subject = message.getSubject(); - commEventMap.put("subject", subject); - - // Set sent and received dates - commEventMap.put("entryDate", nowTimestamp); - commEventMap.put("datetimeStarted", UtilDateTime.toTimestamp(message.getSentDate())); - commEventMap.put("datetimeEnded", UtilDateTime.toTimestamp(message.getReceivedDate())); - - // default role types (_NA_) - commEventMap.put("roleTypeIdFrom", "_NA_"); - commEventMap.put("roleTypeIdTo", "_NA_"); - - // get the content(type) part - Object messageContent = message.getContent(); - if (contentType.startsWith("text")) { - commEventMap.put("content", messageContent); - commEventMap.put("contentMimeTypeId", contentType); - } else if (messageContent instanceof Multipart) { - contentIndex = ""; - commEventMap = addMessageBody(commEventMap, (Multipart) messageContent); - } - - // check for for a reply to communication event (using in-reply-to the parent messageID) - String[] inReplyTo = message.getHeader("In-Reply-To"); - if (inReplyTo != null && inReplyTo[0] != null) { - GenericValue parentCommEvent = null; - try { - List events = delegator.findByAnd("CommunicationEvent", UtilMisc.toMap("messageId", inReplyTo[0])); - parentCommEvent = EntityUtil.getFirst(events); - } catch (GenericEntityException e) { - Debug.logError(e, module); - } - if (parentCommEvent != null) { - String parentCommEventId = parentCommEvent.getString("communicationEventId"); - String orgCommEventId = parentCommEvent.getString("origCommEventId"); - if (orgCommEventId == null) orgCommEventId = parentCommEventId; - commEventMap.put("parentCommEventId", parentCommEventId); - commEventMap.put("origCommEventId", orgCommEventId); - } - } - - // Retrieve all the addresses from the email - Set emailAddressesFrom = new TreeSet(); - Set emailAddressesTo = new TreeSet(); - Set emailAddressesCC = new TreeSet(); - Set emailAddressesBCC = new TreeSet(); - 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); - - // 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) { - commEventMap.put("partyIdFrom", partyIdFrom); - commEventMap.put("contactMechIdFrom", contactMechIdFrom); - } else { - commNote += "Sent from: " + ((InternetAddress)addressesFrom[0]).getAddress() + "; "; - commNote += "Sent Name from: " + ((InternetAddress)addressesFrom[0]).getPersonal() + "; "; - } - - if (partyIdTo != null) { - commEventMap.put("partyIdTo", partyIdTo); - commEventMap.put("contactMechIdTo", contactMechIdTo); - } else { - commNote += "Sent to: " + ((InternetAddress)addressesTo[0]).getAddress() + "; "; - if (deliveredTo != null) { - commNote += "Delivered-To: " + deliveredTo + "; "; - } - } - - commNote += "Sent to: " + ((InternetAddress)addressesTo[0]).getAddress() + "; "; - commNote += "Delivered-To: " + deliveredTo + "; "; - - if (partyIdTo != null && partyIdFrom != null) { - commEventMap.put("statusId", "COM_ENTERED"); - } else { - commEventMap.put("statusId", "COM_UNKNOWN_PARTY"); - } - if (commNote.length() > 255) commNote = commNote.substring(0,255); - - if (!("".equals(commNote))) { - commEventMap.put("note", commNote); - } - - commEventMap.put("userLogin", userLogin); - - // Populate the CommunicationEvent.headerString field with the email headers - String headerString = ""; - Enumeration headerLines = message.getAllHeaderLines(); - while (headerLines.hasMoreElements()) { - headerString += System.getProperty("line.separator"); - headerString += headerLines.nextElement(); - } - commEventMap.put("headerString", headerString); - - result = dispatcher.runSync("createCommunicationEvent", commEventMap); - communicationEventId = (String)result.get("communicationEventId"); - - if (messageContent instanceof Multipart) { - Debug.logInfo("===message has attachments=====", module); - int attachmentCount = EmailWorker.addAttachmentsToCommEvent((Multipart) messageContent, subject, communicationEventId, dispatcher, userLogin); - if (Debug.infoOn()) Debug.logInfo(attachmentCount + " attachments added to CommunicationEvent:" + communicationEventId,module); - } - - // For all addresses create a CommunicationEventRoles - createCommEventRoles(userLogin, delegator, dispatcher, communicationEventId, toParties, "ADDRESSEE"); - createCommEventRoles(userLogin, delegator, dispatcher, communicationEventId, ccParties, "CC"); - createCommEventRoles(userLogin, delegator, dispatcher, communicationEventId, bccParties, "BCC"); - - Map results = ServiceUtil.returnSuccess(); - results.put("communicationEventId", communicationEventId); - results.put("statusId", commEventMap.get("statusId")); - return results; - } catch (MessagingException e) { - Debug.logError(e, module); - return ServiceUtil.returnError(e.getMessage()); - } catch (GenericServiceException e) { - Debug.logError(e, module); - return ServiceUtil.returnError(e.getMessage()); - } catch (IOException e) { - Debug.logError(e, module); - return ServiceUtil.returnError(e.getMessage()); - } catch (Exception e) { - Debug.logError(e, module); - return ServiceUtil.returnError(e.getMessage()); - } - } - - private static void createCommEventRoles(GenericValue userLogin, GenericDelegator delegator, LocalDispatcher dispatcher, String communicationEventId, List 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 - try { - Iterator it = parties.iterator(); - while (it.hasNext()) { - Map result = (Map) it.next(); - String partyId = (String) result.get("partyId"); - GenericValue commEventRole = delegator.findByPrimaryKey("CommunicationEventRole", - UtilMisc.toMap("communicationEventId", communicationEventId, "partyId", partyId, "roleTypeId", roleTypeId)); - if (commEventRole == null) { - Map input = UtilMisc.toMap("communicationEventId", communicationEventId, - "partyId", partyId, "roleTypeId", roleTypeId, "userLogin", userLogin, - "contactMechId", (String) result.get("contactMechId"), - "statusId", "COM_ROLE_CREATED"); - dispatcher.runSync("createCommunicationEventRole", input); - } - } - } catch (GenericServiceException e) { - Debug.logError(e, module); - } catch (Exception e) { - Debug.logError(e, module); - } - } - } Copied: ofbiz/trunk/framework/common/src/org/ofbiz/common/email/NotificationServices.java (from r744706, ofbiz/trunk/applications/content/src/org/ofbiz/content/email/NotificationServices.java) URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/email/NotificationServices.java?p2=ofbiz/trunk/framework/common/src/org/ofbiz/common/email/NotificationServices.java&p1=ofbiz/trunk/applications/content/src/org/ofbiz/content/email/NotificationServices.java&r1=744706&r2=744727&rev=744727&view=diff ============================================================================== --- ofbiz/trunk/applications/content/src/org/ofbiz/content/email/NotificationServices.java (original) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/email/NotificationServices.java Sun Feb 15 19:34:49 2009 @@ -16,10 +16,9 @@ * specific language governing permissions and limitations * under the License. *******************************************************************************/ -package org.ofbiz.content.email; +package org.ofbiz.common.email; import java.io.IOException; -import java.io.InputStreamReader; import java.io.StringWriter; import java.io.Writer; import java.net.InetAddress; @@ -29,8 +28,6 @@ import javolution.util.FastMap; -import freemarker.template.TemplateException; - import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.UtilMisc; import org.ofbiz.base.util.UtilProperties; @@ -46,6 +43,8 @@ import org.ofbiz.service.ModelService; import org.ofbiz.service.ServiceUtil; +import freemarker.template.TemplateException; + /** * Provides generic services related to preparing and * delivering notifications via email. |
Free forum by Nabble | Edit this page |