Expand my Community achievements bar.

SOLVED

Custom error messages?

Avatar

Level 1

First, please forgive my ignorance of AEM, I'm just getting into it and starting to learn how everything works.

Is there a way to provide a custom error message when submitting an AEM Form and invoking a Forms workflow process that uses a sendWithDocument step?

We want to provide a meaningful error message to our users when an error occurs in the case when our SMTP server is down, or the user provided a well-formed email address, that might not exist.  I can see in CRXDE Lite where there is an error.jsp in /libs/fd/af/components/guidefield, is there where I can add my custom error message when exceptions occur?

Also, I'm having difficulty getting the actual form submission process to error out.. I've tried everything from providing an invalid SMTP server, to using a script block in the AEM Workbench .. any input on how to test custom errors would be greatly appreciated as well.  Thanks!

1 Accepted Solution

Avatar

Correct answer by
Level 7

There is a way to pass parameters from a custom submission handler off to the Thankyou Page. They appear in the sling request object when the thankyou page is invoked from the custom submission handler. However, I had some issues with this method a while ago where only some parameters would exist even though I explicitly put them in the sling request object during the custom submission handler. They would get stripped out and we didnt have the Adobe source to fix the bug.

I came up with a different method which is a bit hacky - I passed the errors back to the thankyou page via the formData XML object that is passed back from the LC process into the submission handler after the call. I then looked for the saved formData in the thankyou page, and parsed that to grab the information (ID, errors, etc) that I wanted to show to the user.

It went something like this:

  • I created a custom submission handler. The first half is from "lcprocess" guidesubmitype and the second half is from the Forms Portal guidesubmittype. There should be examples in the /libs/af area of the JCR
  • I made a call to the lcprocess and grabbed the return object called the thankyou page using a GuideSubmitServlet.setForwardPath call instead of a GuideSubmitServlet.setRedirectParameters call (not much documentation on these). Note that this will submit data to forms portal (which is what i wanted) so I could extract the data in the thankyou page.
  • The LC process injects any data it likes into the formData XML object (errors, success messages, etc)
  • Then in the thankyou page, I parsed the formData XML object and extracted the data I wanted from that and displayed it to the user.

This example if from AEM Forms 6.1, so there may be a better way to do this now.

Example lcprocess guidesubmittype JSP

String processName = properties.get("processName", "");

GuideLCServiceConnector guideLCServiceConnector = sling.getService(GuideLCServiceConnector.class);

if (guideLCServiceConnector == null) {

log.error("There is no Forms and Document Workflow associated with this Adaptive Form.");

throw new GuideException("There is no Forms and Document Workflow associated with this Adaptive Form.");

}

if (processName != null && processName.length() > 0) {

String dataXmlParamterName = guideLCServiceConnector.getXmlParameterName();

String fileListParameterName = guideLCServiceConnector.getFileListParameterName();

Map <String,Object> inputParams = new HashMap <String,Object> ();

Document dataXml = null;

if (slingRequest.getParameter("jcr:data") != null) {

dataXml = new Document(slingRequest.getRequestParameter("jcr:data").get());

}

inputParams.put(dataXmlParamterName, dataXml);

List < Document > fileAttachments = new ArrayList < Document > ();

RequestParameterMap requestParameterMap = slingRequest.getRequestParameterMap();

for (Map.Entry < String, RequestParameter[] > param: requestParameterMap.entrySet()) {

RequestParameter rpm = param.getValue()[0];

if (!rpm.isFormField()) {

fileAttachments.add(new Document(rpm.get()));

}

}

inputParams.put(fileListParameterName, fileAttachments);

//Get the runmodes for some stuff

String runModes = sling.getService(SlingSettingsService.class).getRunModes().toString();

inputParams.put("runModes", runModes);

Map outputParams = guideLCServiceConnector.invokeProcess(processName, inputParams);

if (outputParams != null) {

Map < String,

String > redirectParameters = GuideSubmitServlet.getRedirectParameters(slingRequest);

if (redirectParameters == null) {

redirectParameters = new HashMap < String,

String > ();

}

String newDataXml = null;

Iterator entries = outputParams.entrySet().iterator();

while (entries.hasNext()) {

Map.Entry current = (Map.Entry)entries.next();

Object value = current.getValue();

//This always fails - there are no return types in LC that this passes with

//if(value.getClass().isPrimitive())

//LC Process should return a new version of 'formData' (Serialized XML) property

slingRequest.setAttribute((String)current.getKey(), String.valueOf(value));

//log.info("Got "+(String)current.getKey() + " value: " + String.valueOf(value));

}

//GuideSubmitServlet.setRedirectParameters(slingRequest,redirectParameters);

//Taken from Forms Portal Submit Action

String guidePath = resource.getPath();

String path = guidePath + ".json";

String draftID = request.getParameter("draftID");

String profile = request.getParameter("profile");

if (draftID != null)

slingRequest.setAttribute("draftID", draftID);

slingRequest.setAttribute("func", "saveSubmittedGuide");

slingRequest.setAttribute("profile", profile);

slingRequest.setAttribute("formPath", guidePath);

slingRequest.setAttribute("formType", "af");

slingRequest.setAttribute("fpAllowedMetadata", "profile, formPath, formType");

GuideSubmitServlet.setForwardPath(slingRequest, path, "fp.draft", null);

}

} else {

log.error("There is no Forms and Document Workflow associated with this Adaptive Form.");

throw new GuideException("There is no Forms and Document Workflow associated with this Adaptive Form.");

}

