1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.mail;
17
18 import com.thoughtworks.xstream.XStream;
19 import org.apache.commons.lang.StringUtils;
20 import org.kuali.rice.core.api.CoreApiServiceLocator;
21 import org.kuali.rice.core.api.config.property.ConfigContext;
22 import org.kuali.rice.core.api.mail.EmailBody;
23 import org.kuali.rice.core.api.mail.EmailContent;
24 import org.kuali.rice.core.api.mail.EmailFrom;
25 import org.kuali.rice.core.api.mail.EmailSubject;
26 import org.kuali.rice.core.api.mail.EmailTo;
27 import org.kuali.rice.core.api.util.xml.XmlHelper;
28 import org.kuali.rice.core.api.util.xml.XmlJotter;
29 import org.kuali.rice.coreservice.api.CoreServiceApiServiceLocator;
30 import org.kuali.rice.kew.api.WorkflowRuntimeException;
31 import org.kuali.rice.kew.api.document.node.RouteNodeInstance;
32 import org.kuali.rice.kew.engine.RouteContext;
33 import org.kuali.rice.kew.engine.RouteHelper;
34 import org.kuali.rice.kew.engine.node.SimpleNode;
35 import org.kuali.rice.kew.engine.node.SimpleResult;
36 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
37 import org.kuali.rice.kew.service.KEWServiceLocator;
38 import org.kuali.rice.kim.api.identity.Person;
39 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Element;
42 import org.w3c.dom.NodeList;
43 import org.xml.sax.InputSource;
44
45 import javax.xml.parsers.DocumentBuilder;
46 import javax.xml.parsers.DocumentBuilderFactory;
47 import javax.xml.transform.Templates;
48 import javax.xml.transform.TransformerConfigurationException;
49 import java.io.StringReader;
50
51
52
53
54
55
56
57 public class EmailNode implements SimpleNode {
58
59 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(EmailNode.class);
60
61 private EmailStyleHelper emailStyleHelper = new EmailStyleHelper();
62 private String styleName;
63 private String from;
64 private String to;
65
66 public SimpleResult process(RouteContext context, RouteHelper helper) throws Exception {
67 if (context.isSimulation()) {
68 if (!context.getActivationContext().isActivateRequests()) {
69 return new SimpleResult(true);
70 }
71 }
72 loadConfiguration(context);
73 Document document = generateXmlInput(context);
74 if (LOG.isDebugEnabled()) {
75 LOG.debug("XML input for email tranformation:\n" + XmlJotter.jotNode(document));
76 }
77 Templates style = loadStyleSheet(styleName);
78 EmailContent emailContent = emailStyleHelper.generateEmailContent(style, document);
79 if (!StringUtils.isBlank(to)) {
80 CoreApiServiceLocator.getMailer().sendEmail(new EmailFrom(from), new EmailTo(to), new EmailSubject(emailContent.getSubject()), new EmailBody(emailContent.getBody()), emailContent.isHtml());
81 }
82 return new SimpleResult(true);
83 }
84
85 protected Document generateXmlInput(RouteContext context) throws Exception {
86 DocumentBuilder db = getDocumentBuilder(true);
87 Document doc = db.newDocument();
88 Element emailNodeElem = doc.createElement("emailNode");
89 doc.appendChild(emailNodeElem);
90 String principalId = null;
91 org.kuali.rice.kew.api.document.Document routeHeaderVO = DocumentRouteHeaderValue.to(context.getDocument());
92 RouteNodeInstance routeNodeInstanceVO = org.kuali.rice.kew.engine.node.RouteNodeInstance.to(context.getNodeInstance());
93 Document documentContent = context.getDocumentContent().getDocument();
94 XStream xstream = new XStream();
95 Element docElem = XmlHelper.readXml(xstream.toXML(routeHeaderVO)).getDocumentElement();
96 Element nodeElem = XmlHelper.readXml(xstream.toXML(routeNodeInstanceVO)).getDocumentElement();
97 emailNodeElem.appendChild(doc.importNode(docElem, true));
98 emailNodeElem.appendChild(doc.importNode(nodeElem, true));
99 emailNodeElem.appendChild(doc.importNode(documentContent.getDocumentElement(), true));
100 Element dConElem = context.getDocumentContent().getApplicationContent();
101 emailNodeElem.appendChild(doc.importNode(dConElem, true));
102 return doc;
103 }
104
105 protected DocumentBuilder getDocumentBuilder(boolean coalesce) throws Exception {
106 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
107 dbf.setCoalescing(coalesce);
108 return dbf.newDocumentBuilder();
109 }
110
111 protected Templates loadStyleSheet(String styleName) {
112 try {
113 Templates style = CoreServiceApiServiceLocator.getStyleService().getStyleAsTranslet(styleName);
114 if (style == null) {
115 throw new WorkflowRuntimeException("Failed to locate stylesheet with name '" + styleName + "'");
116 }
117 return style;
118 } catch (TransformerConfigurationException tce) {
119 throw new WorkflowRuntimeException("Failed to load stylesheet with name '" + styleName + "'");
120 }
121 }
122
123 protected boolean isProduction() {
124 return ConfigContext.getCurrentContextConfig().isProductionEnvironment();
125 }
126
127 protected void loadConfiguration(RouteContext context) throws Exception {
128 String contentFragment = context.getNodeInstance().getRouteNode().getContentFragment();
129 DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
130 Document document = db.parse(new InputSource(new StringReader(contentFragment)));
131 if (!isProduction()) {
132 NodeList testAddresses = document.getElementsByTagName("testAddress");
133 if (testAddresses.getLength() >= 1) {
134 this.to = testAddresses.item(0).getTextContent();
135 }
136 } else {
137 NodeList toAddresses = document.getElementsByTagName("to");
138 if (toAddresses.getLength() != 1) {
139 throw new WorkflowRuntimeException("Must have exactly one 'to' address");
140 }
141 to = toAddresses.item(0).getTextContent();
142 if ("initiator".equalsIgnoreCase(to))
143 {
144 Person person = KimApiServiceLocator.getPersonService().getPerson(context.getDocument().getInitiatorWorkflowId());
145 to = (person == null ? "" : person.getEmailAddressUnmasked());
146 }
147 if (StringUtils.isBlank(to)) {
148 throw new WorkflowRuntimeException("Email Address is missing from user's profile.");
149 }
150 }
151
152 NodeList fromAddresses = document.getElementsByTagName("from");
153 if (fromAddresses.getLength() != 1) {
154 throw new WorkflowRuntimeException("Must have exactly one 'from' address");
155 }
156 this.from = fromAddresses.item(0).getTextContent();
157
158 if ("initiator".equalsIgnoreCase(this.from)) {
159 Person initiator = KEWServiceLocator.getIdentityHelperService().getPerson(context.getDocument().getInitiatorWorkflowId());
160
161
162 this.from = "\"" + initiator.getName() + "\" <";
163 this.from += initiator.getEmailAddress() + ">";
164 }
165 if (StringUtils.isBlank(this.from)) {
166 throw new WorkflowRuntimeException("No email address could be found found for principal with id " + context.getDocument().getInitiatorWorkflowId());
167 }
168
169 if (LOG.isInfoEnabled()) {
170 LOG.info("Email From is set to:" + this.from);
171 LOG.info("Email To is set to:" + this.to);
172 }
173
174 NodeList styleNames = document.getElementsByTagName("style");
175 if (styleNames.getLength() != 1) {
176 throw new WorkflowRuntimeException("Must have exactly one 'style'");
177 }
178 this.styleName = styleNames.item(0).getTextContent();
179 }
180
181
182
183
184 }