KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > info > magnolia > cms > mail > templates > impl > MagnoliaEmail


1 package info.magnolia.cms.mail.templates.impl;
2
3 import freemarker.template.Template;
4 import info.magnolia.cms.core.Path;
5 import info.magnolia.cms.mail.templates.MailAttachment;
6 import info.magnolia.cms.security.User;
7 import info.magnolia.context.MgnlContext;
8
9 import java.io.BufferedInputStream JavaDoc;
10 import java.io.File JavaDoc;
11 import java.io.FileOutputStream JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.io.InputStream JavaDoc;
14 import java.io.StringReader JavaDoc;
15 import java.io.StringWriter JavaDoc;
16 import java.net.URL JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.Map JavaDoc;
20
21 import javax.mail.Session JavaDoc;
22
23 import org.apache.commons.httpclient.HttpClient;
24 import org.apache.commons.httpclient.NameValuePair;
25 import org.apache.commons.httpclient.cookie.CookiePolicy;
26 import org.apache.commons.httpclient.methods.GetMethod;
27 import org.apache.commons.httpclient.methods.PostMethod;
28 import org.jdom.Attribute;
29 import org.jdom.Document;
30 import org.jdom.Element;
31 import org.jdom.filter.Filter;
32 import org.jdom.input.SAXBuilder;
33 import org.jdom.output.XMLOutputter;
34
35
36 /**
37  * Date: Apr 6, 2006 Time: 9:24:29 PM
38  * @author <a HREF="mailto:niko@macnica.com">Nicolas Modrzyk</a>
39  */