This is an excerpt from the thankyoupage component (I wanted to display the value of auditNumber that was generated in the LC process)

String adaptiveFormPath = slingRequest.getParameter("path");

    if(adaptiveFormPath != null) {

        adaptiveFormPath = adaptiveFormPath.replace(".html", "");

    }

log.info(adaptiveFormPath);

Resource res= resourceResolver.getResource(adaptiveFormPath);

if(res != null) {

    Node node = res.adaptTo(Node.class);

    String dataXMLPath = node.getProperty("userdataID").getValue().getString();

     res = resourceResolver.getResource(dataXMLPath);

     node = res.adaptTo(Node.class);

     String dataXML = node.getProperty("jcr:data").getValue().getString();

     javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();

     javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();

    org.w3c.dom.Document dataDoc = db.parse(new ByteArrayInputStream(dataXML.getBytes("UTF-8")));

     dataDoc.getDocumentElement().normalize();

     log.info("Root element: " + dataDoc.getDocumentElement().getNodeName());

     auditNumber = dataDoc.getElementsByTagName("AuditNumber").item(0).getTextContent();

}

<% <p>Please note down your Audit Number for future reference: <strong><%=auditNumber%></strong></p> %>

View solution in original post

2 Replies

Avatar

Correct answer by
Level 7

There is a way to pass parameters from a custom submission handler off to the Thankyou Page. They appear in the sling request object when the thankyou page is invoked from the custom submission handler. However, I had some issues with this method a while ago where only some parameters would exist even though I explicitly put them in the sling request object during the custom submission handler. They would get stripped out and we didnt have the Adobe source to fix the bug.

I came up with a different method which is a bit hacky - I passed the errors back to the thankyou page via the formData XML object that is passed back from the LC process into the submission handler after the call. I then looked for the saved formData in the thankyou page, and parsed that to grab the information (ID, errors, etc) that I wanted to show to the user.

It went something like this:

  • I created a custom submission handler. The first half is from "lcprocess" guidesubmitype and the second half is from the Forms Portal guidesubmittype. There should be examples in the /libs/af area of the JCR
  • I made a call to the lcprocess and grabbed the return object called the thankyou page using a GuideSubmitServlet.setForwardPath call instead of a GuideSubmitServlet.setRedirectParameters call (not much documentation on these). Note that this will submit data to forms portal (which is what i wanted) so I could extract the data in the thankyou page.
  • The LC process injects any data it likes into the formData XML object (errors, success messages, etc)
  • Then in the thankyou page, I parsed the formData XML object and extracted the data I wanted from that and displayed it to the user.

This example if from AEM Forms 6.1, so there may be a better way to do this now.

Example lcprocess guidesubmittype JSP

String processName = properties.get("processName", "");

GuideLCServiceConnector guideLCServiceConnector = sling.getService(GuideLCServiceConnector.class);

if (guideLCServiceConnector == null) {

log.error("There is no Forms and Document Workflow associated with this Adaptive Form.");

throw new GuideException("There is no Forms and Document Workflow associated with this Adaptive Form.");

}

