Alex/Erik,
I've attached a change to the email processor that allows it to pass credentials by adding the following to the config. <credentials> <username>user</username> <password>password</password> </credentials> Thanks Ryan Ryan Puddephatt Software Engineer Teleflex Group - IT UK 1 Michaelson Square Livingston West Lothian Scotland EH54 7DP e> [hidden email] <mailto:[hidden email]> t> +44(0)1506 407 110 f> +44(0)1506 407 108 w> www.teleflex.com <http://www.teleflex.com> /** * Copyright (C) 2004 Orbeon, Inc. * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; either version * 2.1 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html */ package org.orbeon.oxf.processor; import org.apache.commons.fileupload.DefaultFileItemFactory; import org.apache.commons.fileupload.FileItem; import org.apache.log4j.Logger; import org.dom4j.Document; import org.dom4j.Element; import org.orbeon.oxf.common.OXFException; import org.orbeon.oxf.common.ValidationException; import org.orbeon.oxf.pipeline.api.PipelineContext; import org.orbeon.oxf.processor.generator.RequestGenerator; import org.orbeon.oxf.processor.generator.URLGenerator; import org.orbeon.oxf.resources.URLFactory; import org.orbeon.oxf.util.Base64; import org.orbeon.oxf.util.LoggerFactory; import org.orbeon.oxf.util.NetUtils; import org.orbeon.oxf.util.SystemUtils; import org.orbeon.oxf.xml.ForwardingContentHandler; import org.orbeon.oxf.xml.ProcessorOutputXMLReader; import org.orbeon.oxf.xml.TransformerUtils; import org.orbeon.oxf.xml.XMLUtils; import org.orbeon.oxf.xml.dom4j.LocationData; import org.orbeon.oxf.xml.dom4j.LocationSAXWriter; import org.orbeon.oxf.xml.dom4j.NonLazyUserDataDocument; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.mail.Message; import javax.mail.Part; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.*; import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import java.io.*; import java.util.Iterator; import java.util.Properties; /** * This processor allows sending emails. It supports multipart messages and inline as well as * out-of-line attachments. * * For some useful JavaMail information: http://java.sun.com/products/javamail/FAQ.html * * TODO: * o revise support of text/html * o built-in support for HTML could handle src="cid:*" with part/message ids * o support text/xml? or just XHTML? * o build message with SAX, not DOM, so streaming of input is possible [not necessarily a big win] */ public class EmailProcessor extends ProcessorImpl { static private Logger logger = LoggerFactory.createLogger(EmailProcessor.class); // Properties for this processor public static final String EMAIL_SMTP_HOST = "smtp-host"; public static final String EMAIL_TEST_TO = "test-to"; public static final String EMAIL_TEST_SMTP_HOST = "test-smtp-host"; public static final String EMAIL_FORCE_TO_DEPRECATED = "forceto"; // deprecated public static final String EMAIL_HOST_DEPRECATED = "host"; // deprecated public static final String EMAIL_CONFIG_NAMESPACE_URI = "http://www.orbeon.com/oxf/email"; private static final String DEFAULT_MULTIPART = "mixed"; private static final String DEFAULT_TEXT_ENCODING = "iso-8859-1"; //private String username; //private String password; public EmailProcessor() { addInputInfo(new ProcessorInputOutputInfo(INPUT_DATA, EMAIL_CONFIG_NAMESPACE_URI)); } public void start(PipelineContext pipelineContext) { try { Document dataDocument = readInputAsDOM4J(pipelineContext, INPUT_DATA); Element messageElement = dataDocument.getRootElement(); // Get system id (will likely be null if document is generated dynamically) LocationData locationData = (LocationData) messageElement.getData(); String dataInputSystemId = locationData.getSystemID(); // Set SMTP host Properties properties = new Properties(); String testSmtpHostProperty = getPropertySet().getString(EMAIL_TEST_SMTP_HOST); if (testSmtpHostProperty != null) { // Test SMTP Host from properties overrides the local configuration properties.setProperty("mail.smtp.host", testSmtpHostProperty); } else { // Try regular config parameter and property String host = messageElement.element("smtp-host").getTextTrim(); if (host != null && !host.equals("")) { // Precedence goes to the local config parameter properties.setProperty("mail.smtp.host", host); } else { // Otherwise try to use a property host = getPropertySet().getString(EMAIL_SMTP_HOST); if (host == null) host = getPropertySet().getString(EMAIL_HOST_DEPRECATED); if (host == null) throw new OXFException("Could not find SMTP host in configuration or in properties"); properties.setProperty("mail.smtp.host", host); } } // Get credentials Element credentials = messageElement.element("credentials"); // Create session variable, but don't assign it Session session = null; // Check if credentials are supplied if(credentials != null && !credentials.equals("")) { if(logger.isInfoEnabled()) logger.info("Authentication"); // Set the auth property to true properties.setProperty("mail.smtp.auth", "true"); String username = credentials.element("username").getStringValue(); String password = credentials.element("password").getStringValue(); if(logger.isInfoEnabled()) logger.info("Username: "+username+"; Password: "+password); // Create an authenticator Authenticator auth = new SMTPAuthenticator(username,password); // Create session with auth session = Session.getInstance(properties,auth); } else { if(logger.isInfoEnabled()) logger.info("No Authentication"); session = Session.getInstance(properties); } // Create message Message message = new MimeMessage(session); // Set From message.setFrom(createAddress(messageElement.element("from"))); // Set To String testToProperty = getPropertySet().getString(EMAIL_TEST_TO); if (testToProperty == null) testToProperty = getPropertySet().getString(EMAIL_FORCE_TO_DEPRECATED); if (testToProperty != null) { // Test To from properties overrides local configuration message.addRecipient(Message.RecipientType.TO, new InternetAddress(testToProperty)); } else { // Regular list of To elements for (Iterator i = messageElement.elements("to").iterator(); i.hasNext();) { Element toElement = (Element) i.next(); InternetAddress address = createAddress(toElement); message.addRecipient(Message.RecipientType.TO, address); } } // Set Cc for (Iterator i = messageElement.elements("cc").iterator(); i.hasNext();) { Element toElement = (Element) i.next(); InternetAddress address = createAddress(toElement); message.addRecipient(Message.RecipientType.CC, address); } // Set Bcc for (Iterator i = messageElement.elements("bcc").iterator(); i.hasNext();) { Element toElement = (Element) i.next(); InternetAddress address = createAddress(toElement); message.addRecipient(Message.RecipientType.BCC, address); } // Set headers if any for (Iterator i = messageElement.elements("header").iterator(); i.hasNext();) { final Element headerElement = (Element) i.next(); final String headerName = headerElement.element("name").getTextTrim(); final String headerValue = headerElement.element("value").getTextTrim(); message.addHeader(headerName, headerValue); } // Set subject message.setSubject(messageElement.element("subject").getStringValue()); // Handle body Element textElement = messageElement.element("text"); Element bodyElement = messageElement.element("body"); if (textElement != null) { // Old deprecated mechanism (simple text body) message.setText(textElement.getStringValue()); } else if (bodyElement != null) { // New mechanism with body and parts handleBody(pipelineContext, dataInputSystemId, message, bodyElement); } else { throw new OXFException("Main text or body element not found");// TODO: location info } // Send message Transport transport = session.getTransport("smtp"); Transport.send(message); transport.close(); } catch (Exception e) { throw new OXFException(e); } } private void handleBody(PipelineContext pipelineContext, String dataInputSystemId, Part parentPart, Element bodyElement) throws Exception { // Find out if there are embedded parts Iterator parts = bodyElement.elementIterator("part"); String multipart; if (bodyElement.getName().equals("body")) { multipart = bodyElement.attributeValue("mime-multipart"); if (multipart != null && !parts.hasNext()) throw new OXFException("mime-multipart attribute on body element requires part children elements"); String contentTypeFromAttribute = NetUtils.getContentTypeMediaType(bodyElement.attributeValue("content-type")); if (contentTypeFromAttribute != null && contentTypeFromAttribute.startsWith("multipart/")) contentTypeFromAttribute.substring("multipart/".length()); if (parts.hasNext() && multipart == null) multipart = DEFAULT_MULTIPART; } else { String contentTypeAttribute = NetUtils.getContentTypeMediaType(bodyElement.attributeValue("content-type")); multipart = (contentTypeAttribute != null && contentTypeAttribute.startsWith("multipart/")) ? contentTypeAttribute.substring("multipart/".length()) : null; } if (multipart != null) { // Multipart content is requested MimeMultipart mimeMultipart = new MimeMultipart(multipart); // Iterate through parts for (Iterator i = parts; i.hasNext();) { Element partElement = (Element) i.next(); MimeBodyPart mimeBodyPart = new MimeBodyPart(); handleBody(pipelineContext, dataInputSystemId, mimeBodyPart, partElement); mimeMultipart.addBodyPart(mimeBodyPart); } // Set content on parent part parentPart.setContent(mimeMultipart); } else { // No multipart, just use the content of the element and add to the current part (which can be the main message) handlePart(pipelineContext, dataInputSystemId, parentPart, bodyElement); } } private void handlePart(PipelineContext pipelineContext, String dataInputSystemId, Part parentPart, Element partOrBodyElement) throws Exception { final String name = partOrBodyElement.attributeValue("name"); String contentTypeAttribute = partOrBodyElement.attributeValue("content-type"); final String contentType = NetUtils.getContentTypeMediaType(contentTypeAttribute); final String charset; { String c = NetUtils.getContentTypeCharset(contentTypeAttribute); charset = (c != null) ? c : DEFAULT_TEXT_ENCODING; } final String contentTypeWithCharset = contentType + "; charset=" + charset; final String src = partOrBodyElement.attributeValue("src"); // Either a String or a FileItem final Object content; if (src != null) { // Content of the part is not inline // Generate a Document from the source SAXSource source = getSAXSource(EmailProcessor.this, pipelineContext, src, dataInputSystemId, contentType); content = handleStreamedPartContent(pipelineContext, source, contentType, charset); } else { // Content of the part is inline // In the cases of text/html and XML, there must be exactly one root element boolean needsRootElement = "text/html".equals(contentType);// || ProcessorUtils.isXMLContentType(contentType); if (needsRootElement && partOrBodyElement.elements().size() != 1) throw new ValidationException("The <body> or <part> element must contain exactly one element for text/html", (LocationData) partOrBodyElement.getData()); // Create Document and convert it into a String Element rootElement = (Element)(needsRootElement ? partOrBodyElement.elements().get(0) : partOrBodyElement); Document partDocument = new NonLazyUserDataDocument(); partDocument.setRootElement((Element) rootElement.clone()); content = handleInlinePartContent(partDocument, contentType); } if (!(ProcessorUtils.isTextContentType(contentType) || ProcessorUtils.isXMLContentType(contentType))) { // This is binary content if (content instanceof FileItem) { final FileItem fileItem = (FileItem) content; parentPart.setDataHandler(new DataHandler(new DataSource() { public String getContentType() { return contentType; } public InputStream getInputStream() throws IOException { return fileItem.getInputStream(); } public String getName() { return name; } public OutputStream getOutputStream() throws IOException { throw new IOException("Write operation not supported"); } })); } else { byte[] data = XMLUtils.base64StringToByteArray((String) content); parentPart.setDataHandler(new DataHandler(new SimpleBinaryDataSource(name, contentType, data))); } } else { // This is text content if (content instanceof FileItem) { // The text content was encoded when written to the FileItem final FileItem fileItem = (FileItem) content; parentPart.setDataHandler(new DataHandler(new DataSource() { public String getContentType() { // This always contains a charset return contentTypeWithCharset; } public InputStream getInputStream() throws IOException { // This is encoded with the appropriate charset (user-defined, or the default) return fileItem.getInputStream(); } public String getName() { return name; } public OutputStream getOutputStream() throws IOException { throw new IOException("Write operation not supported"); } })); } else { parentPart.setDataHandler(new DataHandler(new SimpleTextDataSource(name, contentTypeWithCharset, (String) content))); } } // Set content-disposition header String contentDisposition = partOrBodyElement.attributeValue("content-disposition"); if (contentDisposition != null) parentPart.setDisposition(contentDisposition); // Set content-id header String contentId = partOrBodyElement.attributeValue("content-id"); if (contentId != null) parentPart.setHeader("content-id", "<" + contentId + ">"); //part.setContentID(contentId); } private String handleInlinePartContent(Document document, String contentType) throws SAXException { if ("text/html".equals(contentType)) { // Convert XHTML into an HTML String StringWriter writer = new StringWriter(); TransformerHandler identity = TransformerUtils.getIdentityTransformerHandler(); identity.getTransformer().setOutputProperty(OutputKeys.METHOD, "html"); identity.setResult(new StreamResult(writer)); LocationSAXWriter saxw = new LocationSAXWriter(); saxw.setContentHandler(identity); saxw.write(document); return writer.toString(); } else { // For other types, just return the text nodes return document.getStringValue(); } } public static FileItem handleStreamedPartContent(PipelineContext pipelineContext, SAXSource source, String contentType, String encoding) throws IOException, TransformerException { final FileItem fileItem = new DefaultFileItemFactory(RequestGenerator.getMaxMemorySizeProperty(), SystemUtils.getTemporaryDirectory()) .createItem("dummy", "dummy", false, null); // Make sure the file is deleted when the context is destroyed pipelineContext.addContextListener(new PipelineContext.ContextListenerAdapter() { public void contextDestroyed(boolean success) { fileItem.delete(); } }); // Write character content to the FileItem instance Writer writer = null; OutputStream os = null; final boolean useWriter = ProcessorUtils.isTextContentType(contentType) || ProcessorUtils.isXMLContentType(contentType); try { os = fileItem.getOutputStream(); if (useWriter) writer = new BufferedWriter(new OutputStreamWriter(os, encoding)); final OutputStream _os = os; final Writer _writer = writer; Transformer identity = TransformerUtils.getIdentityTransformer(); identity.transform(source, new SAXResult(new ForwardingContentHandler() { public void characters(char[] chars, int start, int length) { try { if (useWriter) _writer.write(chars, start, length); else _os.write(Base64.decode(new String(chars, start, length))); } catch (IOException e) { throw new OXFException(e); } } })); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { throw new OXFException(e); } } if (os != null) { try { os.close(); } catch (IOException e) { throw new OXFException(e); } } } return fileItem; } private InternetAddress createAddress(Element addressElement) throws AddressException, UnsupportedEncodingException { String email = addressElement.element("email").getStringValue(); Element nameElement = addressElement.element("name"); return nameElement == null ? new InternetAddress(email) : new InternetAddress(email, nameElement.getStringValue()); } private class SimpleTextDataSource implements DataSource { String contentType; String text; String name; public SimpleTextDataSource(String name, String contentType, String text) { this.name = name; this.contentType = contentType; this.text = text; } public String getContentType() { return contentType; } public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(text.getBytes("utf-8")); } public String getName() { return name; } public OutputStream getOutputStream() throws IOException { throw new IOException("Write operation not supported"); } } private class SimpleBinaryDataSource implements DataSource { String contentType; byte[] data; String name; public SimpleBinaryDataSource(String name, String contentType, byte[] data) { this.name = name; this.contentType = contentType; this.data = data; } public String getContentType() { return contentType; } public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(data); } public String getName() { return name; } public OutputStream getOutputStream() throws IOException { throw new IOException("Write operation not supported"); } } public static SAXSource getSAXSource(Processor processor, PipelineContext pipelineContext, String href, String base, String contentType) { try { // There are two cases: // 1. We read the source as SAX // o This is required when reading from a processor input; in this case, we behave like // the inline case // o When reading from another type of URI, the resource could be in theory any type // of file. // 2. We don't read the source as SAX // o It is particularly useful to support this when resources are to be used as binary // attachments such as images. // o Here, we consider that the source can be XML, text/html, text/*, // or binary. We do not handle reading Base64-encoded files. We leverage the URL // generator to obtain the content in XML format. XMLReader xmlReader; { String inputName = ProcessorImpl.getProcessorInputSchemeInputName(href); if (inputName != null) { // Resolve to input of current processor xmlReader = new ProcessorOutputXMLReader(pipelineContext, processor.getInputByName(inputName).getOutput()); } else { // Resolve to regular URI Processor urlGenerator = (contentType == null) ? new URLGenerator(URLFactory.createURL(base, href)) : new URLGenerator(URLFactory.createURL(base, href), contentType, true); xmlReader = new ProcessorOutputXMLReader(pipelineContext, urlGenerator.createOutput(ProcessorImpl.OUTPUT_DATA)); } } // Return SAX Source based on XML Reader SAXSource saxSource = new SAXSource(xmlReader, new InputSource()); saxSource.setSystemId(href); return saxSource; } catch (IOException e) { throw new OXFException(e); } } private class SMTPAuthenticator extends javax.mail.Authenticator { private String username; private String password; public SMTPAuthenticator(String user, String pass){ username = user; password = pass; } public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username,password); } } } // Set content-transfer-encoding header // final String contentTransferEncoding = partElement.attributeValue("content-transfer-encoding"); // // MimeBodyPart part = new MimeBodyPart() { // protected void updateHeaders() throws MessagingException { // super.updateHeaders(); // if (contentTransferEncoding != null) // setHeader("Content-Transfer-Encoding", contentTransferEncoding); // } // }; // // Set content-disposition header // String contentDisposition = partElement.attributeValue("content-disposition"); // if (contentDisposition != null) // part.setDisposition(contentDisposition); // // part.setDataHandler(new DataHandler(new SimpleTextDataSource(name, contentType, content))); // mimeMultipart.addBodyPart(part); -- You receive this message as a subscriber of the [hidden email] mailing list. To unsubscribe: mailto:[hidden email] For general help: mailto:[hidden email]?subject=help ObjectWeb mailing lists service home page: http://www.objectweb.org/wws |
Administrator
|
Ryan,
I have checked in your changes, and updated the documentation accordingly. Thank you for the contribution! Alex On 3/1/07, Ryan Puddephatt <[hidden email]> wrote: > Alex/Erik, > I've attached a change to the email processor that allows it to pass > credentials by adding the following to the config. > > <credentials> > <username>user</username> > <password>password</password> > </credentials> > > Thanks > > Ryan > > Ryan Puddephatt > Software Engineer > > Teleflex Group - IT UK > 1 Michaelson Square > Livingston > West Lothian > Scotland > EH54 7DP > > e> [hidden email] <mailto:[hidden email]> > t> +44(0)1506 407 110 > f> +44(0)1506 407 108 > w> www.teleflex.com <http://www.teleflex.com> > > > mixed alternative related multipart/mixed multipart/alternative > multipart/related multipart/.+ > /** > * Copyright (C) 2004 Orbeon, Inc. > * > * This program is free software; you can redistribute it and/or modify it > under the terms of the > * GNU Lesser General Public License as published by the Free Software > Foundation; either version > * 2.1 of the License, or (at your option) any later version. > * > * This program is distributed in the hope that it will be useful, but > WITHOUT ANY WARRANTY; > * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A > PARTICULAR PURPOSE. > * See the GNU Lesser General Public License for more details. > * > * The full text of the license is available at > http://www.gnu.org/copyleft/lesser.html > */ > package org.orbeon.oxf.processor; > > import > org.apache.commons.fileupload.DefaultFileItemFactory; > import org.apache.commons.fileupload.FileItem; > import org.apache.log4j.Logger; > import org.dom4j.Document; > import org.dom4j.Element; > import org.orbeon.oxf.common.OXFException; > import org.orbeon.oxf.common.ValidationException; > import org.orbeon.oxf.pipeline.api.PipelineContext; > import org.orbeon.oxf.processor.generator.RequestGenerator; > import org.orbeon.oxf.processor.generator.URLGenerator; > import org.orbeon.oxf.resources.URLFactory; > import org.orbeon.oxf.util.Base64; > import org.orbeon.oxf.util.LoggerFactory; > import org.orbeon.oxf.util.NetUtils; > import org.orbeon.oxf.util.SystemUtils; > import org.orbeon.oxf.xml.ForwardingContentHandler; > import org.orbeon.oxf.xml.ProcessorOutputXMLReader; > import org.orbeon.oxf.xml.TransformerUtils; > import org.orbeon.oxf.xml.XMLUtils; > import org.orbeon.oxf.xml.dom4j.LocationData; > import org.orbeon.oxf.xml.dom4j.LocationSAXWriter; > import org.orbeon.oxf.xml.dom4j.NonLazyUserDataDocument; > import org.xml.sax.InputSource; > import org.xml.sax.SAXException; > import org.xml.sax.XMLReader; > > import javax.activation.DataHandler; > import javax.activation.DataSource; > import javax.mail.Message; > import javax.mail.Part; > import javax.mail.Session; > import javax.mail.Transport; > import javax.mail.internet.*; > import javax.mail.Authenticator; > import javax.mail.PasswordAuthentication; > import javax.xml.transform.OutputKeys; > import javax.xml.transform.Transformer; > import javax.xml.transform.TransformerException; > import javax.xml.transform.sax.SAXResult; > import javax.xml.transform.sax.SAXSource; > import javax.xml.transform.sax.TransformerHandler; > import javax.xml.transform.stream.StreamResult; > import java.io.*; > import java.util.Iterator; > import java.util.Properties; > > /** > * This processor allows sending emails. It supports multipart messages and > inline as well as > * out-of-line attachments. > * > * For some useful JavaMail information: > http://java.sun.com/products/javamail/FAQ.html > * > * TODO: > * o revise support of text/html > * o built-in support for HTML could handle src="cid:*" with part/message > ids > * o support text/xml? or just XHTML? > * o build message with SAX, not DOM, so streaming of input is possible [not > necessarily a big win] > */ > public class EmailProcessor extends ProcessorImpl { > static private Logger logger = > LoggerFactory.createLogger(EmailProcessor.class); > > // Properties for this processor > public static final String EMAIL_SMTP_HOST = "smtp-host"; > public static final String EMAIL_TEST_TO = "test-to"; > public static final String EMAIL_TEST_SMTP_HOST = "test-smtp-host"; > > public static final String EMAIL_FORCE_TO_DEPRECATED = "forceto"; // > deprecated > public static final String EMAIL_HOST_DEPRECATED = "host"; // deprecated > > public static final String EMAIL_CONFIG_NAMESPACE_URI = > "http://www.orbeon.com/oxf/email"; > > private static final String DEFAULT_MULTIPART = "mixed"; > private static final String DEFAULT_TEXT_ENCODING = "iso-8859-1"; > > //private String username; > //private String password; > > public EmailProcessor() { > addInputInfo(new > ProcessorInputOutputInfo(INPUT_DATA, > EMAIL_CONFIG_NAMESPACE_URI)); > } > > public void start(PipelineContext pipelineContext) { > try { > Document dataDocument = > readInputAsDOM4J(pipelineContext, INPUT_DATA); > Element messageElement = dataDocument.getRootElement(); > > // Get system id (will likely be null if document is generated > dynamically) > LocationData locationData = (LocationData) > messageElement.getData(); > String dataInputSystemId = locationData.getSystemID(); > > // Set SMTP host > Properties properties = new Properties(); > String testSmtpHostProperty = > getPropertySet().getString(EMAIL_TEST_SMTP_HOST); > > if (testSmtpHostProperty != null) { > // Test SMTP Host from properties overrides the local > configuration > properties.setProperty("mail.smtp.host", > testSmtpHostProperty); > } else { > // Try regular config parameter and property > String host = > messageElement.element("smtp-host").getTextTrim(); > if (host != null && !host.equals("")) { > // Precedence goes to the local config parameter > properties.setProperty("mail.smtp.host", host); > } else { > // Otherwise try to use a property > host = > getPropertySet().getString(EMAIL_SMTP_HOST); > if (host == null) > host = > getPropertySet().getString(EMAIL_HOST_DEPRECATED); > if (host == null) > throw new OXFException("Could not find SMTP host in > configuration or in properties"); > properties.setProperty("mail.smtp.host", host); > > } > } > > // Get credentials > Element credentials = messageElement.element("credentials"); > > // Create session variable, but don't assign it > Session session = null; > > // Check if credentials are supplied > if(credentials != null && !credentials.equals("")) { > if(logger.isInfoEnabled()) > logger.info("Authentication"); > // Set the auth property to true > properties.setProperty("mail.smtp.auth", "true"); > > String username = > credentials.element("username").getStringValue(); > String password = > credentials.element("password").getStringValue(); > > if(logger.isInfoEnabled()) > logger.info("Username: "+username+"; Password: > "+password); > > // Create an authenticator > Authenticator auth = new > SMTPAuthenticator(username,password); > > // Create session with auth > session = Session.getInstance(properties,auth); > } else { > if(logger.isInfoEnabled()) > logger.info("No Authentication"); > session = Session.getInstance(properties); > } > > // Create message > Message message = new MimeMessage(session); > > // Set From > message.setFrom(createAddress(messageElement.element("from"))); > > // Set To > String testToProperty = > getPropertySet().getString(EMAIL_TEST_TO); > if (testToProperty == null) > testToProperty = > getPropertySet().getString(EMAIL_FORCE_TO_DEPRECATED); > > if (testToProperty != null) { > // Test To from properties overrides local configuration > message.addRecipient(Message.RecipientType.TO, new > InternetAddress(testToProperty)); > } else { > // Regular list of To elements > for (Iterator i = messageElement.elements("to").iterator(); > i.hasNext();) { > Element toElement = (Element) i.next(); > InternetAddress address = createAddress(toElement); > message.addRecipient(Message.RecipientType.TO, address); > } > } > > // Set Cc > for (Iterator i = messageElement.elements("cc").iterator(); > i.hasNext();) { > Element toElement = (Element) i.next(); > InternetAddress address = createAddress(toElement); > message.addRecipient(Message.RecipientType.CC, address); > } > > // Set Bcc > for (Iterator i = messageElement.elements("bcc").iterator(); > i.hasNext();) { > Element toElement = (Element) i.next(); > InternetAddress address = createAddress(toElement); > message.addRecipient(Message.RecipientType.BCC, address); > } > > // Set headers if any > for (Iterator i = messageElement.elements("header").iterator(); > i.hasNext();) { > final Element headerElement = (Element) i.next(); > final String headerName = > headerElement.element("name").getTextTrim(); > final String headerValue = > headerElement.element("value").getTextTrim(); > > message.addHeader(headerName, headerValue); > } > > // Set subject > > message.setSubject(messageElement.element("subject").getStringValue()); > > // Handle body > Element textElement = messageElement.element("text"); > Element bodyElement = messageElement.element("body"); > > if (textElement != null) { > // Old deprecated mechanism (simple text body) > message.setText(textElement.getStringValue()); > } else if (bodyElement != null) { > // New mechanism with body and parts > handleBody(pipelineContext, dataInputSystemId, message, > bodyElement); > } else { > throw new OXFException("Main text or body element not > found");// TODO: location info > } > > // Send message > Transport transport = session.getTransport("smtp"); > Transport.send(message); > transport.close(); > } catch (Exception e) { > throw new OXFException(e); > } > } > > private void handleBody(PipelineContext pipelineContext, String > dataInputSystemId, Part parentPart, Element bodyElement) throws Exception { > > // Find out if there are embedded parts > Iterator parts = bodyElement.elementIterator("part"); > String multipart; > if (bodyElement.getName().equals("body")) { > multipart = bodyElement.attributeValue("mime-multipart"); > if (multipart != null && !parts.hasNext()) > throw new OXFException("mime-multipart attribute on body > element requires part children elements"); > String contentTypeFromAttribute = > NetUtils.getContentTypeMediaType(bodyElement.attributeValue("content-type")); > if (contentTypeFromAttribute != null && > contentTypeFromAttribute.startsWith("multipart/")) > > contentTypeFromAttribute.substring("multipart/".length()); > if (parts.hasNext() && multipart == null) > multipart = DEFAULT_MULTIPART; > } else { > String contentTypeAttribute = > NetUtils.getContentTypeMediaType(bodyElement.attributeValue("content-type")); > multipart = (contentTypeAttribute != null && > contentTypeAttribute.startsWith("multipart/")) ? > contentTypeAttribute.substring("multipart/".length()) : null; > } > > if (multipart != null) { > // Multipart content is requested > MimeMultipart mimeMultipart = new MimeMultipart(multipart); > > // Iterate through parts > for (Iterator i = parts; i.hasNext();) { > Element partElement = (Element) i.next(); > > MimeBodyPart mimeBodyPart = new MimeBodyPart(); > handleBody(pipelineContext, dataInputSystemId, mimeBodyPart, > partElement); > mimeMultipart.addBodyPart(mimeBodyPart); > } > > // Set content on parent part > parentPart.setContent(mimeMultipart); > } else { > // No multipart, just use the content of the element and add to > the current part (which can be the main message) > handlePart(pipelineContext, dataInputSystemId, parentPart, > bodyElement); > } > } > > private void handlePart(PipelineContext pipelineContext, String > dataInputSystemId, Part parentPart, Element partOrBodyElement) throws > Exception { > final String name = > partOrBodyElement.attributeValue("name"); > String contentTypeAttribute = > partOrBodyElement.attributeValue("content-type"); > final String contentType = > NetUtils.getContentTypeMediaType(contentTypeAttribute); > final String charset; > { > String c = NetUtils.getContentTypeCharset(contentTypeAttribute); > charset = (c != null) ? c : DEFAULT_TEXT_ENCODING; > } > final String contentTypeWithCharset = contentType + "; charset=" + > charset; > final String src = > partOrBodyElement.attributeValue("src"); > > // Either a String or a FileItem > final Object content; > if (src != null) { > // Content of the part is not inline > > // Generate a Document from the source > SAXSource source = getSAXSource(EmailProcessor.this, > pipelineContext, src, dataInputSystemId, contentType); > content = > handleStreamedPartContent(pipelineContext, source, > contentType, charset); > } else { > // Content of the part is inline > > // In the cases of text/html and XML, there must be exactly one > root element > boolean needsRootElement = > "text/html".equals(contentType);// || > ProcessorUtils.isXMLContentType(contentType); > if (needsRootElement && partOrBodyElement.elements().size() != > 1) > throw new ValidationException("The <body> or <part> element > must contain exactly one element for text/html", > (LocationData) partOrBodyElement.getData()); > > // Create Document and convert it into a String > Element rootElement = (Element)(needsRootElement ? > partOrBodyElement.elements().get(0) : partOrBodyElement); > Document partDocument = new NonLazyUserDataDocument(); > partDocument.setRootElement((Element) rootElement.clone()); > content = handleInlinePartContent(partDocument, > contentType); > } > > if (!(ProcessorUtils.isTextContentType(contentType) > || ProcessorUtils.isXMLContentType(contentType))) { > // This is binary content > if (content instanceof FileItem) { > final FileItem fileItem = (FileItem) content; > parentPart.setDataHandler(new DataHandler(new DataSource() { > public String getContentType() { > return contentType; > } > > public InputStream getInputStream() throws IOException { > return fileItem.getInputStream(); > } > > public String getName() { > return name; > } > > public OutputStream getOutputStream() throws IOException > { > throw new IOException("Write operation not > supported"); > } > })); > } else { > byte[] data = > XMLUtils.base64StringToByteArray((String) content); > parentPart.setDataHandler(new DataHandler(new > SimpleBinaryDataSource(name, contentType, data))); > } > } else { > // This is text content > if (content instanceof FileItem) { > // The text content was encoded when written to the FileItem > final FileItem fileItem = (FileItem) content; > parentPart.setDataHandler(new DataHandler(new DataSource() { > public String getContentType() { > // This always contains a charset > return contentTypeWithCharset; > } > > public InputStream getInputStream() throws IOException { > // This is encoded with the appropriate charset > (user-defined, or the default) > return fileItem.getInputStream(); > } > > public String getName() { > return name; > } > > public OutputStream getOutputStream() throws IOException > { > throw new IOException("Write operation not > supported"); > } > })); > } else { > parentPart.setDataHandler(new DataHandler(new > SimpleTextDataSource(name, contentTypeWithCharset, (String) content))); > } > } > > // Set content-disposition header > String contentDisposition = > partOrBodyElement.attributeValue("content-disposition"); > if (contentDisposition != null) > parentPart.setDisposition(contentDisposition); > > // Set content-id header > String contentId = > partOrBodyElement.attributeValue("content-id"); > if (contentId != null) > parentPart.setHeader("content-id", "<" + contentId + ">"); > //part.setContentID(contentId); > } > > private String handleInlinePartContent(Document > document, String contentType) throws SAXException { > if ("text/html".equals(contentType)) { > // Convert XHTML into an HTML String > StringWriter writer = new StringWriter(); > TransformerHandler identity = > TransformerUtils.getIdentityTransformerHandler(); > identity.getTransformer().setOutputProperty(OutputKeys.METHOD, > "html"); > identity.setResult(new StreamResult(writer)); > LocationSAXWriter saxw = new LocationSAXWriter(); > saxw.setContentHandler(identity); > saxw.write(document); > > return writer.toString(); > } else { > // For other types, just return the text nodes > return document.getStringValue(); > } > } > > public static FileItem > handleStreamedPartContent(PipelineContext pipelineContext, > SAXSource source, String contentType, String encoding) > throws IOException, TransformerException { > > final FileItem fileItem = new > DefaultFileItemFactory(RequestGenerator.getMaxMemorySizeProperty(), > SystemUtils.getTemporaryDirectory()) > .createItem("dummy", "dummy", false, null); > // Make sure the file is deleted when the context is destroyed > pipelineContext.addContextListener(new > PipelineContext.ContextListenerAdapter() { > public void contextDestroyed(boolean success) { > fileItem.delete(); > } > }); > // Write character content to the FileItem instance > Writer writer = null; > OutputStream os = null; > > final boolean useWriter = > ProcessorUtils.isTextContentType(contentType) || > ProcessorUtils.isXMLContentType(contentType); > > try { > os = fileItem.getOutputStream(); > if (useWriter) > writer = new BufferedWriter(new OutputStreamWriter(os, > encoding)); > final OutputStream _os = os; > final Writer _writer = writer; > Transformer identity = > TransformerUtils.getIdentityTransformer(); > identity.transform(source, new SAXResult(new > ForwardingContentHandler() { > public void characters(char[] chars, int start, int length) > { > try { > if (useWriter) > _writer.write(chars, start, length); > else > _os.write(Base64.decode(new String(chars, start, > length))); > > } catch (IOException e) { > throw new OXFException(e); > } > } > })); > } finally { > if (writer != null) { > try { > writer.close(); > } catch (IOException e) { > throw new OXFException(e); > } > } > if (os != null) { > try { > os.close(); > } catch (IOException e) { > throw new OXFException(e); > } > } > } > > return fileItem; > } > > private InternetAddress createAddress(Element addressElement) throws > AddressException, UnsupportedEncodingException { > String email = addressElement.element("email").getStringValue(); > Element nameElement = addressElement.element("name"); > return nameElement == null ? new InternetAddress(email) > : new InternetAddress(email, nameElement.getStringValue()); > } > > private class SimpleTextDataSource implements DataSource { > String contentType; > String text; > String name; > > public SimpleTextDataSource(String name, String contentType, String > text) { > this.name = name; > this.contentType = contentType; > this.text = text; > } > > public String getContentType() { > return contentType; > } > > public InputStream getInputStream() throws IOException { > return new ByteArrayInputStream(text.getBytes("utf-8")); > } > > public String getName() { > return name; > } > > public OutputStream getOutputStream() throws IOException { > throw new IOException("Write operation not supported"); > } > } > > private class SimpleBinaryDataSource implements DataSource { > String contentType; > byte[] data; > String name; > > public SimpleBinaryDataSource(String name, String contentType, > byte[] data) { > this.name = name; > this.contentType = contentType; > this.data = data; > } > > public String getContentType() { > return contentType; > } > > public InputStream getInputStream() throws IOException { > return new ByteArrayInputStream(data); > } > > public String getName() { > return name; > } > > public OutputStream getOutputStream() throws IOException { > throw new IOException("Write operation not supported"); > } > } > > public static SAXSource getSAXSource(Processor processor, > PipelineContext pipelineContext, String href, String base, String > contentType) { > try { > // There are two cases: > // 1. We read the source as SAX > // o This is required when reading from a processor input; in > this case, we behave like > // the inline case > // o When reading from another type of URI, the resource > could be in theory any type > // of file. > // 2. We don't read the source as SAX > // o It is particularly useful to support this when resources > are to be used as binary > // attachments such as images. > // o Here, we consider that the source can be XML, text/html, > text/*, > // or binary. We do not handle reading Base64-encoded > files. We leverage the URL > // generator to obtain the content in XML format. > XMLReader xmlReader; > { > String inputName = > ProcessorImpl.getProcessorInputSchemeInputName(href); > if (inputName != null) { > // Resolve to input of current processor > xmlReader = new > ProcessorOutputXMLReader(pipelineContext, > processor.getInputByName(inputName).getOutput()); > } else { > // Resolve to regular URI > Processor urlGenerator = (contentType == null) > ? new URLGenerator(URLFactory.createURL(base, > href)) > : new URLGenerator(URLFactory.createURL(base, > href), contentType, true); > xmlReader = new > ProcessorOutputXMLReader(pipelineContext, > urlGenerator.createOutput(ProcessorImpl.OUTPUT_DATA)); > } > } > > // Return SAX Source based on XML Reader > SAXSource saxSource = new SAXSource(xmlReader, new > InputSource()); > saxSource.setSystemId(href); > return saxSource; > } catch (IOException e) { > throw new OXFException(e); > } > } > > private class SMTPAuthenticator extends javax.mail.Authenticator { > private String username; > private String password; > > public SMTPAuthenticator(String user, String pass){ > username = user; > password = pass; > } > > public PasswordAuthentication getPasswordAuthentication() { > return new > PasswordAuthentication(username,password); > } > } > } > > // Set content-transfer-encoding header > // final String contentTransferEncoding = > partElement.attributeValue("content-transfer-encoding"); > // > // MimeBodyPart part = new MimeBodyPart() { > // protected void updateHeaders() throws > MessagingException { > // super.updateHeaders(); > // if (contentTransferEncoding != null) > // > setHeader("Content-Transfer-Encoding", > contentTransferEncoding); > // } > // }; > // // Set content-disposition header > // String contentDisposition = > partElement.attributeValue("content-disposition"); > // if (contentDisposition != null) > // part.setDisposition(contentDisposition); > // > // part.setDataHandler(new DataHandler(new > SimpleTextDataSource(name, contentType, content))); > // mimeMultipart.addBodyPart(part); > > > -- > You receive this message as a subscriber of the [hidden email] > mailing list. > To unsubscribe: mailto:[hidden email] > For general help: mailto:[hidden email]?subject=help > ObjectWeb mailing lists service home page: http://www.objectweb.org/wws > > -- Orbeon Forms - Web 2.0 Forms for the Enterprise http://www.orbeon.com/ -- You receive this message as a subscriber of the [hidden email] mailing list. To unsubscribe: mailto:[hidden email] For general help: mailto:[hidden email]?subject=help ObjectWeb mailing lists service home page: http://www.objectweb.org/wws |
In reply to this post by Ryan Puddephatt
All,
attempting to use the 'credentials' element, but seem to get stuck at schema validation ('Error tag name "credentials" is not allowed...') Looking at orbeon\src\java\org\orbeon\oxf\xml\schemas\email.rng, there is no mention of 'credentials'. I can fix this for me, but you might want to update your email.rng in the repository. And thank you for this addition, Ryan! Henrik On 3/1/07,
Ryan Puddephatt <[hidden email]> wrote:
-- You receive this message as a subscriber of the [hidden email] mailing list. To unsubscribe: mailto:[hidden email] For general help: mailto:[hidden email]?subject=help ObjectWeb mailing lists service home page: http://www.objectweb.org/wws |
Administrator
|
Oops, it looks like we forgot to add the changes to email.rng. This is
done now. -Erik Henrik Pettersen wrote: > All, > > attempting to use the 'credentials' element, but seem to get stuck at > schema validation ('Error tag name "credentials" is not allowed...') > > Looking at orbeon\src\java\org\orbeon\oxf\xml\schemas\email.rng, there > is no mention of 'credentials'. > > I can fix this for me, but you might want to update your email.rng in > the repository. > > And thank you for this addition, Ryan! > > Henrik > > On 3/1/07, * Ryan Puddephatt* <[hidden email] > <mailto:[hidden email]>> wrote: > > Alex/Erik, > I've attached a change to the email processor that allows it to pass > credentials by adding the following to the config. > > <credentials> > <username>user</username> > <password>password</password> > </credentials> > > Thanks > > Ryan > > Ryan Puddephatt > Software Engineer > > Teleflex Group - IT UK > 1 Michaelson Square > Livingston > West Lothian > Scotland > EH54 7DP > > e> [hidden email] <mailto:[hidden email]> > <mailto:[hidden email] <mailto:[hidden email]>> > t> +44(0)1506 407 110 > f> +44(0)1506 407 108 > w> www.teleflex.com <http://www.teleflex.com> < http://www.teleflex.com> > > > mixed alternative related multipart/mixed multipart/alternative > multipart/related multipart/.+ > /** > * Copyright (C) 2004 Orbeon, Inc. > * > * This program is free software; you can redistribute it and/or > modify it under the terms of the > * GNU Lesser General Public License as published by the Free > Software Foundation; either version > * 2.1 of the License, or (at your option) any later version. > * > * This program is distributed in the hope that it will be useful, > but WITHOUT ANY WARRANTY; > * without even the implied warranty of MERCHANTABILITY or FITNESS > FOR A PARTICULAR PURPOSE. > * See the GNU Lesser General Public License for more details. > * > * The full text of the license is available at > http://www.gnu.org/copyleft/lesser.html > */ > package org.orbeon.oxf.processor; > > import org.apache.commons.fileupload.DefaultFileItemFactory; > import org.apache.commons.fileupload.FileItem; > import org.apache.log4j.Logger ; > import org.dom4j.Document; > import org.dom4j.Element; > import org.orbeon.oxf.common.OXFException; > import org.orbeon.oxf.common.ValidationException; > import org.orbeon.oxf.pipeline.api.PipelineContext; > import org.orbeon.oxf.processor.generator.RequestGenerator; > import org.orbeon.oxf.processor.generator.URLGenerator; > import org.orbeon.oxf.resources.URLFactory; > import org.orbeon.oxf.util.Base64; > import org.orbeon.oxf.util.LoggerFactory ; > import org.orbeon.oxf.util.NetUtils; > import org.orbeon.oxf.util.SystemUtils; > import org.orbeon.oxf.xml.ForwardingContentHandler; > import org.orbeon.oxf.xml.ProcessorOutputXMLReader; > import org.orbeon.oxf.xml.TransformerUtils ; > import org.orbeon.oxf.xml.XMLUtils; > import org.orbeon.oxf.xml.dom4j.LocationData; > import org.orbeon.oxf.xml.dom4j.LocationSAXWriter; > import org.orbeon.oxf.xml.dom4j.NonLazyUserDataDocument; > import org.xml.sax.InputSource ; > import org.xml.sax.SAXException; > import org.xml.sax.XMLReader; > > import javax.activation.DataHandler; > import javax.activation.DataSource; > import javax.mail.Message; > import javax.mail.Part; > import javax.mail.Session; > import javax.mail.Transport; > import javax.mail.internet.*; > import javax.mail.Authenticator; > import javax.mail.PasswordAuthentication; > import javax.xml.transform.OutputKeys; > import javax.xml.transform.Transformer ; > import javax.xml.transform.TransformerException; > import javax.xml.transform.sax.SAXResult; > import javax.xml.transform.sax.SAXSource; > import javax.xml.transform.sax.TransformerHandler; > import javax.xml.transform.stream.StreamResult ; > import java.io.*; > import java.util.Iterator; > import java.util.Properties; > > /** > * This processor allows sending emails. It supports multipart > messages and inline as well as > * out-of-line attachments. > * > * For some useful JavaMail information: > http://java.sun.com/products/javamail/FAQ.html > <http://java.sun.com/products/javamail/FAQ.html> > * > * TODO: > * o revise support of text/html > * o built-in support for HTML could handle src="cid:*" with > part/message ids > * o support text/xml? or just XHTML? > * o build message with SAX, not DOM, so streaming of input is > possible [not necessarily a big win] > */ > public class EmailProcessor extends ProcessorImpl { > static private Logger logger = > LoggerFactory.createLogger(EmailProcessor.class); > > // Properties for this processor > public static final String EMAIL_SMTP_HOST = "smtp-host"; > public static final String EMAIL_TEST_TO = "test-to"; > public static final String EMAIL_TEST_SMTP_HOST = "test-smtp-host"; > > public static final String EMAIL_FORCE_TO_DEPRECATED = "forceto"; > // deprecated > public static final String EMAIL_HOST_DEPRECATED = "host"; // > deprecated > > public static final String EMAIL_CONFIG_NAMESPACE_URI = " > http://www.orbeon.com/oxf/email"; > > private static final String DEFAULT_MULTIPART = "mixed"; > private static final String DEFAULT_TEXT_ENCODING = "iso-8859-1"; > > //private String username; > //private String password; > > public EmailProcessor() { > addInputInfo(new ProcessorInputOutputInfo(INPUT_DATA, > EMAIL_CONFIG_NAMESPACE_URI)); > } > > public void start(PipelineContext pipelineContext) { > try { > Document dataDocument = readInputAsDOM4J(pipelineContext, > INPUT_DATA); > Element messageElement = dataDocument.getRootElement(); > > // Get system id (will likely be null if document is > generated dynamically) > LocationData locationData = (LocationData) > messageElement.getData(); > String dataInputSystemId = locationData.getSystemID(); > > // Set SMTP host > Properties properties = new Properties(); > String testSmtpHostProperty = > getPropertySet().getString(EMAIL_TEST_SMTP_HOST); > > if (testSmtpHostProperty != null) { > // Test SMTP Host from properties overrides the local > configuration > properties.setProperty("mail.smtp.host", > testSmtpHostProperty); > } else { > // Try regular config parameter and property > String host = messageElement.element > ("smtp-host").getTextTrim(); > if (host != null && !host.equals("")) { > // Precedence goes to the local config parameter > properties.setProperty ("mail.smtp.host", host); > } else { > // Otherwise try to use a property > host = getPropertySet().getString(EMAIL_SMTP_HOST); > if (host == null) > host = > getPropertySet().getString(EMAIL_HOST_DEPRECATED); > if (host == null) > throw new OXFException("Could not find SMTP > host in configuration or in properties"); > properties.setProperty("mail.smtp.host", host); > > } > } > > // Get credentials > Element credentials = messageElement.element("credentials"); > > // Create session variable, but don't assign it > Session session = null; > > // Check if credentials are supplied > if(credentials != null && ! credentials.equals("")) { > if(logger.isInfoEnabled()) > logger.info("Authentication"); > // Set the auth property to true > properties.setProperty("mail.smtp.auth", "true"); > > String username = > credentials.element("username").getStringValue(); > String password = > credentials.element("password").getStringValue(); > > if(logger.isInfoEnabled()) > logger.info ("Username: "+username+"; > Password: "+password); > > // Create an authenticator > Authenticator auth = new > SMTPAuthenticator(username,password); > > // Create session with auth > session = Session.getInstance(properties,auth); > } else { > if(logger.isInfoEnabled()) > logger.info("No Authentication"); > session = Session.getInstance(properties); > } > > // Create message > Message message = new MimeMessage(session); > > // Set From > message.setFrom(createAddress( > messageElement.element("from"))); > > // Set To > String testToProperty = > getPropertySet().getString(EMAIL_TEST_TO); > if (testToProperty == null) > testToProperty = > getPropertySet().getString(EMAIL_FORCE_TO_DEPRECATED); > > if (testToProperty != null) { > // Test To from properties overrides local configuration > message.addRecipient( Message.RecipientType.TO > <http://Message.RecipientType.TO>, new InternetAddress(testToProperty)); > } else { > // Regular list of To elements > for (Iterator i = > messageElement.elements("to").iterator(); i.hasNext();) { > Element toElement = (Element) i.next(); > InternetAddress address = createAddress(toElement); > message.addRecipient( Message.RecipientType.TO > <http://Message.RecipientType.TO>, address); > } > } > > // Set Cc > for (Iterator i = > messageElement.elements("cc").iterator(); i.hasNext();) { > Element toElement = (Element) i.next(); > InternetAddress address = createAddress(toElement); > message.addRecipient( Message.RecipientType.CC > <http://Message.RecipientType.CC>, address); > } > > // Set Bcc > for (Iterator i = > messageElement.elements("bcc").iterator(); i.hasNext();) { > Element toElement = (Element) i.next(); > InternetAddress address = createAddress(toElement); > message.addRecipient(Message.RecipientType.BCC, address); > } > > // Set headers if any > for (Iterator i = > messageElement.elements("header").iterator(); i.hasNext();) { > final Element headerElement = (Element) i.next(); > final String headerName = > headerElement.element("name").getTextTrim(); > final String headerValue = > headerElement.element("value").getTextTrim(); > > message.addHeader(headerName, headerValue); > } > > // Set subject > > message.setSubject(messageElement.element("subject").getStringValue()); > > // Handle body > Element textElement = messageElement.element("text"); > Element bodyElement = messageElement.element("body"); > > if (textElement != null) { > // Old deprecated mechanism (simple text body) > message.setText(textElement.getStringValue()); > } else if (bodyElement != null) { > // New mechanism with body and parts > handleBody(pipelineContext, dataInputSystemId, > message, bodyElement); > } else { > throw new OXFException("Main text or body element not > found");// TODO: location info > } > > // Send message > Transport transport = session.getTransport("smtp"); > Transport.send(message); > transport.close(); > } catch (Exception e) { > throw new OXFException(e); > } > } > > private void handleBody(PipelineContext pipelineContext, String > dataInputSystemId, Part parentPart, Element bodyElement) throws > Exception { > > // Find out if there are embedded parts > Iterator parts = bodyElement.elementIterator("part"); > String multipart; > if (bodyElement.getName().equals("body")) { > multipart = bodyElement.attributeValue("mime-multipart"); > if (multipart != null && !parts.hasNext()) > throw new OXFException("mime-multipart attribute on > body element requires part children elements"); > String contentTypeFromAttribute = > NetUtils.getContentTypeMediaType(bodyElement.attributeValue("content-type")); > if (contentTypeFromAttribute != null && > contentTypeFromAttribute.startsWith ("multipart/")) > > contentTypeFromAttribute.substring("multipart/".length()); > if (parts.hasNext() && multipart == null) > multipart = DEFAULT_MULTIPART; > } else { > String contentTypeAttribute = > NetUtils.getContentTypeMediaType(bodyElement.attributeValue("content-type")); > multipart = (contentTypeAttribute != null && > contentTypeAttribute.startsWith("multipart/")) ? > contentTypeAttribute.substring("multipart/".length()) : null; > } > > if (multipart != null) { > // Multipart content is requested > MimeMultipart mimeMultipart = new MimeMultipart(multipart); > > // Iterate through parts > for (Iterator i = parts; i.hasNext();) { > Element partElement = (Element) i.next(); > > MimeBodyPart mimeBodyPart = new MimeBodyPart(); > handleBody(pipelineContext, dataInputSystemId, > mimeBodyPart, partElement); > mimeMultipart.addBodyPart(mimeBodyPart); > } > > // Set content on parent part > parentPart.setContent(mimeMultipart); > } else { > // No multipart, just use the content of the element and > add to the current part (which can be the main message) > handlePart(pipelineContext, dataInputSystemId, > parentPart, bodyElement); > } > } > > private void handlePart(PipelineContext pipelineContext, String > dataInputSystemId, Part parentPart, Element partOrBodyElement) > throws Exception { > final String name = partOrBodyElement.attributeValue("name"); > String contentTypeAttribute = > partOrBodyElement.attributeValue("content-type"); > final String contentType = > NetUtils.getContentTypeMediaType(contentTypeAttribute); > final String charset; > { > String c = > NetUtils.getContentTypeCharset(contentTypeAttribute); > charset = (c != null) ? c : DEFAULT_TEXT_ENCODING; > } > final String contentTypeWithCharset = contentType + "; > charset=" + charset; > final String src = partOrBodyElement.attributeValue("src"); > > // Either a String or a FileItem > final Object content; > if (src != null) { > // Content of the part is not inline > > // Generate a Document from the source > SAXSource source = getSAXSource( EmailProcessor.this, > pipelineContext, src, dataInputSystemId, contentType); > content = handleStreamedPartContent(pipelineContext, > source, contentType, charset); > } else { > // Content of the part is inline > > // In the cases of text/html and XML, there must be > exactly one root element > boolean needsRootElement = > "text/html".equals(contentType);// || > ProcessorUtils.isXMLContentType(contentType); > if (needsRootElement && > partOrBodyElement.elements().size() != 1) > throw new ValidationException("The <body> or <part> > element must contain exactly one element for text/html", > (LocationData) partOrBodyElement.getData()); > > // Create Document and convert it into a String > Element rootElement = (Element)(needsRootElement ? > partOrBodyElement.elements ().get(0) : partOrBodyElement); > Document partDocument = new NonLazyUserDataDocument(); > partDocument.setRootElement((Element) rootElement.clone()); > content = handleInlinePartContent(partDocument, > contentType); > } > > if (!(ProcessorUtils.isTextContentType(contentType) || > ProcessorUtils.isXMLContentType(contentType))) { > // This is binary content > if (content instanceof FileItem) { > final FileItem fileItem = (FileItem) content; > parentPart.setDataHandler(new DataHandler(new > DataSource() { > public String getContentType() { > return contentType; > } > > public InputStream getInputStream() throws > IOException { > return fileItem.getInputStream(); > } > > public String getName() { > return name; > } > > public OutputStream getOutputStream() throws > IOException { > throw new IOException("Write operation not > supported"); > } > })); > } else { > byte[] data = > XMLUtils.base64StringToByteArray((String) content); > parentPart.setDataHandler(new DataHandler(new > SimpleBinaryDataSource(name, contentType, data))); > } > } else { > // This is text content > if (content instanceof FileItem) { > // The text content was encoded when written to the > FileItem > final FileItem fileItem = (FileItem) content; > parentPart.setDataHandler(new DataHandler(new > DataSource() { > public String getContentType() { > // This always contains a charset > return contentTypeWithCharset; > } > > public InputStream getInputStream() throws > IOException { > // This is encoded with the appropriate > charset (user-defined, or the default) > return fileItem.getInputStream(); > } > > public String getName() { > return name; > } > > public OutputStream getOutputStream() throws > IOException { > throw new IOException("Write operation not > supported"); > } > })); > } else { > parentPart.setDataHandler(new DataHandler(new > SimpleTextDataSource(name, contentTypeWithCharset, (String) content))); > } > } > > // Set content-disposition header > String contentDisposition = > partOrBodyElement.attributeValue("content-disposition"); > if (contentDisposition != null) > parentPart.setDisposition(contentDisposition); > > // Set content-id header > String contentId = > partOrBodyElement.attributeValue("content-id"); > if (contentId != null) > parentPart.setHeader("content-id", "<" + contentId + ">"); > //part.setContentID(contentId); > } > > private String handleInlinePartContent(Document document, String > contentType) throws SAXException { > if ("text/html".equals(contentType)) { > // Convert XHTML into an HTML String > StringWriter writer = new StringWriter(); > TransformerHandler identity = > TransformerUtils.getIdentityTransformerHandler (); > > identity.getTransformer().setOutputProperty(OutputKeys.METHOD, "html"); > identity.setResult(new StreamResult(writer)); > LocationSAXWriter saxw = new LocationSAXWriter(); > saxw.setContentHandler(identity); > saxw.write(document); > > return writer.toString(); > } else { > // For other types, just return the text nodes > return document.getStringValue(); > } > } > > public static FileItem handleStreamedPartContent(PipelineContext > pipelineContext, SAXSource source, String contentType, String encoding) > throws IOException, TransformerException { > > final FileItem fileItem = new > DefaultFileItemFactory(RequestGenerator.getMaxMemorySizeProperty(), > SystemUtils.getTemporaryDirectory()) > .createItem("dummy", "dummy", false, null); > // Make sure the file is deleted when the context is destroyed > pipelineContext.addContextListener(new > PipelineContext.ContextListenerAdapter() { > public void contextDestroyed(boolean success) { > fileItem.delete(); > } > }); > // Write character content to the FileItem instance > Writer writer = null; > OutputStream os = null; > > final boolean useWriter = > ProcessorUtils.isTextContentType(contentType) || > ProcessorUtils.isXMLContentType(contentType); > > try { > os = fileItem.getOutputStream(); > if (useWriter) > writer = new BufferedWriter(new > OutputStreamWriter(os, encoding)); > final OutputStream _os = os; > final Writer _writer = writer; > Transformer identity = > TransformerUtils.getIdentityTransformer(); > identity.transform(source, new SAXResult(new > ForwardingContentHandler() { > public void characters(char[] chars, int start, int > length) { > try { > if (useWriter) > _writer.write(chars, start, length); > else > _os.write(Base64.decode(new String(chars, > start, length))); > > } catch (IOException e) { > throw new OXFException(e); > } > } > })); > } finally { > if (writer != null) { > try { > writer.close(); > } catch (IOException e) { > throw new OXFException(e); > } > } > if (os != null) { > try { > os.close(); > } catch (IOException e) { > throw new OXFException(e); > } > } > } > > return fileItem; > } > > private InternetAddress createAddress(Element addressElement) > throws AddressException, UnsupportedEncodingException { > String email = addressElement.element("email").getStringValue(); > Element nameElement = addressElement.element("name"); > return nameElement == null ? new InternetAddress(email) > : new InternetAddress(email, > nameElement.getStringValue()); > } > > private class SimpleTextDataSource implements DataSource { > String contentType; > String text; > String name; > > public SimpleTextDataSource(String name, String contentType, > String text) { > this.name <http://this.name> = name; > this.contentType = contentType; > this.text = text; > } > > public String getContentType() { > return contentType; > } > > public InputStream getInputStream() throws IOException { > return new ByteArrayInputStream(text.getBytes("utf-8")); > } > > public String getName() { > return name; > } > > public OutputStream getOutputStream() throws IOException { > throw new IOException("Write operation not supported"); > } > } > > private class SimpleBinaryDataSource implements DataSource { > String contentType; > byte[] data; > String name; > > public SimpleBinaryDataSource(String name, String > contentType, byte[] data) { > this.name <http://this.name> = name; > this.contentType = contentType; > this.data = data; > } > > public String getContentType() { > return contentType; > } > > public InputStream getInputStream() throws IOException { > return new ByteArrayInputStream(data); > } > > public String getName() { > return name; > } > > public OutputStream getOutputStream() throws IOException { > throw new IOException("Write operation not supported"); > } > } > > public static SAXSource getSAXSource(Processor processor, > PipelineContext pipelineContext, String href, String base, String > contentType) { > try { > // There are two cases: > // 1. We read the source as SAX > // o This is required when reading from a processor > input; in this case, we behave like > // the inline case > // o When reading from another type of URI, the > resource could be in theory any type > // of file. > // 2. We don't read the source as SAX > // o It is particularly useful to support this when > resources are to be used as binary > // attachments such as images. > // o Here, we consider that the source can be XML, > text/html, text/*, > // or binary. We do not handle reading > Base64-encoded files. We leverage the URL > // generator to obtain the content in XML format. > XMLReader xmlReader; > { > String inputName = > ProcessorImpl.getProcessorInputSchemeInputName(href); > if (inputName != null) { > // Resolve to input of current processor > xmlReader = new > ProcessorOutputXMLReader(pipelineContext, > processor.getInputByName(inputName).getOutput()); > } else { > // Resolve to regular URI > Processor urlGenerator = (contentType == null) > ? new > URLGenerator(URLFactory.createURL(base, href)) > : new URLGenerator( > URLFactory.createURL(base, href), contentType, true); > xmlReader = new > ProcessorOutputXMLReader(pipelineContext, > urlGenerator.createOutput(ProcessorImpl.OUTPUT_DATA)); > } > } > > // Return SAX Source based on XML Reader > SAXSource saxSource = new SAXSource(xmlReader, new > InputSource()); > saxSource.setSystemId(href); > return saxSource; > } catch (IOException e) { > throw new OXFException(e); > } > } > > private class SMTPAuthenticator extends javax.mail.Authenticator { > private String username; > private String password; > > public SMTPAuthenticator(String user, String pass){ > username = user; > password = pass; > } > > public PasswordAuthentication getPasswordAuthentication() { > return new PasswordAuthentication(username,password); > } > } > } > > // Set content-transfer-encoding header > // final String contentTransferEncoding = > partElement.attributeValue("content-transfer-encoding"); > // > // MimeBodyPart part = new MimeBodyPart() { > // protected void updateHeaders() throws > MessagingException { > // super.updateHeaders(); > // if (contentTransferEncoding != null) > // > setHeader("Content-Transfer-Encoding", contentTransferEncoding); > // } > // }; > // // Set content-disposition header > // String contentDisposition = > partElement.attributeValue("content-disposition"); > // if (contentDisposition != null) > // part.setDisposition(contentDisposition); > // > // part.setDataHandler(new DataHandler(new > SimpleTextDataSource(name, contentType, content))); > // mimeMultipart.addBodyPart(part); > > > -- > You receive this message as a subscriber of the > [hidden email] <mailto:[hidden email]> mailing list. > To unsubscribe: mailto:[hidden email] > <mailto:[hidden email]> > For general help: mailto: [hidden email] > <mailto:[hidden email]>?subject=help > ObjectWeb mailing lists service home page: http://www.objectweb.org/wws > > -- Orbeon Forms - Web Forms for the Enterprise Done the Right Way http://www.orbeon.com/ -- You receive this message as a subscriber of the [hidden email] mailing list. To unsubscribe: mailto:[hidden email] For general help: mailto:[hidden email]?subject=help ObjectWeb mailing lists service home page: http://www.objectweb.org/wws |
Free forum by Nabble | Edit this page |