Alternatives to Alfresco Share for Building Generic Forms

Alfresco introduced Share, it’s own collaboration portal based on Spring Surf technology and they have a pretty good idea to reduce the coding effort for building forms for your custom data types. It is called Forms Engine. Here we will point out some alternatives to Alfresco Share.

The following diagram pretty much explains the whole idea. You have services on Alfresco side that can return metadata about a particular node for form creation, persist the form, validate the posted values, etc.

In between you have some facilities on Share that can render the form and consume the configuration using this underlying services.

And finally on browser side you have forms engine that can manage the rendered form, client side validations, fancy AJAX interactions, etc.

Alternatives to Alfresco

See the following steps taken from Forms Developer Guide that explains the flow in detail.

  1. The browser requests a page that contains the Form UI Component.
  2. The Form UI Component uses the ConfigService to look for XML form configuration for the item requested.
  3. If configuration was found for the item a list of fields to be displayed is determined and passed to the formdefinitions REST API, if no configuration is found the REST API is called without any parameters.
  4. The formdefinitions REST API calls the JavaScript FormService.
  5. The JavaScript FormService calls the Java FormService. To process the request an appropriate FormProcessor for the item “kind” is located and asked to generate a form definition. During this process one or more Filters may be called to further process the generated form. The REST API receives the form definition and generates a JSON representation.
  6. The Form UI component takes the JSON form definition and combines it with the form configuration retrieved earlier to produce a Form UI template model. The FreeMarker template is then processed to produce the HTML/JavaScript output that is sent back to the browser. The browser executes the returned HTML/JavaScript which instantiates the Forms Runtime object used to manage the generated form.

But Share is not the only option to use if you want something similar. You could continue to use your favorite UI framework and provide the same flexibility.

Take the following webscript as an example, what it does it to dump the metadata of a given node recursively. It outputs everything you need about that particular node, the attributes, the type of the attributes, the relationships, aspects, etc.

It is even better than the one provided Alfresco by default, because this webscript returns all the metadata about a node recursively including all the children nodes which also enables you to build nested forms.

