Repository webscript in alfresco
Introduction to webscript
Web script is backbone in alfresco. Most of the things in alfresco is built using webscript only. Whether we talk about the user interface or the backend services in alfresco. From the 5th version onwards alfresco introduced AIKAU, in which they have changed few things in terms of implementation of webscript on share side.Old way of creating webscript will remain as it is.On previous versions, alfresco was using surf framework for webscript.They have added few more libraries in aikau for webscript.
Architecture of webscript
Lets have a look on webscript architecture of alfresco.Webscript follows MVC architecture only.There are three phases in MVC design pattern. Request , Controller and Response. Same is the case with webscript. Using Uri request will come to webscript, which will be followed to controller controller will deal with services and finally it will give the response in desired format.
Lets talk on each of this component.
Request Uri of alfresco webscript is defined in descriptor file of alfresco.In descriptor file you can define arguments which are going to be passed in uri.
In webscript, there can be 2 types of controller.Either it will be a java controller or it will be a javascript controller. Java script controller is having access of limited services, while using java you will be having access of all services which alfresco provides.Depends on the requirement you can choose the controller.
Response of webscript can be of any type, it can be HTML, JSON, XML or any thing else.
Types of webscript
We talked about architecture of webscript , now lets talk about the types of webscript available in alfresco.Basically there are 2 types of webscript in alfresco.1. Data Webscript
Data webscript are responsible for dealing with data only.This kind of webscript will be created at alfresco end.For an example, suppose we want to retrieve data of invoice type of document, which will include metadata like Invoice Number, creation date , amount etc..In that case we will create data webscript and will return response in required format.
2. Presentation webscript
Presentation webscript are dealing with the presentation layer of alfresco.This kind of webscript are mostly created at share.On previous version of alfresco there was alfresco client so on those version we can have presentation webscript on alfresco end as well, but in the latest version there is there is no alfresco ui client so , presentation webscripts are created at share end only. Dashlet is one of the best example of presentation webscript.
Implementation of webscript using javascript
There are 2 ways in which we can access repository services in alfresco.First is using Java backed webscripts another is Javascript backed webscript. As i mentioned earlier, java backed webscripts are having more control over services compare to javascript backed webscript.We will talk on both the way of implementation webscript.Let's start with the javascript backed webscript.
Let's talk about deployment, there are few ways using which we can deploy webscript in alfresco (if it is alfresco repository webscript). The places where we can place the alfresco webscript and in which order it will go for finding the webscript are as below.
Repository folder : /Company Home/Data Dictionary/Web Scripts Extensions
Repository folder : /Company Home/Data Dictionary/Web Scripts
Class path folder : /alfresco/extension/templates/webscripts
There are few limitation for webscript when we are deploying it inside repository folder.For example java backed webscript will not be possible in that case.If we are developing it using class path all things will be possible. Let's take a look on each and every component of webscript with small example of it.
- Webscript Descriptor
- Webscript descriptor file is XML file, which includes the webscript configuration elements.This elements defines the mod in which execution will happen, default response template, parameters of webscript, family of webscript etc...Naming convention of webscript descriptor files is also important.It should be named as NameOf Webscript(.)MethodName(.)desc(.)xml. Method can be given as GET, POST, PUT, DELETE etc..Below is one sample webscript descriptor file.
Group Member Listing /groupmember/list argument none required
There are few other elements as well which we can define in webscript descriptor.This webscript descriptor is repository side webscript.All the element of alfresco repository side webscript are very well explained in Webscript Descriptor Documentation link. - Webscript Controller
- In case of javascript backed webscript, javascript filename will be like NameOf Webscript(.)MethodName(.)js. This file will behave as webscript controller.Javascript backed webscript is having limitation on services as its mentioned earlier.You can take a look on few of javascript api on Alfrescp Javascript API link. If business requirement of webscript is not much more complex and it can be achievable using services which javascript api provides in that case we can use that.In case of java backed webscript few we are having full access of services which alfresco provides. All services on java side are very well explained on Foundation API link.Let's take a look on one example of javascript which saves list of users from administrator group in model variable.
var node = people.getGroup("GROUP_ALFRESCO_ADMINISTRATORS"); if(node){ model.members = people.getMembers(node); }
- Webscript Response Template
- Webscript Response template can be of html, json, xml, atom, rss or text type.This response format can be specified in url as argument like ?format=html if no format is specified in url that case default format which is specified in descriptor file of webscript will be taken.If in descriptor file as well there is no format specified than html will be taken as default response template.For each type of response template new file is create.For example for html response file name will be like WebscriptFileName.get.html.ftl, for xml file name it will be like WebscriptFileName.get.xml.ftl etc..ftl stands for freemarker.Response template in alfresco are written in freemarker template engine.
Let's take an previous example which was saving list of admin group users in model variable, from template engine we will print those values.
{ "users":[ <#list members as person> "${person.properties.userName}" </#list> ] }
- Webscript Configuration
- This file is optional file.Its XML file and contains configuration values.Lets take a look on below code , which is written in alfresco javascript for reading config file.
Javascript Code
var xmlElements = new XML(config.script); model.value1 = xmlElements.prop1; model.value2 = xmlElements.prop2;
XML configuration file
hello userName - Webscript Locale Bundle
- This file is an optional file.It is used for achieving Internationalization in webscript.This is nothing but a property file.There will be multiple properties file ,each file will be having its own locale for representing language, for example if we say english in that case the file name will be like webscript_id.methodname._locale.properties.For each locale there will be a new property file.For an example if in above, group member webscript, we want to retrieve "Users" constant from properties file than you can define properties file and display it.Take a look on below files which are changed.
Properties File
users = Users in Admin Group
Response Template
{ " ${msg("users")}":[ <#list members as person> "${person.properties.userName}" </#list> ] }
Implementation of java backed webscript
Java backed webscript have wide range of services which can be used while development compare to javascript backed webscript.In the previous version of alfresco hot reloading was really big issue when we work with java classes in alfresco, but from the 5th version onward hot reloading of java is supported.It was really a great enhancement made by alfresco, though hot reloading of XML file is still not possible.For using java backed webscript, java class which we are going to create must extend either DeclarativeWebScript or AbstractWebScript Class.Both of them can be used depend on the scenario.DeclarativeWebScript class does not have full control over response, while AbstractWebScript have full control over the response.
Let's an example of two different business scenarios.In First case we need to create webscript which will export data list of alfresco site in excel sheet.In this case we can extend AbstractWebScript class for webscript implementation.In other case we need to retrieve all data list which are created in site.In this case we can extend DeclarativeWebScript class for webscript implementation.
Now we will take a look on implementation of java backed webscript. Few things in terms of implementation will remain as it is , which were there in javascript backed webscript implementation.Things which will remain as it is are response template and descriptor file. As it will be java controller there is no need of javascript controller.
For using this java class we need to inject bean inside context file in alfresco.If we are using maven architecture than we should put this bean inside webscript-context.xml. For java backed webscript naming convention of bean id is really important, as based on the bean id only it is going to find the webscript location.Bean id must follow below rules.
- Bean id must start with webscriptprefix.Using that only alfresco engine identifies that it is an webscript.
- Bean id must end with the HTTP method.
- In between this 2 prefix and suffix , you have to add webscript package including name of webscript.
Consider an example of java backed webscript which will save a list of nodes with properties in model and freemarker will print those things in json.We will need to pass one NodeRef as argument.From that noderef we will retrieve its children and it will display its children with few properties of it.
- Webscript Descriptor
- There will be no change in descriptor file if we compare it with the javascript backed webscript.But few of the element may affect the accessibility of services.For an example authentication tag of webscript descriptor.If we keep this as none, services which required authentication will not be accessible.
Node with few properties /list/properties argument user required - Response Template
- As we required output in json and out default out put format in webscript descriptor is json.We will create response template with the name of nodelist.get.json.ftl.Java controller will return object of map in which there will be 2 properties name and title of node.In this freemarker file , we have to iterate map object and print values in json. Below is code for same.
{ "data":[ <#list list?values as node> { <#list node?keys as prop> "${prop}" :"${node[prop]}" <#if prop_has_next>,</#if> </#list> }<#if node_has_next>,</#if> </#list> ] }
- Java Controller
- As we do not need to change the response format, we will extend DeclarativeWebScript class and will create java controller out of it.We will also create one spring bean inside webscript-context.xml file, which will refer this java class.In this classs we will require nodeService of alfresco foundation api, for iterating retrieval of children and properties of it and than saving it in map.
package com.sample; import java.util.HashMap; import java.util.List; import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.DeclarativeWebScript; import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptRequest; public class ListNodeWebScript extends DeclarativeWebScript { private NodeService nodeService; public NodeService getNodeService() { return nodeService; } public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } protected Map
executeImpl(WebScriptRequest req, Status status, Cache cache) { Map model = new HashMap (); Map childrens = new HashMap (); NodeRef nodeRef = new NodeRef(req.getParameter("nodeRef")); List childAssocList = nodeService.getChildAssocs(nodeRef); for (ChildAssociationRef child : childAssocList) { Map nodes = new HashMap (); nodes.put("Name", nodeService.getProperty(child.getChildRef(), ContentModel.PROP_NAME)); nodes.put("Title", nodeService.getProperty(child.getChildRef(), ContentModel.PROP_TITLE)); childrens.put(child.getChildRef().getId(), nodes); } model.put("list", childrens); return model; } } - Webscript Context(Injecting webscript bean)
- In spring bean context file we will inject few services which we are going to use in JavaController. All the foundation api you can use here,apart from that if you have defined your own services those will also be accessible here.While using services make sure you are using safely.You can refer how to safely call java services ? blog for more details.