Creating custom datalist types on the fly, using the new model manager.

  • Posted on: 7 October 2016
  • By: fhp

When creating a datalist you are able to select from a selected few types. The following will tell you how to be able to design your own datalists with the new model manager in Alfresco 5.1 Including setting up a layout. Sorry about the poor layout of the code provided by drupal...

The model manager is not setup to let you create new datalists but if you put this in your content-mode.xml you are able to select it in the dropdown in the model manager:

  1. <types>
  2. <type name="mg:datalistmodel">
  3. <title>Template for custom datalists</title>
  4. <description>You will be able to select this type in the model manager and create a new custom datalist</description>
  5. <parent>dl:dataListItem</parent>
  6. </type>
  7. </types>

The model manager lets you design a layout for your model but unfortunately this does not work for displaying datalists – only when editing them. But there is a workaround :-)

You need to build a webscript that goes through all the custom datalists, gets the layout the user designed, transform that into xml and inject it into share-config-custom.xml – then you just need to refresh your share webscripts and the share-config-custom changes will take effect.

The code for the repo, that gives you a list of the custom datalists:

 private org.json.simple.JSONArray getCustomTypes() {
     PagingResults modelDefinitionPagingResults = customModelService.getCustomModels(new PagingRequest(100));
     Iterator it = modelDefinitionPagingResults.getPage().iterator();
     while (it.hasNext()) {
         CustomModelDefinition cmd = (CustomModelDefinition)it.next();
     }
     PagingResults customModelServiceAllCustomTypes = customModelService.getAllCustomTypes(new PagingRequest(100));
     org.json.simple.JSONArray result = new org.json.simple.JSONArray();
     it = customModelServiceAllCustomTypes.getPage().iterator();
     while (it.hasNext()) {
         JSONObject model = new JSONObject();
         TypeDefinition cmd = (TypeDefinition)it.next();
         try {
             model.put("model", cmd.getModel().getName() );
             model.put("type", cmd.getName());
             result.add(model);
         } catch (JSONException e) {
             e.printStackTrace();
         }
     }
     return result;
}

The code for share, that does the rest of the job. It has some parts that need to be cleaned up, but it works ;-)

/**
 * Created by flemmingheidepedersen on 20/09/2016.
 */
