| /* $Id$ */ |
| |
| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.manifoldcf.crawler.notifications.email; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.apache.manifoldcf.agents.interfaces.ServiceInterruption; |
| import org.apache.manifoldcf.core.interfaces.*; |
| import org.apache.manifoldcf.core.util.URLEncoder; |
| import org.apache.manifoldcf.crawler.interfaces.*; |
| import org.apache.manifoldcf.crawler.system.Logging; |
| |
| import java.io.*; |
| import java.util.*; |
| import javax.mail.*; |
| import javax.mail.internet.MimeBodyPart; |
| import javax.mail.internet.MimeMessage; |
| import javax.mail.search.*; |
| |
| /** |
| */ |
| public class EmailConnector extends org.apache.manifoldcf.crawler.notifications.BaseNotificationConnector { |
| |
| protected final static long SESSION_EXPIRATION_MILLISECONDS = 300000L; |
| |
| // Local variables. |
| protected long sessionExpiration = -1L; |
| |
| // Parameters for establishing a session |
| |
| protected String server = null; |
| protected String portString = null; |
| protected String username = null; |
| protected String password = null; |
| protected String protocol = null; |
| protected Properties properties = null; |
| |
| // Local session handle |
| protected EmailSession session = null; |
| |
| private static Map<String,String> providerMap; |
| static |
| { |
| providerMap = new HashMap<String,String>(); |
| providerMap.put(EmailConfig.PROTOCOL_POP3, EmailConfig.PROTOCOL_POP3_PROVIDER); |
| providerMap.put(EmailConfig.PROTOCOL_POP3S, EmailConfig.PROTOCOL_POP3S_PROVIDER); |
| providerMap.put(EmailConfig.PROTOCOL_IMAP, EmailConfig.PROTOCOL_IMAP_PROVIDER); |
| providerMap.put(EmailConfig.PROTOCOL_IMAPS, EmailConfig.PROTOCOL_IMAPS_PROVIDER); |
| } |
| //////////////////////////////////Start of Basic Connector Methods///////////////////////// |
| |
| /** |
| * Connect. |
| * |
| * @param configParameters is the set of configuration parameters, which |
| * in this case describe the root directory. |
| */ |
| @Override |
| public void connect(ConfigParams configParameters) { |
| super.connect(configParameters); |
| this.server = configParameters.getParameter(EmailConfig.SERVER_PARAM); |
| this.portString = configParameters.getParameter(EmailConfig.PORT_PARAM); |
| this.protocol = configParameters.getParameter(EmailConfig.PROTOCOL_PARAM); |
| this.username = configParameters.getParameter(EmailConfig.USERNAME_PARAM); |
| this.password = configParameters.getObfuscatedParameter(EmailConfig.PASSWORD_PARAM); |
| this.properties = new Properties(); |
| int i = 0; |
| while (i < configParameters.getChildCount()) //In post property set is added as a configuration node |
| { |
| ConfigNode cn = configParameters.getChild(i++); |
| if (cn.getType().equals(EmailConfig.NODE_PROPERTIES)) { |
| String findParameterName = cn.getAttributeValue(EmailConfig.ATTRIBUTE_NAME); |
| String findParameterValue = cn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| this.properties.setProperty(findParameterName, findParameterValue); |
| } |
| } |
| } |
| |
| /** |
| * Close the connection. Call this before discarding this instance of the |
| * repository connector. |
| */ |
| @Override |
| public void disconnect() |
| throws ManifoldCFException { |
| this.server = null; |
| this.portString = null; |
| this.protocol = null; |
| this.username = null; |
| this.password = null; |
| this.properties = null; |
| finalizeConnection(); |
| super.disconnect(); |
| } |
| |
| /** |
| * This method is periodically called for all connectors that are connected but not |
| * in active use. |
| */ |
| @Override |
| public void poll() throws ManifoldCFException { |
| if (session != null) |
| { |
| if (System.currentTimeMillis() >= sessionExpiration) |
| finalizeConnection(); |
| } |
| } |
| |
| /** |
| * Test the connection. Returns a string describing the connection integrity. |
| * |
| * @return the connection's status as a displayable string. |
| */ |
| @Override |
| public String check() |
| throws ManifoldCFException { |
| try { |
| checkConnection(); |
| return super.check(); |
| } catch (ServiceInterruption e) { |
| return "Connection temporarily failed: " + e.getMessage(); |
| } catch (ManifoldCFException e) { |
| return "Connection failed: " + e.getMessage(); |
| } |
| } |
| |
| protected void checkConnection() throws ManifoldCFException, ServiceInterruption { |
| // Force a re-connection |
| finalizeConnection(); |
| getSession(); |
| try { |
| CheckConnectionThread cct = new CheckConnectionThread(session); |
| cct.start(); |
| cct.finishUp(); |
| } catch (InterruptedException e) { |
| throw new ManifoldCFException(e.getMessage(),ManifoldCFException.INTERRUPTED); |
| } catch (MessagingException e) { |
| handleMessagingException(e,"checking the connection"); |
| } |
| } |
| |
| protected void getSession() |
| throws ManifoldCFException, ServiceInterruption { |
| if (session == null) { |
| |
| // Check that all the required parameters are there. |
| if (server == null) |
| throw new ManifoldCFException("Missing server parameter"); |
| if (properties == null) |
| throw new ManifoldCFException("Missing server properties"); |
| if (protocol == null) |
| throw new ManifoldCFException("Missing protocol parameter"); |
| |
| // Create a session. |
| int port; |
| if (portString != null && portString.length() > 0) |
| { |
| try |
| { |
| port = Integer.parseInt(portString); |
| } |
| catch (NumberFormatException e) |
| { |
| throw new ManifoldCFException("Port number has bad format: "+e.getMessage(),e); |
| } |
| } |
| else |
| port = -1; |
| |
| try { |
| ConnectThread connectThread = new ConnectThread(server, port, username, password, |
| providerMap.get(protocol), properties); |
| connectThread.start(); |
| session = connectThread.finishUp(); |
| } catch (InterruptedException e) { |
| throw new ManifoldCFException(e.getMessage(),ManifoldCFException.INTERRUPTED); |
| } catch (MessagingException e) { |
| handleMessagingException(e, "connecting"); |
| } |
| } |
| sessionExpiration = System.currentTimeMillis() + SESSION_EXPIRATION_MILLISECONDS; |
| } |
| |
| protected void finalizeConnection() { |
| if (session != null) { |
| try { |
| CloseSessionThread closeSessionThread = new CloseSessionThread(session); |
| closeSessionThread.start(); |
| closeSessionThread.finishUp(); |
| } catch (InterruptedException e) { |
| } catch (MessagingException e) { |
| Logging.connectors.warn("Error while closing connection to server: " + e.getMessage(),e); |
| } finally { |
| session = null; |
| } |
| } |
| } |
| |
| ///////////////////////////////End of Basic Connector Methods//////////////////////////////////////// |
| |
| //////////////////////////////Start of Notification Connector Method/////////////////////////////////// |
| |
| /** Notify of job stop due to error abort. |
| *@param spec is the notification specification. |
| */ |
| @Override |
| public void notifyOfJobStopErrorAbort(final Specification spec) |
| throws ManifoldCFException, ServiceInterruption { |
| sendMail(spec, EmailConfig.NODE_ERRORABORTED); |
| } |
| |
| /** Notify of job stop due to manual abort. |
| *@param spec is the notification specification. |
| */ |
| @Override |
| public void notifyOfJobStopManualAbort(final Specification spec) |
| throws ManifoldCFException, ServiceInterruption { |
| sendMail(spec, EmailConfig.NODE_MANUALABORTED); |
| } |
| |
| /** Notify of job stop due to manual pause. |
| *@param spec is the notification specification. |
| */ |
| @Override |
| public void notifyOfJobStopManualPause(final Specification spec) |
| throws ManifoldCFException, ServiceInterruption { |
| sendMail(spec, EmailConfig.NODE_MANUALPAUSED); |
| } |
| |
| /** Notify of job stop due to schedule pause. |
| *@param spec is the notification specification. |
| */ |
| @Override |
| public void notifyOfJobStopSchedulePause(final Specification spec) |
| throws ManifoldCFException, ServiceInterruption { |
| sendMail(spec, EmailConfig.NODE_SCHEDULEPAUSED); |
| } |
| |
| /** Notify of job stop due to restart. |
| *@param spec is the notification specification. |
| */ |
| @Override |
| public void notifyOfJobStopRestart(final Specification spec) |
| throws ManifoldCFException, ServiceInterruption { |
| sendMail(spec, EmailConfig.NODE_RESTARTED); |
| } |
| |
| /** Notify of job end. |
| *@param spec is the notification specification. |
| */ |
| @Override |
| public void notifyOfJobEnd(final Specification spec) |
| throws ManifoldCFException, ServiceInterruption { |
| sendMail(spec, EmailConfig.NODE_FINISHED); |
| } |
| |
| protected void sendMail(final Specification spec, final String nodeType) |
| throws ManifoldCFException, ServiceInterruption |
| { |
| final List<String> to = new ArrayList<String>(); |
| String from = null; |
| String subject = ""; |
| String body = ""; |
| for (int i = 0; i < spec.getChildCount(); i++) { |
| SpecificationNode sn = spec.getChild(i); |
| if (sn.getType().equals(EmailConfig.NODE_TO)) |
| to.add(sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE)); |
| else if (sn.getType().equals(EmailConfig.NODE_FROM)) |
| from = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| else if (sn.getType().equals(EmailConfig.NODE_SUBJECT)) |
| subject = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| else if (sn.getType().equals(EmailConfig.NODE_BODY)) |
| body = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } |
| // Look for node of the specified type |
| if (nodeType != null) |
| { |
| for (int i = 0; i < spec.getChildCount(); i++) { |
| SpecificationNode childNode = spec.getChild(i); |
| if (childNode.getType().equals(nodeType)) |
| { |
| for (int j = 0; j < childNode.getChildCount(); j++) { |
| SpecificationNode sn = childNode.getChild(j); |
| if (sn.getType().equals(EmailConfig.NODE_TO)) |
| to.add(sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE)); |
| else if (sn.getType().equals(EmailConfig.NODE_FROM)) |
| from = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| else if (sn.getType().equals(EmailConfig.NODE_SUBJECT)) |
| subject = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| else if (sn.getType().equals(EmailConfig.NODE_BODY)) |
| body = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } |
| } |
| } |
| } |
| |
| if (to.size() == 0) |
| return; |
| |
| // Construct and send an email |
| getSession(); |
| |
| SendThread st = new SendThread(session,to,from,subject,body); |
| st.start(); |
| try { |
| st.finishUp(); |
| } catch (InterruptedException e) { |
| throw new ManifoldCFException(e.getMessage(),ManifoldCFException.INTERRUPTED); |
| } catch (MessagingException e) { |
| handleMessagingException(e,"sending email"); |
| } |
| } |
| |
| |
| //////////////////////////////End of Notification Connector Methods/////////////////////////////////// |
| |
| |
| ///////////////////////////////////////Start of Configuration UI///////////////////////////////////// |
| |
| /** |
| * Output the configuration header section. |
| * This method is called in the head section of the connector's configuration page. Its purpose is to |
| * add the required tabs to the list, and to output any javascript methods that might be needed by |
| * the configuration editing HTML. |
| * The connector does not need to be connected for this method to be called. |
| * |
| * @param threadContext is the local thread context. |
| * @param out is the output to which any HTML should be sent. |
| * @param locale is the desired locale. |
| * @param parameters are the configuration parameters, as they currently exist, for this connection being configured. |
| * @param tabsArray is an array of tab names. Add to this array any tab names that are specific to the connector. |
| */ |
| @Override |
| public void outputConfigurationHeader(IThreadContext threadContext, IHTTPOutput out, |
| Locale locale, ConfigParams parameters, List<String> tabsArray) |
| throws ManifoldCFException, IOException { |
| tabsArray.add(Messages.getString(locale, "EmailConnector.Server")); |
| // Map the parameters |
| Map<String, Object> paramMap = new HashMap<String, Object>(); |
| |
| // Fill in the parameters from each tab |
| fillInServerConfigurationMap(paramMap, out, parameters); |
| |
| // Output the Javascript - only one Velocity template for all tabs |
| Messages.outputResourceWithVelocity(out, locale, "ConfigurationHeader.js", paramMap); |
| } |
| |
| @Override |
| public void outputConfigurationBody(IThreadContext threadContext, IHTTPOutput out, |
| Locale locale, ConfigParams parameters, String tabName) |
| throws ManifoldCFException, IOException { |
| // Output the Server tab |
| Map<String, Object> paramMap = new HashMap<String, Object>(); |
| // Set the tab name |
| paramMap.put("TabName", tabName); |
| // Fill in the parameters |
| fillInServerConfigurationMap(paramMap, out, parameters); |
| Messages.outputResourceWithVelocity(out, locale, "Configuration_Server.html", paramMap); |
| } |
| |
| private static void fillInServerConfigurationMap(Map<String, Object> paramMap, IPasswordMapperActivity mapper, ConfigParams parameters) { |
| int i = 0; |
| String username = parameters.getParameter(EmailConfig.USERNAME_PARAM); |
| String password = parameters.getObfuscatedParameter(EmailConfig.PASSWORD_PARAM); |
| String protocol = parameters.getParameter(EmailConfig.PROTOCOL_PARAM); |
| String server = parameters.getParameter(EmailConfig.SERVER_PARAM); |
| String port = parameters.getParameter(EmailConfig.PORT_PARAM); |
| List<Map<String, String>> list = new ArrayList<Map<String, String>>(); |
| while (i < parameters.getChildCount()) //In post property set is added as a configuration node |
| { |
| ConfigNode cn = parameters.getChild(i++); |
| if (cn.getType().equals(EmailConfig.NODE_PROPERTIES)) { |
| String findParameterName = cn.getAttributeValue(EmailConfig.ATTRIBUTE_NAME); |
| String findParameterValue = cn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| Map<String, String> row = new HashMap<String, String>(); |
| row.put("name", findParameterName); |
| row.put("value", findParameterValue); |
| list.add(row); |
| } |
| } |
| |
| if (username == null) |
| username = StringUtils.EMPTY; |
| if (password == null) |
| password = StringUtils.EMPTY; |
| else |
| password = mapper.mapPasswordToKey(password); |
| if (protocol == null) |
| protocol = EmailConfig.PROTOCOL_DEFAULT_VALUE; |
| if (server == null) |
| server = StringUtils.EMPTY; |
| if (port == null) |
| port = EmailConfig.PORT_DEFAULT_VALUE; |
| |
| paramMap.put("USERNAME", username); |
| paramMap.put("PASSWORD", password); |
| paramMap.put("PROTOCOL", protocol); |
| paramMap.put("SERVER", server); |
| paramMap.put("PORT", port); |
| paramMap.put("PROPERTIES", list); |
| |
| } |
| |
| /** |
| * Process a configuration post. |
| * This method is called at the start of the connector's configuration page, whenever there is a possibility |
| * that form data for a connection has been posted. Its purpose is to gather form information and modify |
| * the configuration parameters accordingly. |
| * The name of the posted form is always "editconnection". |
| * The connector does not need to be connected for this method to be called. |
| * |
| * @param threadContext is the local thread context. |
| * @param variableContext is the set of variables available from the post, including binary file post information. |
| * @param parameters are the configuration parameters, as they currently exist, for this connection being configured. |
| * @return null if all is well, or a string error message if there is an error that should prevent saving of the |
| * connection (and cause a redirection to an error page). |
| */ |
| @Override |
| public String processConfigurationPost(IThreadContext threadContext, IPostParameters variableContext, |
| ConfigParams parameters) throws ManifoldCFException { |
| |
| String userName = variableContext.getParameter("username"); |
| if (userName != null) |
| parameters.setParameter(EmailConfig.USERNAME_PARAM, userName); |
| |
| String password = variableContext.getParameter("password"); |
| if (password != null) |
| parameters.setObfuscatedParameter(EmailConfig.PASSWORD_PARAM, variableContext.mapKeyToPassword(password)); |
| |
| String protocol = variableContext.getParameter("protocol"); |
| if (protocol != null) |
| parameters.setParameter(EmailConfig.PROTOCOL_PARAM, protocol); |
| |
| String server = variableContext.getParameter("server"); |
| if (server != null) |
| parameters.setParameter(EmailConfig.SERVER_PARAM, server); |
| String port = variableContext.getParameter("port"); |
| if (port != null) |
| parameters.setParameter(EmailConfig.PORT_PARAM, port); |
| // Remove old find parameter document specification information |
| removeNodes(parameters, EmailConfig.NODE_PROPERTIES); |
| |
| // Parse the number of records that were posted |
| String findCountString = variableContext.getParameter("findcount"); |
| if (findCountString != null) { |
| int findCount = Integer.parseInt(findCountString); |
| |
| // Loop throught them and add new server properties |
| int i = 0; |
| while (i < findCount) { |
| String suffix = "_" + Integer.toString(i++); |
| // Only add the name/value if the item was not deleted. |
| String findParameterOp = variableContext.getParameter("findop" + suffix); |
| if (findParameterOp == null || !findParameterOp.equals("Delete")) { |
| String findParameterName = variableContext.getParameter("findname" + suffix); |
| String findParameterValue = variableContext.getParameter("findvalue" + suffix); |
| addFindParameterNode(parameters, findParameterName, findParameterValue); |
| } |
| } |
| } |
| |
| // Now, look for a global "Add" operation |
| String operation = variableContext.getParameter("findop"); |
| if (operation != null && operation.equals("Add")) { |
| // Pick up the global parameter name and value |
| String findParameterName = variableContext.getParameter("findname"); |
| String findParameterValue = variableContext.getParameter("findvalue"); |
| addFindParameterNode(parameters, findParameterName, findParameterValue); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * View configuration. This method is called in the body section of the |
| * connector's view configuration page. Its purpose is to present the |
| * connection information to the user. The coder can presume that the HTML that |
| * is output from this configuration will be within appropriate <html> and |
| * <body> tags. |
| * |
| * @param threadContext is the local thread context. |
| * @param out is the output to which any HTML should be sent. |
| * @param parameters are the configuration parameters, as they currently exist, for |
| * this connection being configured. |
| */ |
| @Override |
| public void viewConfiguration(IThreadContext threadContext, IHTTPOutput out, |
| Locale locale, ConfigParams parameters) throws ManifoldCFException, IOException { |
| Map<String, Object> paramMap = new HashMap<String, Object>(); |
| |
| // Fill in map from each tab |
| fillInServerConfigurationMap(paramMap, out, parameters); |
| |
| Messages.outputResourceWithVelocity(out, locale, "ConfigurationView.html", paramMap); |
| } |
| |
| |
| /////////////////////////////////End of configuration UI//////////////////////////////////////////////////// |
| |
| |
| /////////////////////////////////Start of Specification UI////////////////////////////////////////////////// |
| |
| /** Output the specification header section. |
| * This method is called in the head section of a job page which has selected a repository connection of the |
| * current type. Its purpose is to add the required tabs to the list, and to output any javascript methods |
| * that might be needed by the job editing HTML. |
| * The connector will be connected before this method can be called. |
| *@param out is the output to which any HTML should be sent. |
| *@param locale is the locale the output is preferred to be in. |
| *@param ds is the current document specification for this job. |
| *@param connectionSequenceNumber is the unique number of this connection within the job. |
| *@param tabsArray is an array of tab names. Add to this array any tab names that are specific to the connector. |
| */ |
| @Override |
| public void outputSpecificationHeader(IHTTPOutput out, Locale locale, Specification ds, |
| int connectionSequenceNumber, List<String> tabsArray) |
| throws ManifoldCFException, IOException { |
| Map<String, Object> paramMap = new HashMap<String, Object>(); |
| paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber)); |
| // Add the tabs |
| tabsArray.add(Messages.getString(locale, "EmailConnector.Message")); |
| Messages.outputResourceWithVelocity(out, locale, "SpecificationHeader.js", paramMap); |
| } |
| |
| /** Output the specification body section. |
| * This method is called in the body section of a job page which has selected a repository connection of the |
| * current type. Its purpose is to present the required form elements for editing. |
| * The coder can presume that the HTML that is output from this configuration will be within appropriate |
| * <html>, <body>, and <form> tags. The name of the form is always "editjob". |
| * The connector will be connected before this method can be called. |
| *@param out is the output to which any HTML should be sent. |
| *@param locale is the locale the output is preferred to be in. |
| *@param ds is the current document specification for this job. |
| *@param connectionSequenceNumber is the unique number of this connection within the job. |
| *@param actualSequenceNumber is the connection within the job that has currently been selected. |
| *@param tabName is the current tab name. (actualSequenceNumber, tabName) form a unique tuple within |
| * the job. |
| */ |
| @Override |
| public void outputSpecificationBody(IHTTPOutput out, Locale locale, Specification ds, |
| int connectionSequenceNumber, int actualSequenceNumber, String tabName) |
| throws ManifoldCFException, IOException { |
| outputMessageTab(out, locale, ds, tabName, connectionSequenceNumber, actualSequenceNumber); |
| } |
| |
| /** |
| * Take care of "Message" tab. |
| */ |
| protected void outputMessageTab(IHTTPOutput out, Locale locale, |
| Specification ds, String tabName, int connectionSequenceNumber, int actualSequenceNumber) |
| throws ManifoldCFException, IOException { |
| Map<String, Object> paramMap = new HashMap<String, Object>(); |
| paramMap.put("TabName", tabName); |
| paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber)); |
| paramMap.put("SelectedNum", Integer.toString(actualSequenceNumber)); |
| fillInMessageTab(paramMap, ds); |
| Messages.outputResourceWithVelocity(out, locale, "Specification_Message.html", paramMap); |
| } |
| |
| /** |
| * Fill in Velocity context for Metadata tab. |
| */ |
| protected static void fillInMessageTab(Map<String, Object> paramMap, |
| Specification ds) { |
| |
| // Preload default values, for backwards compatibility |
| String toValue = ""; |
| String fromValue = ""; |
| String subjectValue = ""; |
| String bodyValue = ""; |
| for (int i = 0; i < ds.getChildCount(); i++) { |
| SpecificationNode sn = ds.getChild(i); |
| if (sn.getType().equals(EmailConfig.NODE_TO)) { |
| toValue = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } else if (sn.getType().equals(EmailConfig.NODE_FROM)) { |
| fromValue = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } else if (sn.getType().equals(EmailConfig.NODE_SUBJECT)) { |
| subjectValue = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } else if (sn.getType().equals(EmailConfig.NODE_BODY)) { |
| bodyValue = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } |
| } |
| // If ANY of the above are non-empty, we create a new dummy record |
| if (toValue.length() > 0) { |
| // Add the dummy records |
| addRecord(paramMap, EmailConfig.NODE_FINISHED, toValue, fromValue, subjectValue, bodyValue); |
| addRecord(paramMap, EmailConfig.NODE_ERRORABORTED, toValue, fromValue, subjectValue, bodyValue); |
| addRecord(paramMap, EmailConfig.NODE_MANUALABORTED, toValue, fromValue, subjectValue, bodyValue); |
| addRecord(paramMap, EmailConfig.NODE_MANUALPAUSED, toValue, fromValue, subjectValue, bodyValue); |
| addRecord(paramMap, EmailConfig.NODE_SCHEDULEPAUSED, toValue, fromValue, subjectValue, bodyValue); |
| addRecord(paramMap, EmailConfig.NODE_RESTARTED, toValue, fromValue, subjectValue, bodyValue); |
| |
| } |
| else |
| { |
| // Initialize all records with blanks |
| addRecord(paramMap, EmailConfig.NODE_FINISHED, "", "", "", ""); |
| addRecord(paramMap, EmailConfig.NODE_ERRORABORTED, "", "", "", ""); |
| addRecord(paramMap, EmailConfig.NODE_MANUALABORTED, "", "", "", ""); |
| addRecord(paramMap, EmailConfig.NODE_MANUALPAUSED, "", "", "", ""); |
| addRecord(paramMap, EmailConfig.NODE_SCHEDULEPAUSED, "", "", "", ""); |
| addRecord(paramMap, EmailConfig.NODE_RESTARTED, "", "", "" ,""); |
| |
| // Loop through nodes and pick them out that way |
| for (int i = 0; i < ds.getChildCount(); i++) { |
| SpecificationNode childNode = ds.getChild(i); |
| if (childNode.getType().equals(EmailConfig.NODE_FINISHED) || |
| childNode.getType().equals(EmailConfig.NODE_ERRORABORTED) || |
| childNode.getType().equals(EmailConfig.NODE_MANUALABORTED) || |
| childNode.getType().equals(EmailConfig.NODE_MANUALPAUSED) || |
| childNode.getType().equals(EmailConfig.NODE_SCHEDULEPAUSED) || |
| childNode.getType().equals(EmailConfig.NODE_RESTARTED)) { |
| toValue = ""; |
| fromValue = ""; |
| subjectValue = ""; |
| bodyValue = ""; |
| for (int j = 0; j < childNode.getChildCount(); j++) { |
| SpecificationNode sn = childNode.getChild(j); |
| if (sn.getType().equals(EmailConfig.NODE_TO)) { |
| toValue = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } else if (sn.getType().equals(EmailConfig.NODE_FROM)) { |
| fromValue = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } else if (sn.getType().equals(EmailConfig.NODE_SUBJECT)) { |
| subjectValue = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } else if (sn.getType().equals(EmailConfig.NODE_BODY)) { |
| bodyValue = sn.getAttributeValue(EmailConfig.ATTRIBUTE_VALUE); |
| } |
| } |
| addRecord(paramMap, childNode.getType(), toValue, fromValue, subjectValue, bodyValue); |
| } |
| } |
| } |
| } |
| |
| protected static void addRecord(Map<String,Object> paramMap, String nodeType, String toValue, String fromValue, String subjectValue, String bodyValue) { |
| paramMap.put(nodeType+"_TO", toValue); |
| paramMap.put(nodeType+"_FROM", fromValue); |
| paramMap.put(nodeType+"_SUBJECT", subjectValue); |
| paramMap.put(nodeType+"_BODY", bodyValue); |
| } |
| |
| /** Process a specification post. |
| * This method is called at the start of job's edit or view page, whenever there is a possibility that form |
| * data for a connection has been posted. Its purpose is to gather form information and modify the |
| * document specification accordingly. The name of the posted form is always "editjob". |
| * The connector will be connected before this method can be called. |
| *@param variableContext contains the post data, including binary file-upload information. |
| *@param locale is the locale the output is preferred to be in. |
| *@param ds is the current document specification for this job. |
| *@param connectionSequenceNumber is the unique number of this connection within the job. |
| *@return null if all is well, or a string error message if there is an error that should prevent saving of |
| * the job (and cause a redirection to an error page). |
| */ |
| @Override |
| public String processSpecificationPost(IPostParameters variableContext, Locale locale, Specification ds, |
| int connectionSequenceNumber) |
| throws ManifoldCFException { |
| |
| return processMessageTab(variableContext, ds, connectionSequenceNumber); |
| } |
| |
| protected String processMessageTab(IPostParameters variableContext, Specification ds, |
| int connectionSequenceNumber) |
| throws ManifoldCFException { |
| |
| String seqPrefix = "s"+connectionSequenceNumber+"_"; |
| |
| // Remove legacy nodes always |
| removeNodes(ds, EmailConfig.NODE_TO); |
| removeNodes(ds, EmailConfig.NODE_FROM); |
| removeNodes(ds, EmailConfig.NODE_SUBJECT); |
| removeNodes(ds, EmailConfig.NODE_BODY); |
| |
| // Gather all different kinds. |
| gatherRecord(ds, seqPrefix, variableContext, EmailConfig.NODE_FINISHED); |
| gatherRecord(ds, seqPrefix, variableContext, EmailConfig.NODE_ERRORABORTED); |
| gatherRecord(ds, seqPrefix, variableContext, EmailConfig.NODE_MANUALABORTED); |
| gatherRecord(ds, seqPrefix, variableContext, EmailConfig.NODE_MANUALPAUSED); |
| gatherRecord(ds, seqPrefix, variableContext, EmailConfig.NODE_SCHEDULEPAUSED); |
| gatherRecord(ds, seqPrefix, variableContext, EmailConfig.NODE_RESTARTED); |
| |
| return null; |
| } |
| |
| protected static void gatherRecord(Specification ds, String seqPrefix, IPostParameters variableContext, String nodeType) { |
| removeNodes(ds, nodeType); |
| SpecificationNode sn = new SpecificationNode(nodeType); |
| String toString = variableContext.getParameter(seqPrefix + nodeType + "_to"); |
| if (toString != null) |
| { |
| addNodeValue(sn, EmailConfig.NODE_TO, toString); |
| } |
| String fromString = variableContext.getParameter(seqPrefix + nodeType + "_from"); |
| if (fromString != null) |
| { |
| addNodeValue(sn, EmailConfig.NODE_FROM, fromString); |
| } |
| String subjectString = variableContext.getParameter(seqPrefix + nodeType + "_subject"); |
| if (subjectString != null) |
| { |
| addNodeValue(sn, EmailConfig.NODE_SUBJECT, subjectString); |
| } |
| String bodyString = variableContext.getParameter(seqPrefix + nodeType + "_body"); |
| if (bodyString != null) |
| { |
| addNodeValue(sn, EmailConfig.NODE_BODY, bodyString); |
| } |
| ds.addChild(ds.getChildCount(),sn); |
| } |
| |
| /** View specification. |
| * This method is called in the body section of a job's view page. Its purpose is to present the document |
| * specification information to the user. The coder can presume that the HTML that is output from |
| * this configuration will be within appropriate <html> and <body> tags. |
| * The connector will be connected before this method can be called. |
| *@param out is the output to which any HTML should be sent. |
| *@param locale is the locale the output is preferred to be in. |
| *@param ds is the current document specification for this job. |
| *@param connectionSequenceNumber is the unique number of this connection within the job. |
| */ |
| @Override |
| public void viewSpecification(IHTTPOutput out, Locale locale, Specification ds, |
| int connectionSequenceNumber) |
| throws ManifoldCFException, IOException { |
| Map<String, Object> paramMap = new HashMap<String, Object>(); |
| paramMap.put("SeqNum", Integer.toString(connectionSequenceNumber)); |
| fillInMessageTab(paramMap, ds); |
| Messages.outputResourceWithVelocity(out, locale, "SpecificationView.html", paramMap); |
| } |
| |
| ///////////////////////////////////////End of specification UI/////////////////////////////////////////////// |
| |
| protected static void addFindParameterNode(ConfigParams parameters, String findParameterName, String findParameterValue) { |
| ConfigNode cn = new ConfigNode(EmailConfig.NODE_PROPERTIES); |
| cn.setAttribute(EmailConfig.ATTRIBUTE_NAME, findParameterName); |
| cn.setAttribute(EmailConfig.ATTRIBUTE_VALUE, findParameterValue); |
| // Add to the end |
| parameters.addChild(parameters.getChildCount(), cn); |
| } |
| |
| protected static void removeNodes(ConfigParams parameters, String nodeTypeName) { |
| int i = 0; |
| while (i < parameters.getChildCount()) { |
| ConfigNode cn = parameters.getChild(i); |
| if (cn.getType().equals(nodeTypeName)) |
| parameters.removeChild(i); |
| else |
| i++; |
| } |
| } |
| |
| protected static void removeNodes(Specification ds, String nodeTypeName) { |
| int i = 0; |
| while (i < ds.getChildCount()) { |
| SpecificationNode sn = ds.getChild(i); |
| if (sn.getType().equals(nodeTypeName)) |
| ds.removeChild(i); |
| else |
| i++; |
| } |
| } |
| |
| protected static void addNodeValue(SpecificationNode ds, String nodeType, String value) |
| { |
| SpecificationNode sn = new SpecificationNode(nodeType); |
| sn.setAttribute(EmailConfig.ATTRIBUTE_VALUE,value); |
| ds.addChild(ds.getChildCount(),sn); |
| } |
| |
| |
| /** Handle Messaging exceptions in a consistent global manner */ |
| protected static void handleMessagingException(MessagingException e, String context) |
| throws ManifoldCFException, ServiceInterruption |
| { |
| Logging.connectors.error("Email: Error "+context+": "+e.getMessage(),e); |
| throw new ManifoldCFException("Error "+context+": "+e.getMessage(),e); |
| } |
| |
| /** Class to set up connection. |
| */ |
| protected static class ConnectThread extends Thread |
| { |
| protected final String server; |
| protected final int port; |
| protected final String username; |
| protected final String password; |
| protected final String protocol; |
| protected final Properties properties; |
| |
| // Local session handle |
| protected EmailSession session = null; |
| protected Throwable exception = null; |
| |
| public ConnectThread(String server, int port, String username, String password, String protocol, Properties properties) |
| { |
| this.server = server; |
| this.port = port; |
| this.username = username; |
| this.password = password; |
| this.protocol = protocol; |
| this.properties = properties; |
| setDaemon(true); |
| } |
| |
| public void run() |
| { |
| try |
| { |
| session = new EmailSession(server, port, username, password, protocol, properties); |
| } |
| catch (Throwable e) |
| { |
| exception = e; |
| } |
| } |
| |
| public EmailSession finishUp() |
| throws MessagingException, InterruptedException |
| { |
| try |
| { |
| join(); |
| if (exception != null) |
| { |
| if (exception instanceof RuntimeException) |
| throw (RuntimeException)exception; |
| else if (exception instanceof Error) |
| throw (Error)exception; |
| else if (exception instanceof MessagingException) |
| throw (MessagingException)exception; |
| else |
| throw new RuntimeException("Unknown exception type: "+exception.getClass().getName()+": "+exception.getMessage(),exception); |
| } |
| return session; |
| } catch (InterruptedException e) { |
| this.interrupt(); |
| throw e; |
| } |
| } |
| } |
| |
| /** Class to close the session. |
| */ |
| protected static class CloseSessionThread extends Thread |
| { |
| protected final EmailSession session; |
| |
| protected Throwable exception = null; |
| |
| public CloseSessionThread(EmailSession session) |
| { |
| this.session = session; |
| setDaemon(true); |
| } |
| |
| public void run() |
| { |
| try |
| { |
| session.close(); |
| } |
| catch (Throwable e) |
| { |
| exception = e; |
| } |
| } |
| |
| public void finishUp() |
| throws MessagingException, InterruptedException |
| { |
| try |
| { |
| join(); |
| if (exception != null) |
| { |
| if (exception instanceof RuntimeException) |
| throw (RuntimeException)exception; |
| else if (exception instanceof Error) |
| throw (Error)exception; |
| else if (exception instanceof MessagingException) |
| throw (MessagingException)exception; |
| else |
| throw new RuntimeException("Unknown exception type: "+exception.getClass().getName()+": "+exception.getMessage(),exception); |
| } |
| } catch (InterruptedException e) { |
| this.interrupt(); |
| throw e; |
| } |
| } |
| } |
| |
| /** Class to check the connection. |
| */ |
| protected static class CheckConnectionThread extends Thread |
| { |
| protected final EmailSession session; |
| |
| protected Throwable exception = null; |
| |
| public CheckConnectionThread(EmailSession session) |
| { |
| this.session = session; |
| setDaemon(true); |
| } |
| |
| public void run() |
| { |
| try |
| { |
| session.checkConnection(); |
| } |
| catch (Throwable e) |
| { |
| exception = e; |
| } |
| } |
| |
| public void finishUp() |
| throws MessagingException, InterruptedException |
| { |
| try |
| { |
| join(); |
| if (exception != null) |
| { |
| if (exception instanceof RuntimeException) |
| throw (RuntimeException)exception; |
| else if (exception instanceof Error) |
| throw (Error)exception; |
| else if (exception instanceof MessagingException) |
| throw (MessagingException)exception; |
| else |
| throw new RuntimeException("Unknown exception type: "+exception.getClass().getName()+": "+exception.getMessage(),exception); |
| } |
| } catch (InterruptedException e) { |
| this.interrupt(); |
| throw e; |
| } |
| } |
| } |
| |
| /** Class to send email. |
| */ |
| protected static class SendThread extends Thread |
| { |
| protected final EmailSession session; |
| protected final List<String> to; |
| protected final String from; |
| protected final String subject; |
| protected final String body; |
| |
| protected Throwable exception = null; |
| |
| public SendThread(EmailSession session, List<String> to, String from, String subject, String body) |
| { |
| this.session = session; |
| this.to = to; |
| this.from = from; |
| this.subject = subject; |
| this.body = body; |
| setDaemon(true); |
| } |
| |
| public void run() |
| { |
| try |
| { |
| session.send(to,from,subject,body); |
| } |
| catch (Throwable e) |
| { |
| exception = e; |
| } |
| } |
| |
| public void finishUp() |
| throws MessagingException, InterruptedException |
| { |
| try |
| { |
| join(); |
| if (exception != null) |
| { |
| if (exception instanceof RuntimeException) |
| throw (RuntimeException)exception; |
| else if (exception instanceof Error) |
| throw (Error)exception; |
| else if (exception instanceof MessagingException) |
| throw (MessagingException)exception; |
| else |
| throw new RuntimeException("Unknown exception type: "+exception.getClass().getName()+": "+exception.getMessage(),exception); |
| } |
| } catch (InterruptedException e) { |
| this.interrupt(); |
| throw e; |
| } |
| } |
| } |
| |
| } |