From 535c74a9629b4c2656a24043178db6c6e77dc226 Mon Sep 17 00:00:00 2001 From: prabathabey Date: Sat, 12 Mar 2016 12:46:36 +0530 Subject: [PATCH] Improving email sender functionality --- .../org.wso2.carbon.device.mgt.core/pom.xml | 18 +- .../config/DeviceConfigurationManager.java | 24 +-- .../config/email/NotificationMessages.java | 110 ------------ .../email/NotificationMessagesConfig.java | 39 ---- ...ContentProcessingInterruptedException.java | 45 +++++ .../device/mgt/core/email/EmailConstants.java | 14 +- .../mgt/core/email/EmailContentProvider.java | 28 +++ .../email/EmailContentProviderFactory.java | 27 +++ .../device/mgt/core/email/EmailContext.java | 77 ++++++++ .../device/mgt/core/email/EmailData.java | 48 +++++ .../email/EmailSendingFailedException.java | 45 +++++ .../email/RegistryBasedResourceLoader.java | 71 ++++++++ .../device/mgt/core/email/TypedValue.java | 50 ++++++ .../VelocityBasedEmailContentProvider.java | 87 +++++++++ .../mgt/core/email/sender/EmailSender.java | 104 +++++++++++ .../sender/EmailServiceProviderImpl.java | 62 ++++--- ...eManagementAxis2ConfigContextObserver.java | 65 ++++++- .../DeviceManagementServiceComponent.java | 98 +++++++++- .../DeviceManagementProviderService.java | 5 +- .../DeviceManagementProviderServiceImpl.java | 170 +++++------------- .../device/mgt/core/service/EmailService.java | 8 +- .../mgt/core/service/EmailServiceImpl.java | 13 +- pom.xml | 14 +- 23 files changed, 872 insertions(+), 350 deletions(-) delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/email/NotificationMessages.java delete mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/email/NotificationMessagesConfig.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/ContentProcessingInterruptedException.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContentProvider.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContentProviderFactory.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContext.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailData.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailSendingFailedException.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/RegistryBasedResourceLoader.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/TypedValue.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/VelocityBasedEmailContentProvider.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/sender/EmailSender.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/pom.xml b/components/device-mgt/org.wso2.carbon.device.mgt.core/pom.xml index 46b7f07852..d4d6214a17 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/pom.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/pom.xml @@ -83,7 +83,15 @@ org.wso2.carbon.ndatasource.core, org.apache.axis2.transport.mail, org.apache.catalina, - org.apache.catalina.core + org.apache.catalina.core, + org.apache.commons.collections, + org.apache.velocity, + org.apache.velocity.app, + org.apache.velocity.context, + org.apache.velocity.exception, + org.apache.velocity.runtime.resource, + org.apache.velocity.runtime.resource.loader, + org.apache.commons.io !org.wso2.carbon.device.mgt.core.internal, @@ -216,6 +224,14 @@ org.wso2.tomcat tomcat-servlet-api + + org.apache.velocity + velocity + + + commons-io.wso2 + commons-io + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceConfigurationManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceConfigurationManager.java index 0c735ba1ff..51b6b63f2e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceConfigurationManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceConfigurationManager.java @@ -21,7 +21,6 @@ package org.wso2.carbon.device.mgt.core.config; import org.w3c.dom.Document; import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.core.config.email.NotificationMessagesConfig; import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil; import org.wso2.carbon.utils.CarbonUtils; import org.xml.sax.SAXException; @@ -35,21 +34,17 @@ import javax.xml.validation.SchemaFactory; import java.io.File; /** - * Class responsible for the cdm manager configuration initialization. + * Class responsible for the cdm configuration initialization. */ public class DeviceConfigurationManager { private DeviceManagementConfig currentDeviceConfig; - private NotificationMessagesConfig notificationMessagesConfig; private static DeviceConfigurationManager deviceConfigManager; private static final String DEVICE_MGT_CONFIG_PATH = CarbonUtils.getCarbonConfigDirPath() + File.separator + DeviceManagementConstants.DataSourceProperties.DEVICE_CONFIG_XML_NAME; private static final String DEVICE_MGT_CONFIG_SCHEMA_PATH = "resources/config/schema/device-mgt-config-schema.xsd"; - private static final String NOTIFICATION_MSG_CONFIG_PATH = - CarbonUtils.getCarbonConfigDirPath() + File.separator + - DeviceManagementConstants.NotificationProperties.NOTIFICATION_CONFIG_FILE; public static DeviceConfigurationManager getInstance() { if (deviceConfigManager == null) { @@ -63,7 +58,6 @@ public class DeviceConfigurationManager { } public synchronized void initConfig() throws DeviceManagementException { - try { File deviceMgtConfig = new File(DeviceConfigurationManager.DEVICE_MGT_CONFIG_PATH); Document doc = DeviceManagerUtil.convertToDocument(deviceMgtConfig); @@ -76,18 +70,6 @@ public class DeviceConfigurationManager { } catch (JAXBException e) { throw new DeviceManagementException("Error occurred while initializing Data Source config", e); } - - try { - File notificationConfig = new File(DeviceConfigurationManager.NOTIFICATION_MSG_CONFIG_PATH); - Document doc = DeviceManagerUtil.convertToDocument(notificationConfig); - - /* Un-marshaling Notifications Management configuration */ - JAXBContext notificationContext = JAXBContext.newInstance(NotificationMessagesConfig.class); - Unmarshaller unmarshaller = notificationContext.createUnmarshaller(); - this.notificationMessagesConfig = (NotificationMessagesConfig) unmarshaller.unmarshal(doc); - } catch(JAXBException e){ - throw new DeviceManagementException("Error occurred while initializing Notification settings config", e); - } } private static Schema getSchema() throws DeviceManagementException { @@ -105,8 +87,4 @@ public class DeviceConfigurationManager { return currentDeviceConfig; } - public NotificationMessagesConfig getNotificationMessagesConfig() { - return notificationMessagesConfig; - } - } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/email/NotificationMessages.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/email/NotificationMessages.java deleted file mode 100644 index 961497030b..0000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/email/NotificationMessages.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.wso2.carbon.device.mgt.core.config.email; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement(name = "NotificationMessage") -public class NotificationMessages { - - private String header; - private String body; - private String footerLine1; - private String footerLine2; - private String footerLine3; - private String subject; - private String url; - - @XmlAttribute(name = "type") - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - private String type; - - @XmlElement(name = "Header", required = true) - public String getHeader() { - return header; - } - - public void setHeader(String header) { - this.header = header; - } - - @XmlElement(name = "Body", required = true) - public String getBody() { - return body; - } - - public void setBody(String body) { - this.body = body; - } - - @XmlElement(name = "Subject", required = true) - public String getSubject() { - return subject; - } - - public void setSubject(String subject) { - this.subject = subject; - } - - @XmlElement(name = "Url", required = true) - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - @XmlElement(name = "Footer1") - public String getFooterLine1() { - return footerLine1; - } - - public void setFooterLine1(String footerLine1) { - this.footerLine1 = footerLine1; - } - - @XmlElement(name = "Footer2") - public String getFooterLine2() { - return footerLine2; - } - - public void setFooterLine2(String footerLine2) { - this.footerLine2 = footerLine2; - } - - @XmlElement(name = "Footer3") - public String getFooterLine3() { - return footerLine3; - } - - public void setFooterLine3(String footerLine3) { - this.footerLine3 = footerLine3; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/email/NotificationMessagesConfig.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/email/NotificationMessagesConfig.java deleted file mode 100644 index 97aefeaa0f..0000000000 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/email/NotificationMessagesConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.wso2.carbon.device.mgt.core.config.email; - -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import java.util.List; - -@XmlRootElement(name = "Notifications") -public class NotificationMessagesConfig { - - private List notificationMessagesList; - - @XmlElement(name = "NotificationMessage") - public List getNotificationMessagesList() { - return notificationMessagesList; - } - - public void setNotificationMessagesList(List notificationMessagesList) { - this.notificationMessagesList = notificationMessagesList; - } - -} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/ContentProcessingInterruptedException.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/ContentProcessingInterruptedException.java new file mode 100644 index 0000000000..e18db38211 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/ContentProcessingInterruptedException.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +public class ContentProcessingInterruptedException extends Exception { + + private static final long serialVersionUID = -3151279311929070298L; + + public ContentProcessingInterruptedException(String msg, Exception nestedEx) { + super(msg, nestedEx); + } + + public ContentProcessingInterruptedException(String message, Throwable cause) { + super(message, cause); + } + + public ContentProcessingInterruptedException(String msg) { + super(msg); + } + + public ContentProcessingInterruptedException() { + super(); + } + + public ContentProcessingInterruptedException(Throwable cause) { + super(cause); + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailConstants.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailConstants.java index 139a845f85..8a5c395699 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailConstants.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailConstants.java @@ -19,13 +19,11 @@ package org.wso2.carbon.device.mgt.core.email; public final class EmailConstants { - public static final class EnrolmentEmailConstants { - public static final String DOMAIN = "domain-name"; - public static final String USERNAME = "user-name"; - public static final String DOWNLOAD_URL = "downloadUrl"; - public static final String ENCODED_SCHEME = "UTF-8"; - public static final String PASSWORD = "password"; - public static final String FIRST_NAME = "first-name"; - } + public static final String DOMAIN = "domain-name"; + public static final String USERNAME = "user-name"; + public static final String DOWNLOAD_URL = "download-url"; + public static final String ENCODED_SCHEME = "UTF-8"; + public static final String PASSWORD = "password"; + public static final String FIRST_NAME = "first-name"; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContentProvider.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContentProvider.java new file mode 100644 index 0000000000..bb1b48374b --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContentProvider.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +import java.util.Map; + +public interface EmailContentProvider { + + EmailData getContent(String path, + Map, Object>> params) throws ContentProcessingInterruptedException; + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContentProviderFactory.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContentProviderFactory.java new file mode 100644 index 0000000000..eeaecb7515 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContentProviderFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +public class EmailContentProviderFactory { + + public static EmailContentProvider getContentProvider() { + return new VelocityBasedEmailContentProvider(); + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContext.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContext.java new file mode 100644 index 0000000000..a8af2c612f --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailContext.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +import java.util.*; + +public class EmailContext { + + private Set recipients; + private Properties properties; + + public EmailContext(final Set recipients, final Properties properties) { + if (recipients == null) { + throw new IllegalArgumentException("Recipient list cannot be null"); + } + if (recipients.size() == 0) { + throw new IllegalArgumentException("No recipient is configured. Recipient list should carry at " + + "least one recipient"); + } + this.recipients = recipients; + if (properties == null) { + throw new IllegalArgumentException("Email Context property bag cannot be null"); + } + this.properties = properties; + } + + public EmailContext(final String recipient, final Properties properties) { + if (recipient == null || recipient.isEmpty()) { + throw new IllegalArgumentException("Recipient can't be null or empty. Please specify a valid " + + "recipient email address"); + } + this.recipients = new HashSet() {{ + add(recipient); + }}; + if (properties == null) { + throw new IllegalArgumentException("Email Context property bag cannot be null"); + } + this.properties = properties; + } + + public EmailContext(final Set recipients) { + this(recipients, new Properties()); + } + + public Set getRecipients() { + return recipients; + } + + public Properties getProperties() { + return properties; + } + + public String getProperty(String name) { + return (String) properties.get(name); + } + + public void addProperty(String name, String value) { + properties.put(name, value); + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailData.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailData.java new file mode 100644 index 0000000000..6ef02585d9 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailData.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "EmailConfig") +public class EmailData { + + private String subject; + private String body; + + @XmlElement(name = "Subject", required = true) + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + @XmlElement(name = "Body", required = true) + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailSendingFailedException.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailSendingFailedException.java new file mode 100644 index 0000000000..e0457259f7 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/EmailSendingFailedException.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +public class EmailSendingFailedException extends Exception { + + private static final long serialVersionUID = -3151279311929070294L; + + public EmailSendingFailedException(String msg, Exception nestedEx) { + super(msg, nestedEx); + } + + public EmailSendingFailedException(String message, Throwable cause) { + super(message, cause); + } + + public EmailSendingFailedException(String msg) { + super(msg); + } + + public EmailSendingFailedException() { + super(); + } + + public EmailSendingFailedException(Throwable cause) { + super(cause); + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/RegistryBasedResourceLoader.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/RegistryBasedResourceLoader.java new file mode 100644 index 0000000000..9d035e4a45 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/RegistryBasedResourceLoader.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +import org.apache.commons.collections.ExtendedProperties; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.runtime.resource.Resource; +import org.apache.velocity.runtime.resource.loader.ResourceLoader; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.RegistryType; +import org.wso2.carbon.registry.api.Registry; +import org.wso2.carbon.registry.api.RegistryException; + +import java.io.*; + +public class RegistryBasedResourceLoader extends ResourceLoader { + + private static final String EMAIL_CONFIG_BASE_LOCATION = "email-templates"; + + @Override + public void init(ExtendedProperties extendedProperties) { + + } + + @Override + public InputStream getResourceStream(String name) throws ResourceNotFoundException { + try { + Registry registry = + CarbonContext.getThreadLocalCarbonContext().getRegistry(RegistryType.SYSTEM_CONFIGURATION); + if (registry == null) { + throw new IllegalStateException("No valid registry instance is attached to the current carbon context"); + } + if (!registry.resourceExists(EMAIL_CONFIG_BASE_LOCATION + "/" + name + ".vm")) { + throw new ResourceNotFoundException("Resource '" + name + "' does not exist"); + } + org.wso2.carbon.registry.api.Resource resource = + registry.get(EMAIL_CONFIG_BASE_LOCATION + "/" + name + ".vm"); + + return resource.getContentStream(); + } catch (RegistryException e) { + throw new ResourceNotFoundException("Error occurred while retrieving resource", e); + } + } + + @Override + public boolean isSourceModified(Resource resource) { + return false; + } + + @Override + public long getLastModified(Resource resource) { + return 0; + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/TypedValue.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/TypedValue.java new file mode 100644 index 0000000000..11b5c2ed0a --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/TypedValue.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +public class TypedValue { + + private final T type; + private final V value; + + public TypedValue(T type, V value) { + this.type = type; + this.value = value; + } + + public T getType() { + return type; + } + + public V getValue() { + return value; + } + + @Override + public int hashCode() { + return (type.hashCode() ^ value.hashCode()); + } + + @Override + public boolean equals(Object o) { + return o instanceof TypedValue && (this.type == ((TypedValue) o).getType() && + this.value == ((TypedValue) o).getValue()); + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/VelocityBasedEmailContentProvider.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/VelocityBasedEmailContentProvider.java new file mode 100644 index 0000000000..a35d5c448d --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/VelocityBasedEmailContentProvider.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.resource.loader.ResourceLoader; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.RegistryType; +import org.wso2.carbon.registry.api.Registry; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.util.Map; + +public class VelocityBasedEmailContentProvider implements EmailContentProvider { + + private VelocityEngine engine; + private static final Log log = LogFactory.getLog(VelocityBasedEmailContentProvider.class); + + public VelocityBasedEmailContentProvider() { + engine = new VelocityEngine(); + engine.setProperty("resource.loader", "registry"); + engine.setProperty("velocimacro.library", ""); + engine.setProperty("registry.resource.loader.class", + "org.wso2.carbon.device.mgt.core.email.RegistryBasedResourceLoader"); + engine.init(); + } + + @Override + public EmailData getContent(String name, Map, Object>> params) throws ContentProcessingInterruptedException { + VelocityContext ctx = new VelocityContext(); + for (Map.Entry, Object>> param : params.entrySet()) { + ctx.put(param.getKey(), param.getValue().getValue()); + } + Template template = engine.getTemplate(name); + + StringWriter content = new StringWriter(); + template.merge(ctx, content); + + InputStream is = null; + try { + JAXBContext jaxbCtx = JAXBContext.newInstance(EmailData.class); + Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller(); + + is = new ByteArrayInputStream(content.toString().getBytes()); + return (EmailData) unmarshaller.unmarshal(is); + } catch (JAXBException e) { + throw new ContentProcessingInterruptedException("Error occurred while parsing email data", e); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + log.warn("Error occurred while closing input stream used to convert email configuration " + + "to an internal object model", e); + } + } + } + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/sender/EmailSender.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/sender/EmailSender.java new file mode 100644 index 0000000000..2ed3865616 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/sender/EmailSender.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.core.email.sender; + +import org.apache.axiom.om.OMAbstractFactory; +import org.apache.axiom.om.OMElement; +import org.apache.axis2.AxisFault; +import org.apache.axis2.Constants; +import org.apache.axis2.addressing.EndpointReference; +import org.apache.axis2.client.Options; +import org.apache.axis2.client.ServiceClient; +import org.apache.axis2.context.MessageContext; +import org.apache.axis2.transport.base.BaseConstants; +import org.apache.axis2.transport.mail.MailConstants; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; +import org.wso2.carbon.device.mgt.core.config.email.EmailConfigurations; +import org.wso2.carbon.device.mgt.core.email.EmailData; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class EmailSender { + + private static ThreadPoolExecutor threadPoolExecutor; + + static { + EmailConfigurations emailConfig = + DeviceConfigurationManager.getInstance().getDeviceManagementConfig(). + getDeviceManagementConfigRepository().getEmailConfigurations(); + + threadPoolExecutor = new ThreadPoolExecutor(emailConfig.getMinNumOfThread(), + emailConfig.getMaxNumOfThread(), emailConfig.getKeepAliveTime(), TimeUnit.SECONDS, + new LinkedBlockingQueue(emailConfig.getThreadQueueCapacity())); + } + + private static final String EMAIL_URI_SCHEME = "mailto:"; + private static Log log = LogFactory.getLog(EmailSender.class); + + public void sendEmail(EmailData emailData, String... recipients) throws DeviceManagementException { + for (String recipient : recipients) { + threadPoolExecutor + .submit(new EmailSenderTask(recipient, emailData)); + } + } + + public static class EmailSenderTask implements Runnable { + + private String to; + private EmailData data; + + EmailSenderTask(String to, EmailData data) { + this.to = to; + this.data = data; + } + + public void run() { + Map headerMap = new HashMap<>(); + headerMap.put(MailConstants.MAIL_HEADER_SUBJECT, data.getSubject()); + OMElement payload = OMAbstractFactory.getOMFactory().createOMElement( + BaseConstants.DEFAULT_TEXT_WRAPPER, null); + payload.setText(data.getBody()); + try { + ServiceClient serviceClient = new ServiceClient(); + Options options = new Options(); + options.setProperty(Constants.Configuration.ENABLE_REST, Constants.VALUE_TRUE); + options.setProperty(MessageContext.TRANSPORT_HEADERS, headerMap); + options.setProperty(MailConstants.TRANSPORT_MAIL_FORMAT, + MailConstants.TRANSPORT_FORMAT_TEXT); + options.setTo(new EndpointReference(EMAIL_URI_SCHEME + to)); + serviceClient.setOptions(options); + serviceClient.fireAndForget(payload); + if (log.isDebugEnabled()) { + log.debug("Email has been successfully sent to '" + to + "'"); + } + } catch (AxisFault e) { + log.error("Error occurred while delivering the message, subject: '" + data.getSubject() + + "', to: '" + to + "'", e); + } + } + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/sender/EmailServiceProviderImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/sender/EmailServiceProviderImpl.java index cd537f62a8..9df73dc8da 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/sender/EmailServiceProviderImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/email/sender/EmailServiceProviderImpl.java @@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.core.email.sender; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; +import org.apache.axiom.om.impl.llom.util.AXIOMUtil; import org.apache.axis2.AxisFault; import org.apache.axis2.Constants; import org.apache.axis2.addressing.EndpointReference; @@ -31,15 +32,18 @@ import org.apache.axis2.transport.base.BaseConstants; import org.apache.axis2.transport.mail.MailConstants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.common.EmailMessageProperties; import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; import org.wso2.carbon.device.mgt.core.config.email.EmailConfigurations; +import org.wso2.carbon.device.mgt.core.email.EmailData; +import org.wso2.carbon.device.mgt.core.email.EmailSendingFailedException; import org.wso2.carbon.device.mgt.core.internal.EmailServiceDataHolder; import org.wso2.carbon.device.mgt.core.service.EmailService; +import org.wso2.carbon.utils.ConfigurationContextService; +import javax.xml.stream.XMLStreamException; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -62,11 +66,9 @@ public class EmailServiceProviderImpl implements EmailService { private static Log log = LogFactory.getLog(EmailServiceProviderImpl.class); @Override - public void sendEmail(EmailMessageProperties emailMessageProperties) throws DeviceManagementException { - for (String toAddr : emailMessageProperties.getMailTo()) { - threadPoolExecutor - .submit(new EmailSender(toAddr, emailMessageProperties.getSubject(), - emailMessageProperties.getMessageBody())); + public void sendEmail(Set recipients, EmailData emailData) throws EmailSendingFailedException { + for (String recipient : recipients) { + threadPoolExecutor.submit(new EmailSender(recipient, emailData.getSubject(), emailData.getBody())); } } @@ -83,34 +85,42 @@ public class EmailServiceProviderImpl implements EmailService { } public void run() { - Map headerMap = new HashMap(); - headerMap.put(MailConstants.MAIL_HEADER_SUBJECT, subject); - OMElement payload = OMAbstractFactory.getOMFactory().createOMElement( - BaseConstants.DEFAULT_TEXT_WRAPPER, null); - payload.setText(body); + OMElement payload = null; try { - ServiceClient serviceClient; - ConfigurationContext configContext = EmailServiceDataHolder.getInstance(). - getConfigurationContextService().getServerConfigContext(); - //Set configuration service client if available, else create new service client - if (configContext != null) { - serviceClient = new ServiceClient(configContext, null); - } else { - - serviceClient = new ServiceClient(); + payload = AXIOMUtil.stringToOM(body); + } catch (XMLStreamException e) { + log.error("Error occurred while converting email body contents to an XML", e); + } + try { + ConfigurationContextService configCtxService = + EmailServiceDataHolder.getInstance().getConfigurationContextService(); + if (configCtxService == null) { + throw new IllegalStateException("Configuration Context Service is not available"); } + ConfigurationContext configCtx = configCtxService.getServerConfigContext(); + ServiceClient serviceClient = new ServiceClient(configCtx, null); + + Map headerMap = new HashMap<>(); + headerMap.put(MailConstants.MAIL_HEADER_SUBJECT, subject); + Options options = new Options(); - options.setProperty(Constants.Configuration.ENABLE_REST, Constants.VALUE_TRUE); options.setProperty(MessageContext.TRANSPORT_HEADERS, headerMap); - options.setProperty(MailConstants.TRANSPORT_MAIL_FORMAT, - MailConstants.TRANSPORT_FORMAT_TEXT); + options.setProperty("FORCE_CONTENT_TYPE_BASED_FORMATTER", "true"); + options.setProperty(Constants.Configuration.MESSAGE_TYPE, "text/html"); + options.setProperty(Constants.Configuration.CONTENT_TYPE, "text/html"); options.setTo(new EndpointReference(EMAIL_URI_SCHEME + to)); + serviceClient.setOptions(options); serviceClient.fireAndForget(payload); - log.debug("Sending confirmation mail to " + to); + if (log.isDebugEnabled()) { + log.debug("Email has been successfully sent to '" + to + "'"); + } } catch (AxisFault e) { - log.error("Error in delivering the message, subject: '" + subject + "', to: '" + to + "'", e); + log.error("Error occurred while delivering the message, subject: '" + subject + "', to: '" + to + + "'", e); } } + } + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementAxis2ConfigContextObserver.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementAxis2ConfigContextObserver.java index a973deacc9..169ae01bf8 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementAxis2ConfigContextObserver.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementAxis2ConfigContextObserver.java @@ -19,13 +19,31 @@ package org.wso2.carbon.device.mgt.core.internal; import org.apache.axis2.context.ConfigurationContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.CarbonContext; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.context.RegistryType; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.registry.api.Collection; +import org.wso2.carbon.registry.api.Registry; +import org.wso2.carbon.registry.api.RegistryException; +import org.wso2.carbon.registry.api.Resource; import org.wso2.carbon.utils.Axis2ConfigurationContextObserver; +import org.wso2.carbon.utils.CarbonUtils; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +import java.io.File; +import java.io.FilenameFilter; public class DeviceManagementAxis2ConfigContextObserver implements Axis2ConfigurationContextObserver { + private static final String EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH = "email-templates"; + private static final Log log = LogFactory.getLog(DeviceManagementAxis2ConfigContextObserver.class); + @Override public void creatingConfigurationContext(int tenantId) { - + } @Override @@ -43,4 +61,49 @@ public class DeviceManagementAxis2ConfigContextObserver implements Axis2Configur } + private void setupEmailTemplates() throws DeviceManagementException { + File templateDir = + new File(CarbonUtils.getCarbonRepository() + "resources" + File.separator + "email-templates"); + if (!templateDir.exists()) { + if (log.isDebugEnabled()) { + log.debug("The directory that is expected to use as the container for all email templates is not " + + "available. Therefore, no template is uploaded to the registry"); + } + } + if (templateDir.canRead()) { + File[] templates = templateDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + name = name.toLowerCase(); + return name.endsWith(".vm"); + } + }); + try { + Registry registry = + CarbonContext.getThreadLocalCarbonContext().getRegistry(RegistryType.SYSTEM_CONFIGURATION); + if (!registry.resourceExists(EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH)) { + Collection collection = registry.newCollection(); + registry.put(EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH, collection); + for (File template : templates) { + Resource resource = registry.newResource(); + resource.setContent(template); + registry.put(EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH + "/" + template.getName(), resource); + } + } else { + for (File template : templates) { + if (!registry.resourceExists( + EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH + "/" + template.getName())) { + Resource resource = registry.newResource(); + resource.setContent(template); + registry.put( + EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH + "/" + template.getName(), resource); + } + } + } + } catch (RegistryException e) { + throw new DeviceManagementException("Error occurred while setting up email templates", e); + } + } + } + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementServiceComponent.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementServiceComponent.java index c01d740341..57989e3d8a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementServiceComponent.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementServiceComponent.java @@ -17,10 +17,13 @@ */ package org.wso2.carbon.device.mgt.core.internal; +import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; +import org.w3c.dom.Document; +import org.w3c.dom.Element; import org.wso2.carbon.apimgt.impl.APIManagerConfigurationService; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException; @@ -52,10 +55,20 @@ import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderServiceImpl; import org.wso2.carbon.device.mgt.core.util.DeviceManagementSchemaInitializer; import org.wso2.carbon.ndatasource.core.DataSourceService; +import org.wso2.carbon.registry.api.Collection; +import org.wso2.carbon.registry.api.Registry; +import org.wso2.carbon.registry.api.RegistryException; +import org.wso2.carbon.registry.api.Resource; import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.ConfigurationContextService; +import org.xml.sax.SAXException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.*; import java.util.ArrayList; import java.util.List; @@ -108,6 +121,8 @@ public class DeviceManagementServiceComponent { private static List startupListeners = new ArrayList<>(); private DeviceManagementPluginRepository pluginRepository = new DeviceManagementPluginRepository(); + private static final String EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH = "/email-templates"; + @SuppressWarnings("unused") protected void activate(ComponentContext componentContext) { try { @@ -137,6 +152,9 @@ public class DeviceManagementServiceComponent { this.setupDeviceManagementSchema(dsConfig); } + /* Setting up email templates */ + this.setupEmailTemplates(); + /* Registering declarative service instances exposed by DeviceManagementServiceComponent */ this.registerServices(componentContext); @@ -181,9 +199,9 @@ public class DeviceManagementServiceComponent { bundleContext.registerService(DeviceManagementProviderService.class.getName(), deviceManagementProvider, null); /* Registering Tenant Configuration Management Service */ - TenantConfigurationManagementService - tenantConfiguration = new TenantConfigurationManagementServiceImpl(); - bundleContext.registerService(TenantConfigurationManagementService.class.getName(), tenantConfiguration, null); + TenantConfigurationManagementService + tenantConfiguration = new TenantConfigurationManagementServiceImpl(); + bundleContext.registerService(TenantConfigurationManagementService.class.getName(), tenantConfiguration, null); /* Registering Notification Service */ NotificationManagementService notificationManagementService @@ -199,7 +217,7 @@ public class DeviceManagementServiceComponent { DeviceAccessAuthorizationService deviceAccessAuthorizationService = new DeviceAccessAuthorizationServiceImpl(); DeviceManagementDataHolder.getInstance().setDeviceAccessAuthorizationService(deviceAccessAuthorizationService); bundleContext.registerService(DeviceAccessAuthorizationService.class.getName(), - deviceAccessAuthorizationService, null); + deviceAccessAuthorizationService, null); /* Registering App Management service */ try { @@ -213,6 +231,78 @@ public class DeviceManagementServiceComponent { } } + private void setupEmailTemplates() throws DeviceManagementException { + File templateDir = + new File(CarbonUtils.getCarbonHome() + File.separator + "repository" + File.separator + + "resources" + File.separator + "email-templates"); + if (!templateDir.exists()) { + if (log.isDebugEnabled()) { + log.debug("The directory that is expected to use as the container for all email templates is not " + + "available. Therefore, no template is uploaded to the registry"); + } + } + if (templateDir.canRead()) { + File[] templates = templateDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + name = name.toLowerCase(); + return name.endsWith(".vm"); + } + }); + try { + Registry registry = + DeviceManagementDataHolder.getInstance().getRegistryService().getConfigSystemRegistry(); + if (!registry.resourceExists(EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH)) { + Collection collection = registry.newCollection(); + registry.put(EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH, collection); + for (File template : templates) { + Resource resource = registry.newResource(); + String contents = FileUtils.readFileToString(template); + resource.setContent(contents.getBytes()); + registry.put(EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH + "/" + template.getName(), resource); + } + } else { + /* Existence of a given resource is not checked consciously, before performing registry.put() below. + * The rationale is that, the only less expensive way that one can check if a resource exists is + * that through registry.resourceExists(), which only checks if 'some' resource exists at the given + * registry path. However, this does not capture scenarios where there can be updated contents to + * the same resource of which the path hasn't changed after it has been initialized for the first + * time. Therefore, whenever the server starts-up, all email templates are updated just to avoid + * the aforementioned problem */ + for (File template : templates) { + Resource resource = registry.newResource(); + String contents = FileUtils.readFileToString(template); + resource.setContent(contents.getBytes()); + registry.put( + EMAIL_TEMPLATE_DIR_RELATIVE_REGISTRY_PATH + "/" + template.getName(), resource); + } + } + } catch (RegistryException e) { + throw new DeviceManagementException("Error occurred while setting up email templates", e); + } catch (FileNotFoundException e) { + throw new DeviceManagementException("Error occurred while writing template file contents as an " + + "input stream of a resource", e); + } catch (IOException e) { + throw new DeviceManagementException("Error occurred while serializing file contents to a string", e); + } + } + } + + private Element parseFile(File file) throws DeviceManagementException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder; + try { + builder = factory.newDocumentBuilder(); + Document doc = builder.parse(file); + return doc.getDocumentElement(); + } catch (ParserConfigurationException e) { + throw new DeviceManagementException("Error occurred while creating a document builder to parse file '" + + file.getName() + "'", e); + } catch (SAXException | IOException e) { + throw new DeviceManagementException("Error occurred while parsing file '" + file.getName() + "'", e); + } + } + private void setupDeviceManagementSchema(DataSourceConfig config) throws DeviceManagementException { DeviceManagementSchemaInitializer initializer = new DeviceManagementSchemaInitializer(config); log.info("Initializing device management repository database schema"); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java index 7538844755..e017ae5259 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java @@ -26,6 +26,7 @@ import org.wso2.carbon.device.mgt.common.license.mgt.LicenseManager; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager; import org.wso2.carbon.device.mgt.core.dto.DeviceType; +import org.wso2.carbon.device.mgt.core.email.EmailContext; import java.util.List; @@ -59,9 +60,9 @@ public interface DeviceManagementProviderService extends OperationManager { */ PaginationResult getAllDevices(PaginationRequest request) throws DeviceManagementException; - void sendEnrolmentInvitation(EmailMessageProperties config) throws DeviceManagementException; + void sendEnrolmentInvitation(EmailContext emailContext) throws DeviceManagementException; - void sendRegistrationEmail(EmailMessageProperties config) throws DeviceManagementException; + void sendRegistrationEmail(EmailContext emailContext) throws DeviceManagementException; FeatureManager getFeatureManager(String deviceType) throws DeviceManagementException; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index 80a1ae57d5..f9ba0b1098 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -30,24 +30,17 @@ import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; import org.wso2.carbon.device.mgt.core.DeviceManagementPluginRepository; import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; import org.wso2.carbon.device.mgt.core.config.email.EmailConfigurations; -import org.wso2.carbon.device.mgt.core.config.email.NotificationMessages; import org.wso2.carbon.device.mgt.core.dao.*; import org.wso2.carbon.device.mgt.core.dto.DeviceType; -import org.wso2.carbon.device.mgt.core.email.EmailConstants; +import org.wso2.carbon.device.mgt.core.email.*; import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder; import org.wso2.carbon.device.mgt.core.internal.DeviceManagementServiceComponent; import org.wso2.carbon.device.mgt.core.internal.EmailServiceDataHolder; import org.wso2.carbon.device.mgt.core.internal.PluginInitializationListener; import org.wso2.carbon.user.api.UserStoreException; -import java.io.IOException; -import java.net.URLDecoder; -import java.net.URLEncoder; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.*; public class DeviceManagementProviderServiceImpl implements DeviceManagementProviderService, PluginInitializationListener { @@ -56,11 +49,13 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv private DeviceTypeDAO deviceTypeDAO; private EnrollmentDAO enrollmentDAO; private DeviceManagementPluginRepository pluginRepository; + private EmailContentProvider contentProvider; private static Log log = LogFactory.getLog(DeviceManagementProviderServiceImpl.class); public DeviceManagementProviderServiceImpl() { this.pluginRepository = new DeviceManagementPluginRepository(); + this.contentProvider = EmailContentProviderFactory.getContentProvider(); initDataAccessObjects(); /* Registering a listener to retrieve events when some device management service plugin is installed after * the component is done getting initialized */ @@ -517,130 +512,53 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public void sendEnrolmentInvitation(EmailMessageProperties emailMessageProperties) - throws DeviceManagementException { - List notificationMessages = - DeviceConfigurationManager.getInstance().getNotificationMessagesConfig().getNotificationMessagesList(); - String messageHeader = ""; - String messageBody = ""; - String messageFooter1 = ""; - String messageFooter2 = ""; - String messageFooter3 = ""; - String url = ""; - String subject = ""; - - for (NotificationMessages notificationMessage : notificationMessages) { - if (org.wso2.carbon.device.mgt.core.DeviceManagementConstants.EmailNotifications.ENROL_NOTIFICATION_TYPE - .equals(notificationMessage.getType())) { - messageHeader = notificationMessage.getHeader(); - messageBody = notificationMessage.getBody(); - messageFooter1 = notificationMessage.getFooterLine1(); - messageFooter2 = notificationMessage.getFooterLine2(); - messageFooter3 = notificationMessage.getFooterLine3(); - url = notificationMessage.getUrl(); - subject = notificationMessage.getSubject(); - break; - } - } - - StringBuilder messageBuilder = new StringBuilder(); - + public void sendEnrolmentInvitation(EmailContext emailCtx) throws DeviceManagementException { + Map, Object>> params = new HashMap<>(); + EmailConfigurations emailConfig = + DeviceConfigurationManager.getInstance().getDeviceManagementConfig(). + getDeviceManagementConfigRepository().getEmailConfigurations(); + params.put(EmailConstants.FIRST_NAME, + new TypedValue, Object>(String.class, emailCtx.getProperty("first-name"))); + params.put(EmailConstants.DOWNLOAD_URL, + new TypedValue, Object>(String.class, + emailConfig.getlBHostPortPrefix() + emailConfig.getEnrollmentContextPath())); try { - - // Reading the download url from the cdm-config.xml file - EmailConfigurations emailConfig = - DeviceConfigurationManager.getInstance().getDeviceManagementConfig(). - getDeviceManagementConfigRepository().getEmailConfigurations(); - emailMessageProperties.setEnrolmentUrl(emailConfig.getlBHostPortPrefix() + - emailConfig.getEnrollmentContextPath()); - messageHeader = messageHeader.replaceAll("\\{" + EmailConstants.EnrolmentEmailConstants.FIRST_NAME + "\\}", - URLEncoder.encode(emailMessageProperties.getFirstName(), - EmailConstants.EnrolmentEmailConstants.ENCODED_SCHEME)); - messageBody = messageBody.trim() + System.getProperty("line.separator") + url.replaceAll("\\{" - + EmailConstants.EnrolmentEmailConstants.DOWNLOAD_URL + "\\}", - URLDecoder.decode(emailMessageProperties.getEnrolmentUrl(), - EmailConstants.EnrolmentEmailConstants.ENCODED_SCHEME)); - messageBuilder.append(messageHeader).append(System.getProperty("line.separator")) - .append(System.getProperty("line.separator")); - messageBuilder.append(messageBody); - messageBuilder.append(System.getProperty("line.separator")).append(System.getProperty("line.separator")); - messageBuilder.append(messageFooter1.trim()) - .append(System.getProperty("line.separator")).append(messageFooter2.trim()).append(System - .getProperty("line.separator")).append(messageFooter3.trim()); - } catch (IOException e) { - throw new DeviceManagementException("Error replacing tags in email template '" + - emailMessageProperties.getSubject() + "'", e); + EmailData data = contentProvider.getContent("user-enrollment", params); + EmailServiceDataHolder.getInstance().getEmailServiceProvider().sendEmail(emailCtx.getRecipients(), data); + } catch (ContentProcessingInterruptedException e) { + throw new DeviceManagementException("Error occurred while processing contents of the " + + "enrollment invitation", e); + } catch (EmailSendingFailedException e) { + throw new DeviceManagementException("Error occurred while sending enrollment invitation", e); } - emailMessageProperties.setMessageBody(messageBuilder.toString()); - emailMessageProperties.setSubject(subject); - EmailServiceDataHolder.getInstance().getEmailServiceProvider().sendEmail(emailMessageProperties); } @Override - public void sendRegistrationEmail(EmailMessageProperties emailMessageProperties) throws DeviceManagementException { - List notificationMessages = - DeviceConfigurationManager.getInstance().getNotificationMessagesConfig().getNotificationMessagesList(); - String messageHeader = ""; - String messageBody = ""; - String messageFooter1 = ""; - String messageFooter2 = ""; - String messageFooter3 = ""; - String url = ""; - String subject = ""; - - for (NotificationMessages notificationMessage : notificationMessages) { - if (org.wso2.carbon.device.mgt.core.DeviceManagementConstants.EmailNotifications. - USER_REGISTRATION_NOTIFICATION_TYPE.equals(notificationMessage.getType())) { - messageHeader = notificationMessage.getHeader(); - messageBody = notificationMessage.getBody(); - messageFooter1 = notificationMessage.getFooterLine1(); - messageFooter2 = notificationMessage.getFooterLine2(); - messageFooter3 = notificationMessage.getFooterLine3(); - url = notificationMessage.getUrl(); - subject = notificationMessage.getSubject(); - break; - } - } - StringBuilder messageBuilder = new StringBuilder(); + public void sendRegistrationEmail(EmailContext emailCtx) throws DeviceManagementException { + Map, Object>> params = new HashMap<>(); + EmailConfigurations emailConfig = + DeviceConfigurationManager.getInstance().getDeviceManagementConfig(). + getDeviceManagementConfigRepository().getEmailConfigurations(); + params.put(EmailConstants.FIRST_NAME, + new TypedValue, Object>(String.class, emailCtx.getProperty("first-name"))); + params.put(EmailConstants.DOWNLOAD_URL, + new TypedValue, Object>(String.class, + emailConfig.getlBHostPortPrefix() + emailConfig.getEnrollmentContextPath())); + params.put(EmailConstants.USERNAME, + new TypedValue, Object>(String.class, emailCtx.getProperty("username"))); + params.put(EmailConstants.PASSWORD, + new TypedValue, Object>(String.class, emailCtx.getProperty("password"))); + params.put(EmailConstants.DOMAIN, + new TypedValue, Object>(String.class, emailCtx.getProperty("domain"))); try { - // Reading the download url from the cdm-config.xml file - EmailConfigurations emailConfig = - DeviceConfigurationManager.getInstance().getDeviceManagementConfig(). - getDeviceManagementConfigRepository().getEmailConfigurations(); - emailMessageProperties.setEnrolmentUrl(emailConfig.getlBHostPortPrefix() + - emailConfig.getEnrollmentContextPath()); - messageHeader = messageHeader.replaceAll("\\{" + EmailConstants.EnrolmentEmailConstants.FIRST_NAME + "\\}", - URLEncoder.encode(emailMessageProperties.getFirstName(), - EmailConstants.EnrolmentEmailConstants.ENCODED_SCHEME)); - messageBody = messageBody.trim().replaceAll("\\{" + EmailConstants.EnrolmentEmailConstants - .USERNAME - + "\\}", - URLEncoder.encode(emailMessageProperties.getUserName(), EmailConstants.EnrolmentEmailConstants - .ENCODED_SCHEME)); - messageBody = messageBody.trim().replaceAll("\\{" + EmailConstants.EnrolmentEmailConstants.DOMAIN - + "\\}", - URLEncoder.encode(emailMessageProperties.getDomainName(), EmailConstants.EnrolmentEmailConstants - .ENCODED_SCHEME)); - messageBody = messageBody.replaceAll("\\{" + EmailConstants.EnrolmentEmailConstants.PASSWORD + "\\}", - URLEncoder.encode(emailMessageProperties.getPassword(), EmailConstants.EnrolmentEmailConstants - .ENCODED_SCHEME)); - messageBody = messageBody + System.getProperty("line.separator") + url.replaceAll("\\{" - + EmailConstants.EnrolmentEmailConstants.DOWNLOAD_URL + "\\}", - URLDecoder.decode(emailMessageProperties.getEnrolmentUrl(), - EmailConstants.EnrolmentEmailConstants.ENCODED_SCHEME)); - messageBuilder.append(messageHeader).append(System.getProperty("line.separator")); - messageBuilder.append(messageBody).append(System.getProperty("line.separator")).append( - messageFooter1.trim()); - messageBuilder.append(System.getProperty("line.separator")).append(messageFooter2.trim()); - messageBuilder.append(System.getProperty("line.separator")).append(messageFooter3.trim()); - - } catch (IOException e) { - throw new DeviceManagementException("Error replacing tags in email template '" + - emailMessageProperties.getSubject() + "'", e); + EmailData data = contentProvider.getContent("user-registration", params); + EmailServiceDataHolder.getInstance().getEmailServiceProvider().sendEmail(emailCtx.getRecipients(), data); + } catch (ContentProcessingInterruptedException e) { + throw new DeviceManagementException("Error occurred while processing contents of the " + + "enrollment invitation", e); + } catch (EmailSendingFailedException e) { + throw new DeviceManagementException("Error occurred while sending user registration notification", e); } - emailMessageProperties.setMessageBody(messageBuilder.toString()); - emailMessageProperties.setSubject(subject); - EmailServiceDataHolder.getInstance().getEmailServiceProvider().sendEmail(emailMessageProperties); } @Override diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/EmailService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/EmailService.java index 2fb995ecc8..c1d0d2da2a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/EmailService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/EmailService.java @@ -17,11 +17,13 @@ */ package org.wso2.carbon.device.mgt.core.service; -import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.common.EmailMessageProperties; +import org.wso2.carbon.device.mgt.core.email.EmailData; +import org.wso2.carbon.device.mgt.core.email.EmailSendingFailedException; + +import java.util.Set; public interface EmailService { - public void sendEmail(EmailMessageProperties emailMessageProperties) throws DeviceManagementException; + void sendEmail(Set recipients, EmailData emailData) throws EmailSendingFailedException; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/EmailServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/EmailServiceImpl.java index 807c511659..9bc29340b6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/EmailServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/EmailServiceImpl.java @@ -18,14 +18,17 @@ package org.wso2.carbon.device.mgt.core.service; -import org.wso2.carbon.device.mgt.common.DeviceManagementException; -import org.wso2.carbon.device.mgt.common.EmailMessageProperties; +import org.wso2.carbon.device.mgt.core.email.EmailData; +import org.wso2.carbon.device.mgt.core.email.EmailSendingFailedException; import org.wso2.carbon.device.mgt.core.internal.EmailServiceDataHolder; -public class EmailServiceImpl implements EmailService{ +import java.util.Set; + +public class EmailServiceImpl implements EmailService { @Override - public void sendEmail(EmailMessageProperties emailMessageProperties) throws DeviceManagementException { - EmailServiceDataHolder.getInstance().getEmailServiceProvider().sendEmail(emailMessageProperties); + public void sendEmail(Set recipients, EmailData emailData) throws EmailSendingFailedException { + EmailServiceDataHolder.getInstance().getEmailServiceProvider().sendEmail(recipients, emailData); } + } diff --git a/pom.xml b/pom.xml index 096e604193..0c4b67a589 100644 --- a/pom.xml +++ b/pom.xml @@ -1278,7 +1278,16 @@ commons-httpclient ${commons.httpclient.version} - + + org.apache.velocity + velocity + ${velocity.version} + + + commons-io.wso2 + commons-io + ${commons-io.version} + @@ -1581,7 +1590,8 @@ 1.5.6.wso2v1 4.2.3.wso2v1 3.1.0.wso2v2 - + 1.7 + 2.4.0.wso2v1