Chapter 9. How to Create a Web Script

WHAT'S IN THIS CHAPTER?

  • Understanding Web script components

  • Developing a Folder Listing Web script

  • Accessing Alfresco services

  • Debugging Web scripts

  • Creating the Knowledge Base Search Web script

In this chapter you'll discover how to create your own Web scripts. The Web Script Framework is designed with the developer in mind, aiming to make it as easy and quick as possible to create new Web scripts in order to construct a RESTful interface to the Alfresco Content Application Server.

Web scripts are implemented using lightweight scripting languages such as JavaScript and FreeMarker, so their development is not restricted to only those who know the Java language. One of the key advantages of using scripting languages is that minimal tooling is required. An example of this is that there is no need to compile or package a Web script implementation. This simplicity also removes the need for a complex development environment. In fact, Web scripts can be built using only a basic text editor or even just the Alfresco Explorer client.

Scripting also brings immediacy to the development of Web scripts by removing the painful steps of compilation and packaging. It is possible to quickly turn around implementation changes, which can be seen and tested just by refreshing your Web browser. This mode of development has become very attractive to the Alfresco community, making Web scripts a preferred approach to interacting with, integrating with, and extending Alfresco.

To develop a Web script, you'll need to understand the following technologies:

  • XML for expressing the Web script description

  • JavaScript for writing the Web script logic

  • FreeMarker for rendering the Web script response

This chapter will take you step-by-step through the development process of a Web script. You will first build a Web script that provides the ability to list the contents of a folder in the Alfresco content repository: that is, the equivalent of the dir command in Microsoft Windows, or ls in Linux or Mac OS X. Along the way, you'll be introduced to the features of the Web Script Framework, so that by the end you'll be knowledgeable enough to tackle the development of the back-end search capability of the Knowledge Base sample application. Don't panic; you'll step through that one too.

Now you can get started.

COMPONENTS OF A WEB SCRIPT

Before you start writing code, it's worth stepping back and taking a high-level view of how a Web script is constructed. A Web script is comprised of the following components (as shown in Figure 9-1): a description document, a controller script, and one or more response templates (which are MVC views).

FIGURE 9-1

Figure 9.1. FIGURE 9-1

The description document, expressed in XML, describes the Web script—in particular its URI and HTTP method binding. It's also used to configure some of the Web script behavior, such as its authentication and transactional needs.

The controller script, written in JavaScript, is where the actual logic of the Web script is contained. For example, the JavaScript may query or perform actions against content residing in the Alfresco content repository. The output of the JavaScript is a model (a set of data) to render in the Web script response. Context such as the URI used to invoke the Web script and the currently authenticated user is available to the JavaScript.

The response template, written in FreeMarker, renders the output for the response in the requested format, such as HTML, XML, or JSON. Access to the model generated by the controller script is provided, as well as the same context available to invoke the Web script.

Each component is implemented in its own file. The Web Script Framework dictates where the files are to be located and also how they are named. This allows the framework to automatically locate and register Web scripts without you having to tell the framework where they are. This is an approach commonly known as convention over configuration, and is one that the Web Script Framework employs often to ease development of Web scripts.

So, where do you place Web script component files? You actually have two choices: in the file system within the Java classpath, or in the Alfresco content repository. The Web Script Framework searches for Web scripts in the following order:

  • In the content repository under the folder /Company Home/Data Dictionary/Web Scripts Extensions

  • In the content repository under the folder /Company Home/Data Dictionary/Web Scripts

  • In the classpath under the folder /alfresco/extension/templates/webscripts

  • In the classpath under the folder /alfresco/templates/webscripts

Placing Web scripts in the classpath allows you to package them and deploy them with other extensions that make up your solution. It means they can be installed using standard Alfresco tools without the extra step of uploading them into the content repository; however, the ability to edit them while developing them may not be as convenient as if they were located in the Alfresco content repository, where they can be easily edited using Alfresco Explorer or Share. Web scripts located in the content repository may also be exported and imported using the ACP (Alfresco Content Package) mechanism.

Note

For a default installation of Alfresco, the classpath is located at installLocation/tomcat/shared/classes/alfresco/extension.

It's worth considering that a single Alfresco Content Application Server may contain hundreds of Web scripts, each implemented with multiple files. To assist the management of all these Web scripts, the Web Script Framework allows you to organize Web script component files into a hierarchical folder or package structure. If you're familiar with Java, you'll see that it's very similar to Java's package construct. Typically, the package name follows the reverse domain name pattern. For example, Alfresco's Web scripts are all located in a folder named org/alfresco, which is reserved by Alfresco.

As you go through the rest of this chapter, the naming convention for each of the Web script component files will become clear.

CREATING A DESCRIPTION DOCUMENT

It's time to get started on the Folder Listing Web script, which will mimic the behavior of the dir command in Microsoft Windows or ls in Linux and Mac OS X. Given a folder path, the Web script will list the contents of that folder in the Alfresco content repository either in abbreviated or verbose form, depending on a user-provided flag.

First, create a Web script description document for the Folder Listing Web script.

  1. You first need to log in to Alfresco Explorer.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco
    2. Navigate to Company Home > Data Dictionary > Web Scripts Extensions.

  2. Create a folder to represent the top-level package structure.

    1. In the Create menu, click Create Space.

    2. Enter the name for the folder in the Name field, such as:

      org
    3. Click Create Space.

  3. Next, create a sub-package.

    1. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org.

    2. In the Create menu, click Create Space.

    3. Enter the name for the folder in the Name field, such as:

      example
    4. Click Create Space.

  4. Now create a Web script description document for the Folder Listing example.

    1. In the Create menu, click Create Content.

    2. Enter the name for the Web script in the Name field, such as:

      dir.get.desc.xml
    3. In the Content Type list, select XML.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <webscript>
        <shortname>Folder Listing Utility</shortname>
        <description>Sample demonstrating the listing of folder
        contents</description>
        <url>/dir/{folderpath}?verbose={verbose?}</url>
        <format default="html">extension</format>
        <authentication>user</authentication>
      </webscript>

      Code snippet dir.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

The first thing to note is that you now have a Web script package named /org/example. This is where you will place all of your component files for the Folder Listing Web script. In fact, you have already placed the description document there, which is named dir.get.desc.xml.

Component file naming is important and must adhere to the naming conventions defined by the Web Script Framework. Web script description document file names are structured as follows:

<web script id>.<http method>.desc.xml

The <web script id> identifies the Web script and must be unique within a Web script package. Therefore, a Web script is uniquely identified by its Web script package and Web script ID. Your Folder Listing Web script is uniquely identified as:

/org/example/dir

The <http method> specifies which HTTP method will initiate the Web script. Typically, this is GET, but other common methods include POST, PUT, and DELETE. There isn't actually a restriction on the method name but, in reality, most HTTP clients will only know of these four methods. Your Folder Listing Web script will only query the Alfresco content repository, so it is bound to the HTTP GET method.