40 public class MagnoliaEmail extends FreemarkerEmail {
41
42     public static final String JavaDoc SUFFIX = "?mgnlIntercept=PREVIEW&mgnlPreview=true&mail=draw";
43
44     private HttpClient client;
45
46     private int cid = 0;
47
48     private static final String JavaDoc UTF_8 = "UTF-8";
49
50     private static final String JavaDoc MAGNOLIA = "magnolia";
51
52     private static final String JavaDoc IMG = "img";
53
54     private static final String JavaDoc SRC = "src";
55
56     private static final String JavaDoc CID = "cid:";
57
58     private static final String JavaDoc LINK = "link";
59
60     private static final String JavaDoc HREF = "href";
61
62     private static final String JavaDoc STYLE = "style";
63
64     private static final String JavaDoc REL = "rel";
65
66     private static final String JavaDoc ACTION = "action";
67
68     private static final String JavaDoc LOGIN = "login";
69
70     private static final String JavaDoc URL = "url";
71
72     private static final String JavaDoc MGNL_USER_ID = "mgnlUserId";
73
74     private static final String JavaDoc MGNL_USER_PSWD = "mgnlUserPSWD";
75
76     private static final String JavaDoc SLASH = "/";
77
78     public MagnoliaEmail(Session JavaDoc _session) throws Exception JavaDoc {
79         super(_session);
80     }
81
82     public void setBodyFromResourceFile(String JavaDoc resourceFile, Map JavaDoc _map) throws Exception JavaDoc {
83         URL JavaDoc url = new URL JavaDoc(resourceFile);
84         // retrieve the html content
85
String JavaDoc _content = retrieveContentFromMagnolia(resourceFile);
86         StringReader JavaDoc reader = new StringReader JavaDoc(_content);
87
88         // filter the images
89
String JavaDoc urlBasePath = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort();
90         reader = FilterImages(urlBasePath, reader);
91
92         // create the template from the previously filtered stream
93
Template template = new Template(MAGNOLIA, reader, FreemarkerEmail.cfg, UTF_8);
94
95         // execute the template, calling super will make use of Freemarker capabilities
96
super.setBodyFromTemplate(template, _map);
97     }
98
99     /**
100      * Filter the images from the content of the reader. For example:<br>
101      * &lt;img SRC="../../../../../../../magnolia/info.gif"/> is replaced by &lt;img SRC="cid:1"/> and the attachment cid 1 is created and
102      * linked to this email
103      * @param urlBasePath needed to resolve path of images
104      * @param reader where the content is
105      * @return a new <code>StringReader</code> with the filtered content
106      * @throws Exception
107      */

108     private StringReader JavaDoc FilterImages(String JavaDoc urlBasePath, StringReader JavaDoc reader) throws Exception JavaDoc {
109         log.info("Filtering images");
110         SAXBuilder parser = new SAXBuilder();
111         Document doc = parser.build(reader);
112         ArrayList JavaDoc toremove = new ArrayList JavaDoc();
113         ArrayList JavaDoc toadd = new ArrayList JavaDoc();
114
115         // Filter content
116
Iterator JavaDoc iter = doc.getDescendants(new ContentFilter());
117         while (iter.hasNext()) {
118             Element elem = (Element) iter.next();
119             String JavaDoc name = elem.getName();
120             if (name.equalsIgnoreCase(IMG)) {
121                 // stream image and attach it to the email
122
Attribute att = elem.getAttribute(SRC);
123                 if (log.isDebugEnabled()) {
124                     log.debug("Found new img:" + att.toString());
125                 }
126                 String JavaDoc value = att.getValue();
127                 this.cid++;
128                 att.setValue(CID + (this.cid));
129                 String JavaDoc url = urlBasePath + value;
130                 if (log.isDebugEnabled()) {
131                     log.debug("Url is:" + url);
132                 }
133                 this.addAttachment(new MailAttachment(getAttachmentFile(url).toURL(), String.valueOf(this.cid)));
134             }
135             else if (name.equalsIgnoreCase(LINK)) {
136                 // stream the css and put the content into a <style> tag
137
Attribute att = elem.getAttribute(HREF);
138                 Element el = (Element) elem.clone();
139                 if (log.isDebugEnabled()) {
140                     log.debug("Found new css:" + att.toString());
141                 }
142                 String JavaDoc url = urlBasePath + att.getValue();
143                 el.setName(STYLE);
144                 el.removeAttribute(HREF);
145                 el.removeAttribute(REL);
146                 GetMethod streamCss = new GetMethod(url);
147                 getHttpClient(url).executeMethod(streamCss);
148                 el.setText(streamCss.getResponseBodyAsString());
149
150                 toremove.add(elem);
151                 toadd.add(el);
152             }
153         }
154
155         // this is ugly but is there to
156
// avoid concurrent modification exception on the Document
157
for (int i = 0; i < toremove.size(); i++) {
158             Element elem = (Element) toremove.get(i);
159             Element parent = elem.getParentElement();
160             doc.removeContent(elem);
161             parent.addContent((Element) toadd.get(i));
162         }
163
164         // create the return string reader with new document content
165
StringWriter JavaDoc writer = new StringWriter JavaDoc();
166         new XMLOutputter().output(doc, writer);
167         return new StringReader JavaDoc(writer.toString());
168     }
169
170     /**
171      * Retrieve the content of the file. Need this because the content requires login. So temporarily creates the file
172      * @param url the full url where the image is located. The image will be retrieved with the httpclient of this class
173      * @return <code>File</code> with the full content of the image (or whatever is downloaded)
174      * @throws Exception if fails
175      */

176     private File JavaDoc getAttachmentFile(String JavaDoc url) throws Exception JavaDoc {
177         log.info("Streaming content of url:" + url + " to a temporary file");
178
179         // Execute an http get on the url
180
GetMethod redirect = new GetMethod(url);
181         getHttpClient(url).executeMethod(redirect);
182
183         URL JavaDoc _url = new URL JavaDoc(url);
184         String JavaDoc file = _url.getFile();
185
186         // create file in temp dir, with just the file name.
187
File JavaDoc tempFile = new File JavaDoc(Path.getTempDirectoryPath()
188             + File.separator
189             + file.substring(file.lastIndexOf(SLASH) + 1));
190         // if same file and same size, return, do not process
191
if (tempFile.exists() && redirect.getResponseContentLength() == tempFile.length()) {
192             redirect.releaseConnection();
193             return tempFile;
194         }
195
196         // stream the content to the temp file
197
FileOutputStream JavaDoc out = new FileOutputStream JavaDoc(tempFile);
198         final int BUFFER_SIZE = 1 << 10 << 3; // 8KiB buffer
199
byte[] buffer = new byte[BUFFER_SIZE];
200         int bytesRead;
201         InputStream JavaDoc in = new BufferedInputStream JavaDoc(redirect.getResponseBodyAsStream());
202         while (true) {
203             bytesRead = in.read(buffer);
204             if (bytesRead > -1) {
205                 out.write(buffer, 0, bytesRead);
206             }
207             else {
208                 break;
209             }
210         }
211
212         // cleanup
213
in.close();
214         out.close();
215         redirect.releaseConnection();
216
217         return tempFile;
218     }
219
220     /**
221      * Need to login into the site, so this method create an httpclient of many calls. This authenticated the user as
222      * well for an http session
223      * @param baseURL the url to use to login in the site
224      * @return <code>HttpClient</code> that can be used.
225      * @throws Exception if fails
226      */

227     private HttpClient getHttpClient(String JavaDoc baseURL) throws Exception JavaDoc {
228         if (this.client == null) {
229             URL JavaDoc location = new URL JavaDoc(baseURL);
230             User user = MgnlContext.getInstance().getUser();
231             this.client = getHttpClientForUser(location, user);
232         }
233         return this.client;
234     }
235
236     /**
237      * Separate this method from HttpClient in case we want to get the http client for a different user than the current
238      * one
239      * @param location the url to login to
240      * @param _user the user to get credentials from
241      * @return <code>HttpClient</code> logged in to the system
242      * @throws IOException if fails
243      */

244     private HttpClient getHttpClientForUser(URL JavaDoc location, User _user) throws IOException JavaDoc {
245         HttpClient _client = new HttpClient();
246         _client.getHostConfiguration().setHost(location.getHost(), location.getPort(), location.getProtocol());
247         _client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
248         String JavaDoc user = _user.getName();
249         String JavaDoc pass = _user.getPassword();
250         log.info("Creating http client for user:" + user);
251         // login using the id and password of the current user
252
PostMethod authpost = new PostMethod(location.getPath());
253         NameValuePair action = new NameValuePair(ACTION, LOGIN);
254         NameValuePair url = new NameValuePair(URL, location.getPath());
255         NameValuePair userid = new NameValuePair(MGNL_USER_ID, user);
256         NameValuePair password = new NameValuePair(MGNL_USER_PSWD, pass);
257         authpost.setRequestBody(new NameValuePair[]{action, url, userid, password});
258         _client.executeMethod(authpost);
259         authpost.releaseConnection();
260         return _client;
261     }
262
263     /**
264      * Get the html content from a magnolia page
265      * @param _url the url of the page to get the content from. Note that this url will be suffixed with
266      * <code>SUFFIX</code> to remove editing content
267      * @return a <code>String</code> with the html content
268      * @throws Exception if fails
269      */

270     private String JavaDoc retrieveContentFromMagnolia(String JavaDoc _url) throws Exception JavaDoc {
271         log.info("Retrieving content from magnolia:" + _url);
272         GetMethod redirect = new GetMethod(_url + SUFFIX);
273         getHttpClient(_url).executeMethod(redirect);
274         String JavaDoc response = redirect.getResponseBodyAsString();
275         redirect.releaseConnection();
276         return response;
277     }
278
279     /**
280      * Class to filter content when parsing the html
281      */

282     static class ContentFilter implements Filter {
283
284         /**
285          *
286          */

287         private static final long serialVersionUID = 1L;
288
289         public boolean matches(Object JavaDoc object) {
290             if (object instanceof Element) {
291                 Element e = (Element) object;
292                 return e.getName().equalsIgnoreCase(LINK) || e.getName().equalsIgnoreCase(IMG);
293             }
294
295             return false;
296
297         }
298     }
299 }
300
Popular Tags