001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.rm.commands;
020:
021: import java.io.StringWriter;
022: import java.util.*;
023:
024: import javax.xml.transform.*;
025: import javax.xml.transform.dom.DOMSource;
026: import javax.xml.transform.stream.StreamResult;
027:
028: import org.openharmonise.commons.dsi.*;
029: import org.openharmonise.commons.net.Email;
030: import org.openharmonise.rm.DataAccessException;
031: import org.openharmonise.rm.config.*;
032: import org.openharmonise.rm.dsi.DataStoreInterfaceFactory;
033: import org.openharmonise.rm.factory.*;
034: import org.openharmonise.rm.metadata.*;
035: import org.openharmonise.rm.publishing.*;
036: import org.openharmonise.rm.resources.*;
037: import org.openharmonise.rm.resources.publishing.Template;
038: import org.openharmonise.rm.resources.xml.XSLResource;
039: import org.w3c.dom.*;
040:
041: /**
042: * Publishes the 'command object' using a <code>Template</code> specified in the parameters
043: * and sends the result as an email to the recipient specified in the parameters.
044: *
045: * @author Michael Bell
046: * @version $Revision: 1.3 $
047: *
048: */
049: public class CmdEmail extends AbstractCmd {
050:
051: /**
052: * Email recipient tag
053: */
054: public static final String TAG_EMAILRECIPIENT = "EmailRecipient";
055:
056: /**
057: * Send type attribute, i.e. 'user' or 'test'
058: */
059: public static final String ATTRIB_SEND_TYPE = "sendType";
060:
061: /**
062: * Possible value for <code>EMAILFORMID_PNAME</code> parameter to indicate
063: * the submitted for should be used to publish the 'command object'
064: */
065: static final String USE_SUBMITTED_FORM = "submitted";
066:
067: /**
068: * Property name for the 'recipient' property
069: */
070: static final String EMAIL_PROPNAME = "RECIPIENT";
071:
072: /**
073: * Property name for the 'sender' property
074: */
075: static final String SENDER_PROPNAME = "SENDER";
076:
077: /**
078: * Parameter name for the id of the template to be used
079: * in publishing the 'command object'
080: */
081: static final String EMAILFORMID_PNAME = "publish_using_template_id";
082:
083: /**
084: * Parameter name for the recipient list
085: */
086: static final String RECEPIENTLIST_PNAME = "recipient";
087:
088: /**
089: * Parameter name for the sender
090: */
091: static final String SENDER_PNAME = "sender";
092:
093: /**
094: * Parameter name for email subject
095: */
096: static final String SUBJECT_PNAME = "subject";
097:
098: /**
099: * Parameter name for email content type
100: */
101: static final String CONTENTTYPE_PNAME = "content_type";
102:
103: /**
104: * Parameter name for the XSLT file to be used in transforming
105: * the result of publishing the 'command object' to XML
106: */
107: static final String XSL_PNAME = "xsl_file";
108:
109: /**
110: * Parameter name for the output text
111: */
112: static final String OUTTEXT_PNAME = "out_text";
113:
114: /**
115: * Parameter name for sending the published XML
116: */
117: static final String SENDXML_PNAME = "xml_recipient"; // for debugging
118:
119: /**
120: * Name replacement pattern
121: */
122: static final String SUBJECT_INMARKER = "#!N"; // name replacement
123:
124: /**
125: * Property value pattern
126: */
127: static final String SUBJECT_IPMARKER = "#!P:"; // property replacement
128:
129: /**
130: * Config parameter name for the email host
131: */
132: static final String PNAME_EMAIL_HOST = "EMAIL_HOST";
133:
134: /**
135: * Creates a new instance of the command.
136: *
137: */
138: public CmdEmail() {
139: super ();
140: }
141:
142: /* (non-Javadoc)
143: * @see org.openharmonise.rm.commands.AbstractCmd#execute()
144: */
145: public Object execute(Context context) throws CommandException {
146: int nTemplateId = -1;
147: String publish_using_form_id = this
148: .getParameter(EMAILFORMID_PNAME);
149: String xsl_filename = this .getParameter(XSL_PNAME);
150: String sender_address = this .getParameter(SENDER_PNAME);
151:
152: if ((publish_using_form_id != null)
153: && publish_using_form_id.equals(USE_SUBMITTED_FORM)) {
154: String sTemplateId = getParameter(AbstractCmd.PARAM_TEMPLATE_ID);
155: if (sTemplateId != null) {
156: nTemplateId = Integer.parseInt(sTemplateId);
157: }
158:
159: } else if (publish_using_form_id != null) {
160: try {
161: nTemplateId = Integer.parseInt(publish_using_form_id);
162: } catch (NumberFormatException e) {
163: throw new RuntimeException(
164: " The parameter check_with_form is invalid "
165: + ":" + publish_using_form_id
166: + " must be a valid number" + ", or "
167: + USE_SUBMITTED_FORM
168: + " to use the submitted form");
169: }
170: } else {
171: throw new CommandExecutionException(
172: "A form id must be supplied in order to publish the user"
173: + " parameter:" + EMAILFORMID_PNAME
174: + " must be set.");
175: }
176:
177: List recipient_addresses = this
178: .getParameters(RECEPIENTLIST_PNAME);
179:
180: Object cmdObj = getCommandObject(context);
181:
182: try {
183: if ((recipient_addresses == null)
184: || (recipient_addresses.size() == 0)) {
185: org.w3c.dom.Document state = getState();
186: Element root = state.getDocumentElement();
187:
188: NodeList nlEmailRecip = root
189: .getElementsByTagName(TAG_EMAILRECIPIENT);
190:
191: if (nlEmailRecip.getLength() > 0) {
192: Element elEmailRecip = (Element) nlEmailRecip
193: .item(0);
194:
195: if (recipient_addresses == null) {
196: recipient_addresses = new Vector(16);
197: }
198:
199: String sSendType = elEmailRecip
200: .getAttribute(ATTRIB_SEND_TYPE);
201:
202: if (sSendType.equalsIgnoreCase("test")) {
203: Text txt = (Text) elEmailRecip.getFirstChild();
204:
205: if (txt.getNodeValue().indexOf("@") < 0) {
206: throw new CommandException(
207: "Need valid email address.");
208: }
209:
210: recipient_addresses.add(txt.getNodeValue());
211: } else if (sSendType.equalsIgnoreCase("user")) {
212:
213: Profile pro = ((AbstractProfiledObject) cmdObj)
214: .getProfile();
215:
216: AbstractDataStoreInterface dbintrf = DataStoreInterfaceFactory
217: .getDataStoreInterface();
218:
219: }
220: } else {
221: // see if the working object has email addresses
222: AbstractProfiledObject obj = (AbstractProfiledObject) cmdObj;
223: Profile pro = obj.getProfile();
224: AbstractPropertyInstance prop = pro
225: .getPropertyInstance(EMAIL_PROPNAME);
226: if (prop != null) {
227: recipient_addresses = prop.getValues();
228: }
229: if (sender_address == null) {
230: prop = pro.getPropertyInstance(SENDER_PROPNAME);
231: if (prop != null) {
232: sender_address = (String) prop.getValue();
233: }
234: }
235: }
236: }
237:
238: String subject_text = buildSubjectLine((AbstractObject) cmdObj);
239:
240: if ((subject_text == null) || (subject_text.length() == 0)) {
241: subject_text = ((AbstractObject) cmdObj).getName();
242: }
243:
244: Template template = (Template) HarmoniseObjectFactory
245: .instantiateHarmoniseObject(getDataStoreInteface(),
246: Template.class.getName(), nTemplateId);
247:
248: HarmoniseOutput doc = new HarmoniseOutput(this
249: .getDataStoreInteface());
250:
251: org.w3c.dom.Element workflow_obj_root = template
252: .publishObjectToElement((Publishable) cmdObj, doc,
253: getState());
254:
255: doc.appendChild(doc.copyNode(workflow_obj_root));
256:
257: String obj_as_txt = processXSLT(doc.getDocumentElement(),
258: xsl_filename);
259:
260: Iterator recipient_addresses_it = recipient_addresses
261: .iterator();
262:
263: while (recipient_addresses_it.hasNext()) {
264: String recipient_address = (String) recipient_addresses_it
265: .next();
266: Email email = new Email(ConfigSettings
267: .getProperty(PNAME_EMAIL_HOST),
268: recipient_address, sender_address,
269: subject_text, obj_as_txt);
270: String ctype = this .getParameter(CONTENTTYPE_PNAME);
271:
272: if (ctype != null) {
273:
274: email.SetContentType(ctype);
275: }
276:
277: email.send();
278: }
279:
280: String xml_recepient = null;
281:
282: } catch (DataAccessException e) {
283: throw new CommandExecutionException("DataAccessException",
284: e);
285: } catch (HarmoniseFactoryException e) {
286: throw new CommandExecutionException(e);
287: } catch (PublishException e) {
288: throw new CommandExecutionException("PublishException", e);
289: } catch (ConfigException e) {
290: throw new CommandExecutionException("ConfigException", e);
291: } catch (DataStoreException e) {
292: throw new CommandExecutionException("DataStoreException", e);
293: } catch (InvalidPropertyInstanceException e) {
294: throw new CommandExecutionException(
295: e.getLocalizedMessage(), e);
296: }
297:
298: return null;
299: }
300:
301: /* (non-Javadoc)
302: * @see org.openharmonise.rm.commands.AbstractCmd#getName()
303: */
304: public String getName() {
305: return "Email";
306: }
307:
308: /* (non-Javadoc)
309: * @see org.openharmonise.rm.commands.AbstractCmd#isValidCommandObject(java.lang.Object)
310: */
311: public boolean isValidCommandObject(Object obj) {
312: return (obj instanceof Publishable);
313: }
314:
315: /**
316: * Transforms the given XML node using the XSLT specified and returns the result as
317: * a <code>String</code>
318: *
319: * @param xml_node the XML node
320: * @param xsl_filename the XSLT file name
321: * @return the result of transforming the XML using the specified XSLT
322: * @throws CommandException if any errors occur
323: */
324: private String processXSLT(Node xml_node, String xsl_filename)
325: throws CommandException {
326: StringWriter out_str = new StringWriter();
327:
328: try {
329: XSLResource xsl = (XSLResource) HarmoniseObjectFactory
330: .instantiateHarmoniseObject(getDataStoreInteface(),
331: XSLResource.class.getName(), xsl_filename);
332:
333: Transformer trans = xsl.getTemplates().newTransformer();
334:
335: DOMSource ds = new DOMSource(xml_node);
336:
337: StreamResult res = new StreamResult(out_str);
338:
339: trans.transform(ds, res);
340: } catch (HarmoniseFactoryException e) {
341: throw new CommandException(
342: "Error getting xsl from factory - " + xsl_filename,
343: e);
344: } catch (TransformerConfigurationException e) {
345: throw new CommandException(
346: "TransformerConfigurationException", e);
347: } catch (DataAccessException e) {
348: throw new CommandException("DataAccessException", e);
349: } catch (TransformerException e) {
350: throw new CommandException("TransformerException", e);
351: }
352:
353: return out_str.toString();
354: }
355:
356: /**
357: * Returns the subject line for the email, taken from a parameter and
358: * making appropriate substitutions
359: *
360: * @return the subject line for the email
361: * @throws DataAccessException if any errors occur substituting with the required data
362: */
363: private String buildSubjectLine(AbstractObject obj)
364: throws DataAccessException {
365: String subject_line = null;
366: subject_line = this .getParameter(SUBJECT_PNAME);
367:
368: if (subject_line == null) {
369: return "";
370: } else {
371: return (processSubjectLine(obj, subject_line));
372: }
373: }
374:
375: /**
376: * Processes the given subject line making replacements for place holders where
377: * appropriate and returns the result
378: *
379: * @param subject_line the subject line
380: * @return the subject line with appropriate substitions made
381: * @throws DataAccessException if any errors occur accessing data for substitution
382: */
383: private String processSubjectLine(AbstractObject obj,
384: String subject_line) throws DataAccessException {
385: StringBuffer strbuf = new StringBuffer();
386:
387: StringTokenizer tokens = new StringTokenizer(subject_line,
388: " \t\n\r", true);
389:
390: while (tokens.hasMoreTokens()) {
391: String subject_bit = tokens.nextToken();
392:
393: if (subject_bit.startsWith(SUBJECT_IPMARKER)) {
394: strbuf.append(getProperty((AbstractProfiledObject) obj,
395: subject_bit));
396: } else if (subject_bit.startsWith(SUBJECT_INMARKER)) {
397: strbuf.append(obj.getName());
398: } else {
399: strbuf.append(subject_bit);
400: }
401: }
402:
403: return strbuf.toString();
404: }
405:
406: /**
407: * Returns the value of the property of the specified name
408: *
409: * @param prop_desc the property name
410: * @return the value of the property of the specified name
411: * @throws DataAccessException if an error occurs accessing
412: * the value of the property
413: */
414: private String getProperty(AbstractProfiledObject profObj,
415: String prop_desc) throws DataAccessException {
416: String property_name = prop_desc.substring(
417: SUBJECT_IPMARKER.length()).trim();
418:
419: List property_descs = null;
420: boolean got_pvalue = true;
421:
422: Profile object_profile = profObj.getProfile();
423:
424: try {
425: property_descs = object_profile.getPropertyInstance(
426: prop_desc).getValues();
427: } catch (InvalidPropertyInstanceException e) {
428: throw new DataAccessException(e.getLocalizedMessage(), e);
429: }
430:
431: got_pvalue = (property_descs.size() > 0);
432:
433: if (got_pvalue) {
434: return (separatedList(property_descs, ","));
435: } else {
436: return "*NoValue*";
437: }
438: }
439:
440: /**
441: * Returns the given collection as a <code>String</code> of values
442: * seperated by the given separator <code>String</code>
443: *
444: * @param collection the collection
445: * @param separator the separator
446: * @return the given collection as a <code>String</code> of values
447: * seperated by the given separator <code>String</code>
448: */
449: private String separatedList(Collection collection, String seperator) {
450: StringBuffer strbuf = new StringBuffer();
451:
452: Iterator coll_it = collection.iterator();
453:
454: while (coll_it.hasNext()) {
455: strbuf.append((String) coll_it.next());
456:
457: if (coll_it.hasNext()) {
458: strbuf.append(seperator);
459: }
460: }
461:
462: return strbuf.toString();
463: }
464:
465: }
|