Alfresco Web Scrpits

Ramesh Chauhan

November 2014

 In this article by Ramesh Chauhan, the author of Learning Alfresco Web Scripts, we will cover the following topics:

  • Reasons to use web scripts
  • Executing a web script from standalone Java program
  • Invoking a web script from Alfresco Share
  • DeclarativeWebScript versus AbstractWebScript

(For more resources related to this topic, see here.)

Reasons to use web scripts

It's now time to discover the answer to the next question—why web scripts? There are various alternate approaches available to interact with the Alfresco repository, such as CMIS, SOAP-based web services, and web scripts. Generally, web scripts are always chosen as a preferred option among developers and architects when it comes to interacting with the Alfresco repository from an external application. Let's take a look at the various reasons behind choosing a web script as an option instead of CMIS and SOAP-based web services.

In comparison with CMIS, web scripts are explained as follows:

  • In general, CMIS is a generic implementation, and it basically provides a common set of services to interact with any content repository. It does not attempt to incorporate the services that expose all features of each and every content repository. It basically tries to cover a basic common set of functionalities for interacting with any content repository and provide the services to access such functionalities.
  • Alfresco provides an implementation of CMIS for interacting with the Alfresco repository. Having a common set of repository functionalities exposed using CMIS implementation, it may be possible that sometimes CMIS will not do everything that you are aiming to do when working with the Alfresco repository. While with web scripts, it will be possible to do the things you are planning to implement and access the Alfresco repository as required. Hence, one of the best alternatives is to use Alfresco web scripts in this case and develop custom APIs as required, using the Alfresco web scripts.
  • Another important thing to note is, with the transaction support of web scripts, it is possible to perform a set of operations together in a web script, whereas in CMIS, there is a limitation for the transaction usage. It is possible to execute each operation individually, but it is not possible to execute a set of operations together in a single transaction as possible in web scripts.

SOAP-based web services are not preferable for the following reasons:

  • It takes a long time to develop them
  • They depend on SOAP
  • Heavier client-side requirements
  • They need to maintain the resource directory
  • Scalability is a challenge
  • They only support XML

In comparison, web scripts have the following properties:

  • There are no complex specifications
  • There is no dependency on SOAP
  • There is no need to maintain the resource directory
  • They are more scalable as there is no need to maintain session state
  • They are a lightweight implementation
  • They are simple and easy to develop
  • They support multiple formats

In a developer's opinion:

  • They can be easily developed using any text editor
  • No compilations required when using scripting language
  • No need for server restarts when using scripting language
  • No complex installations required

In essence:

  • Web scripts are a REST-based and powerful option to interact with the Alfresco repository in comparison to the traditional SOAP-based web services and CMIS alternatives
  • They provide RESTful access to the content residing in the Alfresco repository and provide uniform access to a wide range of client applications
  • They are easy to develop and provide some of the most useful features such as no server restart, no compilations, no complex installations, and no need of a specific tool to develop them
  • All these points make web scripts the most preferred choice among developers and architects when it comes to interacting with the Alfresco repository

Executing a web script from standalone Java program

There are different options to invoke a web script from a Java program. Here, we will take a detailed walkthrough of the Apache commons HttpClient API with code snippets to understand how a web script can be executed from the Java program, and will briefly mention some other alternatives that can also be used to invoke web scripts from Java programs.

HttpClient

One way of executing a web script is to invoke web scripts using org.apache.commons.httpclient.HttpClient API. This class is available in commons-httpclient-3.1.jar. Executing a web script with HttpClient API also requires commons-logging-*.jar and commons-codec-*.jar as supporting JARs. These JARs are available at the tomcat\webapps\alfresco\WEB-INF\lib location inside your Alfresco installation directory. You will need to include them in the build path for your project. We will try to execute the hello world web script using the HttpClient from a standalone Java program. While using HttpClient, here are the steps in general you need to follow:

  1. Create a new instance of HttpClient.
  2. The next step is to create an instance of method (we will use GetMethod). The URL needs to be passed in the constructor of the method.
  3. Set any arguments if required.
  4. Provide the authentication details if required.
  5. Ask HttpClient to now execute the method.
  6. Read the response status code and response.
  7. Finally, release the connection.

Understanding how to invoke a web script using HttpClient

Let's take a look at the following code snippet considering the previous mentioned steps. In order to test this, you can create a standalone Java program with a main method and put the following code snippet in Java program and then modify the web script URLs/credentials as required. Comments are provided in the following code snippet for you to easily correlate the previous steps with the code:

// Create a new instance of HttpClient
HttpClient objHttpClient = new HttpClient();

// Create a new method instance as required. Here it is GetMethod.
GetMethod objGetMethod = new GetMethod("http://localhost:8080/alfresco/service/helloworld");

// Set querystring parameters if required.
objGetMethod.setQueryString(new NameValuePair[] { new NameValuePair("name", "Ramesh")});

// set the credentials if authentication is required.
Credentials defaultcreds = new UsernamePasswordCredentials("admin","admin");
objHttpClient.getState().setCredentials(new AuthScope("localhost",8080, AuthScope.ANY_REALM), defaultcreds);

