001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.mail;
018:
019: import java.text.SimpleDateFormat;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.Properties;
025:
026: import javax.mail.Folder;
027: import javax.mail.Message;
028: import javax.mail.Provider;
029: import javax.mail.Store;
030: import javax.mail.URLName;
031:
032: import org.apache.avalon.framework.context.ContextException;
033: import org.apache.avalon.framework.logger.Logger;
034: import org.apache.avalon.framework.parameters.Parameters;
035: import org.apache.avalon.framework.thread.ThreadSafe;
036: import org.apache.cocoon.ProcessingException;
037: import org.apache.cocoon.acting.ServiceableAction;
038: import org.apache.cocoon.environment.ObjectModelHelper;
039: import org.apache.cocoon.environment.Redirector;
040: import org.apache.cocoon.environment.Request;
041: import org.apache.cocoon.environment.Session;
042: import org.apache.cocoon.environment.SourceResolver;
043: import org.apache.cocoon.mail.command.AbstractMailCommand;
044:
045: /**
046: * This action creates javamail objects, and puts XMLizable object wrappers
047: * of these objects into the request attribute map.
048: * <p>
049: * This action enables javamail access as action. It creates an http sesion,
050: * and puts the MailContext object into the session attributes.
051: * </p>
052: *
053: * @see MailContext
054: *
055: * @author Bernhard Huber
056: * @version $Id: MailAction.java 468424 2006-10-27 15:44:53Z vgritsenko $
057: * @since Cocoon 2.1, 16 December 2002
058: */
059: public class MailAction extends ServiceableAction implements ThreadSafe {
060:
061: /**
062: * Request attribute name of a XMLizable folder
063: */
064: public final static String REQUEST_ATTRIBUTE_FOLDER = "folder";
065:
066: /**
067: * Request attribute name of a XMLizable folders object
068: */
069: public final static String REQUEST_ATTRIBUTE_FOLDERS = "folders";
070:
071: /**
072: * Request attribute name of a XMLizable message object
073: */
074: public final static String REQUEST_ATTRIBUTE_MESSAGE = "message";
075:
076: /**
077: * Request attribute name of a XMLizable messages object
078: */
079: public final static String REQUEST_ATTRIBUTE_MESSAGES = "messages";
080:
081: /**
082: * Execute mail commands.
083: *
084: * @param redirector Cocoon's redirector
085: * @param resolver Cocoon's source resolver, used for testing if a source is resolvable
086: * @param source the source, e.g.: index.html
087: * @param objectModel Description of the Parameter
088: * @param par Description of the Parameter
089: * @exception Exception Description of the Exception
090: */
091: public Map act(Redirector redirector, SourceResolver resolver,
092: Map objectModel, String source, Parameters par)
093: throws Exception {
094: Map actionMap = new HashMap();
095:
096: Request request = ObjectModelHelper.getRequest(objectModel);
097:
098: String command = request.getParameter("cmd");
099: String folderName = request.getParameter("folder");
100: String userid = request.getParameter("mail-userid");
101: String password = request.getParameter("mail-password");
102:
103: // assert mailContext is available
104: Session session = request.getSession(true);
105: MailContext mailContext = (MailContext) session
106: .getAttribute(MailContext.SESSION_MAIL_CONTEXT);
107: if (mailContext == null) {
108: // no mailContext is yet available
109: // create it and put it into http-session
110: mailContext = new MailContextHttpSession(null);
111: mailContext.enableLogging(getLogger());
112: session.setAttribute(MailContext.SESSION_MAIL_CONTEXT,
113: mailContext);
114: }
115:
116: // assert mailSession is available
117: javax.mail.Session mailSession;
118: Store mailStore;
119: try {
120: try {
121: mailSession = (javax.mail.Session) mailContext
122: .get(MailContext.MAIL_SESSION_ENTRY);
123: } catch (ContextException ce) {
124: // build session properties
125: Properties sessionProperties = new Properties();
126: String[] allParameterNames = par.getNames();
127: for (int i = 0; i < allParameterNames.length; i++) {
128: String parameterName = allParameterNames[i];
129: final String PARAMETER_NAME_PREFIX = "javax.mail.Session.props:";
130: if (parameterName.startsWith(PARAMETER_NAME_PREFIX)) {
131: String sessionPropName = parameterName
132: .substring(PARAMETER_NAME_PREFIX
133: .length());
134: String sessionPropValue = par.getParameter(
135: parameterName, null);
136: if (sessionPropValue != null) {
137: getLogger()
138: .debug(
139: "Add session property "
140: + String
141: .valueOf(sessionPropName)
142: + ": "
143: + String
144: .valueOf(sessionPropValue));
145: sessionProperties.put(sessionPropName,
146: sessionPropValue);
147: }
148: }
149: }
150: mailSession = javax.mail.Session.getDefaultInstance(
151: sessionProperties, null);
152: checkProviders(mailSession);
153: mailContext.put(MailContext.MAIL_SESSION_ENTRY,
154: mailSession);
155: }
156: } catch (Exception e) {
157: String message = "Cannot create mail session";
158: getLogger().error(message, e);
159: throw new ProcessingException(message, e);
160: }
161:
162: // assert mailStore is available
163: String storeURLNameExpanded = null;
164: String storeURLNameTemplate = par.getParameter("store-urlname",
165: null);
166: try {
167: try {
168: mailStore = (Store) mailContext
169: .get(MailContext.MAIL_STORE_ENTRY);
170: } catch (ContextException ce) {
171:
172: // imap://{userid}:{password}@host:port/
173: storeURLNameExpanded = getURLNameExpanded(
174: storeURLNameTemplate, userid, password);
175:
176: URLName urlNameExpanded = new URLName(
177: storeURLNameExpanded);
178: getLogger().info(
179: "get store using URLName "
180: + String.valueOf(urlNameExpanded));
181: mailStore = mailSession.getStore(urlNameExpanded);
182: mailStore.connect();
183: mailContext
184: .put(MailContext.MAIL_STORE_ENTRY, mailStore);
185: }
186: } catch (Exception e) {
187: String message = "Cannot get store, and connect "
188: + String.valueOf(storeURLNameExpanded);
189: getLogger().error(message, e);
190: throw new ProcessingException(message, e);
191: }
192:
193: if (folderName != null) {
194: // make folderName the current working folder (a la cwd)
195: // check foldername a bit
196: mailContext.put(
197: MailContext.MAIL_CURRENT_WORKING_FOLDER_ENTRY,
198: folderName);
199: } else {
200: // no folderName in request parameter, retrieve current working folder
201: folderName = (String) mailContext
202: .get(MailContext.MAIL_CURRENT_WORKING_FOLDER_ENTRY);
203: }
204: actionMap.put(MailContext.MAIL_CURRENT_WORKING_FOLDER_ENTRY,
205: folderName);
206:
207: if (command != null) {
208: mailContext.put(
209: MailContext.MAIL_CURRENT_WORKING_COMMAND_ENTRY,
210: command);
211: } else {
212: command = (String) mailContext
213: .get(MailContext.MAIL_CURRENT_WORKING_COMMAND_ENTRY);
214: }
215: actionMap.put(MailContext.MAIL_CURRENT_WORKING_COMMAND_ENTRY,
216: command);
217:
218: // mailSession and mailStore are available
219:
220: // excecute mail command, and populate request attribute
221: mailContext.setRequest(request);
222: populateRequestAttribute(request, mailContext);
223: // it's better to release ref to request, as it is not needed, and helps
224: // recycling of the request
225: mailContext.setRequest(null);
226:
227: return actionMap;
228: }
229:
230: /**
231: * Gets the uRLNameExpanded attribute of the MailGenerator object
232: *
233: * @param storeURLNameTemplate Description of the Parameter
234: * @param userid Description of the Parameter
235: * @param password Description of the Parameter
236: * @return The uRLNameExpanded value
237: */
238: protected String getURLNameExpanded(String storeURLNameTemplate,
239: String userid, String password) {
240: String tokenStart = "''";
241: String tokenEnd = "''";
242: Properties filters = new Properties();
243: filters.put("mail-userid", userid);
244: filters.put("mail-passwd", password);
245:
246: return filter(tokenStart, tokenEnd, storeURLNameTemplate,
247: filters);
248: }
249:
250: /**
251: * Replace occurences of <code>TOKEN_STARTxxxTOKEN_END</code> by value of entry xxx in tokens table.
252: *
253: * @param tokenStart token start marker
254: * @param tokenEnd token end marker
255: * @param s the string examined
256: * @param tokens Description of the Parameter
257: * @return String replaced all tokenized entries of original String s.
258: */
259: protected String filter(final String tokenStart,
260: final String tokenEnd, String s, Properties tokens) {
261: int index = s.indexOf(tokenStart);
262:
263: if (index > -1) {
264: try {
265: StringBuffer b = new StringBuffer();
266: int i = 0;
267: String token;
268: String value;
269:
270: do {
271: int endIndex = s.indexOf(tokenEnd, index
272: + tokenStart.length() + 1);
273: if (endIndex == -1) {
274: break;
275: }
276: token = s.substring(index + tokenStart.length(),
277: endIndex);
278: b.append(s.substring(i, index));
279: if (tokens.containsKey(token)) {
280: value = (String) tokens.get(token);
281: b.append(value);
282: i = index + tokenStart.length()
283: + token.length() + tokenEnd.length();
284: } else {
285: // just append TOKEN_START and search further
286: b.append(tokenStart);
287: i = index + tokenStart.length();
288: }
289: } while ((index = s.indexOf(tokenStart, i)) > -1);
290:
291: b.append(s.substring(i));
292: return b.toString();
293: } catch (StringIndexOutOfBoundsException e) {
294: return s;
295: }
296: } else {
297: return s;
298: }
299: }
300:
301: /**
302: * Check that the provider need is available
303: *
304: * @param session The javamail Session used for checking its providers.
305: */
306: protected void checkProviders(javax.mail.Session session) {
307: Provider[] providers = session.getProviders();
308: // just log the available providers
309: for (int i = 0; i < providers.length; i++) {
310: getLogger().info("mail provider " + providers[i]);
311: }
312: }
313:
314: /**
315: * Populate request attribute map.
316: * <p>
317: * Execute mail command, and populate request attribute map with
318: * XMLizable javamail objects, created by the mail command
319: * </p>
320: *
321: * @param request triggering the creation of javamail objects
322: * @param mailContext javamail context, store, session, folders
323: * @exception Exception Description of the Exception
324: */
325: protected void populateRequestAttribute(Request request,
326: MailContext mailContext) throws Exception {
327: String folderName = (String) mailContext
328: .get(MailContext.MAIL_CURRENT_WORKING_FOLDER_ENTRY);
329: request.setAttribute(
330: MailContext.MAIL_CURRENT_WORKING_FOLDER_ENTRY,
331: folderName);
332: String command = (String) mailContext
333: .get(MailContext.MAIL_CURRENT_WORKING_COMMAND_ENTRY);
334: request
335: .setAttribute(
336: MailContext.MAIL_CURRENT_WORKING_COMMAND_ENTRY,
337: command);
338:
339: // build javamail objects
340: List javaMailResult = retrieveJavaMailObjects(mailContext);
341: Iterator javaMailResultIterator;
342:
343: // put javamail objects into request attribute map
344: javaMailResultIterator = javaMailResult.iterator();
345: //Request request = ObjectModelHelper.getRequest(objectModel);
346: putXMLizerToRequestAttribute(request, javaMailResultIterator);
347: }
348:
349: /**
350: * Put XMLizable javamail objects into request attribute map
351: *
352: * @param request holding the destination attribute map
353: * @param resultIterator Iterator of
354: */
355: protected void putXMLizerToRequestAttribute(Request request,
356: Iterator resultIterator) {
357: if (resultIterator != null) {
358: // marshal java mail objects
359: Logger logger = getLogger();
360:
361: // make it an optional parameter?
362: String datePattern = "dd.MM.yyyy HH:mm";
363: SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
364:
365: while (resultIterator.hasNext()) {
366: Object objRef = resultIterator.next();
367:
368: getLogger().debug(
369: "Creating XMLizer for "
370: + String.valueOf(objRef));
371:
372: if (objRef instanceof Folder) {
373: MailContentHandlerDelegate.FolderXMLizer fx = new MailContentHandlerDelegate.FolderXMLizer(
374: (Folder) objRef);
375: fx.enableLogging(logger);
376: request.setAttribute(REQUEST_ATTRIBUTE_FOLDER, fx);
377: } else if (objRef instanceof Folder[]) {
378: Folder[] folders = (Folder[]) objRef;
379: MailContentHandlerDelegate.FolderXMLizer[] fxs = new MailContentHandlerDelegate.FolderXMLizer[folders.length];
380: for (int i = 0; i < folders.length; i++) {
381: fxs[i] = new MailContentHandlerDelegate.FolderXMLizer(
382: folders[i]);
383: fxs[i].enableLogging(logger);
384: }
385: // trust that array of XMLizable is handled
386: request
387: .setAttribute(REQUEST_ATTRIBUTE_FOLDERS,
388: fxs);
389: } else if (objRef instanceof Message) {
390: MailContentHandlerDelegate.MessageXMLizer mx = new MailContentHandlerDelegate.MessageXMLizer(
391: (Message) objRef);
392: mx.enableLogging(logger);
393: mx.setSimpleDateFormat(sdf);
394: request.setAttribute(REQUEST_ATTRIBUTE_MESSAGE, mx);
395: } else if (objRef instanceof Message[]) {
396: MailContentHandlerDelegate.MessageEnvelopeXMLizer mex = new MailContentHandlerDelegate.MessageEnvelopeXMLizer(
397: (Message[]) objRef);
398: mex.enableLogging(logger);
399: mex.setSimpleDateFormat(sdf);
400: request.setAttribute(REQUEST_ATTRIBUTE_MESSAGES,
401: mex);
402: }
403: }
404: }
405: }
406:
407: /**
408: * Retrieve javamail objects
409: *
410: * @param mailContext Description of the Parameter
411: * @return List of retrieved javamail objects
412: * @exception ProcessingException thrown iff retrieval fails
413: */
414: protected List retrieveJavaMailObjects(MailContext mailContext)
415: throws ProcessingException {
416:
417: List result;
418: try {
419: // do we have a MailCommandManager ?
420: MailCommandManager mam = new MailCommandManager();
421: mam.enableLogging(getLogger());
422:
423: // build the MailCommand(s)
424: MailCommandBuilder mab = new MailCommandBuilder();
425: mab.enableLogging(getLogger());
426: AbstractMailCommand ama = mab
427: .buildAbstractMailCommand(mailContext);
428:
429: getLogger().debug("Executing " + String.valueOf(ama));
430:
431: // execute the command(s)
432: result = mam.execute(ama);
433:
434: // return the javamail objects
435: return result;
436: } catch (Exception e) {
437: String message = "Cannot retrieve javamail objects";
438: getLogger().error(message, e);
439: throw new ProcessingException(message, e);
440: }
441: }
442: }
|