RE: LR7 Custom email notification in Web Form portlet

thumbnail
Orestes Febles, modified 7 Years ago. New Member Posts: 3 Join Date: 9/28/09 Recent Posts
Hi guys I need to customize email notification located in Web Form portlet. This is the template
Template

I found examples for overwrite jsp in portlets using fragments but, the code I need to change is in a .soy file inside the portlet resources . How can I customize this?
Thanks
thumbnail
David H Nebinger, modified 7 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
You cannot override a non-jsp file in a fragment bundle.

You can, however, create your own DDLFormEmailNotificationSender and register with a higher service ranking. That file has the reference to the form_entry_add_body.soy file, so you can change to point at your own file with your override that is part of your module.

But, since the DDLFormEmailNotificationSender is in a private package, you will likely need to use my blog https://web.liferay.com/web/user.26526/blog/-/blogs/fixing-module-package-access-modifiers to export the com.liferay.dynamic.data.lists.form.web.internal.notification package.
thumbnail
Linda van der Pal, modified 7 Years ago. New Member Posts: 21 Join Date: 2/20/12 Recent Posts
Did you ever solve this problem? I'm trying to do the same, but when I override the service as per David's blog I get the following exception:

09:21:08,351 ERROR [Refresh Thread: Equinox Container: f0ced4ed-ab38-0018-12ea-b6d5253daf22][com_liferay_dynamic_data_lists_form_web:97] [com.liferay.dynamic.data.lists.form.web.internal.notification.DDLFormEmailNotificationSender] Cannot register Component
org.osgi.service.component.ComponentException: The component name 'com.liferay.dynamic.data.lists.form.web.internal.notification.DDLFormEmailNotificationSender' has already been registered by Bundle 144 (com.liferay.dynamic.data.lists.form.web) as Component of Class com.liferay.dynamic.data.lists.form.web.internal.notification.DDLFormEmailNotificationSender

I have a feeling that it might have to do with the fact that DDLFormEmailNotificationSender is a singleton, but can't find confirmation of that.

I've tried setting the name of my CustomDDLFormEmailNotificationSender component explicitly, but that doesn't help either.
thumbnail
David H Nebinger, modified 7 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
You cannot have the same package/class name as a Liferay component. OSGi will not allow that duplicate.

To replace components, you need to implement the necessary service but use a higher service ranking so OSGi will want to use your service vs the original.
thumbnail
Linda van der Pal, modified 7 Years ago. New Member Posts: 21 Join Date: 2/20/12 Recent Posts
Thanks for the quick reply!

Hmm, I did use the same package name, but changing that didn't solve the problem. And my class name was already different (I had prefixed the original name with the word Custom).

package finalist.form.mailer;

import com.liferay.dynamic.data.lists.form.web.internal.notification.DDLFormEmailNotificationSender;
import com.liferay.dynamic.data.lists.model.DDLRecord;
import com.liferay.dynamic.data.lists.model.DDLRecordSet;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.template.Template;
import com.liferay.portal.kernel.template.TemplateConstants;
import com.liferay.portal.kernel.template.TemplateManagerUtil;
import com.liferay.portal.kernel.util.Portal;

import java.lang.reflect.Field;

import javax.portlet.PortletRequest;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

@Component(immediate = true, 
		service = DDLFormEmailNotificationSender.class,
		name = "CustomDDLFormEmailNotificationSender",
		property = {"service.ranking:Integer=100"})
public class CustomDDLFormEmailNotificationSender extends DDLFormEmailNotificationSender {
	
	private static final String _TEMPLATE_PATH =
			"/META-INF/resources/custom-mailtemplate.ftl";
	
	protected Template createTemplate(
			PortletRequest portletRequest, DDLRecordSet recordSet,
			DDLRecord record)
		throws PortalException {

		Template template = TemplateManagerUtil.getTemplate(
			TemplateConstants.LANG_TYPE_FTL,
			getTemplateResource(_TEMPLATE_PATH), false);

		populateParameters(template, portletRequest, recordSet, record);

		return template;
	}
	
	@Reference(unbind = "-")
	protected void setPortal(Portal portal) {
		update("_portal", portal);
	}
	
	protected void update(final String fieldName, final Object value) {
		try {
			Field f = getClass().getSuperclass().getDeclaredField(fieldName);

			f.setAccessible(true);

			f.set(this, value);
		} catch (IllegalAccessException e) {
			LOG.error("Error updating " + fieldName, e);
		} catch (NoSuchFieldException e) {
			LOG.error("Error updating " + fieldName, e);
		}
	}