try {
// Now, execute the method using HttpClient.
int statusCode = objHttpClient.executeMethod(objGetMethod);
if (statusCode != HttpStatus.SC_OK) {
   System.err.println("Method invocation failed: " +
     objGetMethod.getStatusLine());
}

// Read the response body.
byte[] responseBody = objGetMethod.getResponseBody();

// Print the response body.
System.out.println(new String(responseBody));

} catch (HttpException e) {
System.err.println("Http exception: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
System.err.println("IO exception transport error: " +
   e.getMessage());
e.printStackTrace();
} finally {
// Release the method connection.
objGetMethod.releaseConnection();
}

Note that the Apache commons client is a legacy project now and is not being developed anymore. This project has been replaced by the Apache HttpComponents project in HttpClient and HttpCore modules. We have used HttpClient from Apache commons client here to get an overall understanding.

Some of the other options that you can use to invoke web scripts from a Java program are mentioned in subsequent sections.

URLConnection

One option to execute web script from Java program is by using java.net.URLConnection. For more details, you can refer to http://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html.

Apache HTTP components

Another option to execute web script from Java program is to use Apache HTTP components that are the latest available APIs for HTTP communication. These components offer better performance and more flexibility and are available in httpclient-*.jar and httpcore-*.jar. These JARs are available at the tomcat\webapps\alfresco\WEBINF\lib location inside your Alfresco installation directory. For more details, refer to https://hc.apache.org/httpcomponents-client-4.3.x/quickstart.html to get an understanding of how to execute HTTP calls from a Java program.

RestTemplate

Another alternative would be to use org.springframework.web.client.RestTemplate available in org.springframework.web-*.jar located at tomcat\webapps\alfresco\WEB-INF\lib inside your Alfresco installation directory. If you are using Alfresco community 5, the RestTemplate class is available in spring-web-*.jar. Generally, RestTemplate is used in Spring-based services to invoke an HTTP communication.

Calling web scripts from Spring-based services

If you need to invoke an Alfresco web script from Spring-based services, then you need to use RestTemplate to invoke HTTP calls. This is the most commonly used technique to execute HTTP calls from Spring-based classes. In order to do this, the following are the steps to be performed. The code snippets are also provided:

  1. Define RestTemplate in your Spring context file:
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate" />
  2. In the Spring context file, inject restTemplate in your Spring class as shown in the following example:
    <bean id="httpCommService" class="com.test.HTTPCallService">
    <property name="restTemplate" value="restTemplate" /> </bean>
  3. In the Java class, define the setter method for restTemplate as follows:
    private RestTemplate restTemplate;
    public void setRestTemplate(RestTemplate restTemplate) {
       this.restTemplate = restTemplate;
    }
  4. In order to invoke a web script that has an authentication level set as user authentication, you can use RestTemplate in your Java class as shown in the following code snippet. The following code snippet is an example to invoke the hello world web script using RestTemplate from a Spring-based service:
    // setup authentication
    String plainCredentials = "admin:admin";
    byte[] plainCredBytes = plainCredentials.getBytes();
    byte[] base64CredBytes = Base64.encodeBase64(plainCredBytes);
    String base64Credentials = new String(base64CredBytes);

    // setup request headers
    HttpHeaders reqHeaders = new HttpHeaders();
    reqHeaders.add("Authorization", "Basic " + base64Credentials);
    HttpEntity<String> requestEntity = new HttpEntity<String>(reqHeaders);

    // Execute method
    ResponseEntity<String> responseEntity = restTemplate.exchange("http://localhost:8080/alfresco/service/helloworld?name=Ramesh", HttpMethod.GET, requestEntity, String.class);
    System.out.println("Response:"+responseEntity.getBody());

Invoking a web script from Alfresco Share

When working on customizing Alfresco Share, you will need to make a call to Alfresco repository web scripts. In Alfresco Share, you can invoke repository web scripts from two places. One is the component level the presentation web scripts, and the other is client-side JavaScript.

Calling a web script from presentation web script JavaScript controller

Alfresco Share renders the user interface using the presentation web scripts. These presentation web scripts make a call to the repository web script to render the repository data. Repository web script is called before the component rendering file (for example, get.html.ftl) loads.

In out-of-the-box Alfresco installation, you should be able to see the components’ presentation web script available under tomcat\webapps\share\WEB-INF\classes\alfresco\site-webscripts.

When developing a custom component, you will be required to write a presentation web script. A presentation web script will make a call to the repository web script. You can make a call to the repository web script as follows:

var reponse = remote.call("url of web script as defined in description document");
var obj = eval('(' + response + ')');

In the preceding code snippet, we have used the out-of-the-box available remote object to make a repository web script call. The important thing to notice is that we have to provide the URL of the web script as defined in the description document. There is no need to provide the initial part such as host or port name, application name, and service path the way we use while calling web script from a web browser. Once the response is received, web script response can be parsed with the use of the eval function.

In the out-of-the-box code of Alfresco Share, you can find the presentation web scripts invoking the repository web scripts, as we have seen in the previous code snippet. For example, take a look at the main() method in the site-members.get.js file, which is available at the tomcat\webapps\share\components\site-members location inside your Alfresco installed directory. You can take a look at the other JavaScript controller implementation for out-of-the-box presentation web scripts available at tomcat\webapps\share\WEB-INF\classes\alfresco\site-webscripts making repository web script calls using the previously mentioned technique.

When specifying the path to provide references to the out-of-the-box web scripts, it is mentioned starting with tomcat\webapps. This location is available in your Alfresco installation directory.

Invoking a web script from client-side JavaScript

The client-side JavaScript control file can be associated with components in Alfresco Share. If you need to make a repository web script call, you can do this from the client-side JavaScript control files generally located at tomcat\webapps\share\components. There are different ways you can make a repository web script call using a YUI-based client-side JavaScript file. The following are some of the ways to do invoke web script from client-side JavaScript files. References are also provided along with each of the ways to look in the Alfresco out-of-the-box implementation to understand its usage practically:

  • Alfresco.util.Ajax.request: Take a look at tomcat\webapps\share\components\console\groups.js and refer to the _removeUser function.
  • Alfresco.util.Ajax.jsonRequest: Take a look at tomcat\webapps\share\components\documentlibrary\documentlist.js and refer to the onOptionSelect function.
  • Alfresco.util.Ajax.jsonGet: To directly make a call to get web script, take a look at tomcat\webapps\share\components\console\groups.js and refer to the getParentGroups function.
  • YAHOO.util.Connect.asyncRequest: Take a look at tomcat\webapps\share\components\documentlibrary\tree.js and refer to the _sortNodeChildren function.

In alfresco.js located at tomcat\webapps\share\js, the wrapper implementation of YAHOO.util.Connect.asyncRequest is provided and various available methods such as the ones we saw in the preceding list, Alfresco.util.Ajax.request, Alfresco.util.Ajax.jsonRequest, and Alfresco.util.Ajax.jsonGet can be found in alfresco.js. Hence, the first three options in the previous list internally make a call using the YAHOO.util.Connect.asyncRequest (the last option in the previous list) only.

Calling a web script from the command line

Sometimes while working on your project, it might be required that from the Linux machine you need to invoke a web script or create a shell script to invoke a web script. It is possible to invoke a web script from the command line using cURL, which is a valuable tool to use while working on web scripts.

You can install cURL on Linux, Mac, or Windows and execute a web script from the command line. Refer to http://curl.haxx.se/ for more details on cURL. You will be required to install cURL first. On Linux, you can install cURL using apt-get. On Mac, you should be able to install cURL through MacPorts and on Windows using Cygwin you can install cURL.

Once cURL is installed, you can invoke web script from the command line as follows:

curl -u admin:admin "http://localhost:8080/alfresco/service/helloworld?name=Ramesh"

This will display the web script response.

DeclarativeWebScript versus AbstractWebScript

The web script framework in Alfresco provides two different helper classes from which the Java-backed controller can be derived. It's important to understand the difference between them.

The first helper class is the one we used while developing the web script in this article, org.springframework.extensions.webscripts.DeclarativeWebScript. The second one is org.springframework.extensions.webscripts.AbstractWebScript.

DeclarativeWebScript in turn only extends the AbstractWebScript class.

If the Java-backed controller is derived from DeclarativeWebScript, then execution assistance is provided by the DeclarativeWebScript class. This helper class basically encapsulates the execution of the web script and checks if any controller written in JavaScript is associated with the web script or not. If any JavaScript controller is found for the web script, then this helper class will execute it. This class will locate the associated response template of the web script for the requested format and will pass the populated model object to the response template.

For the controller extending DeclarativeWebScript, the controller logic for a web script should be provided in the Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) method. Most of the time while developing a Java-backed web script, the controller will extend DeclarativeWebScript only.

AbstractWebScript does not provide execution assistance in the way DeclarativeWebScript does. It gives full control over the entire execution process to the derived class and allows the extending class to decide how the output is to be rendered. One good example of this is the DeclarativeWebScript class itself. It extends the AbstractWebScript class and provides a mechanism to render the response using FTL templates. In a scenario like streaming the content, there won't be any need for a response template; instead, the content itself needs to be rendered directly. In this case, the Java-backed controller class can extend from AbstractWebScript.

If a web script has both a JavaScript-based controller and a Java-backed controller, then:

If a Java-backed controller is derived from DeclarativeWebScript, then first the Java-backed controller will get executed and then the control would be passed to the JavaScript-backed controller prior to returning the model object to the response template.

If the Java-backed controller is derived from AbstractWebScript, then, only the Java-backed controller will be executed. The JavaScript controller will not get executed.

Summary

In this article, we took a look at the reasons of using web scripts. Then we executed a web script from standalone Java program and move on to invoke a web script from Alfresco Share. Lastly, we saw the difference between DeclarativeWebScript versus AbstractWebScript.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Learning Alfresco Web Scripts

Explore Title