public class LayoutManager extends DeclarativeWebScript {
    private CustomCMMService customCMMService;
    public void setCustomCMMService(CustomCMMService customCMMService) {
        this.customCMMService = customCMMService;
    }
    private ScriptRemote scriptRemote;
    public void setScriptRemote(ScriptRemote scriptRemote) {
        this.scriptRemote = scriptRemote;
    }
    private ConnectorService connectorService;
    public void setConnectorService(ConnectorService connectorService) {
        this.connectorService = connectorService;
    }
    private ArrayList getColumnsForCustomType(String model, String type, String host) {
        ArrayList result = new ArrayList();
        try
        {
            String json_result = customCMMService.getForm(model,type);
            JSONParser parser = new JSONParser();
            Object obj = parser.parse(json_result);
            JSONArray json = (JSONArray) obj;
            if (json.size() > 0) {
                JSONObject elementconfig = (JSONObject)json.get(0);
                JSONArray columns = (JSONArray)elementconfig.get("column");
                Iterator iterator = columns.iterator();
                while (iterator.hasNext()) {
                    JSONObject elementConfig = (JSONObject)iterator.next();
                    result.add((String) elementConfig.get("id"));
                }
            }
            else {
                System.out.println("no layout for type");
                result = null;
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.out.println("no layout for type");
            result = null;
        }
        return result;
    }
    public Element createXML(ArrayList properties, String type) {
        String condition = (String)properties.get(0).split(":")[0] + ":" + type;
        Element config = new Element("config");
        config.setAttribute("evaluator", "model-type");
        config.setAttribute("condition", condition);
        config.setAttribute("id", "custom_form_setup");
        Element forms = new Element("forms");
        Element form = new Element("form");
        Element field_visibility = new Element("field-visibility");
        Element create_form  = new Element("create-form");
        Element appearance  = new Element("appearance");
        create_form.setAttribute("template", "../data-lists/forms/dataitem.ftl");
        Iterator iterator = properties.iterator();
        while (iterator.hasNext()) {
            Element property = new Element("show");
            String property_value = (String) iterator.next();
            property.setAttribute("id", property_value);
            field_visibility.addContent(property);
        }
        form.addContent(field_visibility);
        form.addContent(create_form);
        form.addContent(appearance);
        forms.addContent(form);
        config.addContent(forms);
        return config;
    }
    public void addToShareConfigCustom(ArrayList xmlList) {
        Document d = new Document();
        String workingDir = System.getProperty("user.dir");
        String path = workingDir + "/tomcat/shared/classes/alfresco/web-extension/share-config-custom.xml";
//        String path = workingDir + "/target/test-classes/alfresco/web-extension/share-config-custom.xml";
        try{
            Document document = null;
            Element root = null;
            File xmlFile = new File(path);
            if(xmlFile.exists()){
                FileInputStream fis = new FileInputStream(xmlFile);
                SAXBuilder sb = new SAXBuilder();
                document = sb.build(fis);
                root = document.getRootElement();
                fis.close();
            }else{
                document = new Document();
                root = new Element("banque");
            }
            root = this.removeLayouts(root, "custom_form_setup");
            Iterator i = xmlList.iterator();
            while (i.hasNext()) {
                Element xml = (Element)i.next();
                root.addContent(xml);
            }
            document.setContent(root);
            FileWriter writer = new FileWriter(path);
            XMLOutputter outputter = new XMLOutputter();
            outputter.output(document, writer);
            outputter.output(document, System.out);
            writer.close(); 
        } catch (IOException io) {
            System.out.println(io.getMessage());
        } catch (JDOMException e) {
            e.printStackTrace();
        }
    }
    private Element removeLayouts(Element root, String layoutID) {
        List children = root.getChildren();
        Iterator i = children.iterator();
        ArrayList childrenToRemove = new ArrayList();
        while (i.hasNext()) {
            Element e = (Element)i.next();
            if ((e.getAttributeValue("id") != null ) && e.getAttributeValue("id").equals(layoutID)) {
                // cant mess with the iterator at this point, so we have to pick it up to be removed after the iterator has finished
                childrenToRemove.add(e);
            }
        }
        Iterator it = childrenToRemove.iterator();
        while (it.hasNext()) {
            root.removeContent((Element) it.next());
        }
        return root;
    }
    private ArrayList getCustomTypes() {
        String alfrescoEndPoint = null;
        try {
            alfrescoEndPoint = connectorService.getConnector("alfresco").getEndpoint();
        } catch (ConnectorServiceException e) {
            e.printStackTrace();
        }
        String uri = alfrescoEndPoint + "/layoutmanager";
        Response response = scriptRemote.connect().get(uri);
        ArrayList result = new ArrayList();
        try {
            JSONParser parser = new JSONParser();
            Object obj = parser.parse(response.getText());
            System.out.println(obj);
            JSONArray list = (JSONArray) obj;
            Iterator iterator = list.iterator();
            while (iterator.hasNext()) {
                JSONObject elementConfig = (JSONObject)iterator.next();
                result.add(((String)elementConfig.get("model")).replaceAll("\\{.*\\}", "") + "/" + ((String)elementConfig.get("type")).replaceAll("\\{.*\\}", ""));
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return result;
    }
    protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) {
        Map model = new HashMap();
        ArrayList customTypes = this.getCustomTypes();
        ArrayList xmlList = new ArrayList();
        Iterator i = customTypes.iterator();
        while (i.hasNext()) {
            String type = (String)i.next();
            String model_s = type.split("/")[0];
            String type_s = type.split("/")[1];
            ArrayList properties = this.getColumnsForCustomType(model_s, type_s, req.getServerPath());
            if (properties != null) {
                Element xml = this.createXML(properties, type.split("/")[1]);
                xmlList.add(xml);
            }
        }
        model.put("output", "The Layout of all custom datalists has been reloaded ");
        this.addToShareConfigCustom(xmlList);
        return model;
    }

The customCMMService needed to get the layout of the form:

public class CustomCMMService extends CMMService {
    private static final Log logger = LogFactory.getLog(CMMServiceGet.class);
    public CustomCMMService() {
    }
    public String  getForm(String model, String type) {
        String t = (String)this.getFormDefinitions(model).get(type);
        return t;
    }
}