if (processName != null && processName.length() > 0) {

String dataXmlParamterName = guideLCServiceConnector.getXmlParameterName();

String fileListParameterName = guideLCServiceConnector.getFileListParameterName();

Map <String,Object> inputParams = new HashMap <String,Object> ();

Document dataXml = null;

if (slingRequest.getParameter("jcr:data") != null) {

dataXml = new Document(slingRequest.getRequestParameter("jcr:data").get());

}

inputParams.put(dataXmlParamterName, dataXml);

List < Document > fileAttachments = new ArrayList < Document > ();

RequestParameterMap requestParameterMap = slingRequest.getRequestParameterMap();

for (Map.Entry < String, RequestParameter[] > param: requestParameterMap.entrySet()) {

RequestParameter rpm = param.getValue()[0];

if (!rpm.isFormField()) {

fileAttachments.add(new Document(rpm.get()));

}

}

inputParams.put(fileListParameterName, fileAttachments);

//Get the runmodes for some stuff

String runModes = sling.getService(SlingSettingsService.class).getRunModes().toString();

inputParams.put("runModes", runModes);

Map outputParams = guideLCServiceConnector.invokeProcess(processName, inputParams);

if (outputParams != null) {

Map < String,

String > redirectParameters = GuideSubmitServlet.getRedirectParameters(slingRequest);

if (redirectParameters == null) {

redirectParameters = new HashMap < String,

String > ();

}

String newDataXml = null;

Iterator entries = outputParams.entrySet().iterator();

while (entries.hasNext()) {

Map.Entry current = (Map.Entry)entries.next();

Object value = current.getValue();

//This always fails - there are no return types in LC that this passes with

//if(value.getClass().isPrimitive())

//LC Process should return a new version of 'formData' (Serialized XML) property

slingRequest.setAttribute((String)current.getKey(), String.valueOf(value));

//log.info("Got "+(String)current.getKey() + " value: " + String.valueOf(value));

}

//GuideSubmitServlet.setRedirectParameters(slingRequest,redirectParameters);

//Taken from Forms Portal Submit Action

String guidePath = resource.getPath();

String path = guidePath + ".json";

String draftID = request.getParameter("draftID");

String profile = request.getParameter("profile");

if (draftID != null)

slingRequest.setAttribute("draftID", draftID);

slingRequest.setAttribute("func", "saveSubmittedGuide");

slingRequest.setAttribute("profile", profile);

slingRequest.setAttribute("formPath", guidePath);

slingRequest.setAttribute("formType", "af");

slingRequest.setAttribute("fpAllowedMetadata", "profile, formPath, formType");

GuideSubmitServlet.setForwardPath(slingRequest, path, "fp.draft", null);

}

} else {

log.error("There is no Forms and Document Workflow associated with this Adaptive Form.");

throw new GuideException("There is no Forms and Document Workflow associated with this Adaptive Form.");

}

This is an excerpt from the thankyoupage component (I wanted to display the value of auditNumber that was generated in the LC process)

String adaptiveFormPath = slingRequest.getParameter("path");

    if(adaptiveFormPath != null) {

        adaptiveFormPath = adaptiveFormPath.replace(".html", "");

    }

log.info(adaptiveFormPath);

Resource res= resourceResolver.getResource(adaptiveFormPath);

if(res != null) {

    Node node = res.adaptTo(Node.class);

    String dataXMLPath = node.getProperty("userdataID").getValue().getString();

     res = resourceResolver.getResource(dataXMLPath);

     node = res.adaptTo(Node.class);

     String dataXML = node.getProperty("jcr:data").getValue().getString();

     javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();

     javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();

    org.w3c.dom.Document dataDoc = db.parse(new ByteArrayInputStream(dataXML.getBytes("UTF-8")));

     dataDoc.getDocumentElement().normalize();

     log.info("Root element: " + dataDoc.getDocumentElement().getNodeName());

     auditNumber = dataDoc.getElementsByTagName("AuditNumber").item(0).getTextContent();

}

<% <p>Please note down your Audit Number for future reference: <strong><%=auditNumber%></strong></p> %>

Avatar

Level 1

Hey Devin,

Thanks for the reply!  Your time is greatly appreciated

I'll dig into this today and see what I can come up with. I've been looking at https://helpx.adobe.com/aem-forms/6/custom-submit-action-form.html for a guide creating custom submit processes.  I'm hoping I can take what you provided and adapt it to what I need.  For the most part, everything you said makes good sense - it's certainly a lot better than any stuff I've found as far as Adobe documentation, so again - thank you!  Have a good one!