KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ivata > groupware > business > mail > struts > MailSetupAction


1 /*
2  * Copyright (c) 2001 - 2005 ivata limited.
3  * All rights reserved.
4  * ---------------------------------------------------------
5  * ivata groupware may be redistributed under the GNU General Public
6  * License as published by the Free Software Foundation;
7  * version 2 of the License.
8  *
9  * These programs are free software; you can redistribute them and/or
10  * modify them under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; version 2 of the License.
12  *
13  * These programs are distributed in the hope that they will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * See the GNU General Public License in the file LICENSE.txt for more
18  * details.
19  *
20  * If you would like a copy of the GNU General Public License write to
21  *
22  * Free Software Foundation, Inc.
23  * 59 Temple Place - Suite 330
24  * Boston, MA 02111-1307, USA.
25  *
26  *
27  * To arrange commercial support and licensing, contact ivata at
28  * http://www.ivata.com/contact.jsp
29  * ---------------------------------------------------------
30  * $Log: MailSetupAction.java,v $
31  * Revision 1.3.2.1 2005/10/08 17:35:43 colinmacleod
32  * Extended for hMailServer v4.x
33  * Now uses JDBC to set settings (rather than attempting to re-initializse).
34  *
35  * Revision 1.3 2005/04/27 15:19:24 colinmacleod
36  * Fixed error strings for IMAP and SMTP messages.
37  * Corrected SITE_ID for UNIX.
38  *
39  * Revision 1.2 2005/04/22 10:59:55 colinmacleod
40  * Added extra factory reset to apply
41  * settings changes.
42  *
43  * Revision 1.1 2005/04/11 10:03:43 colinmacleod
44  * Added setup feature.
45  *
46  * ---------------------------------------------------------
47  */

48 package com.ivata.groupware.business.mail.struts;
49
50 import java.io.IOException JavaDoc;
51 import java.io.InputStream JavaDoc;
52 import java.net.Socket JavaDoc;
53 import java.net.UnknownHostException JavaDoc;
54 import java.sql.Connection JavaDoc;
55 import java.sql.DriverManager JavaDoc;
56 import java.sql.PreparedStatement JavaDoc;
57 import java.sql.SQLException JavaDoc;
58 import java.sql.Statement JavaDoc;
59 import java.util.List JavaDoc;
60
61 import javax.servlet.http.HttpServletRequest JavaDoc;
62 import javax.servlet.http.HttpServletResponse JavaDoc;
63 import javax.servlet.http.HttpSession JavaDoc;
64
65 import org.apache.log4j.Logger;
66 import org.apache.struts.action.ActionErrors;
67 import org.apache.struts.action.ActionForm;
68 import org.apache.struts.action.ActionMapping;
69 import org.apache.struts.action.ActionMessage;
70 import org.picocontainer.PicoContainer;
71
72 import com.ivata.groupware.admin.security.Security;
73 import com.ivata.groupware.admin.security.server.SecuritySession;
74 import com.ivata.groupware.admin.setting.Settings;
75 import com.ivata.groupware.admin.struts.HibernateSetupAction;
76 import com.ivata.groupware.admin.struts.HibernateSetupForm;
77 import com.ivata.groupware.container.PicoContainerFactory;
78 import com.ivata.mask.MaskFactory;
79 import com.ivata.mask.util.SystemException;
80 import com.ivata.mask.web.struts.MaskAction;
81 import com.ivata.mask.web.struts.MaskAuthenticator;
82
83 /**
84  * Setup the application to use a database and mail server.
85  *
86  * @since ivata groupware 0.11 (2005-03-25)
87  * @author Colin MacLeod
88  * <a HREF='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
89  * @version $Revision: 1.3.2.1 $
90  */

