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