Finally, all description document file names must end with .desc.xml, which indicates to the Web Script Framework the file is actually a description document that defines a Web script.

Now take a look at the description document, which is expressed in XML. All Web script descriptors have a root <webscript> element within which everything is defined.

The <shortname> and <description> elements provide human-readable titles for the Web script. These can be seen in Web script documentation and the Web script index located at:

http://localhost:8080/alfresco/service/

Your Folder Listing Web script defines the following short name and description:

...
<shortname>Folder Listing Utility</shortname>
<description>Sample demonstrating the listing of folder contents</description>
...

Code snippet dir.get.desc.xml

As the Folder Listing Web script queries the Alfresco content repository, it is necessary to ensure that only authenticated users have access. This means the Web script will only return folder contents that the authenticated user has permission to see. The <authentication> element specifies the level of required authentication to access the Web script, of which the following levels are available:

  • None—The Web script does not require any authentication to be invoked.

  • Guest—The Web script may be invoked by a guest user of the Alfresco Content Application Server.

  • User—The Web script must be invoked by a named user known to the Alfresco Content Application Server.

  • Admin—The Web script must be invoked by a named user who is an administrator of the Alfresco Content Application Server.

Your Folder Listing Web script defines the following level of authentication:

...
<authentication>user</authentication>
...

Code snippet dir.get.desc.xml

Next, define one of the most important parts of the Web script definition: the URI to which the Web script is bound. Your Folder Listing Web script is mapped to the URI /dir, but it is also necessary to decide how to pass arguments to the Web script: that is, how to define the folder to list and the flag to determine if an abbreviated or verbose listing is returned.

There are two options for passing arguments through the URI: as part of the URI path or as a query parameter. Which option you choose mostly depends on your style preference. Often, though, arguments that represent identifiers such as user ID are good candidates for the URI path, while arguments that represent switches for changing the behavior of the Web script are good candidates for query parameters.

Your Folder Listing Web script chooses to specify the folder as part of the URI path and the verbose flag as a query parameter:

...
<url>/dir/{folderpath}?verbose={verbose?}</url>
...

Code snippet dir.get.desc.xml

Note that the URI is expressed as a URI template, which is a URI containing placeholders; that is, slots for specifying arguments. URI templates are described in much greater detail later in this chapter, but for now the {folderpath} token represents where the folder path should be placed and the {verbose?} token represents the flag.

Although your Web script only defines a single URI, it is possible to declare multiple URIs.

You now need to decide how to render the list of folder contents. Your example will provide both a human-readable HTML format, allowing access from a Web browser, and a JSON format, providing a machine-readable format for other clients to parse.

Note

JSON, short for JavaScript Object Notation, is a lightweight data interchange format that is often used for transmitting structured data over a network connection.

The <format> element of the Web script description document allows a Web script to specify (through the default attribute) which response format is returned if a client does not explicitly request a format. In some cases, the returned format may not be known until the Web script is invoked with its arguments, in which case a default value of "" must be set.

The means by which a client can request a format is also specified by the <format> element through its value, which may be one of the following: extension, argument, or any.

A value of extension allows a client to request the format through an extension on the URL, where the extension is the name of the format. If this value were chosen, your Folder Listing URL for returning JSON would be constructed as follows:

/dir/<folderpath>.json?verbose=true

A value of argument allows a client to request the format through a query parameter on the URL. This is useful for cases where the URL path naturally ends in an extension, such as if the path represents a document name in the Alfresco content repository. If this value were chosen, your Folder Listing URL for returning JSON would be constructed as follows:

/dir/<folderpath>?format=json&verbose=true

A value of any allows a client to request the format through either of the above.

Your Folder Listing Web script specifies a default format of HTML and expects a client to request the format through the URL-extension approach:

...
<format default="html">extension</format>
...

It is possible to exclude the <format> section from the descriptor document altogether, in which case the Web Script Framework defaults to returning HTML and allows a client to request a format through any approach.

URI Templates

While you have seen an example of a URI template as defined by your Folder Listing Web script, it is worth spending some time taking a deeper look at what exactly a URI template is and how expressive it can be for defining complex Web script URIs.

A URI template is simply a URI containing tokens that may be substituted with actual values. Tokens may represent values to query parameters or values within the URI path, where the syntax for expressing a token is {<token name>}.

An example of specifying a URI with two query parameters — one named 'a' and the other named 'b' — follows:

/add?a={a}&amp;b={b}

Note

The query parameter delimiter '&' must be expressed as '&amp;' in Web script descriptor documents, as '&' has special meaning within XML.

A client can generate the URI for invoking this Web script when given the URI template and values for 'a' and 'b'. For example, if 'a' is set to '1' and 'b' is set to '2', the resulting URI is:

/add?a=1&b=2

Query parameter tokens can indicate that the parameter is optional through the convention of appending a '?' to the token name. For example, to indicate that the query parameter 'b' is optional, the URI template becomes:

/add?a={a}&amp;b={b?}

Although parameters may be marked as optional, it is only a convention and the Web Script Framework does not enforce mandatory query parameters. This responsibility is given to the Web script developer.

An example of specifying a URI path with embedded tokens — one named 'user' and the other named 'profilekind' — follows:

/user/{user}/profile/{profilekind}

Any URI that matches the URI template will invoke the Web script that defines it. But what does it mean to match? A match is made when:

  • All static parts of the URI template match the URI

  • All tokens within the URI template have been given values by the URI

For example, the following URIs match:

/user/joe/profile/public
/user/fred/profile/full

But the following URIs do not match:

/user/profile/public
/user/joe/profile

The value of a token in a URI path may itself consist of multiple path segments. For example, the following URI specifies the user value joe/smith and matches the previous URI template:

/user/joe/smith/profile/public

When a URI request is made, the Web Script Framework locates the associated Web script by finding the closest matching URI template for the URI. For example, consider that two Web scripts each define their own similar URIs:

  • Web script A defines the URI template: /a/b

  • Web script B defines the URI template /a/{z}

The URI /a/b will invoke Web script A, while the URI /a/c will invoke Web script B. Matching of static parts of the URI template takes precedence over matching a token value.

Finally, the same token name may appear multiple times in a single URI template. Although very rare, it's worth knowing the implications of matching to a Web script. Consider the following URI template where the 'user' token is specified twice:

/user/{user}/profile/{user}

For a match to occur, the value provided for each same-named token must be the same. The following URI matches:

/user/joe/profile/joe

But the following URI does not match:

/user/joe/profile/fred

Web script developers have access to the value provided for each token in both the controller script and response template.

Remember, if you get stuck defining your own URI template, there are plenty of examples provided by out-of-the-box Web scripts, which you can browse through the Web script index.

CREATING A CONTROLLER SCRIPT