	private static final Log LOG = LogFactoryUtil.getLog(CustomDDLFormEmailNotificationSender.class);
}


Bundle-Name: finalist-form-mailer
Bundle-SymbolicName: finalist.form.mailer
Bundle-Version: 1.0.0
Fragment-Host: com.liferay.dynamic.data.lists.form.web;bundle-version="[1.0.0, 2.0.0]"
Export-Package: com.liferay.dynamic.data.lists.form.web.constants,\
	com.liferay.dynamic.data.lists.form.web.internal.notification,\
	finalist.form.mailer;
Liferay-Releng-Module-Group-Description:
Liferay-Releng-Module-Group-Title: Dynamic Data Lists
-dsannotations-options: inherit
thumbnail
David H Nebinger, modified 7 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
Yeah, no you can't do this.

First the service declaration must match; using your own service means that only components that @Reference it are going to get it injected.

Second, the fragment bundle can introduce new classes, but it doesn't have a startable context of its own. Normally you'd have to put your component overrides into a separate bundle from the fragment bundle so they start and register correctly.
thumbnail
Dipti Ranparia, modified 7 Years ago. New Member Posts: 9 Join Date: 10/16/12 Recent Posts
Hi Linda,

Are you able to make this working?

I am not able to ovevrride DDLFormEmailNotificationSender class using approach mentioned by David in the blog.
thumbnail
Linda van der Pal, modified 7 Years ago. New Member Posts: 21 Join Date: 2/20/12 Recent Posts
No, I didn't get it working. We chose a different route by creating an ugly hack: we created a storage provider that didn't store the data, but sent an email instead.
thumbnail
David H Nebinger, modified 7 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
Dipti Ranparia:
I am not able to ovevrride DDLFormEmailNotificationSender class using approach mentioned by David in the blog.


You should end up with two bundles:

  • A fragment bundle. This bundle basically just has a bnd.bnd file, mostly copied from the original, but with the additional Export-Package directive addition.
  • An implementation bundle. This bundle has your class which extends the original but returns a different soy template which is also in this bundle.


If you tried this, which part isn't working?
thumbnail
Dipti Ranparia, modified 7 Years ago. New Member Posts: 9 Join Date: 10/16/12 Recent Posts
Thanks for the reply David .

My goal is to add file selction in web-form and attach that file with email notification. I have already created a custom form field to support file selection but getting error for file attacment customization.

I have 2 bundles;
1. Fragment of dynamc-data-list-form-web with and one jsp file (display/view.jsp) to support multipart data and bnd.bnd.
bnd.bnd file detail;
Bundle-Name: dynamc-data-list-form-web-fragment
Bundle-SymbolicName: dynamc.data.list.form.web.fragment
Bundle-Version: 1.1.17
Fragment-Host: com.liferay.dynamic.data.lists.form.web;bundle-version="[1.0.0,2.0.0)"
Export-Package: \
	com.liferay.dynamic.data.lists.form.web.constants,\
	com.liferay.dynamic.data.lists.form.web.internal.notification\
Liferay-JS-Config: /META-INF/resources/admin/js/config.js
Liferay-Releng-Module-Group-Description:
Liferay-Releng-Module-Group-Title: Dynamic Data Lists
Web-ContextPath: /dynamic-data-lists-form-web
-dsannotations-options: inherit

2. Module activator class with custom DDLFormEmailNotificationSender class as below
/**
 * 
 */
package custom.web.form.portlet.notification;

import java.lang.reflect.Field;

import javax.portlet.PortletRequest;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import com.liferay.dynamic.data.lists.form.web.notification.DDLFormEmailNotificationSender;
import com.liferay.dynamic.data.lists.model.DDLRecord;
import com.liferay.dynamic.data.mapping.form.field.type.DDMFormFieldTypeServicesTracker;
import com.liferay.mail.kernel.service.MailService;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.service.UserLocalService;
import com.liferay.portal.kernel.util.Portal;

/**
 * Override this class to add attachment to email
 * 
 * @author diptivaghasia
 *
 */
@Component(immediate=true,
property={"service.ranking:Integer=100"},
service=DDLFormEmailNotificationSender.class
)

public class CustomDDLFormEmailNotificationSender extends  DDLFormEmailNotificationSender{

