In this article, I will be addressing 2 issues: how to efficiently handle form submission map data in Java and how the AdapterFactory get implemented in Adobe CQ (AEM).

How to efficiently handle form submission map data in Java

  1. You need 1 servlet, 1 service, and 2 classes: FormSubmissionHandlerServlet, FormSubmissionHandlerService, MyCustomClass, and MyCustomClassAdaptFactory
  2. Sameple codes of FormSubmissionHandlerServlet
    package ...

    // developer comments...
    // all the necessary imports

    import ...

    @SlingServlet(paths = "/apps/mycompany/forms", metatype = false)
    @Properties({ @Property(name = "service.pid", value = "mycompany.forms", propertyPrivate = false), @Property(name = "service.description", value = "Handles Form Submission", propertyPrivate = false), @Property(name = "service.vendor", value = "My Company", propertyPrivate = false) })

    public class FormSubmissionHandlerServlet extends SlingAllMethodsServlet { private static final Logger LOGGER = LoggerFactory.getLogger(FormProcessorServlet.class); private static final FormSubmissionHandlerService formSubmissionHandler = new FormSubmissionHandler();
    // some more local variables here... @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException { handleRequestData(request, response); } @Override protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException { handleRequestData(request, response); } private void handleRequestData(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException { //grab form type so we can call correct form process String formType = request.getParameter(params.FORM_FORMTYPE_FIELDNAME);
    MyCustomClass myCustomObj = request.adaptTo(MyCustomClass.class);
    formSubmissionHandler.processFormSubmission(myCustomObj, response); } }
  3. Sample codes for FormSubmissionHandlerService
    package ...
    
    // developer comments
    // all necessary imports

    import ...

    @Component(label = "Form Submission Service", immediate = true, metatype = false)
    @Properties({
    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Form Submission Service"),
    @Property(name = Constants.SERVICE_VENDOR, value = "My Companyh")
    })
    @Service(value = {FormSubmissionService.class })

    public class FormSubmissionHandlerService {

    private static final String RESPONSE_CTYPE = "application/json";

    // some local variables and methods here

    public void processFormSubmission(MyCustomClass myCustomObj, SlingHttpServletResponse response) throws IOException
    {
    response.setContentType(RESPONSE_CTYPE);
    response.getWriter().write(some_output_string_goes_here);
    }
    }
  4. Sample codes of MyCustomClass
    package ...
    
    // developer comments...
    // all necessary imports

    imports ...
    public class MyCustomClass { private HashMap<String, String> mainDataProperties = new HashMap(); // some more local variables and methods here... public void setMainDataProperties(String key, String val) { testKitProperties.put(key, val); } public String getMainDataProperties(String key) { return !mainDataProperties.isEmpty() && mainDataProperties.containsKey(key) ? mainDataProperties.get(key) : ""; } public void setSubDataProperties(String key, String val) { subDataProperties.put(key, val); } }
  5. Sample codes of MyCustomClassAdaptFactory
    package ...
    
    // developer comments...
    // all necessary imports

    import ... @Component(metatype=false) @Properties({ @Property(name = Constants.SERVICE_DESCRIPTION, value = "My Custom Class Adapter Factory"), @Property(name = Constants.SERVICE_VENDOR, value = "My Company"), @Property(name = "adapters", classValue = {MyCustomClass.class}), @Property(name = "adaptables", classValue = {SlingHttpServletRequest.class, Resource.class}) }) @Service(value = AdapterFactory.class) public class MyCustomClassAdapterFactory implements AdapterFactory { private static final Logger LOGGER = LoggerFactory.getLogger(TestKitsFormSubmissionAdapterFactory.class); // FORM FIELDS public static final String[] FIELDS = { "name", "email", "address", "tel", "shortbio", "skills" }; @Override public <AdapterType> AdapterType getAdapter(Object o, Class<AdapterType> adapterTypeClass) { if (o instanceof SlingHttpServletRequest) { return (AdapterType) buildMyCustomObj((SlingHttpServletRequest) o); } return null; } private MyCustomClass buildMyCustomObject(SlingHttpServletRequest request) { MyCustomClass myCustomObj = new MyCustomClass(); /** * FORM FIELD STRUCTURE * data[name]
    * data[email]
    * data[address]
    * data[tel]
    * data[shortbio]
    * data[skills] */ Map dataMap = request.getParameterMap(); for (String key : FIELDS) { if (dataMap.containsKey("data[" + key + "]")) { String[] arrayStr = (String[]) dataMap.get("data[" + key + "]"); testKitsFormSubmission.setTestKitProperties(key, arrayStr[0]); } } return myCustomObj; } }
  6. Sample HTML/JS Form Markups
    HTML
    <form id="myformid" method="post" action="/apps/mycompany/forms" onsubmit="return myCustomAjaxSubmit(this);">
    <p><label>Name: <input type="text" name="data[name]" id="data-name" /></lable></p>
    <p><label>Email: <input type="text" name="data[email]" id="data-email" /></lable></p>
    <p><label>Address: <input type="text" name="data[address]" id="data-address" /></lable></p>
    <p><label>Tel: <input type="text" name="data[tel]" id="data-tel" /></lable></p>
    <p><label>Sort bio: <textarea name="data[shortbio]" id="data-shortbio"></textarea></lable></p>
    <p><label>skills: <textarea name="data[skills]" id="data-skills"></textarea></lable></p>
    </form>

    JS
    function myCustomAjaxSubmit(e)
    {
    // do something here...
    }

How the AdapterFactory get implemented in Adobe CQ (AEM)

  • Examine sample codes for MyCustomClassAdapterFactory above (#5):

    @Property(name = "adapters", classValue = {MyCustomClass.class})

    and

    @Property(name = "adaptables", classValue = {SlingHttpServletRequest.class, Resource.class}) are required.

    Property adapters. The service registration property listing the fully qualified names of classes to which this factory can adapt adaptables.
    Property adaptables. The service name to use when registering implementations of this interface as services.

    More reference on AdapterFactory, go to: Interface AdapterFactory.
  • You can verify if the AdapterFactory exists by going to: http://{host}:{port}/system/console/adapters. For more information on this, go to: New in CQ 5.5: Sling Adapters Console.

Note: this article also posted 6D labs at: http://labs.sixdimensions.com/blog/2014-07-17/handle-form-submission-using-adapterfactory-in-adobe-cq-aem-osgi-component/