Having described the Folder Listing Web script through its description document, it's now time to implement its behavior by developing a controller script in the JavaScript language. In this case, the controller will simply establish the folder to list from the invoked URI and query the Alfresco content repository for that folder, ensuring error conditions are catered for.

You can now create the controller script.

  1. You first need to log in to Alfresco Explorer.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco
    2. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  2. Create a Web script controller script for your Folder Listing example.

    1. In the Create menu, click Create Content.

    2. Enter the name for the Web script in the Name field as follows:

      dir.get.js
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      // extract folder listing arguments from URI
      var verbose = (args.verbose == "true" ? true : false);
      var folderpath = url.templateArgs.folderpath;
      
      // search for folder within Alfresco content repository
      var folder = roothome.childByNamePath(folderpath);
      // validate that folder has been found
      if (folder == undefined || !folder.isContainer) {
         status.code = 404;
         status.message = "Folder " + folderpath + " not found.";
         status.redirect = true;
      }
      
      // construct model for response template to render
      model.verbose = verbose;
      model.folder = folder;

      Code snippet dir.get.js

    6. Click Next.

    7. Click Finish.

    8. Click OK.

The first thing to note is the component script file name dir.get.js, which adheres to the naming convention defined by the Web Script Framework. Controller script file names are structured as follows:

<web script id>.<http method>.js

The <web script id> identifies the Web script and must be the same as the Web script ID defined in the file name of the associated Web script description document. The <http method> specifies which HTTP method will initiate the Web script and again must be the same as the associated Web script description document.

Finally, all controller script file names must end with .js. This indicates to the Web Script Framework that the file is indeed a controller script.

Your Folder Listing example now consists of the following two component files:

/org/example/dir.get.desc.xml
/org/example/dir.get.js

The Web Script Framework knows that both of these files are related to the same Web script, as they share Web script package, Web script ID, and HTTP method.

Parsing the Web Script URI

A Web script is invoked when a URI is requested that matches one of the URI templates defined by the Web script. It is often necessary for the Web script to gain access to the requested URI to allow it to extract arguments that may have been passed in as URI query parameters or embedded as values in the URI path.

Your Folder Listing Web script defines the following URI template with one URI-path token and one query parameter token:

<uri>/dir/{folderpath}?verbose={verbose?}</uri>

To extract the values provided for the {folderpath} and {verbose} tokens, your Folder Listing controller script uses the following JavaScript:

...
var verbose = (args.verbose == "true" ? true : false);
var folderpath = url.templateArgs.folderpath;
...

Code snippet dir.get.js

The args root object is a special object provided by the Web Script Framework to all controller scripts. It represents a map of the URI query-parameter values indexed by their name. In this case, the controller script is extracting the verbose query parameter. If the query parameter is not specified on the URI, the returned value is null.

Note

Web script root objects are globally named values and services provided by the Web Script Framework to the Web script controller and response templates.

The url.templateArgs root object is another special object provided by the Web Script Framework. It represents a map of all values provided for tokens in the URI path, indexed by token name. In this case, the controller script is extracting the value for the folderpath token. URI-path values are never null.

Imagine a client has made the following URI request:

/dir/Company%20Home?verbose=true

The resulting value of verbose is true and the value of folderpath is Company Home.

Calling Alfresco Services

Controller scripts have access to services provided by the Alfresco Content Application Server. This allows a Web script to query or perform operations against content residing in the Alfresco content repository. Services are exposed as root objects and each service provides its own application programming interface (API) to program against.

Your Folder Listing Web script simply needs to retrieve the folder value provided on the URI, identified by the {folderpath} token:

...
var folder = roothome.childByNamePath(folderpath);
...

Code snippet dir.get.js

The roothome root object is a special object provided by the Web Script Framework, which represents the root folder in the Alfresco content repository. From this object, it is possible to navigate through the content repository folder hierarchy or find sub-folders by name. Your controller script finds a sub-folder using the folder name provided in the URI.

There are many other root objects available to controller scripts:

  • args—A map of query parameter values indexed by query parameter name.

  • argsM—A map of multi-valued query parameters, where each key is an argument name and each value is an array containing all respective argument values, even if only one is supplied.

  • headers—A map of request header values indexed by header name.

  • headersM—A map of multi-valued request headers, where each key is a header name and each value is an array containing all respective header values, even if only one is supplied.

  • url—Provides access to the Web script URI, or parts of the URI, that triggered the Web script. See the "Complex Root Objects Reference" section at the end of this chapter for more details.

  • guest—A Boolean indicating if the Web script is executing as a "Guest" user.

  • webscript—A description of the Web script currently being executed. See the "Complex Root Objects Reference" section at the end of this chapter for more details.

  • server—A description of the Web script container hosting the Web script. See the "Complex Root Objects Reference" section at the end of this chapter for more details.

When executing a Web script as an authenticated user, the controller script also has access to the following Alfresco services.

  • roothome—The repository root folder

  • companyhome—The company home folder

  • person—The person node of the currently authenticated user

  • userhome—The user home folder

  • people—A service for accessing people and groups registered with the Alfresco Content Application Server

  • search—A service for querying and searching the content repository

  • actions—A service for invoking Alfresco Actions

  • classification—A service for navigating and managing categories

  • workflow—A service for starting workflows and managing in-flight workflows

Remember, the out-of-the-box, pre-built Web scripts provide plenty of examples demonstrating how to use the root objects provided to controller scripts.

Setting the Response Status Code

A Web script uses a response status code to inform the calling client of its execution outcome. Status codes may be used for the following scenarios:

  • To inform the client of an error situation. For example, an item is not found in the Alfresco content repository.

  • To inform the client of an occurrence of an event. For example, a new item has been created.

  • To instruct the client to perform a follow-up request. For example, to ask for user name and password credentials.

  • To inform the client of success.

Your Folder Listing Web script validates that the provided folder path actually exists in the Alfresco content repository using the following JavaScript in the controller script:

...
if (folder == undefined || !folder.isContainer) {
   status.code = 404;
   status.message = "Folder " + folderpath + " not found.";
   status.redirect = true;
}
...

Code snippet dir.get.js

The status root object is a special object provided to all controller scripts by the Web Script Framework. It allows a Web script to specify the response status code along with an associated status message. Typically, the value of the status code is set to a standard HTTP status code.

Note

The list of HTTP status codes and their meaning can be found at www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.

It is useful when reporting error status codes to provide additional information about the error in the response, such as the cause of the error. To support this, the Web Script Framework allows for a custom status response template to be rendered, but this happens only if the status.redirect value is set to true. A default status response template is provided by the Web Script Framework, which renders everything known about the status, so it's not necessary to develop your own; however, later in this chapter, you will discover how to create a custom status response template.

If the value of status.redirect is set to false, the status code is set on the response, but the response template for the requested format is rendered anyway.

Constructing the Model

One of the responsibilities of the controller script is to create a model for subsequent rendering by a response template. A model is a map of values indexed by their name, which can be read from and written to by the controller script.