	@Override
	public void sendEmailNotification(PortletRequest portletRequest, DDLRecord record) {
		// TODO Auto-generated method stub		
		_log.info("sendEmailNotification");
		super.sendEmailNotification(portletRequest, record);
	}
	
	@Reference(unbind = "-")
	protected void setDDMFormFieldTypeServicesTracker(
		DDMFormFieldTypeServicesTracker ddmFormFieldTypeServicesTracker) {
		update("_ddmFormFieldTypeServicesTracker",ddmFormFieldTypeServicesTracker);
		
	}

	@Reference(unbind = "-")
	protected void setMailService(MailService mailService) {
		update("_mailService", mailService);
	}

	@Reference(unbind = "-")
	protected void setUserLocalService(UserLocalService userLocalService) {		
		update("_userLocalService", userLocalService);
	}
	@Reference(unbind = "-")
	protected void setPortal(Portal portal) {
		update("_portal", portal);
	}
	
	protected void update(final String fieldName, final Object value) {
		try {
			Field f = getClass().getSuperclass().getDeclaredField(fieldName);

			f.setAccessible(true);

			f.set(this, value);
		} catch (IllegalAccessException e) {
			_log.error("Error updating " + fieldName, e);
		} catch (NoSuchFieldException e) {
			_log.error("Error updating " + fieldName, e);
		}
	}

	private static final Log _log = LogFactoryUtil.getLog(CustomDDLFormEmailNotificationSender.class);
	
}


problem with this class is i can not find com.liferay.dynamic.data.lists.form.web.internal.notification package to import and i think this is the problem. because when i deploy this package i am getting DDLFormEmailNotificationSender NoClassDefFoundError error.

This is my gradle file of the custom bundle i have a created for the custom DDLFormEmailNotificationSender.
dependencies {
compileOnly group: "org.osgi", name: "org.osgi.core", version: "6.0.0"
compile group: "org.osgi", name:"org.osgi.service.component.annotations", version:"1.3.0"
compile group: "com.liferay", name:"com.liferay.dynamic.data.lists.api", version: "1.0.0"
 compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1"
compileOnly group: "javax.portlet", name: "portlet-api", version: "2.0"
 compile group: "com.liferay.portal", name:"com.liferay.portal.impl", version:"1.0.1"
 compile group: "com.liferay.portal", name:"com.liferay.portal.kernel", version:"1.0.3"
  compile group: "com.liferay", name: "com.liferay.dynamic.data.lists.form.web", version:"1.0.3"
compile group: "com.liferay", name:"com.liferay.dynamic.data.mapping.form.field.type", version:"2.0.0"
}


Can you please tell me what is wrong with my code?

Thanks for the help.
thumbnail
David H Nebinger, modified 7 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
Dipti Ranparia:
problem with this class is i can not find com.liferay.dynamic.data.lists.form.web.internal.notification package to import and i think this is the problem. because when i deploy this package i am getting DDLFormEmailNotificationSender NoClassDefFoundError error.


Your class doesn't reference com.liferay.dynamic.data.lists.form.web.internal.notification.DDLFormEmailNotificationSender, it is extending com.liferay.dynamic.data.lists.form.web.notification.DDLFormEmailNotificationSender which doesn't exist in later versions of the com.liferay.dynamic.data.lists.form.web bundle.

I think you originally were extending from one of the older versions of the bundle that had that c.l.d.d.l.f.web.notification package, but the newer versions do not have that legacy package anymore.
thumbnail
Amos Fong, modified 7 Years ago. New Member Posts: 9 Join Date: 10/16/12 Recent Posts
Thanks!!

I am using liferay 7 GA5 CE.

I have referenced latest version com.liferay.dynamic.data.lists.form.web and this error is gone, but still it's executing original code of DDLFormEmailNotificationSender class.
thumbnail
David H Nebinger, modified 7 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
Do you know if it is executing both, or just the old one?
thumbnail
Dipti Ranparia, modified 7 Years ago. New Member Posts: 9 Join Date: 10/16/12 Recent Posts
David H Nebinger:
Do you know if it is executing both, or just the old one?

Just older one is being executing.
thumbnail
David H Nebinger, modified 7 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
Drop into gogo and do a diag on your bundle.

Also try the scr:list and verify that all services are active.
Milind Jain, modified 7 Years ago. Junior Member Posts: 28 Join Date: 12/29/17 Recent Posts
Hello,