91 public class MailSetupAction extends HibernateSetupAction {
92     /**
93      * Logger for this class.
94      */

95     private static final Logger logger =
96         Logger.getLogger(MailSetupAction.class);
97     /**
98      * The text of the prepared statement query used to change settings.
99      */

100     private static final String JavaDoc SETTINGS_STATEMENT =
101         "UPDATE SETTING SET value = ? WHERE name = ? AND person_user IS NULL";
102     /**
103      * On <strong>Courier IMAP</strong> and <strong>Cyrus IMAP</strong>,
104      * all mail folder names are prefixed by the value 'INBOX.' - this
105      * setting stores that prefix.
106      */

107     private String JavaDoc mailFolderNamespace = "";
108     /**
109      * Constructor.
110      *
111      * @param securityParam System security object.
112      * @param settingsParam System settings object.
113      * @param maskFactoryParam Creates input and list masks.
114      * @param authenticatorParam Used to check user is auhtorized to see this
115      * page.
116      */

117     public MailSetupAction(final Security securityParam,
118             final Settings settingsParam,
119             final MaskFactory maskFactoryParam,
120             final MaskAuthenticator authenticatorParam) {
121         super(securityParam, settingsParam, maskFactoryParam,
122                 authenticatorParam);
123     }
124     /**
125      * Check a socket on a given host is valid. This is used to check the
126      * SMTP and IMAP connections.
127      *
128      * @param host host we are checking.
129      * @param port port we are checking.
130      * @param errorMessages if there are any errors, they are appended to this
131      * collection.
132      * @param errorString the error message to show the user if all is not well.
133      * @return a string buffer containing all of the output read from the port.
134      */

135     private StringBuffer JavaDoc checkSocket(final String JavaDoc host, final int port,
136             final ActionErrors errorMessages, final String JavaDoc errorString) {
137         Socket JavaDoc socket = null;
138         StringBuffer JavaDoc socketOutput = new StringBuffer JavaDoc();
139         try {
140             socket = new Socket JavaDoc(host, port);
141             logger.info("Connected with server "
142                     + socket.getInetAddress()
143                     + ":"
144                     + socket.getPort());
145             InputStream JavaDoc socketInput = socket.getInputStream();
146             byte [] buffer = new byte[1024];
147             int bytesRead = 0;
148             do {
149                 // wait a total of SOCKET_WAIT_NUMBER times, each time for
150
// SOCKET_WAIT_INTERVAL milliseconds
151
synchronized(this) {
152                     for (int waitCount = 0;
153                             (waitCount < MailSetupConstants.SOCKET_WAIT_NUMBER)
154                                 && (socketInput.available() == 0);
155                             ++waitCount) {
156                         try {
157                              wait(MailSetupConstants.SOCKET_WAIT_INTERVAL);
158                         } catch (InterruptedException JavaDoc e1) {
159                             logger.warn("Socket wait interrupted.", e1);
160                             break;
161                         }
162                     }
163                 }
164                 socketOutput.append(new String JavaDoc(buffer, 0, bytesRead));
165             } while ((socketInput.available() != 0)
166                     && ((bytesRead = socketInput.read(
167                     buffer, 0, buffer.length)) != -1));
168             if (logger.isDebugEnabled()) {
169                 logger.debug("Read the following string from "
170                         + socket.getInetAddress()
171                         + ":"
172                         + socket.getPort());
173                 logger.debug(socketOutput.toString());
174             }
175         } catch (UnknownHostException JavaDoc e) {
176             errorMessages.add(null, new ActionMessage(
177                     errorString,
178                     e.getClass().getName(),
179                     host,
180                     e.getMessage()));
181         } catch (IOException JavaDoc e) {
182             errorMessages.add(null, new ActionMessage(
183                     errorString,
184                     e.getClass().getName(),
185                     host,
186                     e.getMessage()));
187         } finally {
188             if ((socket != null)
189                     && !socket.isClosed()) {
190                 try {
191                     socket.close();
192                 } catch (IOException JavaDoc e) {
193                     logger.error(e.getClass().getName()
194                             + ": closing socket: "
195                             + e.getMessage(),
196                             e);
197                 }
198             }
199         }
200         return socketOutput;
201     }
202     /**
203      * Overridden to check that there are mail domains defined on windows.
204      * @param mappingParam Refer to {@link MaskAction#execute}.
205      * @param errorsParam Refer to {@link MaskAction#execute}.
206      * @param formParam Refer to {@link MaskAction#execute}.
207      * @param requestParam Refer to {@link MaskAction#execute}.
208      * @param responseParam Refer to {@link MaskAction#execute}.
209      * @param sessionParam Refer to {@link MaskAction#execute}.
210      * @return Refer to {@link MaskAction#execute}.
211      * @throws SystemException Refer to {@link MaskAction#execute}.
212      */

213     public String JavaDoc execute(ActionMapping mappingParam, ActionErrors errorsParam,
214             ActionForm formParam, HttpServletRequest JavaDoc requestParam,
215             HttpServletResponse JavaDoc responseParam, HttpSession JavaDoc sessionParam)
216             throws SystemException {
217         MailSetupForm setupForm = (MailSetupForm) formParam;
218         List JavaDoc mailDomains = setupForm.getMailDomains();
219         if (setupForm.isWindows()
220                 && ((mailDomains == null)
221                         || mailDomains.isEmpty())) {
222             errorsParam.add(null, new ActionMessage(
223                     "errors.setup.noMailDomains"));
224         }
225         return super.execute(mappingParam, errorsParam, formParam,
226                 requestParam, responseParam, sessionParam);
227     }
228     /**
229      * Called when the user clicks the 'OK' button to continue with the chosen
230      * setup options. If you chose hibernate settings, this will write them
231      * out.
232      *
233      * @param mappingParam Refer to {@link MaskAction#onConfirm}.
234      * @param errorsParam Refer to {@link MaskAction#onConfirm}.
235      * @param formParam Refer to {@link MaskAction#onConfirm}.
236      * @param requestParam Refer to {@link MaskAction#onConfirm}.
237      * @param responseParam Refer to {@link MaskAction#onConfirm}.
238      * @param sessionParam Refer to {@link MaskAction#onConfirm}.
239      * @param defaultForwardParam Refer to {@link MaskAction#onConfirm}.
240      * @return Refer to {@link MaskAction#onConfirm}.
241      * @throws SystemException Refer to {@link MaskAction#onConfirm}.
242      */

243     public String JavaDoc onConfirm(ActionMapping mappingParam,
244             ActionErrors errorMessages, ActionForm formParam,
245             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc responseParam,
246             HttpSession JavaDoc session, String JavaDoc defaultForwardParam)
247             throws SystemException {
248         MailSetupForm setupForm = (MailSetupForm)formParam;
249
250         // check the mail hosts work as expected
251
String JavaDoc mailHostIMAP = setupForm.getMailHostIMAP();
252         String JavaDoc mailHostSMTP = setupForm.getMailHostSMTP();
253
254         StringBuffer JavaDoc socketOutput = checkSocket(mailHostIMAP,
255                 MailSetupConstants.IMAP_PORT,
256                 errorMessages, "errors.setup.hostIMAP");
257         // look for courier or cyrus - that means we need to set the folder
258
// namespace
259
if (socketOutput.indexOf(MailSetupConstants.CYRUS_SIGNATURE) != -1) {
260             logger.info("IMAP server identified as Cyrus - setting folder "
261                     + "namespace to '"
262                     + MailSetupConstants.CYRUS_FOLDER_NAMESPACE
263                     + "'.");
264             mailFolderNamespace = MailSetupConstants.CYRUS_FOLDER_NAMESPACE;
265         } else if (socketOutput.indexOf(MailSetupConstants.COURIER_SIGNATURE) != -1) {
266             logger.info("IMAP server identified as Courier - setting folder "
267                     + "namespace to '"
268                     + MailSetupConstants.COURIER_FOLDER_NAMESPACE
269                     + "'.");
270             mailFolderNamespace = MailSetupConstants.COURIER_FOLDER_NAMESPACE;
271         } else {
272             logger.info("IMAP server neither Cyrus nor Courier - using "
273                     + "default folder namespace.");
274             mailFolderNamespace = "";
275         }
276
277         checkSocket(mailHostSMTP, MailSetupConstants.SMTP_PORT,
278                 errorMessages, "errors.setup.hostSMTP");
279
280         String JavaDoc superReturn =
281             super.onConfirm(mappingParam, errorMessages, formParam, request,
282                 responseParam, session, defaultForwardParam);
283         // did we get error messages? if so, return to the input page
284
if (!errorMessages.isEmpty()) {
285             return null;
286         }
287
288         // if the superclass told us to go somewhere, we'd better comply!
289
if (superReturn != null) {
290             return superReturn;
291         }
292         // otherwise go to the default place
293
return defaultForwardParam;
294     }
295     /**
296      * Helper. Uses JDBC to set a single setting in the new settings table.
297      *
298      * @param preparedStatement Statement matching {@link SETTINGS_STATEMENT}.
299      * @param settingName The name of the setting to be amended.
300      * @param settingValue New setting value as a string.
301      * @throws SystemException if the setting cannot be set, or more than 1
302      * row is returned.
303      */

304     private void setOneSystemSetting(
305             final PreparedStatement JavaDoc preparedStatement,
306             final String JavaDoc settingName,
307             final String JavaDoc settingValue)
308             throws SystemException {
309         if (logger.isDebugEnabled()) {
310             logger.debug("setOneSystemSetting("
311                     + "PreparedStatement preparedStatement = "
312                     + preparedStatement
313                     + ", String settingName = "
314                     + settingName
315                     + ", String settingValue = "
316                     + settingValue + ") - start");
317         }
318         try {
319             preparedStatement.setString(1, settingValue);
320         } catch (SQLException JavaDoc e) {
321             logger.error ("setOneSystemSetting - Setting setting value to '"
322                 + settingValue
323                 + "'", e);
324             throw new SystemException(e);
325         }
326         try {
327             preparedStatement.setString(2, settingName);
328         } catch (SQLException JavaDoc e) {
329             logger.error ("setOneSystemSetting - Setting setting name to '"
330                 + settingName
331                 + "'", e);
332             throw new SystemException(e);
333         }
334         int numberOfRows;
335         try {
336             numberOfRows = preparedStatement.executeUpdate();
337         } catch (SQLException JavaDoc e) {
338             logger.error("setOneSystemSetting - Executing statement '"
339                 + SETTINGS_STATEMENT
340                 + "'", e);
341             throw new SystemException(e);
342         }
343         if (logger.isDebugEnabled()) {
344             logger.debug("setOneSystemSetting -"
345                     + "Number of rows returned: "
346                     + numberOfRows);
347         }
348         if (numberOfRows != 1) {
349             String JavaDoc message = "setOneSystemSetting - More than 1 row returned "
350                 + "for system setting '"
351                 + settingName
352                 + "'";
353             logger.error(message);
354             throw new SystemException(message);
355         }
356         if (logger.isDebugEnabled()) {
357             logger.debug("setOneSystemSetting - end");
358         }
359     }
360     /**
361      * Reset the pico container factory and update all settings in the new
362      * factory.
363      * @param setupForm the form from the current request.
364      * @param securitySession guest security session, used to access settings.
365      * @param session current HTTP session.
366      * @throws SystemException if any setting cannot be set, or more than
367      * one row is returned when setting.
368      */

369     protected void resetFactoryUpdateSettings(
370             final HibernateSetupForm hibernateSetupForm,
371             final SecuritySession securitySession,
372             final HttpSession JavaDoc session)
373             throws SystemException {
374         if (logger.isDebugEnabled()) {
375             logger.debug("resetFactoryUpdateSettings("
376                     + "HibernateSetupForm hibernateSetupForm = "
377                     + hibernateSetupForm
378                     + ", SecuritySession securitySession = "
379                     + securitySession
380                     + ", HttpSession session = "
381                     + session + ") - start");
382         }
383
384         MailSetupForm setupForm = (MailSetupForm) hibernateSetupForm;
385         String JavaDoc uRL = hibernateSetupForm.getDatabaseURL();
386         String JavaDoc userName = hibernateSetupForm.getDatabaseUserName();
387         String JavaDoc password = hibernateSetupForm.getDatabasePassword();
388
389         if (logger.isDebugEnabled()) {
390             logger.debug("resetFactoryUpdateSettings - "
391                     + "Connecting to new DB with parameters: "
392                     + "uRL = " + uRL + ", "
393                     + "userName = " + userName + ", "
394                     + "password = ******)");
395         }
396         Connection JavaDoc connection;
397         try {
398             connection = DriverManager.getConnection(uRL, userName,
399                 password);
400         } catch (SQLException JavaDoc e) {
401             logger.error("resetFactoryUpdateSettings - "
402                     + "Connecting to new DB with paramteters: "
403                     + "uRL = " + uRL + ", "
404                     + "userName = " + userName + ", "
405                     + "password = ******)", e);
406             throw new SystemException(e);
407         }
408         PreparedStatement JavaDoc preparedStatement;
409         try {
410             preparedStatement = connection.prepareStatement(
411                 SETTINGS_STATEMENT);
412         } catch (SQLException JavaDoc e) {
413             logger.error("resetFactoryUpdateSettings - Preparing statement '"
414                 + SETTINGS_STATEMENT
415                 + "'", e);
416             throw new SystemException(e);
417         }
418         try {
419             setOneSystemSetting(preparedStatement,
420                     "emailAddressHost",
421                     setupForm.getMailDomain());
422             setOneSystemSetting(preparedStatement,
423                     "emailFolderNamespace",
424                     mailFolderNamespace);
425             setOneSystemSetting(preparedStatement,
426                     "emailHost",
427                     setupForm.getMailHostIMAP());
428             setOneSystemSetting(preparedStatement,
429                     "emailHostSmtp",
430                     setupForm.getMailHostSMTP());
431             setOneSystemSetting(preparedStatement,
432                     "emailScriptServerEnvironment",
433                     "SITE_ID=www\nSUDO_USER=root\nSUDO_PATH="
434                         + setupForm.getScriptsPath()
435                         + MailSetupConstants.SCRIPT_PATH_EXIM);
436             setOneSystemSetting(preparedStatement,
437                     "pathScriptMailServer",
438                     setupForm.getScriptsPath()
439                         + MailSetupConstants.SCRIPT_PATH_SUDO);
440             // on windows, we use the COM interface to hMailServer
441
if (setupForm.isWindows()) {
442                 setOneSystemSetting(preparedStatement,
443                         "securitySessionServer",
444                         "com.ivata.groupware.business.mail.server.HMailServer");
445                 // hMailServer needs the folder to be called 'INBOX', all caps
446
setOneSystemSetting(preparedStatement,
447                         "emailFolderInbox",
448                         "INBOX");
449             } else {
450                 // other platforms make do with sudo scripts
451
setOneSystemSetting(preparedStatement,
452                         "securitySessionServer",
453                         "com.ivata.groupware.business.mail.server."
454                             + "ScriptMailServer");
455             }
456         } catch (Exception JavaDoc e) {
457             logger.error("resetFactoryUpdateSettings - Exception, so rolling "
458                 + "back transation", e);
459             try {
460                 preparedStatement.close();
461             } catch (SQLException JavaDoc e2) {
462                 logger.error ("resetFactoryUpdateSettings - Errror rolling "
463                     + "back statement.", e2);
464             }
465             throw new SystemException(e);
466
467         } finally {
468             try {
469                 preparedStatement.close();
470             } catch (SQLException JavaDoc e) {
471                 logger.error ("resetFactoryUpdateSettings - Error closing "
472                     + "prepared statement.", e);
473                 throw new SystemException(e);
474             }
475             // HSQLDB requires us to explicitly shutdown
476
if ((connection != null)
477                     && (uRL.indexOf("hsqldb:file") != -1)) {
478                 logger.info("resetFactoryUpdateSettings - shutting down "
479                     + "HSQLDB file.");
480                 Statement JavaDoc statement = null;
481                 try {
482                     statement = connection.createStatement();
483                     boolean success = statement.execute("SHUTDOWN");
484                     if (!success) {
485                         logger.error("resetFactoryUpdateSettings - shutting "
486                         + "down HSQLDB file returned FALSE.");
487                     }
488                 } catch (SQLException JavaDoc e) {
489                     logger.error ("resetFactoryUpdateSettings - Error closing "
490                         + " shutdown statement.", e);
491                     throw new SystemException(e);
492                 } finally {
493                     if (statement != null) {
494                         try {
495                             statement.close();
496                         } catch (SQLException JavaDoc e) {
497                             logger.error ("resetFactoryUpdateSettings - Error "
498                                 + "closing shutdown statement.", e);
499                             throw new SystemException(e);
500                         }
501                     }
502                 }
503             }
504         }
505         if (logger.isDebugEnabled()) {
506             logger.debug("resetFactoryUpdateSettings() - end");
507         }
508     }
509 }
510
Popular Tags