Your Folder Listing Web script adds the verbose flag and retrieved folder to the model:

...
model.verbose = verbose;
model.folder = folder;
...

Code snippet dir.get.js

The model root object is provided to the controller script by the Web Script Framework. All items added to the model are available to the response template.

CREATING A RESPONSE TEMPLATE

The final stage of Web script execution is to render a response back to the initiating client in the most appropriate format based on the client's preference. A response template written in the FreeMarker language is responsible for rendering each format provided by the Web script.

Your Folder Listing Web script provides two responses: one in HTML for rendering to a Web browser and one in JSON for consumption by other clients. The response will list all the documents and folders contained within the folder retrieved by the controller script, as specified in the Folder Listing Web script URL. For now, focus on creating the HTML response template.

  1. You first need to log in to Alfresco Explorer.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco
    2. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  2. Create a Web script response template for your Folder Listing example.

    1. In the Create menu, click Create Content.

    2. Enter the name for the Web script in the Name field as follows:

      dir.get.html.ftl
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <html>
        <head>
          <title>Folder ${folder.displayPath}/${folder.name}</title>
        </head>
        <body>
           Alfresco ${server.edition} Edition v${server.version} : dir
          <p>
          Contents of folder ${folder.displayPath}/${folder.name}
          <p>
          <table>
          <#list folder.children as child>
             <tr>
                 <td><#if child.isContainer>d</#if></td>
                 <#if verbose>
                    <td>${child.properties.modifier}</td>
                    <td><#if child.isDocument>
                       ${child.properties.content.size}</#if></td>
                    <td>${child.properties.modified?date}</td>
                 </#if>
                 <td>${child.name}</td>
             </tr>
          </#list>
          </table>
        </body>
      </html>

      Code snippet dir.get.html.ftl

    6. Click Next.

    7. Click Finish.

    8. Click OK.

The first thing to note is the component script file name dir.get.html.ftl, which adheres to the naming convention defined by the Web Script Framework. Response template file names are structured as follows:

<web script id>.<http method>.<format>.ftl

The <web script id> identifies the Web script and must be the same as the Web script ID defined in the file name of the associated Web script description document. The <http method> specifies which HTTP method will initiate the Web script and again must be the same as the associated Web script description document.

The format rendered by the response template is represented by <format>, the Web Script Framework abbreviation for a MIME type, for which the following common formats are defined as follows:

  • html maps to text/html.

  • text maps to text/plain.

  • xml maps to text/xml.

  • atom maps to application/atom+xml.

  • atomentry maps to application/atom+xml;type=entry.

  • atomfeed maps to application/atom+xml;type=feed.

  • rss maps to application/rss+xml.

  • json maps to application/json.

  • opensearchdescription maps to application/opensearchdescription+xml.

  • mediawiki maps to MediaWiki markup as text/plain.

  • portlet maps to text/html (where HTML excludes header and footer markup).

  • fbml maps to text/html.

  • php maps to text/html.

  • js maps to text/javascript.

  • calendar maps to text/calendar.

Finally, all response template file names must end with .ftl. This indicates to the Web Script Framework that the file is indeed a response template.

Your Folder Listing example now consists of the following three component files:

/org/example/dir.get.desc.xml
/org/example/dir.get.js
/org/example/dir.get.html.ftl

The Web Script Framework knows that all of these files are related to the same Web script, as they share Web script package, Web script ID, and HTTP method.

Accessing the Model

Response templates have access to the model created by the controller script. Each named value added to the model is accessible as a template root object by its respective model name.

Your Folder Listing controller script placed two values into the model: one named folder, a folder object, and the other named verbose, a Boolean. Your response template uses these two values to drive the rendered output on the response:

...
Contents of folder ${folder.displayPath}/${folder.name}
...
<#list folder.children as child>
...
  <#if verbose>
    ...
  </#if>
</#list>
...

Code snippet dir.get.html.ftl

The folder object is used to render properties of the folder and to iterate through its children while the verbose flag is used to determine if extra detail should be output.

Accessing Alfresco Services

As well as model root objects, response templates have access to services provided by the Alfresco Content Application Server. This allows a response template to directly query or navigate parts of the content repository or access the context within which the Web script is executing, such as the currently authenticated user.

It must be noted that although response templates can perform their own logic, this should not be encouraged. Web script logic is better implemented in controller scripts, allowing the response template to focus only on rendering the output. This allows the easy creation of multiple response templates, as logic does not have to be duplicated in each. It also means logic is encapsulated in one place, so changes to logic are centralized.

Your Folder Listing Web script first renders details about the Alfresco Content Application Server:

...
Alfresco ${server.edition} Edition v${server.version} : dir
...

Code snippet dir.get.html.ftl

The server root object is a special object provided by the Web Script Framework, which represents the server within which the Web script is executing. In this case, the response template simply accesses properties of the server.

There are many other root objects available to response templates:

  • args—A map of query parameter values indexed by query parameter name.

  • argsM—A map of multi-valued query parameters, where each key is an argument name and each value is an array containing all respective argument values, even if only one is supplied.

  • headers—A map of request header values indexed by header name.

  • headersM—A map of multi-valued request headers, where each key is a header name and each value is an array containing all respective header values, even if only one is supplied.

  • url—Provides access to the Web script URI, or parts of the URI, that triggered the Web script. See the "Complex Root Objects Reference" section at the end of this chapter for more details.

  • guest—A Boolean indicating whether the Web script is executing as a "Guest" user.

  • webscript—A description of the Web script currently being executed. See the "Complex Root Objects Reference" section at the end of this chapter for more details.

  • server: A description of the Web script container hosting the Web script. See the "Complex Root Objects Reference" section at the end of this chapter for more details.

  • date: The date and time the Web script was invoked.

When executing a Web script as an authenticated user, the controller script also has access to the following Alfresco services:

  • roothome—The repository root folder

  • companyhome—The company home folder

  • person—The person node of the currently authenticated user

  • userhome—The user home folder

Remember that the out-of-the-box, pre-built Web scripts provide plenty of examples demonstrating how to use the root objects provided to response templates.

FreeMarker Methods

The FreeMarker template language supports the notion of a method. A method encapsulates an action to perform on a set of input parameters and may return an output value. Although FreeMarker provides many methods of its own, it also allows the registration of custom methods. The Web Script Framework takes advantage of this to provide the following methods specifically for developers of Web script response templates:

  • absurl(url)—Returns an absolute URL representation of the passed URL. Useful when rendering links within Atom (and similar formats).

  • xmldate(date)—Returns an ISO8601-formatted result of the passed date. Useful when rendering dates within XML.

  • scripturl(queryString)—Returns a URL that references this Web script. The passed queryString is added to the URL. System arguments such as guest and format are automatically added. Note that this method is particularly useful for protection against the runtime environment within which the Web script is executing. In some environments, such as a Portal, the URL may be encoded.

  • clienturlfunction(funcName)—Generates a client-side JavaScript function that can generate a URL back to this Web script.

  • argreplace(argString, argName, argValue, ...)—Replaces the specified argName with argValue or adds argName if it does not exist in argString.

  • encodeuri(uriString): Encodes the string into URL-safe form.