I am also facing same. Have you resolved.
Please share. Thanks in advance.
thumbnail
Dipti Ranparia, modified 7 Years ago. New Member Posts: 9 Join Date: 10/16/12 Recent Posts
Milind Jain:
Hello, I am also facing same. Have you resolved. Please share. Thanks in advance.

 

 

No I could not solve this way..

 

 

thumbnail
Harish Kumar, modified 7 Years ago. Expert Posts: 483 Join Date: 7/31/10 Recent Posts
Dipti Ranparia:
Milind Jain:
Hello, I am also facing same. Have you resolved. Please share. Thanks in advance.

 

 

No I could not solve this way..

 

 

 

Hi Dipti,

 

We implemented the same customization - adding file upload capability to web form and sending the same in email as attachment.

We did follow the official documentation to achieve this - https://dev.liferay.com/es/develop/tutorials/-/knowledge_base/7-0/creating-form-field-types

Did you already tried the steps mentioned in the official documentation?

Following are the steps - 

1. Implement DDMFORMFIELDTYPE Component to create new field type

2. Create Fragment for com.liferay.dynamic.data.lists.form.web to update view.jsp to add enctype="multipart/form-data" capability to form

3. Overriding Action Command to provide your own customization - (https://dev.liferay.com/es/develop/tutorials/-/knowledge_base/7-0/overriding-mvc-commands)

@Component(immediate = true, property = {"javax.portlet.name=" + DDLFormPortletKeys.DYNAMIC_DATA_LISTS_FORM,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"mvc.command.name=addRecord",<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"service.ranking:Integer=100"}, service = MVCActionCommand.class)

 

Hope this helps!!

 

Regards,

Harish

 

 

 

 

David Weitzel, modified 7 Years ago. Junior Member Posts: 65 Join Date: 10/7/15 Recent Posts

Has anyone successfully written these bundles to enable us to overwrite the default soy template for Forms application?

We are struggling and it would be nice if there was a version we could adopt.

I am amazed this still isn't in the core product capability, my content administrators are waiting on development to enable changing the styles in the email...

We have the build working but not getting deployed now on DXP 7.0

thumbnail
Eric D, modified 6 Years ago. Junior Member Posts: 59 Join Date: 3/25/16 Recent Posts
Has anyone successfully written these bundles to enable us to overwrite the default soy template for Forms application?
Shubhankit Roy, modified 5 Years ago. New Member Posts: 8 Join Date: 4/27/15 Recent Posts
Yes, we have implemeneted this functionality both in DXP 7.0 and DXP 7.2
In 7.2, this is what we did to achieve it:
1. Created a bundle to add a custom 'email template' field in the form settings. For this, we override the
DDMFormInstanceSettings.java
interface and added our custom form setting. This was done to make the template text configurable on per form basis. If this is not your requirement, and you just want to always use a fixed custom email template, then creating this module can be skipped altogether. Note that this module needs to go to /osgi/marketplace/override folder as we are making changes to what is provided by its related lpkg file. Check https://portal.liferay.dev/docs/7-2/customization/-/knowledge_base/c/overriding-lpkg-files
2. Secondly, we created a hook to create override Liferay's
DDMFormEmailNotificationSender.java
with our own custom class and registered it with a higher service ranking. Within this module we also kept a reference to the form_entry_add_body.soy template but didn't make any changes to it because we created our own form setting for custom email template per form. So we wrote our own soy file to fetch the email template from form setting (if its configured) and added it the soy file on-the-fly. Again, if you want a fixed custom template always, you don't need to create this extra soy file, and just modify the
form_entry_add_body.soy
as per your need.

3. Finally, but most importantly, the
DDMFormEmailNotificationSender.java
resides in a private package:
com.liferay.dynamic.data.mapping.internal.notification
, therefore to be able to override it with our custom implementation, we needed it be exposed/available to be overridden. To achieve this, we simply created a fragment module to export that package via bnd :
Export-Package: com.liferay.dynamic.data.mapping.internal.notification
And that's it!
Hope you'll be able to achieve this in a similar way in 7.2/7.0 keeping in mind the names of the related classes and the packages in which they reside.
thumbnail
mehdi tilab, modified 5 Years ago. New Member Posts: 4 Join Date: 5/20/20 Recent Posts
Hi Shubhankit ,
Can you share your code?