{
<#if classdefs.name?exists>
    "name" : "${shortType(classdefs.name.toString())}",
</#if>

<#if classdefs.title?exists>
    "title" : "${classdefs.title}",
    <#else>
        "title" : "",
</#if>

"parent" : {
<#-- @ftlvariable name="classdefs" type="org.alfresco.service.cmr.dictionary.ClassDefinition" -->
<#if classdefs.parentName?exists>
    "name" : "${shortType(classdefs.parentName.toString())}",
    "title" : "${classdefs.parentName.getLocalName()}",
    "url" : "${"/butterfly/metadata/class/" + shortType(classdefs.parentName.toString())}"
</#if>
},
"defaultAspects" : {
<#if classdefs.defaultAspects?exists>
    <#list classdefs.defaultAspects as aspectdef>
        "${shortType(aspectdef.name.toString())}" : {
        "name" : "${shortType(aspectdef.name.toString())}",
        <#if aspectdef.title?exists>
            "title" : "${aspectdef.title}",
        </#if>
        "url" : "${"/butterfly/metadata/class/" + shortType(aspectdef.name.toString())}"
        }
        <#if aspectdef_has_next>,</#if>
    </#list>
</#if>
},
"properties" : {
<#-- @ftlvariable name="propertydefs" type="org.alfresco.service.cmr.dictionary.ClassDefinition" -->
<#list propertydefs as propertydefs>
    "${shortType(propertydefs.name.toString())}": {
    <#if propertydefs.name?exists>
        "name" : "${shortType(propertydefs.name.toString())}",
    </#if>
    <#if propertydefs.title?exists>
        "title" : "${propertydefs.title}",
    </#if>
    <#if propertydefs.description?exists>
        "description" : "${propertydefs.description}",
    </#if>
    <#if propertydefs.defaultValues?exists>
        "defaultValues" : "${propertydefs.defaultValues}",
        <#else>
            "defaultValues" : "",
    </#if>
    <#if propertydefs.dataType?exists>
        "dataType" : "${shortType(propertydefs.dataType.name.toString())}",
    </#if>
    "multiValued" : ${propertydefs.multiValued?string},
    "mandatory" : ${propertydefs.mandatory?string}
    }
    <#if propertydefs_has_next>,</#if>
</#list>
},
"associations" : {
<#assign flag = false>
<#list assocdefs as assocdefs>
    <#if (assocdefs.isChild()==false)&&(flag== true)>
        <#assign flag = false>,
    </#if>
    <#if assocdefs.isChild() == false>
        <#assign flag=true>
            "${shortType(assocdefs.name.toString())}": {
            <#if assocdefs.name?exists>
                "name" : "${shortType(assocdefs.name.toString())}",
            </#if>
            <#if assocdefs.title?exists>
                "title" : "${assocdefs.title}",
            </#if>
            <#if assocdefs.description?exists>
                "description" : "${assocdefs.description}",
                <#else>
                    "description" : "",
            </#if>
            "source" : {
            <#if assocdefs.getSourceClass().name?exists>
                "class" : "${shortType(assocdefs.getSourceClass().name.toString())}",
            </#if>
            <#if assocdefs.getSourceRoleName()?exists>
                "role" : "${assocdefs.getSourceRoleName().toString()}",
            </#if>
            "mandatory" : ${assocdefs.isSourceMandatory()?string},
            "many" : ${assocdefs.isSourceMany()?string}
            },
            "target" : {
            <#if assocdefs.getTargetClass().name?exists>
                "class" : "${shortType(assocdefs.getTargetClass().name.toString())}",
            </#if>
            <#if assocdefs.getTargetRoleName()?exists>
                "role" : "${assocdefs.getTargetRoleName().toString()}",
            </#if>
            "mandatory" : ${assocdefs.isTargetMandatory()?string},
            "many" : ${assocdefs.isTargetMany()?string}
            }
            }
    </#if>
</#list>
},
"childassociations" : {
<#assign flag = false>
<#list assocdefs as assocdefs>
    <#if (assocdefs.isChild()==true)&&(flag== true)>
        <#assign flag = false>,
    </#if>
    <#if assocdefs.isChild() == true>
        <#assign flag=true>
            "${shortType(assocdefs.name.toString())}": {
            <#if assocdefs.name?exists>
                "name" : "${shortType(assocdefs.name.toString())}",
            </#if>
            <#if assocdefs.title?exists>
                "title" : "${assocdefs.title}",
            </#if>
            <#if assocdefs.description?exists>
                "description" : "${assocdefs.description}",
                <#else>
                    "description" : "",
            </#if>
            "source" : {
            <#if assocdefs.getSourceClass().name?exists>
                "class" : "${shortType(assocdefs.getSourceClass().name.toString())}",
            </#if>
            <#if assocdefs.getSourceRoleName()?exists>
                "role" : "${assocdefs.getSourceRoleName().toString()}",
            </#if>
            "mandatory" : ${assocdefs.isSourceMandatory()?string},
            "many" : ${assocdefs.isSourceMany()?string}
            },
            "target" : {
            <#if assocdefs.getTargetClass().name?exists>
                "class" : "${shortType(assocdefs.getTargetClass().name.toString())}",
            </#if>
            <#if assocdefs.getTargetRoleName()?exists>
                "role" : "${assocdefs.getTargetRoleName().toString()}",
            </#if>
            "mandatory" : ${assocdefs.isTargetMandatory()?string},
            "many" : ${assocdefs.isTargetMany()?string}
            },

            <#if assocdefs.getRequiredChildName()?exists>
                "requiredChildName" : "${assocdefs.getRequiredChildName()}",
            </#if>
            <#if assocdefs.getDuplicateChildNamesAllowed() == true>
                "duplicateChildNameAllowed" : true
                <#else>
                    "duplicateChildNameAllowed" : false
            </#if>

            }
    </#if>
</#list>
}
}

What you have to know is to develop a form builder for your favorite UI framework of your choice. For example I developed a generic form builder for GWT using the output coming from this webscript. You are not bound to Share 🙂

Read More Post

STAY CONNECTED

Most Popular

Why Serviced Apartments Are the Perfect Choice for Long-Term Stays in Singapore – Everything You Need to Know
17 Dec

Why Serviced Apartments Are the Perfect Choice for Long-Term Stays in Singapore – Everything You Need to Know

If you’re heading to Singapore for a few weeks or many months, maybe for work or study or just to

Manifesting Your Dream Career: Finding Your Passion And Purpose
01 Aug

Manifesting Your Dream Career: Finding Your Passion And Purpose

Are you passionate about finding your dream career? Manifesting can help you align your career with your passions and purpose.

Revolutionizing Your Ride: Expert Auto Service At Carolina Auto Service
27 Feb

Revolutionizing Your Ride: Expert Auto Service At Carolina Auto Service

Finding a reliable auto service provider is paramount in the bustling world of vehicle maintenance and repair. That's where Carolina

Floratam: The Robust Grass Solution From Council Growers SOD
25 Jan

Floratam: The Robust Grass Solution From Council Growers SOD

Floratam grass, a popular St. Augustine variety, has become a go-to choice for homeowners and landscapers seeking a lush, durable

Carolina Mobile Autoservice: Your Go-To For Expert Brake Service Repair
25 Jan

Carolina Mobile Autoservice: Your Go-To For Expert Brake Service Repair

For vehicle owners, the braking system is among the most critical components for safety and performance. Carolina Mobile Autoservice, a

Safeguarding Your Property: Expert Water Damage Services By MBC Capital
24 Jan

Safeguarding Your Property: Expert Water Damage Services By MBC Capital

Water damage can significantly impact homes and businesses, often leaving a trail of destruction and disruption in its wake. Understanding