The out-of-the-box, pre-built Web scripts provide plenty of examples demonstrating how to use these methods. Imagine, though, you need to output the complete URL that was used to invoke a Web script. This is achieved using:

${absurl(url.full)}

The url root object represents the URL used to invoke the Web script. Access to the URL path, including its query parameters, is provided by the property named full; however, the URL scheme and authority are not included. To render a full URL, including scheme and authority, the absurl method is used.

REGISTERING AND TESTING

Congratulations. You now have a complete Folder Listing Web script implementation. Now begins the fun of testing.

  1. You first need to register the Folder Listing Web script with Alfresco.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco/service/index
    2. Click Refresh Web Scripts. You'll see a message indicating there is one additional Web script.

  2. Perform your first test.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco/service/dir/Company%20Home
    2. If you see the contents of the Company Home folder listed, your Web script is working.

  3. Next, check the verbose flag.

    1. Type the following in your Web browser:

      http://localhost:8080/alfresco/service/dir/Company%20Home?verbose=true
    2. If you see the contents of the Company Home folder listed in verbose form, your Web script is working.

  4. Finally, check the error handling of a folder that does not exist:

    1. Type the following in your Web browser:

      http://localhost:8080/alfresco/service/dir/doesnotexist
    2. If you see an error page detailing a 404 status response, your Web script is working.

When testing status response codes, it is useful to test with the cURL client, as this gives you access to the status code sent on the HTTP response. For example, to repeat the 'folder does not exist' test with cURL, type the following in your command line:

curl -uadmin:admin -v "http://localhost:8080/alfresco/service/dir/doesnotexist"

The returned response is similar to the following, where the 404 status code is explicitly logged:

* About to connect() to localhost port 8080 (#0)
*   Trying ::1... connected
* Connected to localhost (::1) port 8080 (#0)
* Server auth using Basic with user 'admin'
> GET /alfresco/service/dir/doesnotexist HTTP/1.1
> Authorization: Basic YWRtaW46YWRtaW4=
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Server: Apache-Coyote/1.1
< Cache-Control: no-cache
< Pragma: no-cache
< Content-Type: text/html;charset=UTF-8
< Content-Length: 1487
< Date: Tue, 26 Jan 2010 10:28:28 GMT

Each time a Web script component file is modified, the Web script will need to be re-registered via the Web script index page.

Debugging a Controller Script

At some point during the development of a Web script, you may hit an issue for which the solution is not obvious. In this case, it is really useful to be able to step through the controller script code line by line to pinpoint the cause of the issue.

The Alfresco Content Application Server provides a built-in JavaScript Debugger (as shown in Figure 9-2) that can be applied to Web scripts.

FIGURE 9-2

Figure 9.2. FIGURE 9-2

Step through the controller script of your Folder Listing Web script:

  1. You first need to enable the JavaScript Debugger.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco/service/index
    2. Click the Refresh Web Scripts link to ensure the Web Script Framework has cleared its caches, which is required for the JavaScript Debugger.

    3. Click the List Web Scripts link.

    4. Click the Alfresco JavaScript Debugger link.

    5. Click the Enable button, which launches the JavaScript Debugger in a separate window.

  2. Now invoke the Folder Listing Web script.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco/service/dir/Company%20Home
    2. If you see the Folder Listing controller script inside the JavaScript Debugger window, you're ready to debug.

  3. Next, debug the controller script.

    1. Click the Step Over button in the JavaScript Debugger to execute the currently highlighted line.

    2. Interrogate the value of the verbose variable by typing the following in the Expression window of the JavaScript Debugger:

      verbose
    3. Interrogate the value of the {folderpath} token by typing the following in the Expression window of the JavaScript Debugger:

      url.templateArgs.folderpath
  4. Finally, continue Web script execution.

    1. Click the Go button in the JavaScript Debugger.

    2. If you see the output of the Folder Listing Web script in the Web browser, you have successfully used the JavaScript Debugger.

Remember, the JavaScript Debugger is an extremely useful tool for diagnosing the cause of issues. It is also really useful for stepping through other people's controller scripts to learn how they've implemented capabilities and how they've utilized Alfresco's services.

MULTIPLE RESPONSE TEMPLATES

A Web script may support multiple response formats to allow it to be used by a variety of clients. For example, a Web script may render an HTML response for human consumption in a Web browser and render a JSON response for machine consumption by other clients.

So far, your Folder Listing Web script only renders HTML. Now you can add support for JSON:

  1. You first need to log in to Alfresco Explorer.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco
    2. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  2. Create a JSON response template for your Folder Listing example.

    1. In the Create menu, click Create Content.

    2. Enter the name for the Web script in the Name field as follows:

      dir.get.json.ftl
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      {
        "server" : "Alfresco ${server.edition} Edition v${server.version}",
        "folder" :
        {
          "path" : "${folder.displayPath}",
          "name" : "${folder.name}"
        },
        "children" : [
          <#list folder.children as child>
          {
              "isfolder" : <#if child.isContainer>true<#else>false</#if>,
              <#if verbose>
              "modifier" : "${child.properties.modifier}",
              "size" : <#if child.isDocument>
                ${child.properties.content.size?c}<#else>null</#if>,
              "modified" : "${child.properties.modified?date}",
              </#if>
              "name" : "${child.name}"
          }<#if child_has_next>,</#if>
        </#list>
        ]
      }

      Code snippet dir.get.json.ftl

    6. Click Next.

    7. Click Finish.

  3. Next, re-register the Web script.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco/service/index
    2. Click Refresh Web Scripts. You will see a message indicating all Web scripts have been refreshed.

  4. Finally, it's time to test.

    1. Type the following in your command line:

      curl -uadmin:admin "http://localhost:8080/alfresco/service/dir/
      Company%20Home.json"
    2. If you see the contents of the Company Home folder, your response template is working.

Each Web script can support an unlimited number of response templates; however, there can only be one response template for each format. This is enforced by the naming convention for response templates as described in the section "Creating a Response Template".

Your Folder Listing Web script now supports two formats: HTML and JSON. You have seen what happens when the client requests a specific format and the Web script successfully returns the folder contents, but what happens if there is an error?

Type the following in your command line to request the contents of a folder that does not exist in JSON format:

curl -uadmin:admin
"http://localhost:8080/alfresco/service/dir/doesnotexist.json"

The Web script responds with an error response, but in JSON format, as the client requested.

Note

Whenever you change a Web script implementation, including the addition and removal of response templates, you must re-register the Web script via the Web script index.

Response Status Code Templates

Response status code templates allow a Web script to render a custom response for a given status code. This is useful for providing unique information about a status code or to render a custom human-readable interface.

Your Folder Listing Web script returns a 404 (Not Found) status code if the requested folder does not exist in the content repository. By default, the Web script responds with a generic response that provides details about the status, including its descriptive message. This is useful for diagnosis but may not necessarily be consumable by the typical user of the Web script.

Add a custom response status code template that renders a human-readable message when the folder cannot be found:

  1. You first need to log in to Alfresco Explorer.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco
    2. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org > example.

  2. Create the response status code template.

    1. In the Create menu, click Create Content.

    2. Enter the name for the Web script in the Name field, such as:

      dir.get.html.404.ftl
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <html>
         <body>
           Alfresco ${server.edition} Edition v${server.version} : dir
           <p>
           Folder <b>${url.templateArgs.folderpath}</b> not found.
         </body>
      </html>

      Code snippet dir.get.html.404.ftl

    6. Click Next.

    7. Click Finish.

  3. Next, re-register the Web script.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco/service/index
    2. Click Refresh Web Scripts. You'll see a message indicating all Web scripts have been refreshed.

  4. Finally, it's time to test.

    1. Type the following in your Web browser:

      http://localhost:8080/alfresco/service/dir/doesnotexist
    2. If you see the custom message, your response status code template is working.

As with all Web script component files, response status code template file names adhere to a naming convention as defined by the Web Script Framework. The appropriate response status code template is searched for in the following order:

  1. A template located in the same folder as the Web script description document for rendering a specific status code response, which adheres to the naming convention:

    <web script id>.<http method>.<format>.<status code>.ftl
  2. A template located in the same folder as the Web script description document for rendering a response of any status code, which adheres to the naming convention:

    <web script id>.<http method>.<format>.status.ftl
  3. A package-level template located in the package of the Web script. If the template is not found, it is searched for in the parent package hierarchy, up to the root package for rendering a specific status code; it adheres to the naming convention:

    <format>.<status code>.ftl
  4. A package-level template located in the package of the Web script. If the template is not found, it is searched for in the parent package hierarchy, up to the root package for rendering a response of any status code; it adheres to the naming convention:

    <format>.status.ftl
  5. A template located in the root package for rendering an HTML response for the specific status code, which adheres to the naming convention:

    <status code>.ftl
  6. A template located in the root package for rendering an HTML response of any status code, which adheres to the naming convention:

    status.ftl

Response status code templates have access to the same root objects as normal Web script response templates, with the exception that the default templates <code>.ftl and status.ftl only have access to the root objects url, status, server, and date.

When developing Web scripts, a useful tip is to leave the implementation of response status code templates until the end, as the templates are not essential to the Web scripts' execution. Testing can take place without custom response status code templates, as the Web Script Framework will always eventually find the default template status.ftl in the root package.

As with all other response templates, the addition and removal of a response status code template requires the Web script to be re-registered.

STEP-BY-STEP: KNOWLEDGE BASE SEARCH WEB SCRIPT

It is time to build your Web script for supporting the Knowledge Base sample application. The Web script in question provides the back-end search capability for querying Knowledge Base articles within a knowledge base. Knowledge articles are identified by their attached knowledge article aspect and located in the document library of a Knowledge Base site in Alfresco Share. The knowledge article aspect is discussed in detail as part of content modeling in Chapter 5.

The Knowledge Base Search Web script searches the Alfresco content repository for Knowledge Base articles within a specified Alfresco Share site using the Alfresco FTS (Full Text Search) query language. It returns a JSON-formatted response containing the found articles.

You can now get started.

  1. You first need to log in to Alfresco Explorer.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco
    2. Navigate to Company Home > Data Dictionary > Web Scripts Extensions.

  2. Create a folder to represent the top-level package structure. You may skip this step if the org space already exists.

    1. In the Create menu, click Create Space.

    2. Enter the name for the folder in the Name field, such as:

      org
    3. Click Create Space.

  3. Next, create a sub-package. You may skip this step if the example space already exists.

    1. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org.

    2. In the Create menu, click Create Space.

    3. Enter the name for the folder in the Name field, such as:

      example
  4. You can now create a Web script description document for your Knowledge Base Search.

    1. In the Create menu, click Create Content.

    2. Enter the name for the Web script in the Name field, as follows:

      kb-search.get.desc.xml
    3. In the Content Type list, select XML.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <webscript>
         <shortname>Knowledge Base Search</shortname>
         <description>Searches for knowledge base articles</description>
         <url>/slingshot/knowledgebase/search/site/{site}?maxResults={maxResults?}
      </url>
         <format default="json">argument</format>
         <authentication>user</authentication>
      </webscript>

      Code snippet kb-search.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Next, create a controller script for your Knowledge Base Search Web script.

    1. In the Create menu, click Create Content.

    2. Enter the name in the Name field, such as:

      kb-search.get.js
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      /**
       * KnowledgeBase Search Component
       *
       * Inputs:
       *   mandatory: siteId = site ID to search in
       *   optional:  maxResults = max items to return.
       *
       * Outputs:
       *   data.items/data.error - object containing list of search results
       */
      
      /**
       * Search constants
       */
      const DEFAULT_MAX_RESULTS = 500;
      const SITES_SPACE_QNAME_PATH = "/app:company_home/st:sites/";
      
      /**
       * Performs a search for knowledge base articles in a site
       *
       * @method doSearch
       * @param siteId {string} The site to search in
       * @param maxResults {int} Maximum number of results to return
       * @return {array} Articles matching the query
       */
      function doSearch(siteId, maxResults)
      {
         // The initial template
         var alfQuery =
           'ASPECT:"{http://www.alfresco.org/model/knowledgebase/1.0}article"' +
           ' AND PATH:"' + SITES_SPACE_QNAME_PATH + '/cm:' + siteId +
           '/cm:documentLibrary//*"' +
           ' AND NOT TYPE:"{http://www.alfresco.org/model/content/1.0}thumbnail"' +
           ' AND NOT TYPE:"{http://www.alfresco.org/model/content/1.0}folder"';
      
         // Perform fts-alfresco language query for articles
         var queryDef = {
            query: alfQuery,
            language: "fts-alfresco",
            page: {maxItems: maxResults},
            templates: []
         };
      // Get article nodes
         var nodes = search.query(queryDef),
            articles = [],
            item;
      
         // Turn nodes into article objects
         for (var i = 0, j = nodes.length; i < j; i++)
         {
            // Create core object
            node = nodes[i];
            item =
            {
               nodeRef: node.nodeRef.toString(),
               type: node.typeShort,
               name: node.name,
               title: node.properties["cm:title"],
               description: node.properties["cm:description"],
               modifiedOn: node.properties["cm:modified"],
               modifiedByUser: node.properties["cm:modifier"],
               createdOn: node.properties["cm:created"],
               createdByUser: node.properties["cm:creator"],
               author: node.properties["cm:author"],
               nodeDBID: node.properties["sys:node-dbid"],
               properties: {}
            };
      
            // Calculate display names for users
            var person = people.getPerson(item.modifiedByUser);
            item.modifiedBy = (person != null ? (person.properties.firstName +
              " " + person.properties.lastName) : item.modifiedByUser);
            person = people.getPerson(item.createdByUser);
            item.createdBy = (person != null ? (person.properties.firstName +
              " " + person.properties.lastName) : item.createdByUser);
      
            // Add the Article namespace properties
            for (var k in node.properties)
            {
               if (k.match("ˆ{http://www.alfresco.org/model/knowledgebase/1.0}") ==
                 "{http://www.alfresco.org/model/knowledgebase/1.0}")
               {
                  item.properties["kb_" + k.split('}')[1]] = node.properties[k];
               }
            }
            articles.push(item);
         }
      
         return articles;
      }
      
      /**
       * The WebScript bootstrap method
       *
       * @method main
       */
      function main()
      {
         // Gather webscript parameters
         var siteId = url.templateArgs.site;
         var maxResults = (args.maxResults !== null) ? parseInt(args.maxResults) :
           DEFAULT_MAX_RESULTS;
      
         // Perform search
         var articles = doSearch(siteId, maxResults);
      
         // Generate model from results
         model.data = {
            items: articles
         };
      }
      
      main();

      Code snippet kb-search.get.js

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  6. Create a response template for your Knowledge Base Search Web script.

    1. In the Create menu, click Create Content.

    2. Enter the name in the Name field, such as:

      kb-search.get.json.ftl
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <#escape x as jsonUtils.encodeJSONString(x)>
      {
         "items":
         [
            <#list data.items as item>
            {
               "nodeRef": "${item.nodeRef}",
               "type": "${item.type}",
               "name": "${item.name}",
               "title": "${item.title!''}",
               "description": "${item.description!''}",
               "modifiedOn": "${xmldate(item.modifiedOn)}",
               "modifiedByUser": "${item.modifiedByUser}",
               "modifiedBy": "${item.modifiedBy}",
               "createdOn": "${xmldate(item.createdOn)}",
               "createdByUser": "${item.createdByUser}",
      "createdBy": "${item.createdBy}",
               "author": "${item.author!''}",
               "nodeDBID": "${item.nodeDBID}",
               "properties":
               {
               <#assign first=true>
               <#list item.properties?keys as k>
                  <#if item.properties[k]??>
                     <#if !first>,<#else><#assign first=false></#if>"${k}":
                        <#assign prop = item.properties[k]>
                        <#if prop?is_date>"${xmldate(prop)}"
                        <#elseif prop?is_boolean>${prop?string("true", "false")}
                        <#elseif prop?is_enumerable>[
                           <#list prop as p>
                              "${p}"<#if p_has_next>, </#if>
                           </#list>]
                        <#elseif prop?is_number>${prop?c}
                        <#else>"${prop}"
                     </#if>
                  </#if>
               </#list>
               }
            }<#if item_has_next>,</#if>
            </#list>
         ]
      }
      </#escape>

      Code snippet kb-search.get.json.ftl

  7. Now register the Knowledge Base Search Web script with Alfresco.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco/service/index
    2. Click Refresh Web Scripts. You'll see a message indicating there is one additional Web script.

How Does Knowledge Base Search Work?

Authentication is required, as the Web script needs to query the Alfresco content repository.

The Knowledge Base site to search is passed in as a value within the Web script URI path through the {site} token. An Alfresco FTS (Full Text Search) query statement is constructed, which searches within the content repository path that represents the document library of the specified site:

/app:company_home/st:sites/cm:{site}/cm:documentLibrary

The query also filters results to knowledge articles by selecting only items that have the knowledge article aspect attached.

Having constructed the query statement, the query is executed through the search root object where the result set is optionally constrained to a maximum number of items, as specified by the {maxResults} URI query parameter.

Each row of the result set is converted to a knowledge-article item whose properties are fully calculated where necessary, such as the calculation of the author's full name. The converted result set is placed into the Web script model with the name data.

A default JSON response format is specified in the Web script descriptor, for which a single response template is provided. Each knowledge article item in the data model is visited and rendered into JSON. To ensure valid JSON is generated, the template utilizes the FreeMarker escape capability in conjunction with the Web script JSON encoding helper named jsonUtils.encodeJSONString().

Testing Knowledge Base Search

You can't test the Knowledge Base Search Web script unless there are some knowledge articles to search for. To create knowledge articles you will develop another Web script, which first constructs an Alfresco Share site with a document library and then adds a knowledge article into the document library. The Web script may be executed repeatedly to create further knowledge articles.

  1. You first need to log in to Alfresco Explorer.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco
    2. Navigate to Company Home > Data Dictionary > Web Scripts Extensions.

  2. Create a folder to represent the top-level package structure. You may skip this step if the org space already exists.

    1. In the Create menu, click Create Space.

    2. Enter the name for the folder in the Name field, such as:

      org
    3. Click Create Space.

  3. Next, create a sub-package. You may skip this step if the example space already exists.

    1. Navigate to Company Home > Data Dictionary > Web Scripts Extensions > org.

    2. In the Create menu, click Create Space.

    3. Enter the name for the folder in the Name field, such as:

      example
  4. You can now create a description document for your Create Knowledge Base Web script.

    1. In the Create menu, click Create Content.

    2. Enter the name for the Web script in the Name field, as follows:

      kb-create.get.desc.xml
    3. In the Content Type list, select XML.

    4. Click Next.

    5. Type the following in the Enter Content box:

      <webscript>
         <shortname>Create Knowledge Base</shortname>
         <description>Create knowledge base article for testing</description>
         <url>/slingshot/knowledgebase/create</url>
         <authentication>user</authentication>
      </webscript>

      Code snippet kb-create.get.desc.xml

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  5. Next, create a controller script for your Knowledge Base Create Web script.

    1. In the Create menu, click Create Content.

    2. Enter the name in the Name field, such as:

      kb-create.get.js
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      // establish site with document library
      var doclib = null;
      var site = siteService.getSite("kbtest");
      if (site == null) {
         site = siteService.createSite(null, "kbtest", "KB Search Test",
           "KB Search Test", siteService.PUBLIC_SITE);
         doclib = site.createContainer("documentLibrary");
         site.save();
         doclib.save();
      } else {
         doclib = site.getContainer("documentLibrary");
      }
      
      // create knowledge article
      var article = doclib.createNode("article", "cm:content");
      article.addAspect("kb:article");
      article.properties["cm:name"] = "article" + doclib.children.length;
      article.properties["kb:articletype"] = "FAQ";
      article.content = "The attached tutorial...";
      article.save();
      
      // create model
      model.article = article;

      Code snippet kb-create.get.js

    6. Click Next.

    7. Click Finish.

    8. Click OK.

  6. Create a response template for your Knowledge Base Create Web script.

    1. In the Create menu, click Create Content.

    2. Enter the name in the Name field, such as:

      kb-create.get.html.ftl
    3. In the Content Type list, select Plain Text.

    4. Click Next.

    5. Type the following in the Enter Content box:

      Created ${article.name} within site 'kbtest'.

      Code snippet kb-create.get.json.ftl

  7. Now register the Knowledge Base Create Web script with Alfresco.

    1. Type the following in your Web browser, and log in with the user name admin and password admin if requested:

      http://localhost:8080/alfresco/service/index
    2. Click Refresh Web Scripts. You'll see a message indicating there is one additional Web script.

You can now create some test data for the Knowledge Base Search Web script. Type the following in your command line to create the Alfresco Share site named kbtest and an initial knowledge article:

curl -uadmin:admin
"http://localhost:8080/alfresco/service/slingshot/knowledgebase/
create"

If successful, the response is:

Created article1 within site 'kbtest'.

You may repeat the command to create further knowledge articles.

With data created, it is finally time to test the Knowledge Base Search Web script. Type the following in your command line:

curl -uadmin:admin
"http://localhost:8080/alfresco/service/slingshot/knowledgebase/
search/site/kbtest"

If successful, the response is similar to the following, where each knowledge article is represented in JSON.

{
  "items":
  [
    {
      "nodeRef":
        "workspace://SpacesStore/1016b656-6288-4e17-be30-787138d1693b",
      "type": "cm:content",
      "name": "How to Create Content Models",
      "title": "",
      "description": "",
      "modifiedOn": "2010-01-29T10:57:59.608Z",
      "modifiedByUser": "admin",
      "modifiedBy": "Administrator ",
      "createdOn": "2010-01-29T10:57:59.451Z",
      "createdByUser": "admin",
      "createdBy": "Administrator",
      "author": "",
      "nodeDBID": "614",
      "properties":
        {
          "kb_articletype": "FAQ",
          "kb_status": "Draft"
        }
    }
  ]
}

You've now completed your first set of Web scripts that interact with the Alfresco Content Application Server. You'll see how they are used in Chapters 1416, which go through the exercise of building the Knowledge Base application in Alfresco Share.

COMPLEX ROOT OBJECTS REFERENCE

There are many root objects available to Web scripts. Most are just scalars whose value can be read and potentially updated; however, some root objects are more complex and have structures of their own. This reference details those complex root objects.

url

url is a root object providing access to the URL (or parts of the URL) that triggered the Web script. Access to the URL parts is via the following properties on the url object:

  • context—(read-only string) Alfresco context path.

  • serviceContext—(read-only string) Alfresco service context path.

  • service—(read-only string) Web script path.

  • full—(read-only string) Web script URI with query parameters.

  • templateArgs—(read-only map) A map of substituted token values (within the URI path) indexed by token name.

  • args—(read-only map) Web script URI query parameters.

  • match—(read-only string) The part of the Web script URI that matched the Web script URI template.

  • extension—(read-only string) The part of the Web script URL that extends beyond the match path (if there is no extension, an empty string is returned).

For example, imagine a Web script URI template of:

/user/{userid}

When the following URI is requested:

/alfresco/service/user/fred?profile=full&format=html

The url root object returns:

  • url.context => /alfresco

  • url.serviceContext => /alfresco/service

  • url.service => /alfresco/service/user/fred

  • url.full => /alfresco/service/user/fred?profile=full&format=html

  • url.args => profile=full&format=html

  • url.templateArgs.userid => fred

  • url.match => /user/

  • url.extension => fred

status

The status object represents a response status. The following properties allow for access to the status or the setting of a new status.

  • code—(read/write int) Status code; this is primarily an HTTP status code, but can be any number.

  • codeName—(read-only string) Human-readable status code name.

  • codeDescription—(read-only string) Human-readable status code description.

  • message—(read/write string) The status message.

  • redirect—(read/write Boolean) Indicates whether to redirect to a status-specific response template.

  • exception—(read/write java.lang.Exception) The exception, if any, that has caused this status.

  • location—(read/write string) The absolute URI to which the client should resubmit a request; this is often used with 3xx redirect status codes.

cache

The cache object allows control over how the Web script response is cached. Caching is controlled via the following properties.

  • neverCache—(read/write Boolean) Controls whether Web script response should be cached at all; true means never cache. If not set, the default value is specified by the cache control section of the Web script definition.

  • isPublic—(read/write Boolean) Controls whether Web script response should be cached by public caches. If not set, the default value is specified by the cache control section of the Web script definition.

  • mustRevalidate—(read/write Boolean) Controls whether cache must revalidate its version of the Web script response to ensure freshness. If not set, the default value is specified by the cache control section of the Web script definition.

  • maxAge—(read/write long) Specifies the maximum amount of time (in seconds, relative to the time of request) that the response will be considered fresh. If not set, the default value is null.

  • lastModified—(read/write date) Specifies the time that the content of the response last changed. If not set, the default value is null.

  • ETag—(read/write string) Specifies a unique identifier that changes each time the content of the response changes. If not set, the default value is null. This is useful for indicating to a client cache when content has changed.

format

The format object represents the chosen format of the rendered response. The format is interrogated via the following properties.

  • Name—(read-only string) Format name

  • Mimetype—(read-only string) MIME type associated with format

webscript

The webscript object provides metadata describing the Web script currently being executed. Web script metadata is accessed via the following properties of the webscript object.

  • id—(read-only string) The Web script identifier

  • shortName—(read-only string) The Web script short name

  • description—(read-only string) The Web script description

  • defaultFormat—(read-only string) The default response format if none is explicitly specified in the Web script URI

  • formatStyle—(read-only string) The accepted ways of specifying the format in the Web script URI

  • URIs—(read-only string array) URI templates

  • method—(read-only string) HTTP method

  • requiredAuthentication—(read-only string) Required level of authentication

  • requiredTransaction—(read-only string) Required level of transaction

  • storePath—(read-only string) The path of the persistent store where the Web script is stored

  • scriptPath—(read-only string) The path (within storePath) of Web script implementation files

  • descPath—(read-only string) The path (within storePath) of the Web script description document

server

The server object provides metadata describing the host Alfresco server within which the Web script is currently being executed. Server metadata is accessed via the following properties of the server object.

  • versionMajor—(read-only string) Server major version number; for example 1.2.3

  • versionMinor—(read-only string) Server minor version number; for example 1.2.3

  • versionRevision—(read-only string) Server revision number; for example 1.2.3

  • versionLabel—(read-only string) Server version label; for example, Dev

  • versionBuild—(read-only string) Server build number; for example, build-1

  • version—(read-only string) Server version; for example, major.minor.revision (label)

  • edition—(read-only string) Server edition; for example, Enterprise

  • schema—(read-only string) Server schema; for example, 10

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.131.212